4

我以为我已经理解了闭包的概念,但是下面的代码对我来说表现得令人惊讶:

function A(x)
{
  this.getX1 = function () { return x; }
  A.prototype.getX2 = function () { return x; }
}
var a1 = new A(1);
var a2 = new A(2);
console.log ('a1.getX1()=%d', a1.getX1 ()); // 1
console.log ('a2.getX1()=%d', a2.getX1 ()); // 2
console.log ('a1.getX2()=%d', a1.getX2 ()); // 2 ???
console.log ('a2.getX2()=%d', a2.getX2 ()); // 2

我可以理解原型方法的行为是否与实例方法不同,但这看起来 x 已成为静态变量。更改调用顺序不会改变结果。

4

4 回答 4

4

当您更改 时,prototype您正在更改给定类function所有实例,包括那些已经存在的实例。

因此,当您调用...

A.prototype.getX2 = function () { return x; }

您正在a1A. 因此,您最终会得到以下伪代码:

<all instances of A>.getX2 = function () {
    return <latest value of x passed to A constructor>;
}
于 2012-10-08T08:58:46.297 回答
2

这里的静态成员是A.prototype.getX2. 第二次调用A.prototype.getX2 = function () { return x; }(due to var a2 = new A(2);) 替换了第一次调用。要理解它,您可以颠倒实例化的顺序:

var a2 = new A(2);
var a1 = new A(1);

然后你将拥有:

a1.getX1()=1
a2.getX1()=2
a1.getX2()=1
a2.getX2()=1
于 2012-10-08T08:55:28.607 回答
2

您定义 getX2 两次,每次创建一个新的 A。该函数的结果将始终是最后一个 X。考虑像这样重写代码:

function A(x) {

    this.x = x;
    this.getX1 = function() {
        return this.x;
    }
}
A.prototype.getX2 = function() {
    return this.x;
}
var a1 = new A(1);
var a2 = new A(2);
console.log('a1.getX1()=%d', a1.getX1()); // 1
console.log('a2.getX1()=%d', a2.getX1()); // 2
console.log('a1.getX2()=%d', a1.getX2()); // 1
console.log('a2.getX2()=%d', a2.getX2()); // 2​​​ 

这样,您只需定义一次 getX2 并按预期工作。

于 2012-10-08T09:02:24.147 回答
1

你写

function A(x)
{
  this.getX1 = function () { return x; }
  A.prototype.getX2 = function () { return x; }
}

A.prototype.getX2此构造函数每次都会覆盖。

所以首先

var a1 = new A(1); // This invokes A and adds a function `getX2` to the prototype of `A`which returns `x` that is `1`

var a2 = new A(2); // This invokes A and overwrites the function `getX2` in the prototype of `A` with a function which returns `x` that is `2` now.

所以应该是这样的

function A(x)
{
  this.getX1 = function () { return x; }
}

A.prototype.getX2 = function () { return this.getX1(); }
于 2012-10-08T09:00:26.517 回答