原型链笔记

124 阅读3分钟

原型链

1.JavaScript中万物皆对象,JavaScript是基于原型的语言。

 => JavaScript 中万物皆为对象,对象皆有原型。
 【几乎所有 JavaScript 中的对象都是位于原型链顶端的 Object 的实例。】

2. 构造函数升级具体化

   ES5时期
   - 普通函数: function function () {}
               但是支持 let cupcustom = new function(); 普通函数能new调用
   - 构造函数: function CupCustom (diameter, height) { // 制作杯子的模具
                   this.diameter = diameter;           // 可传入不同直径
                   this.height = height;               // 可传入不同高度
               } 
               构造函数一般函数名首字母大写;
               但是也支持CupCustom(10, 15); //  构造函数同样也能普通调用
               let cup12 = new CupCustom(10, 15);
               
   ① 构造函数就是普通函数。函数都支持new调用和普通调用。
   ② cupcustom <=> CupCustom , Function <=> functionES6 推出 Class 类: 只支持 new 调用。
         Class Parent {
             addNumber () { console.log('加1'); }
         }
         1) let child1 = new Parent(); // 只支持 new 调用。
            child.addNumber();        // 加1;
         2) let child2 = Parent();     // 普通调用不支持!!!会报错!!!
    
    构造函数属性继承理解:
        构造函数相当于杯子模具;
        let cup1 = new CupCustom(10, 15); 
        let cup2 = new CupCustom(8, 9);
        cup1、cup2 为用模具 new 出来的杯子。 
        =>【杯子即实例】;
        =>【即杯子继承了模具的直径和高度】。
        =>【实例 可以继承 构造函数的构造器属性(直径和高度)】
        CupCustom.prototype.color = 'blue';
        =>【实例 可以继承构造器属性 又可以 继承原型属性(颜色)】
        注意: 颜色属性存放在'__proto__'上面。
        
        => 【所有的对象都有__proto__属性,但只有函数拥有 prototype 属性。】
           (js类型中仅 nullundefined 没有 __proto__属性)
        => 【构造函数有:自身属性 + __proto__属性 + prototype属性(仅构造函数本身有)】
        
        __proto__: 
                 - 是访问器属性;
                 - 是实例的属性,指向 创造它的 构造函数的prototype。
                 - 所以,杯子通过 __proto__的指向 找到了模具的prototype,
                        从而访问prototype上的原型属性color。
                 - 即:【实例通过__proto__指向 访问到了构造函数的prototype上的所有原型属性。】
        
    ③ 因为CupCustom模具本身是构造函数所以有prototype, 同时它也是由构造函数Function
     new出来的实例所以CupCustom的__proto__指向构造函数Function的原型。
    ④【每一个函数都属于原始构造函数Function的实例,而每一个函数又能做为构造函数生产属于自己的实例】
    ⑤  let F = new Function; 
       F.__proto__ = Function.prototype;
       Function.prototype.constructor = Function; 
                // prototype下constructor指向当前本身构造函数
       【F.__proto__ 通过指向Function的prototype找到constructor。】
     注释:很多人说实例的`constructor`指向创建自己的构造函数,但通过打印我们可以发现,
          实例自己并没有`constructor`属性,而是通过`__proto__`属性,找到了构造函数的原型,
          而构造函数的原型中有一个`constructor`属性指向自己。
          
     原型链:
           let F = new Function;
           首先查找F自身是否具有某一属性,没有,就顺着F的__proto__往上查找创建F的构造函数
           的原型上是否具有,没有,就沿着F的构造函数的原型对象的__proto__指向的构造
           函数Object()的原型上找,还没有,就返回undefined。因为在往上就是null.
           
           实例fn:{__proto__: ..., ...}
           构造函数Fn:{prototype: {
                                  constructor: 该构造函数本身
                                  __proto__: {
                                              constructor: Object(),
           // 这里的constructor继承了 Fn的构造函数 的prototype下的constructor
           // Fn的构造函数 的prototype被__proto__继承而来,指向Fn的构造函数Object()
           // console.log(Object.prototype.__proto__)  为null
                                             ...
                                              },
                                  ...},
                      ...}
                      
      总结:
        1) null<-- 构造函数Object()<-- 构造函数Fn()<--构造函数Fn-1()...构造函数F1()
        原型链顶端.....................__proto__............................实例
        2) 未修改prototype时:
                Fn.prototype.constructor指向自身构造函数,值为Fn
                Fn.prototype.__proto__.constructor指向Fn的构造函数
        3) 每个函数function都有一个`prototype`,即显式原型(属性);
        4) 每个实例对象都有一个 `__proto__`,即隐式原型(属性 )

注: [[prototype]],双中括号中的属性是系统的内置属性。

prototype.png

参考文档:

原型和原型链重详细 原型和原型链重图解