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?