20行 手写代码 小片段集合 面试准备

17 阅读3分钟

javascript 基础

instanceof

function myInstanceof(obj, constructor) {
    // 检查参数的有效性
    if (obj === null || typeof obj !== 'object') {
        return false
    }

    // 获取 obj 的原型
    let proto = Object.getPrototypeOf(obj)
    
    // 不断向上遍历原型链,直到找到 constructor.prototype
    while (proto != null) {
        if (proto === constructor.prototype) {
            return true
        }
        proto = Object.getPrototypeOf(proto)
    }
    return false
}
// 测试示例
const strObj = new String('Hello');
console.log(strObj instanceof String);
console.log(myInstanceof(strObj, String)); 
const strObj2 = 'hello';
console.log(strObj2 instanceof String);
console.log(myInstanceof(strObj2, String)); 

new


function myNew(constructor, ...args) {
    // 创建一个新对象,该对象的原型指向构造函数的原型对象
    let obj = Object.create(constructor.prototype)
    // 将构造函数作为普通函数调用,将 this 绑定到新创建的对象上
    const result = constructor.apply(obj, args)
    // 如果构造函数显式返回了一个对象,则返回该对象;否则返回新创建的对象
    return typeof result === 'object' ? result : obj
}

// 测试示例
function Person(name, age) {
    this.name = name;
    this.age = age;
}
Person.prototype.sayHello = function () {
    console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
};
const john = new Person('John', 30)
const john1 = myNew(Person, 'John', 30);
john.sayHello();
john1.sayHello();

call

Function.prototype.myCall = function(context, ...args) {
  // 将函数绑定到指定的上下文
  context = context || window; // 如果没有传入上下文,则默认为全局对象
  context.fn = this;

  // 执行函数,并传入参数列表
  const result = context.fn(...args);

  // 删除临时添加的属性
  delete context.fn;

  // 返回函数执行的结果
  return result;
};

// 测试示例
const obj = {
  name: 'John'
};

function greet(message) {
  console.log(`${message}, ${this.name}`);
}

greet.myCall(obj, 'Hello'); // 输出: Hello, John

apply

Function.prototype.myApply = function (context, argsArray) {
    // 将函数绑定到指定的上下文
    context = context || window; // 如果没有传入上下文,则默认为全局对象
    context.fn = this;

    // 执行函数,并传入参数数组
    const result = context.fn(...argsArray);

    // 删除临时添加的属性
    delete context.fn;

    // 返回函数执行的结果
    return result;
};

// 测试示例
const obj = {
    name: 'John'
};

function greet(message) {
    console.log(`${message}, ${this.name}`);
}
greet.apply(obj, ['hello'])
greet.myApply(obj, ['Hello']); // 输出: Hello, John

bind

Function.prototype.myBind = function(context, ...args) {
  const fn = this; // 要绑定的原函数
  return function(...newArgs) {
    // 合并传入的参数
    const combinedArgs = args.concat(newArgs);
    // 使用 apply 将 fn 函数绑定到指定的上下文,并传入合并后的参数
    return fn.apply(context, combinedArgs);
  };
};

// 测试示例
const obj = {
  name: 'John'
};

function greet(message) {
  console.log(`${message}, ${this.name}`);
}

const boundFn = greet.myBind(obj, 'Hello');
boundFn(); // 输出: Hello, John

防抖

const debounce = (fn, delay) => {
    let timerId = null
    return (...args) => {
        clearTimeout(timerId)
        timerId = setTimeout(() => {
            fn(...args)
        }, delay);
    }
}

柯里化

// 定义一个普通的加法函数
function add(x, y, z) {
    return x + y + z;
}

//  柯里化函数
function curry(fn) {
    return function curried(...args) {

        // 如果接收的参数个数大于等于原始函数的参数个数,则执行原始函数并返回结果
        if (args.length >= fn.length) {
            // return fn(...args)
            return fn.apply(this, args)
        } else {
        // 否则返回一个新的函数,继续接收参数
            return function (...newArgs) {
                return curried.apply(this, args.concat(newArgs))
            }
        }
    }
}

// 使用柯里化函数转换加法函数
const curriedAdd = curry(add);

// 分步调用
const step1 = curriedAdd(2); // 返回一个新的函数
const step2 = step1(3); // 返回一个新的函数
const result = step2(4); // 返回加法结果
console.log(result); // 输出: 9
console.log(curriedAdd(2)(3, 4)); // 输出: 9
console.log(curriedAdd(2, 3, 4)); // 输出: 9

浅拷贝

function shallowCopy(obj) {
    // 如果 obj 不是对象,则直接返回
    if (typeof obj !== 'object' || obj === null) return obj;
    // 创建一个新对象
    const newObj = Array.isArray(obj) ? [] : {};
    // 遍历原始对象的每个属性,并将其复制到新对象中
    for (let key in obj) {
        //如果不加这个if,拷贝的结果会包括继承原型对象的方法
        if (obj.hasOwnProperty(key)) { // 只拷贝对象自身的属性
            newObj[key] = obj[key];
        }
    }
    return newObj;
}


const obj1 = {
    name: 'John', age: 30
};
const obj2 = shallowCopy(obj1);
console.log(obj2); // 输出: { name: 'John', age: 30 }
console.log(obj1 === obj2); // 输出: false
obj1.name = 'Bob';
console.log(obj1); // 输出: { name: 'Bob', age: 30 }
console.log(obj2); // 输出: { name: 'John', age: 30 }

深拷贝

function cloneDeep(obj) {
    if (typeof obj !== 'object' || !obj) return obj
    let newObj = Array.isArray(obj) ? [] : {}
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            //多了一句,判断递归
            newObj[key] = typeof obj[key] === 'object' ? cloneDeep(obj[key]) : obj[key]
        }
    }
    return newObj;
}