JavaScript函数表达式前面加加号的含义

913

我一直在寻找有关立即调用函数的信息,然后在某个地方看到了这种符号:

+function(){console.log("Something.")}()

有人能解释一下函数前面的+符号是什么意思/作用吗?


17
本·阿尔曼在这里解释了一切:http://mths.be/iife - Mathias Bynens
4个回答

1360

它强制解析器将+后面的部分视为表达式。这通常用于立即调用的函数,例如:

+function() { console.log("Foo!"); }();
没有 +,如果解析器处于期望语句的状态(它可以是表达式或多个非表达式语句),单词 function 看起来像一个函数声明的开始,而不是函数表达式,因此后面的 () (如上行的括号)将是语法错误(在该示例中也应有名称)。使用 +,它使其成为函数表达式,这意味着名称是可选的,并且结果是对函数的引用,可以调用,因此括号是有效的。

+只是其中一种选项。它也可以是 -!~ 或几乎任何其他一元运算符。或者,您可以使用括号(这更常见,但从语法上来说既不更正确也不更不正确):

(function() { console.log("Foo!"); })();
// or
(function() { console.log("Foo!"); }());

13
这里有更多详细说明,请参考 http://benalman.com/news/2010/11/immediately-invoked-function-expression/。 - Kundan Singh Chouhan
170
我们能否说括号包裹是一种更优秀的表示法呢?我非常熟悉括号用于包含表达式。如果你不知道 JavaScript 中这个神秘的怪癖,那么在这种情况下加号的作用根本不清楚。 - Chris
1
注意:对于两个括号选项,jsLint 更喜欢第二个。我认为 jsHint 不太挑剔。 - Beetroot-Beetroot
45
常用的使用“加号”符号表示法的库之一是Bootstrap(这也是我阅读这个帖子的原因)。 - Ville
顺便说一下,Bootstrap正在执行此操作: https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.js - AlexGrafe
但是,当我上面说“正确”时,我指的是语法上的正确,而不是更广泛的意义上的正确。正如@Beetroot-Beetroot所指出的那样,在JSLint的狭义更广泛的意义上,括号实际上是更正确的。;^) - ruffin

102
作为 @TJCrowder 的回答的补充,+ 通常用于强制将值转换为数字 正如这个 Stack Overflow 回答所解释的那样。在这种情况下,它被称为“一元加运算符”(方便搜索)。
var num = +variant;

因此,在函数前面使用它可以强制将函数的结果解释为数字。我怀疑这种情况还没有发生,但从理论上讲,JIT可以使用它将函数编译为仅限数字的函数等。然而,为了防止一元加号在较大表达式中用作连接符,您需要使用括号:

blah + (+(function(){ var scope; return "4"; })());

5
иҝҷдёӘй—®йўҳжҖҺд№ҲдјҡиҺ·еҫ—37дёӘиөһе‘ўпјҹ(+function() { ... })()иҝҷз§ҚеҶҷжі•жҖ»жҳҜдјҡеҮәй”ҷзҡ„пјҲйҷӨдәҶиҝҷдёӘдёҚеӣһзӯ”й—®йўҳпјүгҖӮ - whitequark
9
@whitequark: 函数和调用之间缺少一对括号。我怀疑得到赞的原因更多是因为数字转换的解释。 - Phil H
11
好的,也许我有点过于挑剔了。 - whitequark
1
你有一些不必要的括号,这样做完全足够:3 + +function(){ return "4"; }(); - Christoph
2
@Christoph 我倾向于保留那些括号。事实上,如果它们缺失的话,我会进一步添加它们。这样可以更清楚地了解正在发生的事情,并且还可以防止在通过删除空格来最小化代码时出现问题,导致 3++function... 不同。 - Benjam
3
经过进一步思考,+function...本身是不必要的。使用blah + function( ){ ... }( );可以得到相同的结果,这将消除需要添加括号的需要。 - Benjam

65

那么简短的回答是,通过以某种方式使用函数结果,它可以防止语法错误。

您还可以使用void运算符告诉引擎您甚至不关心返回值:

void function() { console.log("Foo!"); }();

当然,将整个内容用大括号括起来也能达到同样的目的。


51
空值或者括号是非常可取的选择,它们不会让人感到困惑。使用加号这种聪明却不够明智的做法可能会带来麻烦。 - Peter Wone
2
一个很好的观点。使用其中一个运算符似乎会违背目前的行业标准。也许“酷炫”的开发人员会选择它,否则我仍然看不出使用某些东西而不是void或()的意义。 - dudewad

1

TL;DR (快速答案)

加号会将其后的操作数转换为数字,如果它还不是数字。

解决方案与起源

函数前的+符号实际上被称为一元加号(Unary plus),它是一组一元运算符(Unary Operators)中的一员。一元加号用于将字符串和其他表示形式转换为数字(整数或浮点数)。

一元运算是只有一个操作数的运算,即一个输入。这与使用两个操作数的二元运算相反

基本用法:

const x = "1";
const y = "-1";
const n = "7.77";

console.log(+x);
// expected output: 1

console.log(+n);
// expected output: 7.77

console.log(+y);
// expected output: -1

console.log(+'');
// expected output: 0

console.log(+true);
// expected output: 1

console.log(+false);
// expected output: 0

console.log(+'hello');
// expected output: NaN

当加号(+)位于变量、函数或任何返回字符串表示的值之前时,输出将被转换为整数或浮点数;一元运算符(+)也会将非字符串值 true、false 和 null 转换。
高级用法
使用上述函数的正确方式是:
+function(){return "3.141"}()
// expected output: 3.141

我喜欢使用+将一个new Date()对象转换为时间戳,就像这样:

+new Date()
// expected output: 1641387991035

其他一元运算符

- 一元负号运算符将其操作数转换为数字类型,然后取反。

~ 按位非运算符。

! 逻辑非运算符。

delete delete运算符从一个对象中删除一个属性。

void void运算符丢弃表达式的返回值。

typeof typeof运算符确定给定对象的类型。


1
一元运算符 +副作用 是将其参数强制转换为数字。在我看来,这相当令人反感,特别是考虑到二元运算符 + 也执行字符串连接。所以 'hello' + 'world' 变成了 'helloworld',但 +'hello' 变成了 NaN,而不是与空字符串连接的结果 'hello' - Peter Bašista

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接