JavaScript原型——构造函数

来源:互联网 发布:产品矩阵是什么意思 编辑:程序博客网 时间:2024/06/06 01:10

没有构造函数,只有对函数的构造调用

构造函数是在类中的知识,很多人以为JavaScript中也有构造函数是因为这样的代码:

function Foo() {    //...}var a = new Foo();

认为Foo是一个类的原因是

  • 看到了关键字new,在面向类中的语言中(比如Java)实例化对象的时候也会用到。
  • Foo()的调用方式类似初始化类的时候类的构造函数的调用方式。

其实,Foo和其它函数没有任何区别。函数本身不是构造函数。当你在普通的函数调用前面加上new关键字之后,就会把这个函数调用变成一个“构造函数调用”。new会劫持所有普通函数并用构造对象的形式来调用它。

举个例子:

function NothingSpecial() {    console.log("nothing");}var a = new NothingSpecial();//nothinga;  //NothingSpecial {}

NothingSpecial只是一个普通的函数,但是,使用new调用时,它就会构造一个对象并赋值给a。
函数不是构造函数,当且仅当使用new时,函数调用会变成“构造函数调用”。


有人可能会有疑问,他们也许是因为这样的代码才认为Foo是构造函数的:

function Foo() {    //...}Foo.prototype.constructor === Foo;  //truevar a = new Foo();a.constructor ===Foo;   //true

Foo.prototype默认有一个公有并且不可枚举的属性.constructor,这个属性引用的是对象关联的函数Foo)。

看起来a.constructor === Foo 意味着a有一个指向Foo的.constructor属性。将.constructor属性指向Foo看作是a对象由Foo“构造“很好理解。但是,事实是这样吗?

function Foo() {    //...}var a = new Foo();Object.getOwnPropertyNames(a);  //[](并没有constructor属性)

Foo.prototype的.constructor属性只是Foo函数在声明时的默认属性。如果你创建了一个新对象并替换了函数默认的.prototype对象引用,那么新对象并不会自动获得.constructor属性

function Foo() {    //...}//创建一个新原型对象Foo.prototype = {    //...}var a = new Foo();a.constructor === Foo;  //falsea.constructor === Object;   //true

很多人认为是Foo()执行了构造工作,但是,如果”constructor”表示”由…构造”,a.constructor应该是Foo,但是并不是这样。
为什么会这样的?我们解释一下:

a没有.constructor属性,它会委托原型链上的Foo.prototype。但是Foo.prototype对象也没有.constructor属性(默认的有),继续委托。委托给顶端的Object.prototype。这个对象有.constructor属性,指向内置的Object()函数。

当然,可以自己手动给Foo.prototype添加一个不可枚举的.constructor属性:

function Foo() {    //...}Foo.prototype = {    //...}Object.defineProperty(Foo.prototype, "constructor", {    value: Foo,    //让constructor指向Foo    configurable: false,    writable: true,    enumerable: false});

综上所述,.constructor是一个非常不可靠、不安全的引用,尽量避免使用。

阅读全文
0 0