Javascript 构造函数中闭包的神秘行为

Javascript 构造函数中闭包的神秘行为,javascript,Javascript,考虑下面的代码 function Test(){ var a = 'prabhu'; Test.prototype.print = function (){ alert(a); a=10; } } 我正在为测试创建对象实例 var x = new Test(); var y = new Test(); 现在访问这两种方法的print方法,该方法在其原型中可用 x.print() //"prabhu" ok!! x.print() //10 Double ok!! 但是 这是怎么

考虑下面的代码

function Test(){
  var a = 'prabhu';
  Test.prototype.print = function (){ alert(a); a=10; }
}
我正在为测试创建对象实例

var x = new Test();
var y = new Test();
现在访问这两种方法的
print
方法,该方法在其原型中可用

x.print() //"prabhu"  ok!!
x.print() //10  Double ok!!
但是

这是怎么发生的?因为在创建
y
实例时,将调用
构造函数
,它将覆盖原型中的
print
函数。它将为
a
创建一个
闭包
,值为
“prabhu”
。所以当通过
print()
访问它时,它应该打印
“prabhu”
对吗?为什么没有发生这种情况?对这种行为的逐步解释将非常有用


p.S:如果我们使用
这个,我知道代码的行为。a
无处不在,而不是
a
var a
。所以,请不要建议使用它。我正在努力弄清楚为什么会发生上述行为。

不要从构造函数内部将函数分配给构造函数上的
原型
对象,它会设置这种串扰

原因是通过
newtest
创建的对象与其原型有实时链接,而不是其副本。这意味着,如果修改原型对象,下次对象在其上查找某个对象时(如
print
),它会看到新对象。这是件好事™, 但这确实意味着您不应该从
Test
中分配到
Test.prototype

您看到的是您所看到的,因为当您执行
var y=new Test()
时,您正在更改现有
x
使用的原型,更改其
print
函数,使其从第二次调用(创建
y
的调用)关闭
a
,而不是第一次调用。因此,如果在此之后调用
x.print()
,则更新的
a
是第二个,而不是第一个

让我们按照您的代码进行操作:

function Test(){
  var a = 'prabhu';
  Test.prototype.print = function (){ alert(a); a=10; }
}

var x = new Test();
在这一点上,我们记住了这一点(省略一些不相关的细节):

现在我们有:

+-----------------+ +---------------+ +---------------+ | (function) | | Environment 1 | x-->| (object) | +-----------------+ +---------------+ +---------------+ | env |-->| a: 'prabhu' | | [[Prototype]] |--+ | alert(a); a=10; | +---------------+ +---------------+ | +-----------------+ | | +----------+ +-----------------+ +---------------+ +->| (object) | | (function) | | Environment 2 | | +----------+ +-----------------+ +---------------+ | | print |-->| env |-->| a: 'prabhu' | | +----------+ | alert(a); a=10; | +---------------+ | +-----------------+ +---------------+ | y-->| (object) | | +---------------+ | | [[Prototype]] |--+ +---------------+ 给我们(我现在已经把垃圾扔了;可能是被收集的,可能不是,没关系):

不会改变任何事情

最后:

y.print() //10  what the?? It should be prabhu. Isn't it?

显示10的原因与
x.print()
显示10的原因完全相同:
print
函数正在使用第二次调用
Test
a
,而不是第一次调用。

感谢您花时间回答这个问题。但是,在为
y
调用
new Test
时,
print
函数将以具有值
的新变量
a
作为其闭包。我有点怀疑。它是如何引用旧的更新变量
a
?您可以引用我的代码示例来解释它吗?“但是当调用
y
new Test
时,
print
函数将使用新变量
a
,该变量的值“prabhu”作为其闭包。“该值不是闭包,但是的,这就是发生的情况。”。“它是如何引用较旧的更新变量a的?”事实并非如此,
x
y
用作原型的对象现在已
print
结束了第二次调用
Test
(创建
y
的对象)的环境
x.print()
,如果在
var y=new Test()
之后调用,则修改第二个
a
,而不是第一个。我已经添加了一些ASCII艺术和进一步的细节,希望对您有所帮助。@T.J.Crowder哇!!!你的图表解释了我的期望。只要合适,我一定会给你一笔赏金。感谢您为此投入宝贵的时间。:)
var y = new Test();
+-----------------+ +---------------+ +---------------+ | (function) | | Environment 1 | x-->| (object) | +-----------------+ +---------------+ +---------------+ | env |-->| a: 'prabhu' | | [[Prototype]] |--+ | alert(a); a=10; | +---------------+ +---------------+ | +-----------------+ | | +----------+ +-----------------+ +---------------+ +->| (object) | | (function) | | Environment 2 | | +----------+ +-----------------+ +---------------+ | | print |-->| env |-->| a: 'prabhu' | | +----------+ | alert(a); a=10; | +---------------+ | +-----------------+ +---------------+ | y-->| (object) | | +---------------+ | | [[Prototype]] |--+ +---------------+
x.print() //"prabhu"  ok!!
+-----------------+ +---------------+ +---------------+ | (function) | | Environment 1 | x-->| (object) | +-----------------+ +---------------+ +---------------+ | env |-->| a: 'prabhu' | | [[Prototype]] |--+ | alert(a); a=10; | +---------------+ +---------------+ | +-----------------+ | | +----------+ +-----------------+ +---------------+ +->| (object) | | (function) | | Environment 2 | | +----------+ +-----------------+ +---------------+ | | print |-->| env |-->| a: 10 | | +----------+ | alert(a); a=10; | +---------------+ | +-----------------+ +---------------+ | y-->| (object) | | +---------------+ | | [[Prototype]] |--+ +---------------+
x.print() //10  Double ok!!
y.print() //10  what the?? It should be prabhu. Isn't it?