new运算符、bind、Object.create、instanceof实现原理探讨

lihaixing
如何手写new运算符、bind方法、Object.create

一、new 运算符

  • 首先我们自己写new运算符,无法写成 NEW F()这种方法,因为js不识别呀,所以只能将第一个参数看做构造函数,剩余是其它传参,例如
let m = NEW(M,'lihaixing',30);
// 等同于js中的
let m = new M('lihaixing',30);
  • 然后就开始吧!
function NEW(){
    // 获取参数
    let func = arguments[0]; // 构造函数
    let paras = [].slice.call(arguments,1); // 传入的参数
    // 继承func.prototype的属性
    let o = Object.create(func.prototype);
    // 继承构造函数中的属性
    func.call(o,..paras);
    return o;
}
  • 测试一下,并和js原生的new对比一下

    function M (name, age) {
      this.name = name;
      this.age = age;
    }
    
    M.prototype.sayYear = () => {
      console.log('2018');
    }
    
    let m = NEW(M, 'haixing', 30); 
    let mm = new M('haixing', 30);
    • 在控制台中依次输入m, mm, m.sayYear, mm.sayYear调用,结果如下

    图片描述

    • 一某一样,那就进入下一个环节!

    二、bind方法手写

    • bind方法其实和call非常一样,唯一的区别就是,call会将函数绑到对象中,并且调用;而bind只是将函数绑到对象中,并不调用,也就是:
f.call(obj)
// 等同于
f.bind(obj)();
  • 那么该怎么写呢?我们知道bind方法是在绑在函数上的,而在js中,每个函数都是一个new Function(), 也就是和实例对象差不多了,所以我们要想使每个函数都能调用bind方法,就应该把它放在Function.prototype中,这样就是把bind方法写到了每个函数的原型中。
Function.prototype.BIND = function () {
    // this指向的就是我们的函数哦
    let self = this;
    // 获取参数,由于return中的函数也有arguments, 这里需重新赋值一下
    let paras = arguments;
    return function () {
        self.call(...paras); // 不要忘记解构
    }
}

优化一下,有助于函数科里化

Function.prototype.Bind = function(obj,...args1){
    const self = this;
      return function(...args2){
        self.call(obj,...args1,...args2)
    }
}
  • 然后测试一下, 这里M还是上一节中的M构造函数
let c = {};
let cc = {};
M.BIND(c, 'haixing', 31)();
M.bind(cc, 'haixing', 31)();
  • 结果如下

图片描述

  • 好像也没啥问题,但是c和cc是一个字面量对象, 那如果c和cc是构造函数生成的实例对象,那会如何呢?继续上代码:
function A (name, age) {
    this.name = name;
    this.age = age;
}

let d = new A('haixi', 22);
let dd = new A('haixi', 22);
M.BIND(d, 'haixing', 31)();
M.bind(dd, 'haixing', 31)();

图片描述

  • 还是没问题哈,constructor也是对的, 那就进入下一环节吧

    三、Object.create怎么写?

// 这个要简单一些,就直接写了
Object.CREATE= function (obj, properties) {
    function F () {}
    F.prototype = obj;
    let o = new F();
    // 注意Object.create可以传入第二个参数,是一个对象,但格式必须是Object.defineProperties()方法一样
    if (typeof properties === 'object') {
        Object.defineProperties(o, properties);
    }
    return o;
}

let e = Object.create(d, {year: {value: 2019}});
let ee = Object.CREATE(d, {year: {value: 2019}});
  • 上图看执行结果

图片描述

  • 奇怪哈,为什么一个显示A一个显示F呢,但两个都是A的实例啊?哪位知道,欢迎留言

四、instanceof

Object.prototype.Instanceof = (M){
      let o = this;
    while(o){
      if(o.__proto__ === M.prototype){
          return true
      }
      o = o.__proto__ 
    }
  return false
}
阅读 3.2k

大前端
专注前端开发,分享技术难题,共同进步
31 声望
6 粉丝
0 条评论
你知道吗?

31 声望
6 粉丝
宣传栏