(这个答案已有 4 年多了(截至 2015 年 4 月),虽然它仍然正确,但我认为它需要一个更一般的解释 - 见下文)
原答案
想一想:
(function (x) {
// ...
})(y);
as:
function functionName(x) {
// ...
}
functionName(y);
但不需要给它一个名称(如 functionName)。
So this:
(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);
其中(如果只调用一次)是usually(例外情况见下文)也与此相同:
function functionName() {
var x = y;
// ...
}
functionName();
回到匿名立即调用函数,如下:
(function (x) {
// ...
})(y);
与此相同:
(function () {
var x = y;
// ...
})();
这对大多数人来说可能有更明显的意义。 (这里立即调用的函数没有参数,仅用于为变量和其他嵌套函数提供一个隔离的作用域,这样我们就不会污染外部或全局作用域 - 这也是在中使用参数的主要原因首先立即调用匿名函数。)
在括号上
顺便说一下,这个:
(function () {
// ...
})();
与此相同:
(function () {
// ...
}());
由于语言歧义,函数周围需要括号,但它们可能包括()
实际上调用该函数,也可能不调用该函数 - 尽管有些人认为这里的第二种形式看起来更清晰。看道格拉斯·克罗克福德 (Douglas Crockford) 的解释 https://youtu.be/taaEzHI9xyY?t=33m39s了解更多细节以及为什么他认为第一个版本看起来像“狗球”。
例外情况
之前我说过这样的:
(function (x) {
// ...
}(y));
与此相同:
(function () {
var x = y;
// ...
}());
大多数情况下,对于一个参数来说这是正确的(这不会在同时依赖于其值的同时屏蔽外部作用域中的同名变量),并且对于多个参数来说通常是正确的(如果它们不这样做)也相互依赖)。我希望通过示例可以更加清楚。
当我们有这段代码时:
(function (x) {
// ...
}(x + 1));
那么我们不能将其翻译为:
(function () {
var x = x + 1;
// ...
}());
因为在第一个版本中我们添加 1outer x
并将结果绑定到inner x
一旦我们进入函数内部,我们就只有内部的了x
与(甚至是新的let https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let声明对我们没有帮助)。
另一个例子:
(function (x, outer_x) {
// ...
}(1, x));
在这里你可以设置old_x
的值x
从外部范围和x
在内部范围中将其设置为新值 1,并且您不必担心顺序。但如果你这样做了:
Summary
正如您所看到的,在某些情况下您不能简单地翻译:
(function (x) {
// ...
}(y));
into:
(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'});
它的含义仍然是一样的,但同时可读性却大大降低。
也可以看看我的另一个答案 https://stackoverflow.com/questions/5305634/jquery-question-what-does-it-really-mean/5305786#5305786我在其中解释了类似的概念。