(这个答案已经超过 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 () {
// ...
}());
由于语言歧义,函数周围的括号是必需的,但它们可能包括()
实际调用函数的,也可能不包括 - 尽管有些人认为这里的第二种形式看起来更清楚。有关更多详细信息以及为什么他认为第一个版本看起来像“狗球”,请参阅Douglas Crockford 的解释。
例外
之前我说过这个:
(function (x) {
// ...
}(y));
与此相同:
(function () {
var x = y;
// ...
}());
这在大多数情况下对于一个参数是正确的(它不会在外部范围内屏蔽同名变量,同时取决于它的值)并且通常对于多个参数是正确的(如果他们不这样做) t 也相互依赖)。我希望它会在示例中变得更加清晰。
当我们有这段代码时:
(function (x) {
// ...
}(x + 1));
那么我们不能把它翻译成:
(function () {
var x = x + 1;
// ...
}());
因为在第一个版本中,我们将 1 添加到外部 x
并将结果绑定到内部 x
,一旦我们进入函数内部,我们就只有内部x
可以使用(即使是 newlet
语句也无济于事)。
另一个例子:
(function (x, outer_x) {
// ...
}(1, x));
在这里你可以设置从外部作用域和内部作用域的old_x
值到一个新的值1,你不必担心顺序。但如果你这样做了:x
x
概括
如您所见,在某些情况下您不能简单地翻译:
(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'});
它仍然意味着相同,同时可读性要低得多。
另请参阅我解释类似概念的其他答案。