【问题标题】:Help understanding javascript global abatement techniques帮助理解 javascript 全局消减技术
【发布时间】:2011-07-16 04:35:05
【问题描述】:

来自 DailyJS "Let's build a JavaScript Framework" 我不太确定以下代码,显然是用作全局减排技术。

到目前为止,我的理解还停留在 (function(){}) 上。我了解设置 turing var,将 global.turing 设置为 turing,并返回 window 或 this(如果不在浏览器中),但是 (function(global){})(this or window) 事情让我感到困惑......我见过类似的东西

var mything = {} 并将你所有的代码都设置在神话之下,但这个成语让我有点困惑。

我真的很想理解这里的推理而不是记住它“有效”

(function(global) {
  var turing = {
    VERSION: '0.0.1',
    lesson: 'Part 1: Library Architecture'
  };

  if (global.turing) {
    throw new Error('turing has already been defined');
  } else {
    global.turing = turing;
  }
})(typeof window === 'undefined' ? this : window);

【问题讨论】:

    标签: javascript globals


    【解决方案1】:

    (此答案已有 4 年之久(截至 2015 年 4 月),虽然它仍然正确,但我认为它需要更一般的解释 - 见下文)

    原答案

    想一想:

    (function (x) {
        // ...
    })(y);
    

    作为:

    function functionName(x) {
        // ...
    }
    functionName(y);
    

    但不需要给它一个名字(比如functionName)。

    所以这个:

    (function(global) {
        // ...
    })(typeof window === 'undefined' ? this : window);
    

    真的只是:

    function functionName(global) {
        // ...
    }
    functionName(typeof window === 'undefined' ? this : window);
    

    它是一个有一个参数的函数(在函数中称为global),它以typeof window === 'undefined' ? this : window 调用,含义相同:

    function functionName(global) {
        // ...
    }
    if (typeof window === 'undefined') {
        functionName(this);
    } else {
        functionName(window);
    }
    

    但使用更短的符号(并且没有命名函数)。

    更一般的解释

    我在 4 年前写了这个答案,我认为是时候对这里涉及的概念添加一些更一般的解释了。

    如上所述,这是:

    (function (x) {
        // ...
    })(y);
    

    是这个的匿名版本:

    function functionName(x) {
        // ...
    }
    functionName(y);
    

    其中(如果您只调用一次)通常(见下文例外)也与此相同:

    function functionName() {
        var x = y;
        // ...
    }
    functionName();
    

    回到匿名立即调用的函数,这个:

    (function (x) {
        // ...
    })(y);
    

    和这个是一样的:

    (function () {
        var x = y;
        // ...
    })();
    

    这对大多数人来说可能具有更明显的含义。 (这里立即调用的函数没有参数,只是为了给我们一个变量和其他嵌套函数的隔离范围,这样我们就不会污染外部或全局范围——这也是在首先立即调用匿名函数。)

    在括号内

    顺便说一句:

    (function () {
        // ...
    })();
    

    和这个是一样的:

    (function () {
        // ...
    }());
    

    由于语言的歧义,函数周围的括号是必需的,但它们可能包括实际调用函数的(),也可能不包括——尽管有些人认为这里的第二种形式看起来更清晰。请参阅this explanation by Douglas Crockford 了解更多详细信息以及为什么他认为第一个版本看起来像“狗球”。

    例外情况

    之前我说过这个:

    (function (x) {
        // ...
    }(y));
    

    和这个是一样的:

    (function () {
        var x = y;
        // ...
    }());
    

    这在大多数情况下对于一个参数是正确的(它不会在外部范围内屏蔽同名变量同时取决于它的值)并且通常对于多个参数是正确的(如果它们也不相互依赖)。我希望这些例子会更清楚。

    当我们有这个代码时:

    (function (x) {
        // ...
    }(x + 1));
    

    那么我们不能把它翻译成:

    (function () {
        var x = x + 1;
        // ...
    }());
    

    因为在第一个版本中,我们将 1 添加到 outer x 并将结果绑定到 inner x 并且一旦我们进入函数内部我们只有内部的x 可以使用(甚至新的let 语句也无济于事)。

    另一个例子:

    (function (x, outer_x) {
        // ...
    }(1, x));
    

    这里你可以将外部作用域的old_x设置为x的值,将内部作用域的x设置为一个新的值1,你不必担心顺序。但如果你这样做了:

    总结

    如您所见,有些情况您不能简单地翻译:

    (function (x) {
        // ...
    }(y));
    

    进入:

    (function () {
        var x = y;
        // ...
    }());
    

    但我认为,如果它可以翻译成第二种形式,那么它应该是为了可读性。特别是对于较大的函数,您必须滚动到函数末尾才能知道函数顶部使用的变量的含义是不方便的。

    回到问题

    这意味着我会从问题中翻译这段代码:

    (function(global) {
      var turing = {
        VERSION: '0.0.1',
        lesson: 'Part 1: Library Architecture'
      };
    
      if (global.turing) {
        throw new Error('turing has already been defined');
      } else {
        global.turing = turing;
      }
    })(typeof window === 'undefined' ? this : window);
    

    进入这个:

    (function () {
      var global = typeof window === 'undefined' ? this : window;
      var turing = {
        VERSION: '0.0.1',
        lesson: 'Part 1: Library Architecture'
      };
    
      if (global.turing) {
        throw new Error('turing has already been defined');
      } else {
        global.turing = turing;
      }
    }());
    

    我希望这个答案能解释为什么这两者是等价的,甚至可以写成:

    (function (global, turing) {
      if (global.turing) {
        throw new Error('turing has already been defined');
      } else {
        global.turing = turing;
      }
    })(typeof window === 'undefined' ? this : window,
       {VERSION: '0.0.1', lesson: 'Part 1: Library Architecture'});
    

    它的含义仍然相同,但同时可读性要低得多。

    另请参阅my other answer,我在其中解释了类似的概念。

    【讨论】:

      【解决方案2】:

      这是一个匿名或 lambda 函数。大多数语言都支持这一点。

      使用匿名函数确实是作者的偏好问题。如果不设置匿名函数来处理先前调用的返回值,您将不得不在客户端分配额外的内存,方法是初始化一个变量以包含返回的对象,然后稍后将其传递给全局声明的函数串行方式。

      如果是1次函数,则节省空间、内存、时间。

      附带说明:通过谷歌搜索函数式编程背后的一些概念,您可能会对此有更好的感觉。 Lambda 函数最近似乎风靡一时,尤其是在 Python 中。

      【讨论】:

      • “Lambda 函数似乎风靡一时”——这是因为我们可以用 Lisp 以外的东西进行编程。 :-)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-05
      • 1970-01-01
      • 1970-01-01
      • 2013-09-18
      相关资源
      最近更新 更多