我有这样的例子。
function Rabbit() {
var jumps = "yes";
};
var rabbit = new Rabbit();
alert(rabbit.jumps); // undefined
alert(Rabbit.prototype.constructor); // outputs exactly the code of the function Rabbit();
我想更改Rabbit()
中的代码,以便var jumps
变为公开。我是这样做的:
Rabbit.prototype.constructor = function Rabbit() {
this.jumps = "no";
};
alert(Rabbit.prototype.constructor); // again outputs the code of function Rabbit() and with new this.jumps = "no";
var rabbit2 = new Rabbit(); // create new object with new constructor
alert(rabbit2.jumps); // but still outputs undefined
为什么不能以这种方式更改构造函数中的代码?
答案 0 :(得分:70)
您无法通过重新分配到prototype.constructor
正在发生的事情是Rabbit.prototype.constructor
是指向原始构造函数(function Rabbit(){...}
)的指针,因此'class'的用户可以从实例中检测构造函数。因此,当您尝试执行此操作时:
Rabbit.prototype.constructor = function Rabbit() {
this.jumps = "no";
};
您只会影响依赖prototype.constructor
的代码来动态实例化实例中的对象。
当你调用new X
时,JS引擎不引用X.prototype.constructor
,它使用X
作为构造函数,X.prototype
作为新创建的对象的原型。 ,忽略X.prototype.constructor
。
解释这个的好方法是自己实现new
运算符。 (克罗克福德会很开心,也不会有新的;)
// `new` emulator
//
// Doesn't reference `.constructor` to show that prototype.constructor is not used
// when istantiating objects a la `new`
function make(ctorFun, argsArray) {
// New instance attached to the prototype but the constructor
// hasn't been called on it.
const newInstance = Object.create(ctorFun.prototype);
ctorFun.apply(newInstance, argsArray);
return newInstance;
}
// If you create a utility function to create from instance, then it uses the
// inherited `constructor` property and your change would affect that.
function makeFromInstance(instance, argsArray) {
return make(instance.constructor, argsArray);
}
function X(jumps) {
this.jumps = jumps;
}
// Flip the constructor, see what it affects
X.prototype.constructor = function(jumps) {
this.jumps = !jumps;
}
const xFromConstructorIsGood = make(X, [true]);
const xFromInstanceIsBad = makeFromInstance(xFromConstructorIsGood, [true]);
console.log({
xFromConstructorIsGood,
xFromInstanceIsBad
});
JS中的继承
帮助JS继承的库实现了继承,并依赖于prototype.constructor
以下内容:
function extend(base, sub) {
function surrogateCtor() {}
// Copy the prototype from the base to setup inheritance
surrogateCtor.prototype = base.prototype;
sub.prototype = new surrogateCtor();
// The constructor property is set to the base constructor
// with the above trick, let's fix it
sub.prototype.constructor = sub;
}
您可以看到,在上面的代码中,我们必须修复构造函数属性,因为它有时用于在您只有实例时创建实例化对象。但它不会影响实际的构造函数。请参阅我关于JS继承的帖子http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html
如何重新定义构造函数 如果您真的想重新定义构造函数,只需执行
// If Rabbit had any custom properties on it
// (or static properties as some call it), they would not be copied, you'd have to do that manually using getOwnPropertyNames
// See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames
var oldProto = Rabbit.prototype;
Rabbit = function() {...};
Rabbit.prototype = oldProto;
请注意,这不会影响已复制该引用的代码,例如:
const myRefRabbit = Rabbit
答案 1 :(得分:0)
尝试以下
function Rabbit() {
this.jumps = "no";
};
var rabbit = new Rabbit();
alert(rabbit.jumps); // Prints "no"
答案 2 :(得分:0)
这是一个很好的解决方法,从文字创建对象,而不是从构造函数创建。
首先,如果您希望jumps
成员包含在对象中,而不仅仅是构造函数中的局部变量,那么您需要this
个关键字。
function Rabbit() {
this.jumps = "yes";
};
var rabbit = new Rabbit();
alert(rabbit.jumps); // not undefined anymore
现在您可以轻松地以您想要的方式公开访问jumps
:
rabbit.jumps = 'no';
alert(rabbit.jumps); // outputs 'no'
但是如果你创建另一个Rabbit对象,它最初会有'是''正如构造函数中所定义的那样吗?
var rabbit2 = new Rabbit();
alert(rabbit.jumps); // outputs 'no' from before
alert(rabbit2.jumps); // outputs 'yes'
你可以做的是从一些默认的Rabbit Object创建一个Rabbit。除非您更改了具体兔子对象(实现)中的值,否则具体的兔子将始终具有默认Rabbit对象的默认值,即使您在运行中进行更改也是如此。这与@Juan Mendes的解决方案不同,这可能是最好的,但它可以打开另一种观点。
Rabbit = {jumps : 'yes'}; // default object
rabbit = Object.create(Rabbit);
Rabbit.jumps = 'no';
rabbit2 = Object.create(Rabbit);
console.log(rabbit.jumps); // outputs "no" - from default object
console.log(rabbit2.jumps); // outputs "no" - from default object
// but...
rabbit.jumps = 'yes';
Rabbit.jumps = 'unknown';
console.log(rabbit.jumps); // outputs "yes" - from concrete object
console.log(rabbit2.jumps); // outputs "unknown" - from default object