题 感觉标记在功能之前做了什么?


!function () {}();

1021
2017-09-20 21:21


起源


@Dykam在这个答案中解释了它的用处: stackoverflow.com/questions/5422585/... - hectorct
有关: JavaScript加号在功能名称前面 - Bergi
我们称之为 自执行匿名功能 --- - befzz
@befzz最好将此引用为立即调用的函数表达式,正如该文章后面解释的那样(“自执行”意味着递归) - Zach Esposito


答案:


JavaScript语法101.这是一个 功能声明

function foo() {}

请注意,没有分号:这只是一个函数 宣言。你需要一个调用, foo(),实际运行该功能。

现在,当我们添加看似无害的感叹号时: !function foo() {} 它变成了一个 表达。现在是一个 功能表达

! 当然,单独不调用函数,但我们现在可以放 () 最后: !function foo() {}() 优先级高于 ! 并立即调用该功能。

所以作者正在做的是为每个函数表达式保存一个字节;一种更易读的写作方式是:

(function(){})();

最后, ! 使表达式返回true。这是因为默认情况下所有IIFE都返回 undefined离开了我们 !undefined 是的 true。不是特别有用。


1737
2018-04-13 20:02



+1。这真的是最好的答案,遗憾的是,几乎没有投票。明显, ! 返回布尔值,我们都知道,但你要做的重点是它还将函数声明语句转换为函数表达式,以便可以立即调用该函数而不将其包含在括号中。不明显,而且显然是编码人员的意图。 - gilly3
+1这是实际解决你想要做什么的唯一答案,以及为什么人们认为它的使用超过了对返回结果的否定似乎是值得的。一元运算符! (也是〜, - 和+)从函数声明中消除歧义,并允许end()中的parens就地调用函数。这通常用于在编写模块化代码时为变量创建局部范围/命名空间。 - Tom Auger
另一个好处是!导致分号插入,因此不能将此版本与不以;结尾的文件错误地连接起来。如果你有()表单,它会认为它是前一个文件中定义的函数调用。给我的同事戴帽子的小费。 - Jure Triglav
@Carnix var foo = 打破语句/表达歧义,你可以简单地写 var foo = function(bar){}("baz"); 等等 - Neil
这看起来很难看......长篇大论不会太长,不能选择感叹号。这种方式可以为开发人员节省一小部分时间,并且可以为其他人节省数小时。 - Pablo Ezequiel Leone


功能:

function () {}

什么都不返回(或未定义)。

有时我们想在创建函数时调用函数。你可能想尝试这个:

function () {}()

但它导致了一个 SyntaxError

使用 ! 函数之前的运算符导致它被视为表达式,所以我们可以调用它:

!function () {}()

在这种情况下,这也将返回与函数返回值相反的布尔值 true因为 !undefined 是 true。如果您希望实际返回值是调用的结果,那么尝试这样做:

(function () {})()

327
2017-09-20 21:28



谁能够需要这个? - Andrey
这是 只要 回答说明问题中的案例,勇敢! - Andrey
您的第二个代码示例不是有效的JavaScript。的目的 ! 是将函数声明转换为函数表达式,这就是全部。 - Skilldrick
@Andrey bootstrap twitter在所有javascript(jQuery)插件文件中都使用了这个。添加此评论以防其他人也可能有相同的问题。 - Anmol Saraf
d3.js也使用了 !function 句法 - Kristian


使用有好处 ! 用于标记的函数调用 airbnb JavaScript指南

通常在单独的文件(也称为模块)上使用此技术的想法,后来得到连接。这里需要注意的是,文件应该通过将新文件放在新行的工具连接起来(这对于大多数concat工具来说无论如何都是常见的行为)。在那种情况下使用 ! 如果以前连接的模块错过了后续分号,将有助于避免错误,但这样可以灵活地将它们置于任何顺序而不用担心。

!function abc(){}()
!function bca(){}();

将工作相同

!function abc(){}()
;(function bca(){})();

但保存两个字符和任意看起来更好。

顺便说一下 +-~void 在调用函数方面,运算符具有相同的效果,因为如果您使用某些东西从该函数返回,它们将采取不同的行为。

abcval = !function abc(){return true;}() // abcval equals false
bcaval = +function bca(){return true;}() // bcaval equals 1
zyxval = -function zyx(){return true;}() // zyxval equals -1
xyzval = ~function xyz(){return true;}() // your guess?

但是如果你将IIFE模式用于一个文件,一个模块代码分离并使用concat工具进行优化(这使得一行一个文件工作),而不是构造

!function abc(/*no returns*/) {}()
+function bca() {/*no returns*/}()

将执行安全的代码,与第一个代码示例相同。

这个会抛出错误导致JavaScript ASI无法完成其工作。

!function abc(/*no returns*/) {}()
(function bca() {/*no returns*/})()

关于一元运算符的一个注释,它们会做类似的工作,但仅限于它们不在第一个模块中使用的情况。因此,如果您无法完全控制连接顺序,那么它们就不那么安全了。

这有效:

!function abc(/*no returns*/) {}()
^function bca() {/*no returns*/}()

这不是:

^function abc(/*no returns*/) {}()
!function bca() {/*no returns*/}()

46
2017-10-01 18:10



实际上,那些其他符号没有相同的效果。是的,它们允许您按照描述调用函数,但它们并不相同。考虑:var foo =!function(bar){console.debug(bar); }(“蝙蝠”);无论你放在前面的哪个符号,你都会在你的控制台中得到“蝙蝠”。现在,添加console.debug(“foo:”,foo); - 根据您使用的符号,您会得到非常不同的结果。 !强制一个并不总是令人满意的返回值。为了清晰和准确,我更喜欢({})()语法。 - Carnix


它返回语句是否可以计算为false。例如:

!false      // true
!true       // false
!isValid()  // is not valid

您可以使用它两次将值强制为布尔值:

!!1    // true
!!0    // false

所以,更直接地回答你的问题:

var myVar = !function(){ return false; }();  // myVar contains true

编辑: 它具有将函数声明更改为函数表达式的副作用。例如。以下代码无效,因为它被解释为缺少必需的函数声明 识别码 (要么 功能名称):

function () { return false; }();  // syntax error

26
2017-09-20 21:25



为了清楚,读者可能希望使用具有立即调用函数的赋值作为示例代码 var myVar = !function(){ return false; }() 可以省略 ! 喜欢 var myVar = function(){ return false; }() 并且函数将正确执行,返回值将不受影响。 - Mark Fox
要清楚,你可以使用它一次强制布尔,因为它是一个 逻辑不对 运营商。 !0 = true,和!1 = false。对于JavaScript缩小目的,您需要替换 true 同 !0 和 false 同 !1。它可以节省2或3个字符。 - Triynko


这是我从控制台中发现的更多内容。如前所述,感叹号使函数返回一个布尔值。

对于后一种语法:

( function my_function() {} )()

我们可以这样做:

(function add_them(a,b) { return a+b;} )(9,4)

像同时的函数定义和调用。

编辑:
现在你会问''有什么用?类型函数定义。我们考虑以下几点:

!function a_would_be_function() { alert("Do some junk but inside a function"); }()

你想要执行一个像上面这样的函数,但没有'!'会产生错误。希望我很清楚。


5
2018-05-06 14:49





 是合乎逻辑的  运算符,它是一个布尔运算符,它将反转某些东西。

虽然您可以使用。绕过调用函数的括号  (!)在函数之前,它仍然会反转返回,这可能不是你想要的。与IEFE的情况一样,它将返回 未定义,倒置时变为布尔值true。

相反,使用右括号和BANG() 如果需要的话。

// I'm going to leave the closing () in all examples as invoking the function with just ! and () takes away from what's happening.

(function(){ return false; }());
=> false

!(function(){ return false; }());
=> true

!!(function(){ return false; }());
=> false

!!!(function(){ return false; }());
=> true

其他有效的运营商......

+(function(){ return false; }());
=> 0

-(function(){ return false; }());
=> -0

~(function(){ return false; }());
=> -1

联合运营商......

+!(function(){ return false; }());
=> 1

-!(function(){ return false; }());
=> -1

!+(function(){ return false; }());
=> true

!-(function(){ return false; }());
=> true

~!(function(){ return false; }());
=> -2

~!!(function(){ return false; }());
=> -1

+~(function(){ return false; }());
+> -1

3
2017-07-31 16:36





它是编写IIFE的另一种方式(立即调用函数表达式)。

它的另一种写作方式 -

(function( args ) {})()

与...一样

!function ( args ) {}();

2
2018-03-06 09:56



嗯,它不完全一样;第二种形式否定函数调用的结果(然后抛出它,因为没有值赋值)。我更倾向于更明确 (function (args) {...})() 语法并留下 !function 形成缩小和混淆工具。 - Tobias


它只是为了在我们进行javascript缩小时保存一个字节的数据。

考虑下面的匿名函数

function (){}

为了使上述作为自调用函数,我们通常会将上面的代码更改为

(function (){}())

现在我们添加了两个额外字符 (,) 除了添加 () 在函数结束时调用该函数所必需的。在缩小的过程中,我们通常专注于减小文件大小。所以我们也可以把上面的函数写成

!function (){}()

两者都是自调用函数,我们也保存一个字节。而不是2个字符 (,) 我们只使用了一个角色 !


2
2017-09-05 10:05