Javascript对象实例属性意外地设置

时间:2014-03-28 07:02:01

标签: javascript prototypal-inheritance function-constructor

我有以下代码:

function Foo() {
    Foo.prototype.test = 0;
}

Foo.prototype.incTest = function() {
    Foo.prototype.test++;
};

Foo.prototype.getTest = function(name) {
    console.log(name +" this: " + this.test + " proto: " + Foo.prototype.test);
};

var bar = new Foo();
var baz = new Foo();

bar.getTest('bar');
bar.incTest();
bar.getTest('bar');

baz.incTest();
bar.getTest('bar');
baz.getTest('baz');

可以预测输出是:

bar this: 0 proto: 0
bar this: 1 proto: 1 
bar this: 2 proto: 2 
baz this: 2 proto: 2 

现在我尝试利用this查找原型链,并将incTest更改为:

Foo.prototype.incTest = function() {
    this.test++;
};

这给了我完全不同的输出!

bar this: 0 proto: 0 
bar this: 1 proto: 0 
bar this: 1 proto: 0 
baz this: 1 proto: 0

不应该this.test引用Foo原型属性吗?到底发生了什么?

编辑:

此外,将行更改为Foo.prototype.test = this.test++;也会产生第二个输出,我不确定原因。

编辑2:

首次编辑的解决方案是后缀与前缀。前缀增量产生第一个输出。

2 个答案:

答案 0 :(得分:2)

第一种情况:

您只是递增原型变量,原型变量的所有实例都会共享该原型变量。

这里需要注意的重要事项是,当您在第一种情况下使用test访问this.test时,JavaScript会尝试在test中找到this test(当前对象)。它找不到它,它在原型链中上升。它在Foo.prototype中找到this.test并返回该值。这就是为Foo.prototype.testthis.test获得相同值的原因。

第二种情况:

您正在递增this.test++this.test = this.test + 1 可以像这样理解

test

现在,它从pototype链中获取Foo.prototype.test的值(将使用test,这是0),向其中添加1并将其存储为this成员当前对象。因此,您要在test中创建一个名为Foo.prototype.test的新成员。这就是为什么它的价值与Foo.prototype.deleteTest = function () { delete this.test; } ... ... bar.deleteTest(); bar.getTest('bar'); 不同。

您可以通过再添加一个方法来确认这一点,例如

bar.getTest

现在0将打印test,因为我们从this删除了deleteTest()test。因此,它会上升并在Foo.prototype中找到{{1}},即0。

答案 1 :(得分:-1)

this将引用函数的当前实例,而不是原型。