gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-01 15:07:40 24 4
gpt4 key购买 nike

考虑下面的代码,

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

我正在为测试创建对象实例,

var x = new Test();
var y = new Test();

现在正在访问 print两者的方法在他们的原型(prototype)中可用,

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

但是

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

这是怎么回事?因为在创建 y 时例如,constructor将被调用,它将覆盖 print在其原型(prototype)中发挥作用。它将创建一个 closure对于 a具有值(value) "prabhu" .因此,在通过 print() 访问它时它应该打印 "prabhu"正确的?为什么这没有发生?对此行为的逐步解释将非常有帮助。

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

最佳答案

永远不要将函数分配给 prototype 对象上的构造函数构造函数中,它会设置此串扰。

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

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

让我们跟随您的代码:

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

var x = new Test();

此时,我们在内存中有这个(省略一些不相关的细节):

    +---------------+   x-->|   (object)    |       +---------------+     +----------+         | [[Prototype]] |---->| (object) |         +---------------+     +----------+   +-----------------+                             | print    |-->| (function)      |                             +----------+   +-----------------+   +---------------+                                         | env             |-->| Environment 1 |                                         | alert(a); a=10; |   +---------------+                                         +-----------------+   | a: 'prabhu'   |                                                                               +---------------+

Now we do this:

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]] |--+    +---------------+

Note that the old print function is no longer connected to the object x refers to in any way; it's been replaced with the new one, which refers to the new environment created by calling Test a second time.The old function and the environment it used to close over are both eligible for garbage collection now.

Then:

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]] |--+    +---------------+

Note that the call changed the a from the second call to Test (the one that created y), not the first one (the garbage).

Then:

x.print() //10  Double ok!!

不改变任何东西。

最后:

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

出于完全相同的原因显示 10 x.print() 显示 10:print 函数正在使用 a 来自 second 调用 Test,而不是第一个。

关于javascript - 构造函数中闭包的神秘行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35794914/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com