阅读 John Resig 的 Learning Advanced Javascript , 我遇到了两张我不完全理解的幻灯片。
幻灯片 #13 - 引用作为匿名函数的属性。第二个断言失败。
var ninja = {
yell: function(n){
return n > 0 ? ninja.yell(n-1) + "a" : "hiy";
}
};
assert( ninja.yell(4) == "hiyaaaa", "A single object isn't too bad, either." ); // PASS
var samurai = { yell: ninja.yell };
var ninja = null;
try {
samurai.yell(4);
} catch(e){
assert( false, "Uh, this isn't good! Where'd ninja.yell go?" ); // FAIL
}
幻灯片 #14 - 引用作为已定义函数的属性。第二个断言通过。
var ninja = {
yell: function yell(n){
return n > 0 ? yell(n-1) + "a" : "hiy";
}
};
assert( ninja.yell(4) == "hiyaaaa", "Works as we would expect it to!" ); // PASS
var samurai = { yell: ninja.yell };
var ninja = {};
assert( samurai.yell(4) == "hiyaaaa", "The method correctly calls itself." ); // PASS
此处唯一的区别是 yell
是幻灯片 14 中的命名函数。为什么即使在设置原始对象后,对定义为命名函数的属性的引用仍然存在 (ninja
) 到一个新对象(甚至是 null)?
最佳答案
The only difference here is that yell is a named function in slide 14.
不,这不是唯一的区别,也不是最重要的区别(尽管它与重要的区别有关)。
在第一个中,注意 ninja.yell
是如何定义的:
var ninja = {
yell: function(n){
return n > 0 ? ninja.yell(n-1) + "a" : "hiy";
// ----------------^^^^^^^^^^^^^^^
}
};
它在自身内部明确使用了 ninja.yell
。因此调用它会查找变量 ninja
,然后尝试查找 yell
作为 ninja
的属性。
将其与第二个示例中的定义进行比较:
var ninja = {
yell: function yell(n){
return n > 0 ? yell(n-1) + "a" : "hiy";
// ----------------^^^^^^^^^
}
};
yell
不再使用变量 ninja
,它仅使用自身的范围内标识符(通过命名函数表达式为函数命名而创建的标识符).
这就是为什么在第一个例子中 ninja
被清空的原因:
var ninja = null;
...第一个开始失败;你不能在 null
上查找 yell
。
但是当 ninaj
在第二个中被替换时(我不明白为什么 John 在这两种情况下都没有使用 null
,但无论如何):
var ninja = {};
...yell
不在乎,因为它不使用ninja
。
旁注:从 ES2015 开始,yell
的两个版本都不是匿名函数,即使第一个版本是使用匿名函数表达式创建的。在 ES2015 中,函数可以根据上下文获取其名称,其中一种获取名称的方法是在对象初始值设定项中分配给对象属性。不过,这对解决这个问题没有帮助,因为名称不是函数内的范围内标识符,就像您使用命名函数表达式时那样。
关于javascript - 引用匿名函数与命名函数的属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42766177/