使用相同的构造函数创建对象
重要性:5
假设我们有一个由构造函数创建的任意对象 obj - 我们不知道是哪个构造函数,但我们想用它创建一个新对象。
我们可以这样吗?
let obj2 = new obj.constructor();
给出一个 obj 的构造函数示例,它可以让这样的代码正常工作。再给出一个使它无法正常工作的示例。
如果我们确定 "constructor" 属性具有正确的值,则可以使用这种方法。
例如,如果我们不触碰默认的 "prototype",那么这段代码肯定可以正常工作
function User(name) {
this.name = name;
}
let user = new User('John');
let user2 = new user.constructor('Pete');
alert( user2.name ); // Pete (worked!)
它起作用了,因为 User.prototype.constructor == User。
…但是,如果有人,这么说吧,覆盖了 User.prototype 并忘记重新创建 constructor 来引用 User,那么它就会失败。
例如
function User(name) {
this.name = name;
}
User.prototype = {}; // (*)
let user = new User('John');
let user2 = new user.constructor('Pete');
alert( user2.name ); // undefined
为什么 user2.name 是 undefined?
以下是 new user.constructor('Pete') 的工作原理
- 首先,它在
user中查找constructor。没有。 - 然后它沿着原型链向上查找。
user的原型是User.prototype,它也没有constructor(因为我们“忘记”设置它了!)。 - 继续向上查找,
User.prototype是一个普通对象,它的原型是内置的Object.prototype。 - 最后,对于内置的
Object.prototype,有一个内置的Object.prototype.constructor == Object。所以它被使用了。
最后,我们得到了 let user2 = new Object('Pete')。
可能,这不是我们想要的。我们想创建 new User,而不是 new Object。这就是缺少 constructor 的结果。
(如果你好奇,new Object(...) 调用会将它的参数转换为一个对象。这是一个理论上的东西,在实践中没有人用一个值调用 new Object,而且通常我们根本不使用 new Object 来创建对象)。