【问题标题】:javascript named function expressions - scope accessibility [duplicate]javascript命名函数表达式-范围可访问性[重复]
【发布时间】:2013-07-03 11:23:59
【问题描述】:

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

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

【问题讨论】:

  • "有人能解释一下为什么会这样吗" 如果你问这个设计决定的原因,你应该联系从事 ECMAScript 标准工作的人。
  • @FelixKling 嗨,再见!你是从我的问题中复制评论吗?
  • @FelixKling 好吧,这与设计决策无关 :) 我只是想了解这个概念在内部是如何运作的,而不是为什么 ECMA 中的某个人喜欢这个概念 ;)
  • @tkoomzaaskz:这样的话,你可以在规范中找到技术解释:es5.github.io/#x13。它明确表示:FunctionExpression 中的Identifier 可以从FunctionExpressionFunctionBody 内部引用,以允许函数递归调用自身。但是,与FunctionDeclaration 不同, FunctionExpression 中的 Identifier 不能被引用,并且不影响包含 FunctionExpression 的范围。"

标签: javascript function


【解决方案1】:

在他的书中,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.范围和功能

变量声明的范围从它们的声明点到 声明它们的函数的结尾,无论 块嵌套。

如果您想了解更多有关此概念的信息,本书将为您提供帮助。

【讨论】:

    【解决方案2】:

    这是为什么呢?

    函数表达式每次计算时都会创建一个新的函数对象。这个结果会发生什么一开始是无关紧要的。但是……

    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() 的调用很明显,它引用了最后分配给该变量的函数。 console.log 中的 myNinja 引用 current 函数对象 - 它在其 自己的 范围内。

    myNinja 标识符在函数本身之外会是模棱两可的。

    相比之下,函数声明被提升并可从整个范围访问。它的标识符唯一地引用了在作用域初始化时创建的单个函数对象。

    【讨论】:

      【解决方案3】:

      想象一下,当你简单地定义一个函数(cheese)时,你告诉当前作用域——“我想让你知道这个函数,它的名字叫 cheese。 当您使用 var ninja 时,您现在正在处理 ninja 范围,告诉它基本相同的事情。所以现在你的新功能(myNinja)只在当前(ninja)范围内知道......

      【讨论】:

      • 我正在努力理解您的解释。我知道当控件进入 javascript 中的新函数时,会创建新的范围上下文并附加新的变量对象 - 这很清楚。现在您写道:当您使用 var ninja 时,您现在正在处理 ninja 范围 - 您的意思是当我声明一个新变量时(在这种情况下,该变量指的是一个函数)变量的新作用域(不是函数)?
      【解决方案4】:

      名称是函数对象的一个​​属性。如果您要在调试器中检查 Function 实例,您将在其上看到 name 属性。对于在全局范围内定义的函数,name 的值会自动用作 window 引用它的对象。

      对于内联函数,您正在定义引用该函数的属性的名称。 JS 引擎不需要使用 Function 实例中的 name 属性。

      【讨论】:

        猜你喜欢
        • 2017-06-27
        • 1970-01-01
        • 1970-01-01
        • 2016-08-13
        • 1970-01-01
        • 2013-04-11
        • 1970-01-01
        • 2012-05-16
        • 2015-12-20
        相关资源
        最近更新 更多