我正在查看John Resig网站上的这段代码。我不明白的是当忍者对象被设置为空对象时,yell方法仍然可供武士使用。
是因为因为忍者周围还有一个参考物,所以它不是垃圾收集的吗?
var ninja = {
yell: function(n){
return n > 0 ? yell(n-1) + "a" : "hiy";
}
};
var samurai = { yell: ninja.yell };
ninja = {};
console.log(samurai.yell(2)); //hiy
http://ejohn.org/apps/learn/#14(原始来源,我稍微修改了一下以删除指定的函数表达式)。
答案 0 :(得分:5)
在以下代码中:
var ninja = {
yell: function(n){
return n > 0 ? yell(n-1) + "a" : "hiy";
}
};
ninja.yell 的值是对函数的引用。作业:
var samurai = { yell: ninja.yell };
为 samurai.yell 指定一个值,该值是对同一函数的引用(即 ninja.yell 引用的那个)。然后:
ninja = {};
为 ninja 指定一个值,这是一个新的空对象。它对分配给 samurai.yell 的值没有影响,它仍然引用该函数。
变量有一个值,值为Type。有一个名为Reference Type的特殊类型是" ...用于解释诸如delete,typeof和赋值运算符"等运算符的行为。因此,当对象位于assignment expression时,分配的值为Type Reference。
因此变量仍然有一个值,但它的值是一个参考。
答案 1 :(得分:1)
打破'ninja'的'yell'属性引用的匿名函数:
function yell(n) {
return n > 0 ? yell(n-1) + "a" : "hiy";
}
var ninja = {
yell: yell
};
现在,当你重新分配'ninja'时,更容易看到'yell'功能没有被'删除'。
当你这样做时:
var samurai = { yell: ninja.yell };
您将任何ninja.yell引用(function yell()
}指定给'samurai.yell'。
答案 2 :(得分:0)
查看此原始未修改的来源非常重要:
1. | var ninja = {
2. | yell: function(n){
3. | return n > 0 ? ninja.yell(n-1) + "a" : "hiy";
4. | }
5. | };
6. | assert( ninja.yell(4) == "hiyaaaa", "A single object isn't too bad, either." );
7. |
8. | var samurai = { yell: ninja.yell };
9. | var ninja = null;
10. |
11. | try {
12. | samurai.yell(4);
13. | } catch(e){
14. | assert( false, "Uh, this isn't good! Where'd ninja.yell go?" );
15. | }
您将ninja.yell
更改为yell
所做的更改是对脚本的无效修改。
我不明白的是,当忍者对象被设置为空对象时,yell方法仍可供武士使用。
了解如何在JavaScript中进行赋值非常重要。 JavaScript有很多方便的简写符号,当你对这门语言不熟悉时,它会让你更难理解。
var samurai = { yell: ninja.yell };
是一种简写的说法:
var samurai;
samurai = new Object();
samurai.yell = ninja.yell;
调用samurai.yell = ninja.yell
后,ninja.yell
功能的引用会添加到samurai
。
在JavaScript中,函数也是对象。它们通过引用传递。 samurai.yell = ninja.yell
未执行的操作会复制对ninja
的任何类型的引用。
在示例的第9行, var ninja = null
不会以任何方式修改ninja.yell
处的功能。它也不会以任何方式修改以ninja
存储的对象。它的作用是删除对ninja
存储的对象的引用,并将其替换为值null
。这意味着ninja
引用的对象的任何其他副本仍将指向ninja引用的对象。
通过示例更容易看到:
var foo,
bar;
foo = {
fizz: 'buzz'
};
bar = foo;
foo = null;
console.log(bar.fizz); //buzz
是因为因为忍者周围还有一个参考,所以它不是垃圾收集的吗?
在执行示例脚本的第9行之后,不再有对ninja
处对象的任何引用。 是对ninja.yell
处的函数的引用。这意味着ninja
对象可以被垃圾收集,但ninja.yell
对象(恰好是一个函数)不能。
答案 3 :(得分:0)
以JavaScript解释器的方式运行执行:
obj1
)。func1
的新匿名函数return n > 0 ? ...
。obj1
添加一个名为yell
的新属性,该对象是函数func1
的别名。ninja
的新根属性(变量可以被视为字段属性)。此时,“堆”看起来像这样:
func1 = n => return n > 0 ? yell(n-1) + "a" : "hiy"
obj1 = { yell: func1 }
ninja = obj1
obj2
)。obj2
添加一个名为yell
的新属性,该对象是函数func1
的别名 - 不是 ninja.yell
的别名 - 对“函数值”本身的引用被复制到obj2.yell
而不是引用到函数的引用。obj2
分配给samurai
。obj3
)。ninja
。此时,“堆”看起来像这样:
func1 = n => return n > 0 ? yell(n-1) + "a" : "hiy"
obj1 = { yell: func1 } // this no-longer has any references and will be GC'd at some point
obj2 = { yell: func1 }
obj3 = {}
samurai = obj2
ninja = obj3
samurai.yell
,取消引用obj2
,然后func1
成功拨打电话。