我正在关注John Resig's Secrets of JS ninja slides,我发现了一些我不太清楚的事情。以下代码定义了命名函数表达式:
var ninja = function myNinja(){
console.log(myNinja); // function myNinja() {...}
};
myNinja; // undefined
正如我所看到的,在当前范围内(假设它是全局的),ninja
是保存对命名函数myNinja
的引用的变量。 ninja
变量可以在范围内访问 - 很明显,但是myNinja
在范围内是不可访问的(但它可以在自己的函数中访问)。怎么样?
如果我定义一个函数(不使用函数表达式,但函数声明):
function Cheese() {
console.log(Cheese);
}
然后它可以在当前范围内访问。我知道这就是这样 - 但有人可以解释为什么会这样吗?
答案 0 :(得分:2)
在他的书 The Secrets of the JavaScript Ninja 中,John Resig对这个概念作了精彩的解释。
以下是本书的引用:
<强> 4.2.4。内联命名函数
<script type="text/javascript">
var ninja = function myNinja(){
assert(ninja == myNinja, "this is named two things at once!");
};
ninja();
assert(typeof myNinja == "undefined",
"But myNinja isn't defined outside of the function.");
</script>
此列表提出了有关内联的最重要的观点 函数:即使可以命名内联函数,这些名称也是如此 只在功能本身内可见。
还记得我们在第3章中讨论过的范围规则吗? <强>内联 函数名称有点像变量名,其范围是 仅限于声明它们的功能。
<强> 3.2.1。范围和功能
变量声明的范围从它们的声明到 无论如何,它们被宣布为的函数的结尾 阻止嵌套。
如果您想了解更多有关此概念的信息,本书将为您提供帮助。
答案 1 :(得分:0)
想象一下,当你简单地定义一个函数(奶酪)时,你告诉当前的范围 - “我想让你知道这个函数,它的名字是奶酪。 当你使用var忍者时,你现在正在处理忍者范围,告诉它基本相同的事情。所以现在你只知道当前(忍者)范围内的新功能(myNinja)......
答案 2 :(得分:0)
为什么会这样?
每次计算时,函数表达式都会创建一个新的函数对象。结果发生的事情一开始就无关紧要。但...
var ninja;
// myNinja; - what would you expect it to be here?
for (var i=0; i<5; i++)
ninja = function myNinja(){
console.log(myNinja);
};
// myNinja; - *which one* would you expect it to be here?
ninja();
对ninja()
的调用很明显,它引用了最后赋给该变量的函数。 myNinja
中的console.log
引用了当前函数对象 - 它位于自己的范围内。
但是myNinja
标识符在函数本身之外是不明确的。
相反,函数声明被提升并可从整个范围访问。它的标识符唯一地引用在范围初始化时创建一次的单个函数对象。
答案 3 :(得分:0)
Name是函数对象的属性。如果您要在调试器中检查Function实例,您将在其上看到name
属性。对于在全局范围中定义的函数,name
的值将自动用作属性的名称。
引用它的window
对象。
对于内联函数,您将定义将引用该函数的属性的名称。 JS引擎不需要使用Function实例中的name
属性。