constructor属性详解
在JavaScript中,每个具有原型的对象都会自动获得constructor属性,除了arguments、Enumerator、Error、Global、Math、RegExp、Regular Expression等一些特殊对象之外,其他所有的JavaScript内置对象都具备constructor属性。例如:Array、Boolean、Date、Function、Number、Object、String等。
在定义一个函数(代码如下所示)时,
1 | function F() { |
JavaScript 内部会执行如下几个动作:
1.为该函数添加一个原形(即 prototype)属性
- 为 prototype 对象额外添加一个 constructor 属性,并且该属性保存指向函数F 的一个引用
这样当我们把函数 F 作为自定义构造函数来创建对象的时候,对象实例内部会自动保存一个指向其构造函数(这里就是我们的自定义构造函数 F)的 prototype 对象的一个属性_proto_
f._proto_ = F.prototype;(就是原型链)
所以我们在每一个对象实例中就可以访问构造函数的 prototype 所有拥有的全部属性和方法,就好像它们是实例自己的一样。当然该实例也有一个 constructor属性了(从 prototype 那里获得的),每一个对象实例都可以通过 constrcutor 对象访问它的构造函数,请看下面代码:
1 | var f = new F(); |
之前提到 constructor 易变,那是因为函数的 prototype 属性容易被更改,我们用时下很流行的编码方式来说明问题,请看下面的示例代码:
1 | function F() {} |
怎么回事?F 不是实例对象 f 的构造函数了吗?当然是!只不过构造函数 F 的原型被开发者重写了,这种方式将原有的 prototype 对象用一个对象的字面量{}来代替。而新建的对象{}只是 Object 的一个实例,系统(或者说浏览器)在解析的时候并不会在{}上自动添加一个 constructor 属性,因为这是 function 创建时的专属操作,仅当你声明函数的时候解析器才会做此动作。然而你会发现 constructor 还是不存在的,下面代码可以
测试它的存在性:
1 | alert(typeof f.constructor == 'undefined');// output false |
既然存在,那这个 constructor 是从哪儿冒出来的呢?我们要回头分析这个对象字面量
{}。
因为{}是创建对象的一种简写,所以{}相当于是 new Object()。那既然{}是 Object
的实例,自然而然他获得一个指向构造函数 Object()的 prototype 属性的一个引用proto,又因为 Object.prototype 上有一个指向 Object 本身的 constructor属性。所以可以看出这个constructor其实就是Object.prototype的constructor,
下面代码可以验证其结论:
1 | alert(f.constructor === Object.prototype.constructor);//output true |
一个解决办法就是手动恢复他的 constructor,下面代码非常好地解决了这个问题
1 | function F() {} |
之后一切恢复正常,constructor 重新获得的构造函数的引用
1 | var f = new F(); |
拓展:
构造函数上怎么还有一个 constructor ?它又是哪儿来的?
细心的会发现,像 JavaScript 内建的构造函数,
如 Array, RegExp, String,Number, Object, Function 等等居然自己也有一个 constructor:
1 | alert(typeof Array.constructor != ‘undefined’);// output true |
经过测试发现,此物非彼物它和 prototype 上 constructor 不是同一个对象,他们是共存的:
1 | alert(typeof Array.constructor != 'undefined');// output true |
不过这件事情也是好理解的,因为 构造函数也是函数。是函数说明它就是 Function 构造函数的实例对象,自然他内部也有一个指向 Function.prototype 的内部引用_proto_啦。因此我们很容易得出结论,这个 constructor(构造函数上的constructor 不是 prototype 上的)其实就是 Function 构造函数的引用:
1 | alert(Array.constructor === Function);// output true |