考虑下面的代码,
function Test(){
var a = 'prabhu';
Test.prototype.print = function (){ alert(a); a=10; }
}
Run Code Online (Sandbox Code Playgroud)
我正在为Test创建对象实例,
var x = new Test();
var y = new Test();
Run Code Online (Sandbox Code Playgroud)
现在访问print他们的原型中可用的两者的方法,
x.print() //"prabhu" ok!!
x.print() //10 Double ok!!
Run Code Online (Sandbox Code Playgroud)
但
y.print() //10 what the?? It should be prabhu. Isn't it?
Run Code Online (Sandbox Code Playgroud)
这是怎么回事?因为在创建y实例时,constructor将调用它,它将覆盖print其原型中的函数.它会创建一个closure用于a与价值"prabhu".因此,通过print()它访问它应该打印"prabhu"正确吗?为什么这不会发生?对这种行为的逐步解释将非常有帮助.
PS:我知道代码的行为,如果我们this.a在任何地方使用而不是a和var a.所以请不要建议使用它.我努力弄清楚为什么上面解释的行为正在发生.
决不功能分配给prototype从一个构造函数对象内的构造,它设置了这个串扰.
原因是通过创建的对象new Test具有到其原型的实时链接,而不是它的副本.这意味着如果您修改原型对象,下次对象在其上查找某些内容(例如print)时,它会看到新对象.这是一个Good Thing™,但它确实意味着你不应该Test.prototype从内部分配Test.
你正在看到你正在看到的东西,因为当你这样做时var y = new Test(),你正在改变现有的原型,修改x它的print功能,以便它a从第二个调用(创建的那个y)开始关闭,而不是第一个调用.因此,如果您x.print()在执行此操作后调用,则a更新的是第二个,而不是第一个.
让我们按照您的代码:
function Test(){
var a = 'prabhu';
Test.prototype.print = function (){ alert(a); a=10; }
}
var x = new Test();
Run Code Online (Sandbox Code Playgroud)
在这一点上,我们在内存中有这个(留下一些不相关的细节):
+---------------+
x-->| (object) |
+---------------+ +----------+
| [[Prototype]] |---->| (object) |
+---------------+ +----------+ +-----------------+
| print |-->| (function) |
+----------+ +-----------------+ +---------------+
| env |-->| Environment 1 |
| alert(a); a=10; | +---------------+
+-----------------+ | a: 'prabhu' |
+---------------+
现在我们这样做:
var y = new Test();
Run Code Online (Sandbox Code Playgroud)
现在我们有:
+-----------------+ +---------------+
+---------------+ | (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]] |--+
+---------------+
注意旧print函数不再x以任何方式连接到对象; 它已被新的替换,它指的是通过第二次调用创建的新环境Test.旧功能和它用来关闭的环境现在都符合垃圾收集的条件.
然后:
x.print() //"prabhu" ok!!
Run Code Online (Sandbox Code Playgroud)
给我们(我现在已经离开了垃圾;也许是收集的,也许不是,无所谓):
+-----------------+ +---------------+
+---------------+ | (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]] |--+
+---------------+
请注意,调用a将第二次调用更改为Test(创建的y),而不是第一次调用(垃圾).
然后:
x.print() //10 Double ok!!
Run Code Online (Sandbox Code Playgroud)
什么都不改变.
最后:
y.print() //10 what the?? It should be prabhu. Isn't it?
Run Code Online (Sandbox Code Playgroud)
示出了10完全相同的原因x.print()示出了10:该print功能是使用a从第二呼叫Test,而不是第一个.
| 归档时间: |
|
| 查看次数: |
66 次 |
| 最近记录: |