为什么 JavaScript IIFE 周围需要括号?
Why are parentheses required around JavaScript IIFE?
我正在阅读 JavaScript IIFE 以及目前理解的概念,但我想知道外面的括号。具体来说,为什么需要它们?例如,
(function() {var msg='I love JavaScript'; console.log(msg);}());
效果很好,但是
function() {var msg='I love JavaScript'; console.log(msg);}();
产生语法错误。为什么?关于 IIFE 有很多讨论,但我没有看到关于为什么需要括号的明确解释。
括号中的 IIFE 版本有效,因为这将内部函数声明的声明标记为表达式。
http://benalman.com/news/2010/11/immediately-invoked-function-expression/
更详细的解释请看:
Advanced JavaScript: Why is this function wrapped in parentheses?
提示:
调用运算符 (()) 仅适用于表达式,不适用于声明。
在JavaScript中有两种创建函数的方法(好吧,3,但让我们忽略new Function()
)。可以写函数声明,也可以写函数表达式。
函数声明本身就是一个语句,语句本身不会 return 值(我们也忽略调试控制台或 Node.js REPL 打印 return 语句的值)。然而,函数表达式是一个适当的表达式,并且表达式在 JavaScript return 的值中可以立即使用。
现在,你可能已经看到有人说下面是一个函数表达式:
var x = function () {};
可能很容易得出结论,语法:
function () {};
是使它成为一个表达式的原因。但那是错误的。上面的语法使它成为一个匿名函数。匿名函数可以是声明或表达式。使它成为表达式的是这种语法:
var x = ...
也就是说,=
符号右边的所有内容都是表达式。表达式使用编程语言编写数学公式变得更加容易。所以一般来说,任何需要处理数学的地方都是一个表达式。
JavaScript中的一些表达式形式包括:
=
运算符右侧的所有内容
- 大括号
()
中的内容不是函数调用大括号
- 数学运算符右边的所有内容 (
+
,-
,*
,/
)
- 三元运算符的所有参数
.. ? .. : ..
当你写:
function () {}
它是一个声明,而不是 return 一个值(声明的函数)。因此尝试调用非结果是错误的。
但是当你写的时候:
(function () {})
它是一个表达式,return它是一个可以立即使用(例如,可以调用或可以赋值)的值(声明的函数)。
请注意上述表达式的计算规则。由此可见,大括号并不是您可以用来构造 IIFE 的唯一东西。以下是构造 IIFE 的有效方法(因为我们写的是函数表达式):
tmp=function(){}()
+function(){}()
-function(){}()
0/function(){}()
0*function(){}()
0?0:function(){}()
(function(){}())
(function(){})()
你可能会在第三方库中实际看到上述非标准形式之一(特别是 +
版本),因为他们想要节省一个字节。但我强烈建议您只使用大括号形式(都可以),因为它们被其他程序员广泛认为是 IIFE。
这将是一个冗长的答案,但会为您提供必要的背景知识。在 JavaScript 中有两种方法可以定义函数:
一个函数定义(经典的那种)
function foo() {
//why do we always use
}
然后是更晦涩的类型,一个函数表达式
var bar = function() {
//foo and bar
};
本质上,执行时发生了同样的事情。创建一个函数对象,分配内存,并为该函数绑定一个标识符。区别在于语法。前者本身就是一个声明新函数的语句,后者是一个表达式。
函数表达式使我们能够在需要普通表达式的任何地方插入函数。这有助于匿名函数和回调。举个例子
setTimeout(500, function() {
//for examples
});
在这里,只要 setTimeout 这么说,匿名函数就会执行。但是,如果我们想立即执行一个函数表达式,我们需要确保语法可以被识别为一个表达式,否则我们会不清楚我们指的是函数表达式还是语句。
var fourteen = function sumOfSquares() {
var value = 0;
for (var i = 0; i < 4; i++)
value += i * i;
return value;
}();
这里直接调用sumOfSquares
,因为可以识别为表达式。 fourteen
变为 14
并且 sumOfSquares 被垃圾收集。 在您的示例中,分组运算符 ()
将其内容强制转换为表达式,因此该函数是一个表达式,可以立即调用。
关于我的第一个 foo 和 bar 示例之间的区别,需要注意的一件重要事情是提升。如果您不知道它是什么,快速 Google 搜索或两次应该会告诉您,但快速而肮脏的定义是提升是 JavaScript 带来声明(变量和函数)的行为) 到范围的顶部。这些声明通常只提升标识符而不是它的初始化值,所以整个范围将能够在它被赋值之前看到variable/function。
对于函数定义,情况并非如此,这里整个声明被提升并且在整个包含范围内可见。
console.log("lose your " + function() {
fiz(); //will execute fiz
buzz(); //throws TypeError
function fiz() {
console.log("lose your scoping,");
}
var buzz = function() {
console.log("and win forever");
};
return "sanity";
}()); //prints "lose your scoping, lose your sanity"
我正在阅读 JavaScript IIFE 以及目前理解的概念,但我想知道外面的括号。具体来说,为什么需要它们?例如,
(function() {var msg='I love JavaScript'; console.log(msg);}());
效果很好,但是
function() {var msg='I love JavaScript'; console.log(msg);}();
产生语法错误。为什么?关于 IIFE 有很多讨论,但我没有看到关于为什么需要括号的明确解释。
括号中的 IIFE 版本有效,因为这将内部函数声明的声明标记为表达式。
http://benalman.com/news/2010/11/immediately-invoked-function-expression/
更详细的解释请看:
Advanced JavaScript: Why is this function wrapped in parentheses?
提示:
调用运算符 (()) 仅适用于表达式,不适用于声明。
在JavaScript中有两种创建函数的方法(好吧,3,但让我们忽略new Function()
)。可以写函数声明,也可以写函数表达式。
函数声明本身就是一个语句,语句本身不会 return 值(我们也忽略调试控制台或 Node.js REPL 打印 return 语句的值)。然而,函数表达式是一个适当的表达式,并且表达式在 JavaScript return 的值中可以立即使用。
现在,你可能已经看到有人说下面是一个函数表达式:
var x = function () {};
可能很容易得出结论,语法:
function () {};
是使它成为一个表达式的原因。但那是错误的。上面的语法使它成为一个匿名函数。匿名函数可以是声明或表达式。使它成为表达式的是这种语法:
var x = ...
也就是说,=
符号右边的所有内容都是表达式。表达式使用编程语言编写数学公式变得更加容易。所以一般来说,任何需要处理数学的地方都是一个表达式。
JavaScript中的一些表达式形式包括:
=
运算符右侧的所有内容- 大括号
()
中的内容不是函数调用大括号 - 数学运算符右边的所有内容 (
+
,-
,*
,/
) - 三元运算符的所有参数
.. ? .. : ..
当你写:
function () {}
它是一个声明,而不是 return 一个值(声明的函数)。因此尝试调用非结果是错误的。
但是当你写的时候:
(function () {})
它是一个表达式,return它是一个可以立即使用(例如,可以调用或可以赋值)的值(声明的函数)。
请注意上述表达式的计算规则。由此可见,大括号并不是您可以用来构造 IIFE 的唯一东西。以下是构造 IIFE 的有效方法(因为我们写的是函数表达式):
tmp=function(){}()
+function(){}()
-function(){}()
0/function(){}()
0*function(){}()
0?0:function(){}()
(function(){}())
(function(){})()
你可能会在第三方库中实际看到上述非标准形式之一(特别是 +
版本),因为他们想要节省一个字节。但我强烈建议您只使用大括号形式(都可以),因为它们被其他程序员广泛认为是 IIFE。
这将是一个冗长的答案,但会为您提供必要的背景知识。在 JavaScript 中有两种方法可以定义函数: 一个函数定义(经典的那种)
function foo() {
//why do we always use
}
然后是更晦涩的类型,一个函数表达式
var bar = function() {
//foo and bar
};
本质上,执行时发生了同样的事情。创建一个函数对象,分配内存,并为该函数绑定一个标识符。区别在于语法。前者本身就是一个声明新函数的语句,后者是一个表达式。
函数表达式使我们能够在需要普通表达式的任何地方插入函数。这有助于匿名函数和回调。举个例子
setTimeout(500, function() {
//for examples
});
在这里,只要 setTimeout 这么说,匿名函数就会执行。但是,如果我们想立即执行一个函数表达式,我们需要确保语法可以被识别为一个表达式,否则我们会不清楚我们指的是函数表达式还是语句。
var fourteen = function sumOfSquares() {
var value = 0;
for (var i = 0; i < 4; i++)
value += i * i;
return value;
}();
这里直接调用sumOfSquares
,因为可以识别为表达式。 fourteen
变为 14
并且 sumOfSquares 被垃圾收集。 在您的示例中,分组运算符 ()
将其内容强制转换为表达式,因此该函数是一个表达式,可以立即调用。
关于我的第一个 foo 和 bar 示例之间的区别,需要注意的一件重要事情是提升。如果您不知道它是什么,快速 Google 搜索或两次应该会告诉您,但快速而肮脏的定义是提升是 JavaScript 带来声明(变量和函数)的行为) 到范围的顶部。这些声明通常只提升标识符而不是它的初始化值,所以整个范围将能够在它被赋值之前看到variable/function。
对于函数定义,情况并非如此,这里整个声明被提升并且在整个包含范围内可见。
console.log("lose your " + function() {
fiz(); //will execute fiz
buzz(); //throws TypeError
function fiz() {
console.log("lose your scoping,");
}
var buzz = function() {
console.log("and win forever");
};
return "sanity";
}()); //prints "lose your scoping, lose your sanity"