2012-04-09 95 views
2

退房這段JavaScript代碼:的JavaScript代碼片段解釋

(function (w, d) { 
    var loader = function() { 
     var s = d.createElement("script"), tag = d.getElementsByTagName("script")[0]; 
     s.src = "https://example.org/script.js"; 
     tag.parentNode.insertBefore(s,tag); 
    }; 
    w.addEventListener ? w.addEventListener("load", loader, false) : 
         w.attachEvent("onload", loader); 
}) (window, document); 

爲什麼這段代碼使用這種方法的作者,包括文檔中的腳本? 什麼是該行的用處:

w.addEventListener ? w.addEventListener("load", loader, false) : 
        w.attachEvent("onload", loader); 

最後一點:我是一個JavaScript初學者,什麼是(window, document)在結束了嗎?

+2

您最後一點的快速'n'簡單解釋:http://www.youtube.com/watch?v = i_qE1iAmjFg&t = 1m30s – 2012-04-09 01:00:31

+1

@Darragh - 我要去看那個。這看起來像是一個很好的解釋! – jmort253 2012-04-09 01:11:53

回答

2

以下addEventListener行用於註冊該函數,以便在頁面加載完成時調用該函數。 Internet Explorer和Firefox(等)使用不同的功能來執行此操作。

w.addEventListener ? w.addEventListener("load", loader, false) : 
       w.attachEvent("onload", loader); 

在JavaScript中,函數本身就是一個對象。因此,它的'價值'可以被分配給一個變量或立即消費。要立即使用它,它必須包裝在圓括號中(否則它不會做你想做的),然後把它稱爲常規函數。

(function (w, d) { ... }) (window, document); 

如果我們把它分解成兩行,這就更加明顯。

var a = function(w, d){ ... }; 
a(window, document); 

這樣做是爲了不污染具有臨時值或功能的全局範圍。更不用說不搗毀任何其他變量。這可以分爲兩部分:

  1. 通過將代碼封裝在閉包中,明確聲明的任何內容都在閉包的範圍內,而不是全局範圍。 var loader在關閉範圍內。
  2. 通過立即使用閉包,它不會被存儲在全局範圍的變量中。由於它是匿名聲明的,它不會作爲全局範圍內的命名函數存在。
+0

因此,作者使用閉包,因爲他可能不會污染全球範圍,你的意思是不創建任何使用某個名字的函數? – 2012-04-09 01:20:42

+0

是的。如果它不在關閉中,那麼'var loader'會出現在全局範圍內,可能會被意外或惡意地再次調用。通過使用閉包,它只存在於閉包範圍中。 – BlindWanderer 2012-04-09 01:37:06

3

第一個問題,代碼檢查是否定義了window.addEventListener。如果是,則使用它,否則使用window.attachEvent。這是爲了瀏覽器的兼容性。

第二個問題,這個代碼是一個匿名函數,它需要2個參數w和d。立即調用該函數,傳遞參數windowdocument

1

它看起來像作者正在等待頁面被完全加載之前,附加腳本標記。 addEventListener(DOM級別2)和attachEvent(Microsoft stuff)是更靈活的附加事件方式。該代碼類似於說w.onload = loader

最後一位是將參數傳遞到匿名函數中,它們被命名爲wd。通過將()放在最後,即可立即調用匿名函數。

+0

什麼是DOM級別2?另外,如果作者想等待頁面完全加載,他也可以使用jQuery'$(document).ready()',對吧? – 2012-04-09 01:03:42

+0

@FredCollins dom 2級只是一個規範。如果作者使用jQuery,那會產生一個類似(但更快)的結果。 – tau 2012-04-09 04:57:45

1

所以這個函數被封裝在一個閉包中。這又意味着w = windowd = document

當該方法被稱爲它創建一個名爲loader功能這對於兩個可能的事件監聽器的觸發器的一個回調(意思是,當loadonload事件被稱爲窗口上會調用)。

x ? y : z語法是簡寫if then else調用。

如果我們擴大了這一點,它會是這樣的:

if (w.addEventListener) { 
    w.addEventListener("load", loader, false); 
} else { 
    w.attachEvent("onload", loader); 
} 

使用這種說法迎合IE和其他瀏覽器的方法。

2

首先,w.addEventListener ?確保瀏覽器是否支持窗口

其次的addEventListener方法,(window, document)是他function(w,d) {}

1

以前寫過匿名函數只是參數調用這實際上是一樣的:

function RegisterEventListener(w, d) { 
    var loader = function() { 
     var s = d.createElement("script"), tag = d.getElementsByTagName("script")[0]; 
     s.src = "https://example.org/script.js"; 
     tag.parentNode.insertBefore(s,tag); 
    }; 
    if (w.addEventListener) { 
     w.addEventListener("load", loader, false); 
    } else { 
     w.attachEvent("onload", loader); 
    } 
} 

RegisterEventListener(window, document); 

唯一真正的區別是:

  1. 如果您定義一個匿名函數(使用function() {};)而不將它分配給任何東西,它只能用於有限使用(因爲沒有辦法引用它)。與此同時,匿名函數也允許立即執行(就像您的問題function(a, b) {}(a, b);中的代碼中那樣)。
  2. condition ? true : false(高級操作員)只是簡寫if語句的簡寫,因此它需要較少的輸入才能寫出,但也有人認爲它的可讀性較差。
+0

整潔。那麼爲什麼很多用戶使用閉包方式呢?哪個優勢? – 2012-04-09 01:07:09

+0

用更清晰的差異定義更新答案。 – 2012-04-09 01:13:19

1

我可能是錯的,但這是Google使用他們的分析腳本實現的。

這被稱爲閉包,是一個自動執行的函數,並將變量放在裏面,所以它們不能混淆你的代碼。

該代碼實質上創建了一個腳本標記,並將其附加到DOM,然後在文檔中找到第一個腳本標記。

第一個問題的答案是關於瀏覽器兼容性。一些瀏覽器使用addEventListener和其他attachEvent將事件附加到頁面中的元素(在本例中爲窗口),並且它將放在窗口的加載事件上(當所有內容被加載時,在文檔準備好之後)。看看這個更詳細的答案:window.onload vs $(document).ready()

第二個答案很簡單。這是在封閉(自動調用函數)使用的參數,並可以以這種方式來閱讀:

function anonymous(w, d) { 
    ... 
} 
anonymous(window, document); 
+0

謝謝。你能解釋一下「(當所有的HTML被加載,但在文檔準備好之前)」?它不等同於jQuery'$(document).ready()'? – 2012-04-09 01:09:49

+0

對不起,我交換了意思。 window.onload在document.ready之後觸發,當所有內容完成加載時。我會更新答案。 – rcdmk 2012-04-09 01:14:35

1

這段代碼的作者是用包裹在一個封閉的匿名函數來斷火的功能,這注冊一個加載事件。在窗口的onload事件觸發之前,頁面上的腳本實際上不會被加載。

作者可能會延遲腳本加載的原因可能是在實際加載其他腳本之前爲網頁提供更多時間進行渲染。這是一種很好的技術,可以在不延遲加載不需要的資源的情況下快速加載頁面內容。

作者正在使用的技術是封裝在一個封閉的匿名函數。拍下這一刻:

myFunction (window, document); 

現在,我要和一個匿名函數來代替函數調用:

function(w, d) { 
    // do stuff 
    alert("w = " + w); 
    alert("d = " + d); 
} 

現在我要去會導致功能立即運行,實際上並沒有給它一個名字。我也要去兩個參數傳遞到匿名函數:

(function(w, d) { 
     // do stuff 
     alert("w = " + w); 
     alert("d = " + d); 
}) ("1234", "5678"); 

此示例中的輸出是:

w = 1234 
d = 5678 

如果你看括號搭配起來,第一外括號匹配字符2的最後一行的最後一個括號,即函數名稱,下面的一組括號將傳遞給該函數的兩個值作爲參數進行包裝。

這可能是一個很難理解的問題,在你看到它做了幾次後,它開始變得更有意義。

+0

但是沒有問題,頁面可以加載,用戶點擊使用加載的腳本中包含的JavaScript代碼的東西? – 2012-04-09 01:12:57

+1

絕對!所以作爲一名開發人員,您必須確保資源不是立即需要的,因爲這可能會導致問題。我的建議是隻使用該腳本加載技術來處理不涉及用戶發起行爲的事情。有人使用了在後臺默默運行的分析跟蹤代碼示例。這是該技術的完美人選。 – jmort253 2012-04-09 01:14:45

+0

感謝jmort253,所以不建議用於包含按鈕,表單等行爲的加載腳本。僅適用於默默「次要」行爲。 – 2012-04-09 01:26:40

1
  1. 以這種方式添加腳本允許作者將該腳本包含在文檔中而不直接編輯HTML文件。也可以用於僅在需要時動態加載腳本。 (即如果你有一堆代碼在頁面上編輯某些東西,你不想下載它,直到用戶實際點擊編輯按鈕,這樣當你不需要時,不會浪費帶寬)。

  2. addEventListener和attachEvent是在頁面加載完成時觸發函數的方法。在這種情況下,有一個名爲loader 的函數兩者的原因是一些瀏覽器支持一個,另一個支持另一個。我一直在使用jQuery足夠長的時間,我不記得哪個是哪個。

  3. (窗口,文檔)是一種將範圍內的變量封裝和/或通過簡寫w和d引用它們的方法。作者正在創建一個函數,期望這些參數,然後將窗口和文檔作爲參數傳遞給它們。

關閉還可以幫助作者避免讓他的腳本與頁面上的其他腳本發生衝突。想想在這裏聲明的每個變量,就像它是其他語言的私有變量一樣。

1

第一個代碼塊末尾的window, document是在代碼塊其餘部分定義的匿名函數的參數。由於JavaScript幾乎是一種功能性語言,程序員可以定義這些匿名函數,甚至可以在不給他們命名的情況下使用它們。

您用問號粘貼的代碼塊是中綴符號的一個例子,它是一種符合以下模式的語言結構:condition ? ifTrueExpression : ifFalseExpression。在condition爲真的情況下,整個表達式將等於ifTrueExpression。否則,整個表達式將等於ifFalseExpression

您粘貼的中綴記法的使用在檢測使用哪種類型的互聯網瀏覽器時很常見。儘管我不確定這段代碼試圖檢測哪個瀏覽器,但其目的是以瀏覽器特定方式實現事件處理程序。