在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

Javascript属性constructor/prototype的底层原理的更多相关文章

  1. JavaScript 原型和对象创建底层原理

    1. prototype/__proto__/constructor JS原型链和继承网上已经烂大街了,5毛可以买一堆,这里只提一下: constructor:普通对象和函数对象都有,指向创建它的函数 ...

  2. 深入理解JavaScript原型:prototype,__proto__和constructor

    JavaScript语言的原型是前端开发者必须掌握的要点之一,但在使用原型时往往只关注了语法,其深层的原理并未理解透彻.本文结合笔者开发工作中遇到的问题详细讲解JavaScript原型的几个关键概念, ...

  3. [javascript基础]constructor与prototype

    最初对js中 object.constructor 的认识: 在学习JS的面向对象过程中,一直对constructor与prototype感到很迷惑,看了一些博客与书籍,觉得自己弄明白了,现在记录如下 ...

  4. 深入理解Javascript中this, prototype, constructor

    在Javascript面向对象编程中经常需要使用到this,prototype和constructor这3个关键字. 1.首先介绍一下this的使用:this表示当前对象;如果在全局中使用this,则 ...

  5. JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能

    摘要: 理解浏览器渲染. 原文:JavaScript是如何工作的: CSS 和 JS 动画底层原理及如何优化它们的性能 作者:前端小智 Fundebug经授权转载,版权归原作者所有. 这是专门探索 J ...

  6. JavaScript中的 prototype 和 constructor

    prototype属性  任何js函数都可以用作构造函数, 而构造函数需要用到prototype属性, 因此, 每个js函数F(除了ES5的Function.bind()方法返回的函数外) 都自动拥有 ...

  7. JavaScript中Object.prototype.toString方法的原理

    在JavaScript中,想要判断某个对象值属于哪种内置类型,最靠谱的做法就是通过Object.prototype.toString方法. ? 1 2 var arr = []; console.lo ...

  8. Javascript object.constructor属性与面向对象编程(oop)

    定义和用法 在 JavaScript 中, constructor 属性返回对象的构造函数. 返回值是函数的引用,不是函数名: JavaScript 数组 constructor 属性返回 funct ...

  9. javascript中的prototype和constructor

    构造函数 我们知道,ECMAScript5中的Object.Array.Date.RegExp.Function等引用类型都是基于构造函数的,他们本身就是ECMAScript5原生的构造函数.比如,我 ...

随机推荐

  1. DRF的版本和认证

    DRF的版本 版本控制是做什么用的, 我们为什么要用 首先我们要知道我们的版本是干嘛用的呢~~大家都知道我们开发项目是有多个版本的~~ 当我们项目越来越更新~版本就越来越多~~我们不可能新的版本出了~ ...

  2. 洛谷 P1064 金明的预算方案【有依赖的分组背包】

    题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:"你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱 ...

  3. Codeforces Round #445 C. Petya and Catacombs【思维/题意】

    C. Petya and Catacombs time limit per test 1 second memory limit per test 256 megabytes input standa ...

  4. 如何理解java反射?

    一.反射基本概念 反射之中包含了一个"反"的概念,所以要想解释反射就必须先从"正"开始解释,一般而言,当用户使用一个类的时候,应该先知道这个类,而后通过这个类产 ...

  5. UAF学习之Adobe reader CVE-2013-3346

    学习了UAF,分析了几个漏洞,同时,也熟悉了windbg的用法,收获挺大. 基本的UAF分析流程如下: i:找有漏洞的函数 ii:找到被释放对象的类型,以及被释放对象在内存中的位置 iii:理解对象的 ...

  6. 八. 输入输出(IO)操作5.面向字节流的应用

    文件输入输出流 文件输入输出流 FileInputStream 和 FileOutputStream 负责完成对本地磁盘文件的顺序输入输出操作. [例 10-5]通过程序创建一个文件,从键盘输入字符, ...

  7. maven配置memcached.jar

    由于目前java memcached client没有官方的maven repository可供使用,因此使用时需要手动将其安装到本地repository. java memcached client ...

  8. What is Mocking?

    Mocking is primarily used in unit testing. An object under test may have dependencies on other (comp ...

  9. 今天终于看了一下tanh函数的形式,双曲正切函数

    tanh = sinh / cosh sinh  = Hyperbolic sin cosh = Hyperbolic cos

  10. ES6中的迭代器(Iterator)和生成器(Generator)(二)

    一.内建迭代器 迭代器是ES6的一个重要组成部分,在ES6中,已经默认为许多内建类型提供了内建迭代器,只有当这些内建迭代器无法实现目标时才需要自己创建.通常来说当定义自己的对象和类时才会遇到这种情况, ...