实现 new \ deepClone \ call \ apply \ bind

71 阅读3分钟

1.new实现:

new实现步骤:

1. 创建一个空对象
2.设置该对象的_proto_为构造函数的prototype
3.将构造函数内的this指向1步骤中创建的空对象,执行构造函数;
4.判断函数的返回值类型,如果是值类型,返回创建的对象obj。如果是引用类型,就返回这个引用类型的对象。

function Father () {
  ...
}

// 使用 new 实现
var child = new Father(...);
// 使用 objectFactory 实现
var child = objectFactory(Father,...)

function objectFactory() {
   // 创建一个对象
   var obj = new Object(),
   // 取第一个参数
   Constructor = [].shift.call(arguments);
   // 让新建对象的 __proto__ 属性会指向构造函数的 prototype
   obj.__proto__ = Constructor.prototype;
   // 将 this 指向新建对象,并执行函数
   var res = Constructor.apply(obj, arguments);
   // 判断返回值是不是一个对象
   return typeof res === 'object' ? res : obj;

};

2. 深拷贝

// 第一种实现:
function deepCopy(object) {
  if (!object || typeof object !== "object") return object;
 
  let newObject = Array.isArray(object) ? [] : {};
 
  for (let key in object) {
    if (object.hasOwnProperty(key)) {
      newObject[key] = deepCopy(object[key]);
    }
  }
 
  return newObject;
}
 
 
// 第二种实现:
// 缺点:不能拷贝函数。
const deepClone = (obj) => {
    if (obj) {
        let str = JSON.stringify(obj);
        let newObj = JSON.parse(str);
        return newObj;
    } else {
        return {};
    }
}

3. call实现

call 实现步骤
1.判断调用对象是否为函数。
2.判断传入上下文对象是否存在,如果不存在,则设置为 window 。
3.处理传入的参数,截取第一个参数后的所有参数。
4.将函数作为上下文对象的一个属性。
5.使用上下文对象来调用这个方法,并保存返回结果。
6.删除刚才新增的属性。
7.返回结果。

// call函数实现
Function.prototype.myCall = function(context) {
  // 判断调用对象
  if (typeof this !== "function") {
    console.error("type error");
  }
  // 获取参数
  let args = [...arguments].slice(1),
    result = null;
  // 判断 context 是否传入,如果未传入则设置为 window
  context = context || window;
  // 将调用函数设为对象的方法
  context.fn = this;
 
  // 调用函数
  result = context.fn(...args);
 
  // 将属性删除
  delete context.fn;
 
  return result;
};

4. apply实现

apply 实现步骤
1.判断调用对象是否为函数。
2.判断传入上下文对象是否存在,如果不存在,则设置为 window 。
3.将函数作为上下文对象的一个属性。
4.判断参数值是否传入
4.使用上下文对象来调用这个方法,并保存返回结果。
5.删除刚才新增的属性
6.返回结果

Function.prototype.myApply = function(context) {
  // 判断调用对象是否为函数
  if (typeof this !== "function") {
    throw new TypeError("Error");
  }
 
  let result = null;
 
  // 判断 context 是否存在,如果未传入则为 window
  context = context || window;
 
  // 将函数设为对象的方法
  context.fn = this;
 
  // 调用方法
  if (arguments[1]) {
    result = context.fn(...arguments[1]);
  } else {
    result = context.fn();
  }
 
  // 将新增属性删除
  delete context.fn;
  return result;
};

5.bind实现

bind 实现步骤:
1.判断调用对象是否为函数。
2.保存当前函数的引用,获取其余传入参数值。
3.创建一个函数返回。
4.函数内部使用 apply 来绑定函数调用,需要判断函数作为构造函数的情况,这个时候需要传入当前函数的 this 给 apply 调用,其余情况都传入指定的上下文对象。

Function.prototype.myBind = function(context) {
  // 判断调用对象是否为函数
  if (typeof this !== "function") {
    throw new TypeError("Error");
  }
  // 获取参数
  var args = [...arguments].slice(1),
    fn = this;
 
  return function Fn() {
    // 根据调用方式,传入不同绑定值
    return fn.apply(
      this instanceof Fn ? this : context,
      args.concat(...arguments)
    );
  };
};

参考文档:

github.com/CavsZhouyou…

github.com/mqyqingfeng…