为什么要声明jQuery两次?

以下代码的目的是什么?

请注意,在下面的第二个脚本代码之前, jquery.min.js已经包含在googleapis

 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> <script>window.jQuery || document.write('<script src="/assets/js/vendor/jquery.min.js"><\/script>')</script> 

当CDNclosures或无法访问时,它将回jquery.min.js存储在同一台服务器上的jquery.min.js文件。

这本质上是说:

 // 1. Try to download and run https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js // 2. Was jQuery successfully loaded from the CDN? If so, it will be defined: if (window.jQuery) { // Yes, it's defined. Good. Nothing more needed. } else { // No, it's not defined. Use my copy: document.write('<script src="/assets/js/vendor/jquery.min.js"><\/script>') } 

在这里阅读更多 ,你可以在这里find原始代码。

关于window.jQuery || document.write(...) window.jQuery || document.write(...)基本上是上面代码的简写。 当定义的window.jQuery将truthy ,所以在右侧的声明 将不会被执行; 但是,如果它没有被定义,它将是谬误,并在右侧的声明 被执行。

它试图首先使用托pipe在Google CDN上的版本。 浏览该网站的人有一个机会,已经从访问其他网站caching了确切的脚本,所以他们不妨先尝试一下。

如果加载CDN版本,则设置window.jQuery, 或者短路,代码继续运行。

如果由于某种原因无法加载CDN版本,则会向指向本地托pipe版本的脚本的页面添加另一个脚本标记。

编辑:正如MTCoster在上面的评论中指出的,这个技巧依赖于JavaScript正常加载的方式。 浏览器暂停执行,直到标签加载或超时。 如果jQuery是asynchronous加载使用async属性,这个技巧是行不通的。

第一个脚本将尝试从外部网站(在这种情况下,谷歌CDN)加载jQuery。

第二个将尝试在windowfindjQuery对象,只有当它没有find它,然后它会从一个内部链接加载库。 在CDN失败的情况下,这只是一个倒退。

 window.jQuery || document.write(...) // the code above means the same as the code below if (window.jQuery === undefined) document.write(...) 

在Javascript中,除了布尔(真/假)之外,还有真理和谬误的价值。 任何不同于0falseundefinednull都是真值。

在这种情况下,如果jQuery属性存在于窗口上,它将是一个对象,它将是一个真值,所以,第二个语句将不会运行(因为第一个语句已经是真的 – 在一个OR运算符中,如果任何陈述是真实的,则跳过其他(从左到右)。

虽然,如果jQuery属性不存在,那是因为第一个脚本没有正确加载,并且该属性将是undefined ,是一个虚假的值。 所以,第二个语句将运行,并且本地jQuery将作为后备加载。

这是一个回退机制,如果从CDN的jquery由于某种原因,如防火墙阻止,CDN下来等

我会再增加一个我去年面对的实际情况。 我的一个客户决定在没有networking的情况下主持和使用我在局域网中创build的networking应用程序。 在本地IIS中,应用程序正确部署,但由于CDN不可用而失败,如果我使用了上述代码,则Web应用程序将在第一次运行时没有任何变化。

我希望现在有意义:)对我来说,这是一个教训。