简体   繁体   English

返回后定义函数

[英]Defining functions after return

I'm currently reading John Papa's AngularJS style guide and saw the code : 我正在阅读John Papa的AngularJS风格指南,并看到了代码

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

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

    function save() {
        /* */
    };

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

You can see that the functions save and validate are defined after the function returned a value. 您可以看到函数savevalidate函数返回值定义的。 How does this work? 这是如何运作的? Is it standard-compliant and works in all browsers (say, from IE 6)? 它是否符合标准并适用于所有浏览器(例如,来自IE 6)?

You can see that the functions save and validate are defined after the function returned a value. 您可以看到函数savevalidate是在函数返回值后定义的。

That's what it looks like from where they're written, yes, but in fact they're defined before any step-by-step code in the function runs at all. 这就是从它们写入的地方看起来的样子,是的,但实际上它们是在函数中的任何分步代码运行之前定义的。 Sometimes this is called "hoisting" the declarations to the top of the function (something similar happens with var , too; more below). 有时这被称为“提升”声明到函数的顶部(类似的情况也发生在var ;更多下面)。

When control enters an execution context (eg, when you enter a function, enter the global environment at the beginning of the program, or enter eval code), one of the several things that happens before any step-by-step code is executed is that all of the function declarations in that context are processed and those functions are created. 当控件进入执行上下文时(例如,当您输入函数时,在程序开头输入全局环境,或输入eval代码), 在执行任何分步代码之前发生的几件事之一是处理该上下文中的所有函数声明并创建这些函数。 Since save and validate are defined by function declarations, they're created before the first step-by-step line of the code runs, and so it doesn't matter that they're after the return . 由于savevalidate是由函数声明定义的,因此它们是在代码的第一个逐步行之前创建的,因此它们在return之后并不重要。

Here's what the JavaScript engine does when you call a function (eg, when calling dataService ), with the function declarations step highlighted: 以下是JavaScript引擎在调用函数时所执行的操作(例如,在调用dataService ),并突出显示了函数声明步骤:

  1. Set the value of this 设置的值, this
  2. Create a new environment (let's call it env ) for the call 为呼叫创建一个新环境(让我们称之为env
  3. Set up a reference to the function's [[Scope]] property on env (this is part of how closures work) env上设置对函数[[Scope]]属性的引用(这是闭包工作方式的一部分)
  4. Create a binding object (let's call it bindings ) for the environment to hold our the various names defined by the function (this is another part of how closures work, and also how variable references are resolved) 为环境创建一个绑定对象 (让我们称之为bindings )来保存我们由函数定义的各种名称(这是闭包如何工作的另一部分,以及如何解析变量引用)
  5. If the function has a name, add it to bindings as a property referring to the function 如果函数具有名称,请将其作为引用该函数的属性添加到bindings
  6. Add the formal function arguments to bindings 将正式函数参数添加到bindings
  7. Process function declarations, adding their names to bindings 处理函数声明,将其名称添加到bindings
  8. Create the arguments object, add it to bindings 创建arguments对象,将其添加到bindings
  9. Add each variable declared with var to bindings (if not already defined) with the value undefined 将使用var声明的每个变量添加到bindings (如果尚未定义),并使用值undefined
  10. Process the stepwise code in the function 处理函数中的逐步代码
  11. Set the call expression's result 设置调用表达式的结果

This is laid out in excruciating detail in the spec in §10.4.1 and the sections it links to. 这在§10.4.1中的规范及其链接的部分中以极其详细的方式列出 (If you go to read that, brace yourself, the prose is...turgid...) That's a link to the current spec, but this was clearly laid out in §10 of the old third edition spec in 1999 as well, and I'm fairly sure it's been true right from the beginning. (如果你去阅读那个,自我鼓励,散文就是......不稳定......)这是当前规范的一个链接,但这在1999年旧版第三版规范的§10中也有明确规定,而且我很确定从一开始就是如此。

Is it standard-compliant and works in all browsers (say, from IE 6)? 它是否符合标准并适用于所有浏览器(例如,来自IE 6)?

Yes. 是。 It used to make me nervous, so several years back (probably ~2005) I proved it to myself on all of the then-current and not-quite-dead browsers I could find (including IE6), and it was universally handled correctly. 它曾经让我感到紧张,所以几年前(可能〜2005年)我在我能找到的所有当时和非常死的浏览器(包括IE6)上证明了这一点,并且它得到了普遍正确的处理。 Which isn't actually surprising, because it's what makes this code work: 这实际上并不令人惊讶,因为它是使这段代码工作的原因:

doSomething();

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

...and people do that all the time . ......人们这样做, 所有的时间


This "hoisting" is one of the key differences between function declarations and function expressions . 这种“提升”是函数声明和函数表达式之间的关键差异之一。 If save and validate were created by function expressions , then it would matter a great deal that they were written after the return — they'd never get created at all: 如果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
        /* */
    };
}

The save and validate variables would get created (thanks to Step 9 in the above), but as of where they're used, they'd have the value undefined and so the returned object wouldn't be useful. 将创建savevalidate变量(由于上面的步骤9),但是在使用它们的地方,它们的值undefined ,因此返回的对象将没有用处。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM