關于事件
1、事件的三個階段
捕獲 目標 冒泡
低版本IE(IE8及以下版本)不支持捕獲階段
捕獲事件流:Netscape提出的事件流,即事件由頁面元素接收,主機箱下,傳播到最具體的元素
冒泡事件流:IE提出的事件流,即事件由最具體的元素接收,逐級向上,傳播到頁面
2、IE和W3C不同綁定事件解綁事件的方法有什么區別,參數是什么,以及事件對象ev有什么區別
W3C:target.addEventListener(event,listener,useCapture);
event——事件類型;
listener——事件觸發時執行的函數;
useCapture——指定時間是否再補貨或冒泡階段執行,為true時事件句柄在捕獲階段執行,為false(默認false)時,事件句柄在冒泡階段執行。
例:
btn.addEventListener('click',function(){
//do something...
},false);
對應的事件移除:
removeEventListener(event,function,capture/bubble);
例:
removeEventListener(event,function,capture/bubble);
IE:target.attacEvent(type,listener);
type——字符串,事件名稱,含"on",比如"onclick","onmouseover"等。
listener——實現了EventListener接口或者是JavrScript中的函數。
例:
btn.attachEvent('onclick',function(){
//do something...
})
對應的事件移除:
detachEvent(event,function);
目前支持以addEventListener綁定事件的瀏覽器:FF、Chrome、Safari、Opera、IE9-11
目前支持以attachEvent綁定事件的瀏覽器:IE6-10
阻止:
通過stopPropagation()或cancelBubble來阻止事件向下一級元素傳遞。
cancelBubble是IE標準下阻止事件傳遞的屬性,設置cancelBubble=true表示阻止冒泡
3、【事件的代理/委托】的原理以及優缺點
原理:靠事件的冒泡機制來實現的
優點:
1.可以大量節省內存占用,減少事件注冊,比如在table上代理所有td的click事件就非常棒
2.可以實現當新增子對象時無需再次對其綁定事件,對于動態內容部分尤為合適
缺點:
事件代理的應用常用應該僅限于上述需求下,如果把所有事件都代理就可能會出現事件誤判,即本不應用觸發事件的被綁上了事件(有人把頁面里所有的時間都綁定到document用委托的,只是及其不智的做法)
4、實現事件代理,要求兼容瀏覽器(考核對事件對象ev的了解程度,以及在IE下對應的屬性名)
用target,currentTarget,以及IE下的srcElement和this(說完這些可略過了)
5、實現事件模型
即寫一個類或是一個模塊,有兩個函數,一個bind一個trigger,分別實現綁定事件和觸發事件,核心需求就是可以對末一個事件名稱綁定多個事件響應函數,然后觸發這個事件名稱時,依次按綁定順序觸發相應的響應函數。
(這個需求如果對于做過C#的人來講就再熟悉不過,他根本就是C#中的【委托】(delegate)。而委托與事件幾乎是一家子。回到前面說的題目,大致實現思路就是創建一個類或是匿名函數,在bind和trigger函數外層作用域創建一個字典對象,用于存儲注冊的事件及響應函數列表,bind時,如果字典沒有則創建一個,key是事件名稱,value是數組,里面放著當前注冊的響應函數,如果字段中有,那么就直接push到數組即可。trigger時調出來依次觸發事件響應函數即可)
6、事件廣播(dispatchEvent)
一般在元素上綁定事件后,是靠用戶在這些元素上的鼠標行為來捕獲或者觸發事件的,或者自帶的瀏覽器行為事件,比如click,mouseover,load等等,有些時候我們需要自定義事件或者在特定的情況下需要觸發這些事件。這時可以使用IE下fireEvent方法,高級瀏覽器(chrome,firefox等)有dispatchEvent方法。
性能優化
簡單來說,常用的優化有兩部分:
第一:面向內容的優化
- 減少 HTTP 請求
從設計實現層面簡化頁面
合理設置HTTP緩存(即能緩存越多越好,能存越久越好)
- 減少 DNS 查找
- 避免重定向
- 使用 Ajax 緩存
- 延遲載入組件
- 預先載入組件
- 減少 DOM 元素數量
- CDN加速的原理
通過緩存技術,將網站文字,圖片,視頻等內容緩存到分布與各地的節點服務器上,使終端訪問用戶就近訪問,從而提高訪問速度。
- 最小化 iframe 的數量
- 不要出現http 404 錯誤
第二:面向 Server
1.cookie優化
減少Cookie大小
頁面內容使用無Cookie域名
- 針對 Web 組件使用域名無關性的
怎樣實現原生JS異步加載
默認情況javascript是同步加載的,也就是javascript的加載時阻塞的,后面的元素要等待javascript加載完畢后才能進行再加載,對于一些意義不是很大的javascript,如果放在頁頭會導致加載很慢的話,是會嚴重影響用戶體驗的。
有以下三種方法:
(1) defer,只支持IE
defer屬性的定義和用法(我摘自w3school網站)
defer 屬性規定是否對腳本執行進行延遲,直到頁面加載為止。
有的 javascript 腳本 document.write 方法來創建當前的文檔內容,其他腳本就不一定是了。
如果您的腳本不會改變文檔的內容,可將 defer 屬性加入到 <script> 標簽中,以便加快處理文檔的速度。
因為瀏覽器知道它將能夠安全地讀取文檔的剩余部分而不用執行腳本,它將推遲對腳本的解釋,直到文檔已經顯示給用戶為止。
示例:
代碼如下:
<script type="text/javascript" defer="defer">
alert(document.getElementById("p1").firstChild.nodeValue);
</script>
(2) async:
async的定義和用法(是HTML5的屬性)
async 屬性規定一旦腳本可用,則會異步執行。
示例:
代碼如下:
<script type="text/javascript" src="demo_async.js" async="async"></script>
注釋:async 屬性僅適用于外部腳本(只有在使用 src 屬性時)。
注釋:有多種執行外部腳本的方法:
?如果 async="async":腳本相對于頁面的其余部分異步地執行(當頁面繼續進行解析時,腳本將被執行)
?如果不使用 async 且 defer="defer":腳本將在頁面完成解析時執行
?如果既不使用 async 也不使用 defer:在瀏覽器繼續解析頁面之前,立即讀取并執行腳本
(3) 創建script,插入到DOM中,加載完畢后callBack,見代碼:
代碼如下:
function loadScript(url, callback){
var script = document.createElement_x("script")
script.type = "text/javascript";
if (script.readyState){ //IE
script.onreadystatechange = function(){
if (script.readyState == "loaded" || script.readyState == "complete"){
script.onreadystatechange = null;
callback();
}
};
} else { //Others: Firefox, Safari, Chrome, and Opera script.onload = function(){
callback();
};
}
script.src = url;
document.body.appendChild(script);
JSONP原理
只要說到跨域,就必須聊到JSONP,就必須講一下JSONP的實現原理,以及在項目中哪個需求使用了JSONP,簡單講就是HTML里面所有帶src屬性的標簽都可以跨域,如iframe,img,script等。
所以可以把需要跨域的請求改用成script腳本加載即可,服務器返回執行字符串,但是這和字符串實在window全局作用下執行的,你需要把他返回到你的代碼的作用域內,這里就需要臨時創建一個全局的回掉函數,并傳到后臺,最后再整合實際要求的數組,返回給前端,讓瀏覽器直接調用,用回調的形式回到你的源代碼流程中
將url的查詢參數解析成字典對象
這個題目不約而同的出現在了多家公司的面試題中,當然也是因為太過于典型,解決方案無非就是拆字符或者用正則匹配來解決,我個人強烈建議用正則匹配,因為url允許用戶隨意輸入,如果用拆字符的方式,有任何一處沒有考慮到容錯,就會導致整個js都報錯。而正則就沒有這個問題,他只匹配出正確的配對,非法的全部過濾掉,簡單,方便。
實現代碼:
function getQueryObject(url){
url = url == null? window.location.href : url;
var search = url.substring(url.lastIndexOf("?") + 1);
var obj = {};
var reg = /([^?&=]+)=([^?&=]*)/g;
search.replace(reg,function(rs,$1,$2){
var name = decodeURIComponent($1);
var val = decodeURIComponent($2);
var = String(val);
obj[name] = val;
return rs;
});
return obj;
}
設計模式
面試時被問到較多的有觀察者模式,職責鏈模式,工廠模式
主要是應用于js開發組件中經常設計,純粹的頁面業務邏輯可能涉及不多
比如如何去設計一個前端UI組件,應該公開出哪些方法,應該提供哪些接口,應該提供哪些事件。哪部分邏輯流程應該開放出去讓用戶自行編寫,如何實現組件與組件之間的通信,如何實現高內聚低耦合,如何實現組件的高復用等等