原型链

150 阅读2分钟

创建对象的3种方法

  //方法一:
  var o1 = {name: 'o1'};
  var o11 = new Object({name: 'o11'});

  //方法二:
  var M = function () {
      this.name = 'o2';
  }
  var o2 = new M();

  //方法三:
  var p = {name: 'o3'};
  var o3 = Object.create(p);

new Object()Object.create()区别:

  • {} 等同于 new Object(), 原型对象是 Object.prototype
  • Object.create(null) 没有原型
  • Object.create({...}) 可以指定原型

原型链

看图说话:

  1. 一个函数f 被new f() 操作会成为构造函数;
  2. 构造函数有prototype属性(其实所有函数都有prototype属性)指向 原型对象;所以当我们给数组统一添加方法的时候,即给原型对象上添加方法:
Array.prototype.flatter = function(){}  

所有数组的实例都可以使用flatter方法。

  1. 实例对象有__proto__属性,也是指向原型对象的;
  2. 原型对象有一个constructor属性指向构造函数;
  3. 原型对象也可以看成一个对象实例,也有__proto__属性,指向它的原型对象。
  4. 构造函数的原型对象的__proto__会指向 Object.prototype, Object.prototype.__proto__ 最终指向 null
  function Person(name){
      this.name = name;
  }
  let p = new Person("William");
  console.log(Person.prototype.__proto__ === Object.prototype);   //true
  console.log(Object.prototype.__proto__);               //null

instanceof 实际是什么?

p instance Person; 其实看的是 p._proto_ 跟 Person.prototype 是否指向同一个对象。

手写 instanceof

  function myinstanceof(L, R){
      const t = L.__proto__;
      if(t===null){
          return false;
      }
      if(t===R.prototype){
          return true;
      }else{
          return myinstanceof(t, R);
      }
  }

new操作运算符做了什么?

  1. 创建了一个对象o;
  2. 将对象o的__proto__指向 构造函数 的 prototype,即使得 o的__proto_指向 原型对象;
  3. 转换上下文到o对象执行构造函数体里面的逻辑,得到结果 result;
  4. 判断result 结果是否是 object 类型;如果是,返回 result; 如果不是返回 o 对象。
    const create = function(fn, ...rest){
        let o = {};
        o.__proto__ = fn.prototype;
        // 等价于 
        // let o = Object.create(fn.prototype); 
        
        let result = fn.apply(o, rest);
        if(typeof result==='object'){
            return result;
        }else{
            return o;
        }
    }
    function Person(name, age) {
        this.name = name;
        this.age = age;
    }

    let p = create(Person, 'zs', 12);
    console.log(p);

其中,o = Object.create(f), 相当于把o的原型对象指向 f。