帮助理解javascript全局减排技术

时间:2011-03-15 22:37:31

标签: javascript globals

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

到目前为止,我对(function(){})的理解很好。我理解设置turing var up,将global.turing设置为turing,然后返回窗口或者这个(如果不是在浏览器中),但是(function(global){})(this或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);

2 个答案:

答案 0 :(得分:9)

(这个答案超过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;
    // ...
}());

这对于一个参数来说大部分时间都是正确的(它不会同时覆盖外部作用域中同名的变量,同时依赖于它的值),并且对于多个参数通常为true(如果他们也不依赖彼此。我希望这些例子会更清楚。

当我们有这个代码时:

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

然后我们无法将其翻译成:

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

因为在第一个版本中我们将外部 x添加1并将结果绑定到内部 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,其中我解释了类似的概念。

答案 1 :(得分:1)

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

使用匿名函数实际上是作者的首选问题。如果不设置匿名函数来处理先前调用的返回值,则必须在客户端分配额外的内存,方法是初始化一个变量以包含返回的对象,然后将其传递给全局声明的函数。连续的方式。

如果它是1次功能,它可以节省空间,内存和时间。

作为旁注:你可以通过谷歌搜索函数式编程背后的一些概念来获得更好的感觉。 Lambda函数最近似乎风靡一时,特别是在Python中。