JavaScript语法101。 下面是一个函数声明:
function foo() {}
注意没有分号:这只是一个函数声明。 您需要调用foo()
来实际运行函数。
现在,当我们添加一个看似无伤大雅的感叹号:!function foo(){}
时,它将它转换成一个表达式。 它现在是一个函数表达式。
当然,!
本身并不能调用该函数,但是我们现在可以将()
放在末尾:!函数foo(){}()
,它的优先级高于!
,并立即调用该函数。
所以作者所做的是为每个函数表达式保存一个字节; 一种更易读的写作方式是:
(function(){})();
最后,!
使表达式返回true。 这是因为默认情况下,所有生命都返回undefined
,这就留下了!undefined
,它是true
。 不是特别有用。
功能:
function () {}
不返回任何内容(或未定义)。
有时我们想在创建函数时调用它。 您可能想尝试一下:
function () {}()
但会导致语法错误
。
在函数之前使用!
运算符会使它被视为表达式,因此我们可以调用它:
!function () {}()
这还将返回函数返回值的布尔相反值,在本例中为true
,因为!undefined
是true
。 如果您希望实际返回值是调用的结果,那么可以尝试这样做:
(function () {})()
在《爱彼迎JavaScript指南》中,有一个很好的方法是使用!
进行函数调用
通常,在单独的文件(也就是模块)上使用这种技术的想法,这些文件后来会被连接起来。 这里需要注意的是,文件应该由将新文件放在新行的工具连接起来(这是大多数concat工具的常见行为)。 在这种情况下,使用!
将有助于避免在if先前连接的模块缺少尾随分号时出错,但这将提供灵活性,使它们可以毫无顾虑地按任何顺序排列。
!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?
但是如果您使用iLife模式进行一个文件一个模块的代码分离,并使用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*/}()