• 原型链中的prototype、__proto__和constructor的关系


    先来看一张图,这张图可以说是围绕以下代码完整的描述了各对象之间的关系。接下来我们来看看如何一步步画出这张图。

    function Foo(){};
    var foo = new Foo();

    绘图1

    首先,明确几点概念(现在不懂没关系),后面会不断提到:

    过程1:只要创建一个函数Foo,就会为该函数创建一个prototype属性,这个属性指向函数的原型对象

    过程2:原型对象会默认去取得constructor属性,指向构造函数。

    过程3:当调用构造函数创建一个新实例foo后,该实例的内部将包含一个指针__proto__,指向构造函数的原型对象。

    以上两点,出现了3种对象:构造函数、构造函数的原型、构造函数创建的实例;出现了3种属性:constructor、prototype、__proto__。接下来,我们就围绕这3个对象和3个属性展开讨论。

    原型对象

    1)先来看看第一行代码发生了什么:

    function Foo(){};
    console.log(Foo.prototype.constructor === Foo);//true

    第一行代码定义了一个函数,此时就发生了过程1和过程2,如图:

    image

    (这里的Foo的原型对象一般表示为Foo.prototype,但为了更清晰理解,我们就称之为Foo的原型对象)

    2)再来看看第二行代码

    function Foo(){};
    var foo = new Foo();
    console.log(foo.__proto__ === Foo.prototype);//true

    第二行代码创建了一个实例,发生了过程3,如图:

    image

    仔细观察,可以发现实例foo与构造函数之间是没有直接联系的,所有关系都是通过Foo的原型对象连接起来的。(这一点一定要明确)

    3)foo继承constructor属性

    function Foo(){};
    var foo = new Foo();
    console.log(foo.constructor === Foo);//true
    console.log(foo.hasOwnProperty("constructor"));//false

    实例对象foo与Foo之间没有直接联系,但foo继承了Foo的原型对象的constructor的属性,有了间接的联系。通过hasOwnProperty函数(判断对象是否拥有某个属性,不检查原型链)可以看出,实例对象foo本身没有constructor属性。

    image

    小结:到这里,博客最开始的两行代码的所有过程就结束了。不过这只是露在外面的冰山一角,我们来看看冰山下面有什么。

    默认原型

    我们知道,所有引用对象都默认继承了Object,所有函数的默认原型都是Object的实例。

    1)同上,Object与其原型对象之间也存在如下关系

    image

    2)既然函数的默认原型都是Object的实例,那么类似以上创建foo实例时的过程,自然有了以下关系:

    image

    注意一点,此时Foo的原型对象有自己的constructor属性,自然就不用继承Object原型对象的了,所以仍然指向Foo,而不是Object。

    3)Object的原型对象的原型

    Object的原型对象已经是最根部了,所以它没有__proto__属性。

    console.log(Object.prototype.__proto__);

    image

    Function

    我们知道,函数也是对象,任何函数都可以看作是由构造函数Function实例化的对象。

    1)同上,Function与其原型对象之间也存在如下关系

    image

    2)如果将Foo函数看作实例对象的话,其构造函数就是Function(),原型对象自然就是Function的原型对象;同样Object函数看作实例对象的话,其构造函数就是Function(),原型对象自然也是Function的原型对象。

    image

    3)Function的__proto__指针

    Function自身可以看作通过构造函数Function实例化的对象,所以Function的__proto__指针指向Function的原型对象

    image

    4)Function的原型对象的__proto__指针

    如果Function的原型对象看作实例对象的话,如前所述所有对象都可看作是Object的实例化对象,所以Function的原型对象的__proto__指向Object的原型对象。

    image

    总结:

    到这里,创建一个实例对象foo时内部的联系就都说清楚了。观察图可以发现,只有一个入口(foo),一个出口(null),所以每一个对象都是同一个起源。

  • 相关阅读:
    <JavaScript> 组合继承
    <JavaScript> 稳妥构造函数模式与工厂模式的区别
    <JavaScript> call()、apply()、bind() 的用法
    <JavaScript>可枚举属性与不可枚举属性
    <JavaScript>闭包(closure)
    在MongoDB中实现聚合函数
    (转)如何入门 Python 爬虫
    Python爬虫实战四之抓取淘宝MM照片
    转载:十年驾车经验总结:活着,才是硬道理
    设计模式之单例模式的七种写法
  • 原文地址:https://www.cnblogs.com/youhong/p/6838611.html
Copyright © 2020-2023  润新知