!function ($) { $(function(){ }) }(window.jQuery) 是什么意思?

61
我正在使用Twitter Bootstrap创建一个网站,并尝试初始化工具提示。除了在application.js中添加类似于"
 $("[rel=tooltip]").tooltip() "这样的内容之外,除非我保留Bootstrap文档中使用的以下代码片段,否则我的工具提示不会初始化:

!function ($) {
$(function(){
})
}(window.jQuery)
上面的代码是做什么用的?
1个回答

165
让我们通过拆分代码来解释
function () {
}()

通常写作

(function () {
})()

这是一个“自执行匿名”函数,也称为“立即调用函数表达式(IIFEs)”,它会立即内联执行匿名函数。
请在Explain the encapsulated anonymous function syntax中了解更多相关信息。
匿名函数是一项强大的功能,具有诸如作用域(“变量名称空间”)等优点,请参见What is the purpose of a self executing function in javascript?
现在他们正在使用。
function ($) {

}(window.jQuery)

现在先忽略 !

他们将 window.jQuery 作为参数传递给函数,并接受为 $

这样做的作用是将 $ 别名设置为 window.jQuery(原始 jQuery 对象),因此确保在该闭包内,$ 总是指向 jQuery 对象,无论其他库是否将其 ($) 取出。

因此,在使用 $ 编写的闭包内的代码始终有效。

另一个好处是,$ 作为匿名函数的参数出现,它在 作用域链 中更加接近,因此 JS 解释器查找闭包内的 $ 对象所需的时间较少,而不是使用全局 $ 所需的时间。


$(function(){  

})

这是jQuery的文档就绪块,你可能已经知道了,它确保此函数内的代码将在dom准备好后运行,因此所有事件绑定将正常工作。

更多信息请参见http://api.jquery.com/ready/

而那个!的作用已经在这里在函数前面加感叹号有什么作用?中得到了很好的解释。

简而言之:

为了演示!的好处,让我们考虑一个情况,

(function() {
    alert('first');
}())


(function() {
    alert('second');
}())

如果您将上述代码粘贴到控制台中,您将收到两个警报,但随后会出现此错误。
TypeError: undefined is not a function

为什么会发生这种情况?让我们模拟一下JS引擎执行上述代码块的过程。它执行这个匿名函数function() {alert('first');}(),显示警报,由于它没有返回任何内容,所以在()内返回undefined。第二个函数也是同样的情况。因此,在执行完这个块之后,它最终会变成类似这样的东西。
(undefined)(undefined)

由于它的语法类似于“自调用匿名”函数,因此它试图调用该函数,但第一个“(undefined)”不是函数。因此,您会得到“undefined is not a function”错误。 “!”可以解决这种类型的错误。使用“!”会发生什么。我引用了上面答案链接中的行。
当您使用!时,函数成为一元(逻辑)NOT运算符的单个操作数。这迫使函数作为表达式进行评估,从而允许它立即内联调用。
这解决了上述问题,我们可以使用“!”重写上面的块。
!(function() {
    alert('first');
}())


!(function() {
    alert('second');
}())

对于您的情况,您可以将您的工具提示代码放在文档准备块内,像这样:
$(function(){  
    $("[rel=tooltip]").tooltip();  
});

它将能够正常工作。

如果您只是使用 $("[rel=tooltip]").tooltip() 而没有任何 doc ready block,那么当这段代码运行时,DOM 中可能还不存在任何具有 rel=tooltip 的元素。因此,$("[rel=tooltip]") 将返回一个空集合,tooltip 将无法工作。

以下是一个示例标记,如果没有 doc ready block,则它将无法正常工作:

.
.
.
<script type="text/javascript">
    $("[rel=tooltip]").tooltip();
</script>
.
.
.
.
<a href="#" rel="tooltip">Something</a>
<a href="#" rel="tooltip">Something</a>
<a href="#" rel="tooltip">Something</a>

作为浏览器,它会按顺序解释标记,并在遇到JS代码时立即执行。当它执行此处的JS块时,它尚未解析 a rel="tooltip"标记,因为它出现在JS块之后,所以它们在那时不在DOM中。
因此,在上述情况下,$("[rel=tooltip]")为空,因此工具提示将无法正常工作。因此,将所有JS代码放在document ready块中始终是安全的。
$(function){
    // put all your JS code here
});

希望现在对您来说所有这些都是有意义的。

5
很棒的写作,我在这里学到了不少。我认为这被称为“标准答案” :) - brasofilo
7
很好,但我认为它过于强调使用 ! 的理由而且表述不够好。例如,在问题中没有外部括号时,答案使用了 !(function(){}()) 。更不用说你几乎永远不会在单个脚本中使用两个不同的 (function(){}()) 作为“包装器”。还可以补充一点,通过在 IIFE 后添加分号来轻松解决这个问题,即 (function(){}()); ,我认为这比将返回值强制转换为布尔值要合理得多 - Fabrício Matté
那么我理解得对,如果我使用这个,就不需要jQuery的noConflict模式了吗? - Snowball
@Snowball,你是对的。如果你只使用这个模式,就不需要调用noConflict。$将始终在IIFE内引用jQuery对象。 - Prasenjit Kumar Nag
function(...){...}() 这样的写法是不合法的,应该使用 (function(...){...})() - matpop
显示剩余3条评论

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