JavaScript中constructor属性一直不是很清楚,今日终于弄清了其中缘由,下面举例说明。
首先是一个典型的JavaScript实例声明:
function Person(){ this.name = name; } var p = new Person('Joe'); console.log(p.constructor === Person); //true console.log(p.__proto__ === Person.prototype); //true
如果此时对Person的prototype中添加属性或函数:
function Person(){ this.name = name; } Person.prototype.getName = function(){ return this.name; } var p = new Person('Joe'); console.log(p.constructor === Person); //true console.log(p.__proto__ === Person.prototype); //true
但是如果对Person的prototype重新定义,将会产生如下结果:
function Person(){ this.name = name; } Person.prototype = { getName : function(){ return this.name; } } var p = new Person('Joe'); console.log(p.constructor === Person); //false console.log(p.__proto__ === Person.prototype); //true
这里面关系到constructor属性的归属问题,本人试着用下面的代码验证:
Person.__proto__.constructor===Person.constructor //true p.__proto__.constructor === p.constructor; //true
经过上述验证,可以证明constructor其实是__proto__的属性(此处存疑,因为是个人验证,不清楚上面的验证代码是否精准,如果有误,希望各位指出)。
根据new的工作原理(详见http://www.cnblogs.com/ihardcoder/p/3667372.html),我们知道
p.__proto__ = Person.prototype;
所以
p.constructor = p.__proto__.constructor = Person.prototype.constructor
这样就将问题追溯到Person的prototype指向问题。当用Person.prototype = {}的方式重新定义时,同样根据new的工作原理,其实产生如下改变:
Person.prototype.__proto__ = Object.prototype
从而
p.constructor = Person.prototype.constructor = Person.prototype.__proto__.constructor = Object.prototype.constructor
此时
p.constructor === Object; //true
如何避免constructor属性的混乱,归根结底,我们需要做的是保证instance的constructor属性指向Person.prototype.constructor,而不是Person的父类,所以当修改Person.prototype时需要保证Person.prototype.constructor指向自己。
function Person(){ this.name = name; } Person.prototype = { getName : function(){ return this.name; } } Person.prototype.constructor = Person; var p = new Person('Joe'); console.log(p.constructor === Person); //false console.log(p.__proto__ === Person.prototype); //true