javascript命名函数表达式 - 范围可访问性

时间:2013-07-03 11:24:00

标签: javascript function

我正在关注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);
}

然后它可以在当前范围内访问。我知道这就是这样 - 但有人可以解释为什么会这样吗?

4 个答案:

答案 0 :(得分:2)

在他的书 The Secrets of the JavaScript Ninja 中,John Resig对这个概念作了精彩的解释。

http://jsninja.com/

以下是本书的引用:

<强> 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属性。