一尘不染

返回后定义函数

angularjs

我目前正在阅读John Papa的AngularJS样式指南,并看到了以下代码

function dataService() {
    var someValue = '';
    var service = {
        save: save,
        someValue: someValue,
        validate: validate
    };
    return service;

    ////////////

    function save() {
        /* */
    };

    function validate() {
        /* */
    };
}

您可以看到函数savevalidate 函数返回值 之后
定义的。这是如何运作的?它是否符合标准并且可以在所有浏览器中使用(例如,来自IE 6)?


阅读 252

收藏
2020-07-04

共1个答案

一尘不染

您可以看到函数savevalidate是在函数返回值之后定义的。

那是从它们的编写位置看的样子,是的,但是实际上它们是在函数中的任何分步代码完全运行之前定义的。有时这被称为“提升”函数顶部的声明(类似的情况var也发生在;下面还有更多)。

当控件进入执行上下文时(例如,当您输入函数,在程序开头输入全局环境或输入eval代码时), 在执行 任何分步代码 之前
发生的几件事之一是:处理该上下文中的所有函数 声明
,并创建这些函数。由于savevalidate是由函数声明定义的,因此它们是在代码的第一行逐步运行之前创建的,因此它们位于的后面也没关系return

在调用函数时(例如,在调用时dataService),其中突出显示了函数声明步骤,这是JavaScript引擎的工作:

  1. 设定值 this
  2. env为通话创建一个新环境(我们称之为)
  3. 设置对函数[[Scope]]属性的引用env(这是闭包工作方式的一部分)
  4. 为环境创建一个 绑定对象 (让我们称之为bindings),以容纳函数定义的各种名称(这是闭包如何工作以及变量引用如何解析的另一部分)
  5. 如果函数具有名称,则将其添加bindings为引用该函数的属性
  6. 将形式函数参数添加到 bindings
  7. 处理函数声明,将其名称添加到bindings
  8. 创建arguments对象,将其添加到bindings
  9. 添加与声明的每个变量varbindings(如果尚未定义)与价值undefined
  10. 处理函数中的逐步代码
  11. 设置调用表达式的结果

§10.4.1的规范及其链接的各节中,详细地列出了这一点。(如果您读懂了,大胆地做吧,散文是……笨拙的……)这是当前规范的链接,但这在1999年旧的第三版规范的§10中也有明确规定,我很确定从一开始就是对的。

它是否符合标准并且可以在所有浏览器中使用(例如,来自IE 6)?

是。它曾经使我感到紧张,所以几年前(大概是2005年),我在所有我能找到的当时流行且不死的浏览器(包括IE6)上向我证明了这一点,并且普遍正确地对其进行了处理。实际上这并不奇怪,因为这是使此代码起作用的原因:

doSomething();

function doSomething() {
    // ....
}

…人们 一直在 这样做。


这种“吊装”是函数 声明 和函数 表达式 之间的主要区别之一。如果savevalidate是由函数 表达式
创建的,那么在它们之后写的代码就很重要了return -它们根本不会被创建:

// It wouldn't work like this, for instance
function dataService() {
    var someValue = '';
    var service = {
        save: save,             // `save` has the value `undefined` at this point
        someValue: someValue,
        validate: validate      // So does `validate`
    };
    return service;

    ////////////

    var save = function() {      // Now this is a function expression
        /* */
    };

    var validate = function() {  // This too
        /* */
    };
}

savevalidate变量会得到创建(由于在上述步骤9),但他们已经习惯的地方,他们就会有值undefined,因此返回的对象是没有用的。

2020-07-04