JS中原型对象中的constructor的作用?
最近被同事问道一个问题:
function Father() {
this.color = ['red', 'green'];
}
function Child() {
this.test = 1;
}
Child.prototype = new Father();
let instance = new Child();
这个例子是经典原型链继承,未做constructor修复的一个例子。
问:
instance的属性test哪里来的,要知道这里的此时instance的构造函数instance.constructor是Father,我们再根据一般Java,ES6类中的构造函数的拷贝属性用法,instance的属性要有也是Father的color?
问题就在这里了,js的new并不像Java 这种OOP语言的new一样,js的new后面的不是类,就是普通函数,普通函数以new调用,内部过程为:MDN,New
test的属性是通过this的改变获取到的,压根没走js原型对象中的constructor。所以这里就是一个误区。
那么js原型对象中的constructor有什么作用?上面的继承让我们instance.color通过原型链访问到了Father的color属性,最后为什么一般要修复Child.prototype.constructor = Child呢。
答案其实也没那么重要:
constructor属性不影响任何JavaScript的内部属性。constructor其实没有什么用处,只是JavaScript语言设计的历史遗留物。由于constructor属性是可以变更的,所以未必真的指向对象的构造函数,只是一个提示。不过,从编程习惯上,我们应该尽量让对象的constructor指向其构造函数,以维持这个惯例。
目前看到的作用之一,通过实例的构造函数给闭包中的函数增加属性方法。
var a,b;
(function(){
function A (arg1,arg2) {
this.a = 1;
this.b=2;
}
A.prototype.log = function () {
console.log(this.a);
}
a = new A();
b = new A();
})()
a.log();
// 1
b.log();
// 1
通过以上代码我们可以得到两个对象,a,b,他们同为类A的实例。因为A在闭包里,所以现在我们是不能直接访问A的,那如果我想给类A增加新方法怎么办?
// a.constructor.prototype 在chrome,firefox中可以通过 a.__proto__ 直接访问
a.constructor.prototype.log2 = function () {
console.log(this.b)
}
a.log2();
// 2
b.log2();
// 2
通过访问constructor就可以了。
这位老哥的解释也就是上面的代码的一个应用了。
不过你拿到 prototype 也不见得能拿到 正确的 constructor,JS没有提供方式确保你拿到“正确”的
constructor。我们只能根据惯例相信对象上的 constructor 应该是“正确”的 constructor。
这也是我们上面做constructor修复的一个原因了。
参考:
知乎
红宝石书