zoukankan      html  css  js  c++  java
  • Javascript属性constructor/prototype的底层原理

    在Javascript语言中,constructor属性是专门为function而设计的,它存在于每个function的prototype属性中。

    这个constructor保存了指向function的一个引用。

    在定义一个函数(代码例如以下所看到的)时,

    function F() {
        // some code
     }

    JavaScript内部会运行例如以下几个动作:
    为该函数加入一个原形属性(即prototype对象).
    为prototype对象额外加入一个constructor属性。而且该属性保存指向函数F的一个引用。

    这样当我们把函数F作为自己定义构造函数来创建对象的时候。对象实例内部会自己主动保存一个指向其构造函数(这里就是我们的自己定义构造函数F)的prototype对象的一个属性__proto__。所以我们在每个对象实例中就能够訪问构造函数的prototype所有拥有的所有属性和方法。就好像它们是实例自己的一样。
    当然该实例也有一个constructor属性了(从prototype那里获得的),这时候constructor的作用就非常明显了,由于在这时,每个对象实例都能够通过constrcutor对象訪问它的构造函数,请看以下代码:
     



    [javascript] view plaincopy




    var f = new F();
    alert(f.constructor === F);// output true
    alert(f.constructor === F.prototype.constructor);// output true


    我们能够利用这个特性来完毕以下的事情: 对象类型推断,如



    [javascript] view plaincopy




    if(f.constructor === F) {
        // do sth with F
    }


    事实上constructor的出现原本就是用来进行对象类型推断的,可是constructor属性易变。不可信赖。
    我们有一种更加安全可靠的判定方法:instanceof 操作符。


    以下代码仍然返回true

    if(f instanceof F) {
        // do sth with F
    }.

    原型链继承。因为constructor存在于prototype对象上,因此我们能够结合constructor沿着原型链找到最原始的构造函数,如以下代码:

    function Base() {
    }
    // Sub1 inherited from Base through prototype chain
    function Sub1() {
    }
    Sub1.prototype = new Base();
    Sub1.prototype.constructor = Sub1;
    Sub1.superclass = Base.prototype;
    // Sub2 inherited from Sub1 through prototype chain
    function Sub2() {
    }
    Sub2.prototype = new Sub1();
    Sub2.prototype.constructor = Sub2;
    Sub2.superclass = Sub1.prototype;
    // Test prototype chain
    alert(Sub2.prototype.constructor);
    // function Sub2(){}
    alert(Sub2.superclass.constructor);
    // function Sub1(){}
    alert(Sub2.superclass.constructor.superclass.constructor);
    // function Base(){}

    上面的样例仅仅是为了说明constructor在原型链中的作用,更实际一点的意义在于:一个子类对象能够获得其父类的全部属性和方法。称之为继承,关于继承我们有好多能够分析和讨论,本篇限于篇幅不在此讨论。
    一个easy掉入的陷阱(gotchas) 之前提到constructor易变,那是由于函数的prototype属性easy被更改。我们用时下非常流行的编码方式来说明问题。请看以下的演示样例代码:

    function F() {

    }
    F.prototype = {
        _name:Eric,
        getName: function () {
            return this._name;
        }
    }

    初看这样的方式并无问题。可是你会发现以下的代码失效了:
    var f = new F();
    alert(f.constructor === F); // output false
    怎么回事?F不是实例对象f的构造函数了吗?
    当然是!

    仅仅只是构造函数F的原型被开发人员重写了。这样的方式将原有的prototype对象用一个对象的字面量{}来取代。


    而新建的对象{}仅仅是Object的一个实例,系统(或者说浏览器)在解析的时候并不会在{}上自己主动加入一个constructor属性,由于这是function创建时的专属操作。仅当你声明函数的时候解析器才会做此动作。
    然而你会发现constructor并非不存在的,以下代码能够測试它的存在性:
    alert(typeof f.constructor == ‘undefined’);// output false
    既然存在。那这个constructor是从哪儿冒出来的呢?
    我们要回头分析这个对象字面量{}。
    由于{}是创建对象的一种简写,所以{}相当于是new Object()。
    那既然{}是Object的实例,自然而然他获得一个指向构造函数Object()的prototype属性的一个引用__proto__,又由于Object.prototype上有一个指向Object本身的constructor属性。

    所以能够看出这个constructor事实上就是Object.prototype的constructor,以下代码能够验证其结论:
    alert(f.constructor === Object.prototype.constructor);//output true
    alert(f.constructor === Object);// also output true
    一个解决的方法就是手动恢复他的constructor。以下代码很好地攻克了这个问题:

    function F() {
    }
    F.prototype = {
        constructor: F, /* reset constructor */
        _name: Eric,
        getName: function () {
            return this._name;
        }
    };

    之后一切恢复正常。constructor又一次获得的构造函数的引用,我们能够再一次測试上面的代码。这次返回true
    var f = new F();
    alert(f.constructor === F); // output true this time ^^
    解惑:构造函数上怎么另一个constructor?它又是哪儿来的?
    细心的朋友会发现,像JavaScript内建的构造函数,如Array, RegExp, String, Number, Object, Function等等竟然自己也有一个constructor:
    alert(typeof Array.constructor != ‘undefined’);// output true
    经过測试发现。此物非彼物它和prototype上constructor不是同一个对象,他们是共存的:
    alert(typeof Array.constructor != ‘undefined’);// output true
    alert(typeof Array.prototype.constructor === Array); // output true
    只是这件事情也是好理解的,由于构造函数也是函数。


    是函数说明它就是Function构造函数的实例对象。自然他内部也有一个指向Function.prototype的内部引用__proto__啦。
    因此我们非常easy得出结论,这个constructor(构造函数上的constructor不是prototype上的)事实上就是Function构造函数的引用:
    alert(Array.constructor === Function);// output true
    alert(Function.constructor === Function); // output true

    OK, constructor从此真相大白,你不在对它陌生了

    本文转自:原帖地址:http://blog.csdn.net/hikvision_java_gyh/article/details/8937157

  • 相关阅读:
    【Android数据存储】内部存储
    【Android数据存储】SharedPreferences
    【JAVA】Java开发使用技巧_获取当前项目中某个文件路径
    【Android Studio】Android Studio 常用快捷键
    跨域问题:解决跨域的三种方案
    maven问题:如何启动maven项目
    maven问题:如何不继承父工程的依赖
    itmacy_我的博客
    springboot定时器
    管理者最高境界:看不见,听不见,做不了
  • 原文地址:https://www.cnblogs.com/lytwajue/p/7239734.html
Copyright © 2011-2022 走看看