返回后定义函数 [英] Defining functions after return

查看:88
本文介绍了返回后定义函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在阅读 John Papa的AngularJS样式指南,并看到了 function dataService() { var someValue = ''; var service = { save: save, someValue: someValue, validate: validate }; return service; //////////// function save() { /* */ }; function validate() { /* */ }; }

您可以看到之后,函数savevalidate均已定义,该函数返回了一个值.这是如何运作的?是否符合标准并且可以在所有浏览器中使用(例如,从IE 6开始)?

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

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

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

当您调用函数时(例如,调用dataService时),JavaScript引擎将执行以下操作,其中突出显示了函数声明步骤:

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

这在 §10.4.1及其链接的部分. (如果您阅读该书,请准备好自己,散文是...笨拙的...)这是当前规范的链接,但这在1999年旧的第三版规范的§10中也有明确规定,而且我很确定从一开始它就是真的.

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

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

doSomething();

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

...人们一直在这样做 .


此吊装"是功能声明和功能 expressions 之间的主要区别之一.如果savevalidate是由函数 expressions 创建的,那么在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,因此返回的对象将不会会有用的.

I'm currently reading John Papa's AngularJS style guide and saw the code:

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. How does this work? Is it standard-compliant and works in all browsers (say, from IE 6)?

解决方案

You can see that the functions save and validate are defined after the function returned a value.

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).

When control enters an execution context (e.g., 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. 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.

Here's what the JavaScript engine does when you call a function (e.g., when calling dataService), with the function declarations step highlighted:

  1. Set the value of this
  2. Create a new environment (let's call it env) for the call
  3. Set up a reference to the function’s [[Scope]] property on env (this is part of how closures work)
  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)
  5. If the function has a name, add it to bindings as a property referring to the function
  6. Add the formal function arguments to bindings
  7. Process function declarations, adding their names to bindings
  8. Create the arguments object, add it to bindings
  9. Add each variable declared with var to bindings (if not already defined) with the value 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. (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.

Is it standard-compliant and works in all browsers (say, from 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. 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:

// 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.

这篇关于返回后定义函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆