js事件相關面試題


說是面試題,其實也相當於是對js事件部分知識點的一個總結。簡單內容一筆帶過,了解詳情我都給出了參考鏈接,都是之前寫的一些相關文章。JavaScript本身沒有事件模型,但是環境可以有。

DOM:addEventListener、removeEventListener、dispatchEvent
IE-DOM:attachEvent、detachEvent、fireEvent
jQuery:on、off、trigger

一、描述js里事件的三個階段

捕獲、處於目標階段、冒泡階段(IE8以下只支持冒泡)

了解更多可參考:事件流

二、IE和W3C標准 綁定事件的區別?參數分別是什么?以及IE事件對象中的e有什么區別

標准:

/*
參數:
eventName:事件的名字
function:事件處理函數
Boolean:捕獲或者冒泡,默認是false冒泡
*/
/*事件對象e作為參數傳入*/
addEventListener(eventName,function(e){
},false);

IE8以下

/*
參數:
onEvnet:是事件處理程序的名字,而不是事件名,就是說在事件名前加上on
function:事件處理函數
*/
/*
e=window.event,事件event是window的一個屬性
*/
attachEvent(onEventName,function(){
   var e=window.event; 
})

了解更多可以參考事件處理程序

三、事件代理的原理及優缺點

原理:靠事件冒泡實現的

優點:

  • 大量減少內存占用,減少事件注冊
  • 新增子對象時無需再次對其綁定事件,對於動態內容不符尤其適用

 缺點:

適用於表格/列表等重復性dom元素,事件代理用不好可能出現事件誤判,即本不應該觸發事件的元素被綁定了事件

四、手寫原生js實現事件代理

要求:兼容瀏覽器

考點:事件對象e,IE下事件對應的屬性名。

重點是要說到target,currentTarget以及IE下的srcElement和this。

三、四2部分具體可參考:事件的典型應用事件代理

五、實現事件模型

核心需求:可以對某一個事件名稱綁定多個事件處理函數,然后觸發這個事件名稱時,依次按照綁定順序觸發相應的事件處理函數。

原理:寫一個類或者匿名函數,有兩個函數,一個bind,一個trigger,分別實現綁定事件和觸發事件。

在bind和trigger函數外層作用域創建一個字典對象,用於存儲注冊的事件名稱和事件處理函數列表。

bind時,如果字典沒有則創建一個,key是事件名稱,value是數組,里面放着當前注冊的響應函數。

如果字段匯總有,那么就直接push到數組中即可。

trigger時調出來依次觸發事件響應函數即可。

還有很多細節:

觸發響應函數時的上下文應該是什么?【我覺得應該就是誰觸發了這個事件處理函數this就是誰,大家有懂的可以評論一下】

觸發響應函數的參數列表應該是什么?

如果要求把trigger的參數列表都傳到響應函數中還要考慮把arguments對象轉化為純數組才行。

js中自定義事件模型

function Emitter() {
    this._listener = {}; //_listener[自定義的事件名] = [所用執行的匿名函數1, 所用執行的匿名函數2]
}

//注冊事件
Emitter.prototype.bind = function(eventName, funCallback) {
        var listenersArr = this._listener[eventName] || []; ////this._listener[eventName]沒有值則將listener定義為[](數組)。
        listenersArr.push(funCallback);
        this._listener[eventName] = listenersArr;
    }
    //觸發事件
Emitter.prototype.trigger = function(eventName) {
        //未綁定事件    
        if (!this._listener.hasOwnProperty(eventName)) {
            console.log('you do not bind this event');
            return;
        }
        var args = Array.prototype.slice.call(arguments, 1); ////args為獲得除了eventName后面的參數(最后被用作注冊事件的參數)
        var listenersArr = this._listener[eventName];
        var _this = this;
        if (!Array.isArray(listenersArr)) return; ////自定義事件名不存在

        listenersArr.forEach(function(callback) {
            try {
                callback.call(_this, args);
            } catch (e) {
                console.log(e);
            }
        });
    }
    //解綁
Emitter.prototype.unbind = function(eventName, callback) {
    this._listener.hasOwnProperty(eventName) && delete this._listener[eventName];
    callback && callback();
}

測試用例

var emitter = new Emitter();
emitter.bind("selfEvent", function() {
    console.log("第一個綁定");
    Array.prototype.forEach.call(arguments, function(item) {
        console.log(item);
    });
});
emitter.bind("selfEvent", function() {
    console.log("第二個綁定");
    Array.prototype.forEach.call(arguments, function(item) {
        console.log(item);
    });
});
emitter.trigger('selfEvent', 'a', 'b', 'c');
emitter.unbind('selfEvent', function() {
    console.log("解除綁定");
});
emitter.trigger('selfEvent', 'a', 'b', 'c');

運行結果

六、事件廣播(dispatchEvent)

 dispatchEvent是js的事件觸發器,事件觸發器就是用來觸發某個元素下的某個事件。

可以自定義事件,通過觸發器觸發。

<p id="pElement">事件被觸發后文字變紅</p>

<script>
var pElement=document.getElementById("pElement");

var event=new Event('selfEvent');
pElement.addEventListener('selfEvent', function (e) {
    alert(e.type);  //selfEvent
    this.style.color="red";
},false);
pElement.dispatchEvent(event);

</script>

如果初始化自定義事件時需要添加一些額外的數據,可以用CustomEvent構造函數。

var event=new CustomEvent('lxyEvent',{'detail':'liuxiaoyan'});  //detail屬性值即自定義數據
pElement.addEventListener('lxyEvent', function (e) {
    alert(e.type+ e.detail);
    this.style.color="red";
},false);
pElement.dispatchEvent(event);

 

 

參考:

2016十家公司前端面試小記

MDN create_and_trigger_events

http://www.cnblogs.com/pcd12321/p/5223347.html

http://www.cnblogs.com/1wen/p/5640997.html 

 

 

本文作者starof,因知識本身在變化,作者也在不斷學習成長,文章內容也不定時更新,為避免誤導讀者,方便追根溯源,請諸位轉載注明出處:http://www.cnblogs.com/starof/p/6767655.html有問題歡迎與我討論,共同進步。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM