、請解釋一下 JavaScript和CSS阻塞。
JavaScript的阻塞特性是所有瀏覽器在下載 JavaScript代碼的時候,會阻止其他一切活動,比如其他資源的下載,內容的呈現等,直到 JavaScript代碼下載、解析、執行完畢后才開始繼續并行下載其他資源并渲染內容。
為了提高用戶體驗,新一代瀏覽器都支持并行下載 JavaScript代碼,但是 JavaScript代碼的下載仍然會阻塞其他資源的下載(例如圖片、CSS文件等)。
為了防止 JavaScript修改DOM樹,瀏覽器需要重新構建DOM樹,所以就會阻塞其他資源的下載和渲染。
嵌入的 JavaScript代碼會阻塞所有內容的呈現,而外部 JavaScript代碼只會阻塞其后內容的顯示,兩種方式都會阻塞其后資源的下載。也就是說,外部腳本不會阻塞外部腳本的加載,但會阻塞外部腳本的執行。
CSS本來是可以并行加載的,但是當CSS后面跟著嵌入的 JavaScript代碼的時候,該CSS就會阻塞后面資源的下載。
而當把嵌入的 JavaScript代碼放到CSS前面時,就不會出現阻塞的情況了(在IE6下CSS都會阻塞加載)。
根本原因是因為瀏覽器會維持HTML中CSS和 JavaScript代碼的順序,樣式表必須在嵌入的 JavaScript代碼執行前先加載、解析完。而嵌入的 JavaScript代碼會阻塞后面的資源加載,所以就會出現CSS阻塞資源加載的情況。
2、闡述一下事件冒泡。
Java Script允許DOM元素嵌套在一起。在這種情況下,如果單擊子級的處理程序,父級的處理程序也將執行同樣的工作。
3、和DOM事件流的區別是什么?
區別如下。
(1)執行順序不一樣
(2)參數不一樣。
(3)事件名稱是否加on不一樣。
(4)this指向問題不一樣。
4、解釋一下什么是構造函數?
構造函數是一種特殊的方法,主要用來創建對象時初始化對象,經常與new運算符一起使用,創建對象的語句中構造函數的名稱必須與類名完全相同。
5、解釋一下for-in循環。
for-in循環用于循環對象的屬性。
for-in循環的語法如下。
for (var iable name in object){}
在每次循環中,來自對象的一個屬性與變量名相關聯,循環繼續,直到對象的所有屬性都被遍歷。
6、兩個嵌套for循環的執行順序
外層判斷循環條件,滿足進入外層循環體
內層判斷循環條件
內層循環體執行
內層循環變量累加,回到2執行,直到不滿足內層條件
外層循環變量累加,回到1執行,直到不滿足外層循環條件,徹底退出循環
7、如何理解 JavaScript中的閉包?
閉包就是能夠讀取其他函數內部變量的函數。
閉包的用途有兩個,一是可以讀取函數內部的變量,二是讓這些變量的值始終保持在內存中。
8、解釋一下 window. onload和 onDocumentReady。
在載入頁面的所有信息之前,不運行 window. onload。這導致在執行任何代碼之前會出現延遲。
window.onDocumentReady在加載DOM之后加載代碼。這允許代碼更早地執行(早于 window. onload)。
9、在 JavaScript中, unshift方法的作用是什么?
unshift方法就像在數組開頭工作的push方法。該方法用于將一個或多個元素添加到數組的開頭。
10、typeof是用來做什么的?
typeof是一個運算符,用于返回變量類型的字符串描述。
冒泡意味著事件從目標元素(即button用戶點擊)向上傳播到其祖先樹,從最近的元素開始。默認情況下,所有事件都會冒泡。
為了更好地理解事件冒泡,請考慮以下 HTML 示例,我們將在本文的大部分內容中引用該示例:
HTML
<html>
<body>
<div id="btn-container">
<button class="btn">Click me</button>
</div>
</body>
</html>
JavaScript
const ancestors = [
window, document, document.documentElement,
document.body, document.getElementById('btn-container')
];
// 目標階段
document.querySelector('.btn').addEventListener('click', e => {
console.log(`Hello from ${e.target}`);
});
// 泡沫階段
ancestors.forEach(a => {
a.addEventListener('click', e => {
console.log(`Hello from ${e.currentTarget}`);
});
});
如果我們為樹中的每個元素添加一個事件偵聽器,如上所示,我們會?看到第一個觸發了一個偵聽器button,然后其他每個元素都從最近的祖先一直觸發到Window.
捕獲與冒泡完全相反,這意味著外部事件處理程序在最具體的處理程序(即 上的處理程序button)之前被觸發。請注意,首先運行所有捕獲事件處理程序,然后運行所有冒泡事件處理程序。
您可以通過將第三個參數應用于 EventTarget.addEventListener,將其設置為 true 來使用事件捕獲。例如:
// 捕獲階段
ancestors.forEach(a => {
a.addEventListener('click', e => {
console.log(`Hello from ${e.currentTarget}`);
}, true);
});
給定這段代碼,我們會看到第一個 button 的每個祖先觸發了一個偵聽器,然后觸發了 button 偵聽器。
解釋了事件冒泡和捕獲之后,我們現在可以解釋事件傳播的三個階段:
事件委托是指委托事件偵聽父元素而不是直接將事件偵聽器添加到事件目標的想法。使用這種技術,父級可以根據需要捕獲和處理冒泡事件。
window.addEventListener('click', e => {
if (e.target.className === 'btn') console.log('Hello there!');
});
在上面的示例中,我們將事件處理委托給button 到 Window并用Event.target獲取原始事件的目標。
使用事件委托模式有兩個優勢:
更多內容請訪問我的網站:https://www.icoderoad.com
過JavaScript事件的冒泡來動態為元素綁定事件的方法稱為事件委托(Event Delegation,也稱為“事件代理”),是 JavaScript 中最熱門的技術之一,在筆試和面試中是常考察的重點知識點,今天來簡單介紹一下相關的原理知識。
1、DOM事件流
1.1 事件流描述的是從頁面中接收事件的順序。
1.2 事件發生時會在元素節點之間按照特定的順序傳播,這個傳播過程即DOM事件流。
比如:我們給頁面中的一個div注冊了單擊事件,當你單擊了div時,也就單擊了body,單擊了html,單擊了document。
1.3 DOM 事件流會經歷3個階段:
(1)、捕獲階段:事件從文檔的根節點流向目標對象。
(2)、當前目標階段:在目標對象上被觸發。
(3)、冒泡階段:回溯到文檔的根節點。
2、事件捕獲
事件從最不精確的對象(document 對象)開始觸發,然后到最精確(也可以在窗口級別捕獲事件,不過必須由開發人員特別指定),與事件冒泡相反,事件會從最外層開始發生,直到最具體的元素。同樣形象的比喻一下可以想象成警察逮捕屋子內的小偷,就要從外面一層層的進入到房子內。
3、事件冒泡
微軟提出了名為事件冒泡的事件流。事件按照從最特定的事件目標到最不特定的事件目標(document對象)的順序觸發??梢韵胂蟀岩活w石頭投入水中,泡泡會一直從水底冒出水面。也就是說,事件會從最內層的元素開始發生,一直向上傳播,直到document對象。
防止事件冒泡的方法:
4、事件委托
什么是事件委托?
事件委托也稱為事件代理。當有多個列表元素需要綁定事件時,一個一個去綁定即浪費時間,又不利于性能,這時候就可以用到事件委托,給他們的一個共同父級元素添加一個事件函數去處理他們所有的事件情況。
事件委托的原理
給父元素注冊事件,利用事件冒泡,當子元素的事件觸發,會冒泡到父元素,然后去控制相應的子元素。
案例
<ul>
<li>事件冒泡,事件委派</li>
<li>事件冒泡,事件委派</li>
<li>事件冒泡,事件委派</li>
<li>事件冒泡,事件委派</li>
<li>事件冒泡,事件委派</li>
</ul>
<script>
// 事件委托的核心原理:給父節點添加偵聽器, 利用事件冒泡影響每一個子節點
var ul = document.querySelector('ul');
ul.addEventListener('click', function (e) {
// e.target 這個可以得到我們點擊的對象
e.target.style.backgroundColor= 'aqua';
})
</script>
在上述代碼沒有給每個li標簽綁定事件,而是通過給ul標簽綁定事件,然后判斷target的形式(冒泡)來設置每個子節點相應的處理。
tips:addEventListener(type,listener[,useCapture])第三個參數如果是true,表示在事件捕獲階段調用事件處理程序,如果是false(默認為false),表示事件冒泡階段調用事件處理程序。
為什么要使用事件委托?
在 javascript 中,頁面中事件處理程序的數量與頁面整體性能直接相關。
每個函數都是對象,都占用內存空間,對象越多,性能越差。
為指定事件處理程序所需訪問 DOM 的次數會造成整個頁面交互的延遲。
“過多事件處理程序“的解決方案是使用事件委托。
事件委托是利用事件冒泡,可以只使用一個事件處理程序來管理一種類型的事件。
只要給所有元素共同的祖先節點添加一個事件處理程序,就可以解決大片雷同的只為指定事件處理程序的代碼的問題。
事件委托的作用
事件委托的注意事項
使用“事件委托”時,并不是說把事件委托給的元素越靠近頂層就越好。事件冒泡的過程也需要耗時,越靠近頂層,事件的“事件傳播鏈”越長,也就越耗時。如果DOM嵌套結構很深,事件冒泡通過大量祖先元素會導致性能損失。
不支持冒泡的事件
冒泡事件有很多,常見的不支持冒泡的事件如下:
原因是在于:這些事件僅發生于自身上,而它的任何父節點上的事件都不會產生,所以不會冒泡。
總結
事件委托是基于事件冒泡實現的動態綁定事件的方法。因為把事件綁定到父節點上,因此減少了綁定事件(減少內存消耗)和減少DOM讀取次數。就算后面新增的子節點也有了相關事件,刪除部分子節點不用去銷毀對應節點上綁定的事件。父節點是通過event.target來找對應的子節點的。
*請認真填寫需求信息,我們會在24小時內與您取得聯系。