对于JS原型链的浅层理解

298 阅读3分钟

每个对象,不管是对象直接量、还是构造函数创建的对象,都与另外一个对象关联,这个对象就是我们所说的原型。这里有两个重要的、容易混淆的项:__proto__和prototype。

(1)__proto__:是指向父构造器prototype的引用,称原型属性,就是我们所说的原型。所有实例对象都具有__proto__。

(2)prototype:称原型对象,子类就是从父类的prorotype继承属性,或者实例对象从对应的构造器上继承属性。所有构造器都具有prototype,用于被子构造器或者由他生成的实例对象继承。

设N1、N2、N3是构造器,n3是N3的实例对象,其中N1的父构造器是Object,N1是N2的父亲、N2是N3的父亲,则满足以下:

 n3.__proto__ === N3.prototype 
 N3.prototype.__proto__ === N2.prototype
 N2.prototype.__proto__ === N1.prototype
 N1.prototype.__proto__ === Object.prototype
 Object.prototype.__proto__ === null

简单来说,所有对象实例都会通过__proto__去继承父构造器的prototype上的属性,所有构造器若存在父构造器,都会继承父构造器的prototype上属性,以此类推,直至最终Object.prototype。而非prototype上的属性是不会被继承的。以上这种链式继承结构成为原型链。

如何实例化一个对象?

实例对象是通过构造器的constructor构造的,而任意构造器N满足:

 N.prototype.constructor = N

因此实例化一个n可以:

 let n = new N()
 或者
 let n = new N.prototype.constructor()

由于根据原型链知:n.__proto__ === N.prototype,因此在已知已有实例n的情况下,可以通过以下方式去实例化一个实例n_,效果等同于上述的实例化方法。

 let n_ = new n.__proto__.contructor() 

简单描述继承关系

为方便理解,给出以下定义:

(1)从构造器继承而来的属性称继承属性

(2)实例或者构造器在自身prototype内定义的属性,称其自有prototype属性(或prototype属性)

(3)实例或者构造器定义的非prototype属性称自有属性

    let obj = new Object() 
    //  设置Object的自有属性
    Object.some_property = 'some_property'
    Object.some_property === 'some_property' //true
    
    // 设置Object的prototype属性,结果覆盖其自有属性,返回其自有prototype属性
    Object.prototype.some_property = 'some_property_of_prototype'
    Object.some_property === 'some_property_of_prototype' //true
    
    //*1* 实例不能继承构造器自有属性,继承了其自有prototype属性**
    //*2* 实例生成后,即使更改构造器的自有prototype属性内容,只要实例
    //    没有覆盖这个属性,它获取属性值是个原型链追溯的过程,最终值会与
    //    目标构造器prototype属性值保持一致
    obj.some_property === 'some_property_of_prototype'  //true
    
    //*3* 实例覆盖继承属性,生成自有属性some_property 
    obj.some_property = 'some_property_of_self'
    obj.some_property === 'some_property_of_self' //true
    
    //*4* 删除自有属性,属性值仍从构造器property属性继承
    delete obj.some_property
    obj.some_property === 'some_property_of_prototype'  //true
    
    //*5* 删除构造器自有property属性,实例的属性为undefined
    delete Object.Object.some_property
    obj.some_property === undefined   //true
    

总结

  1. 每个构造器都可以自定义属性,包括自有属性和自有prototype属性,其中prototype属性是可以被子类或者实例继承。

  2. 查找任一实例o的属性x,会从实例自身的自有属性——>构造器自有属性——>构造器自有prototype属性——>...根据原型链依次查找祖先构造器的自有属性、自有prototype属性...——>Object自有属性、自有prototype属性依次遍历,中间一旦找到匹配项,便立即结束查找,返回结果。

  3. 任意构造器O查找属性x,会从构造器自有属性——>构造器自有prototype属性——>...根据原型链依次查找祖先构造器的自有属性、自有prototype属性...——>Object自有属性、自有prototype属性依次遍历,中间一旦找到匹配项,便立即结束查找,返回结果。