1. 程式人生 > >2018秋招之前端面試題自我總結(JavaScript部分)

2018秋招之前端面試題自我總結(JavaScript部分)

第一題.請解釋事件代理

事件代理又稱事件委託,事件委託就是利用事件冒泡,只指定一個事件處理程式,就可以管理某一型別的所有事件。
1.1那為什麼要使用事件委託呢?
在JavaScript中,新增到頁面上的事件處理程式數量直接關係到頁面的整體的執行效能,因為需要不斷的與dom節點進行互動,訪問dom的次數越多,引起瀏覽器重繪與重拍的次數也就越多,會延長整個頁面的互動就緒時間,這就是為什麼效能優化的主要思想之一就是減少dom操作的原因。如果用事件委託,就會將所有的操作放到js程式中,與dom的操作就只需要互動一次,大大減少了與dom的互動次數,提高效能。
1.2事件委託的原理:
事件委託就是利用事件冒泡的原理來實現的。(以下是分不同情況舉的例子)
1.2.1對document載入完成的現有dom節點進行操作
<ul id="ul1">
    <li>li1</li>
    <li>l12</li>
    <li>li3</li>
    <li>li4</li>
</ul>

/*這是一般情況下,我們為li新增事件的方式;首先要找到ul,然後遍歷li,然後點選li的時候,又要找一次目標的li的位置,才能執行最後的操作,每次點選都要找一次li*/
window.onload = function(){
    var oUl = document.getElementById("ul1"
); var aLi = oUl.getElementsByTagName('li'); for(var i=0;i<aLi.length;i++){ aLi[i].onclick = function(){ alert("li"); } } } /*這是使用事件委託的方式;這裡用父級ul做事件處理,當ul(或li)被點選的時候,就會觸發ul的事件處理程式*/ window.onload=function(){ var oUl=document.getElementById("ul1"); oUl.onclick=function
(){
alert("li"); } }
 那麼,如果想實現事件代理的效果跟直接給節點的事件效果一樣(只有點選li才會觸發)怎麼辦呢?
 Event物件提供了一個屬性叫target,可以返回事件的目標節點,意思是,target就可以表示為當前的事件操作的dom,but不是真正操作dom,標準瀏覽器用ev.target,IE瀏覽器用event.srcElement,(ev.target||event.srcElement)這只是獲取了當前節點的位置,並不知道節點名稱,使用nodeName來獲取具體的標籤名,這返回的是一個大寫的,我們最好轉成小寫在做比較: 
   window.onload = function(){
      var oUl = document.getElementById("ul1");
      oUl.onclick = function(ev){
        var ev = ev || window.event;
        var target = ev.target || ev.srcElement;
        if(target.nodeName.toLowerCase() == 'li'){
         alert("li");
         alert(target.innerHTML);
        }
      }
   }
這樣改下就只有點選li會觸發事件了,且每次只執行一次dom操作,如果li數量很多的話,將大大減少dom的操作,優化的效能可想而知!上述例子中 所有的li的效果相同。接下來用事件代理實現不同效果的例子:
    <ul id="ul2">
      <li id="li1">li1</li>
      <li id="li2">l12</li>
      <li id="li3">li3</li>
      <li id="li4">li4</li>
    </ul>

     window.onload = function(){
         var oBox = document.getElementById("ul2");
         ul2.onclick = function (ev) {
             var ev = ev || window.event;
             var target = ev.target || ev.srcElement;
             if(target.nodeName.toLocaleLowerCase() == 'li'){
                 switch(target.id){
                     case 'li1' :
                         target.style.background = 'blue';
                         break;
                    case 'li2' :
                        target.style.background = 'green';
                        break;
                    case 'li3' :
                        target.style.background = 'pink';
                        break;
                    case 'li4' :
                        target.style.background = 'yellow';
                        break;
                 }
             }
         }    
     }
1.2.2對新增的dom節點進行操作,使其有對應的事件處理程式
    <input type="button" name="" id="btn" value="新增" />
    <ul id="ul1">
        <li>111</li>
        <li>222</li>
        <li>333</li>
        <li>444</li>
    </ul>
    window.onload = function(){
        var oBtn = document.getElementById("btn");
        var oUl = document.getElementById("ul1");
        var aLi = oUl.getElementsByTagName('li');
        var num = 4;

         //事件委託,新增的子元素也有事件
        oUl.onmouseover = function(ev){
             var ev = ev || window.event;
             var target = ev.target || ev.srcElement;
             if(target.nodeName.toLowerCase() == 'li'){
                 target.style.background = "red";
             }             
         };
         oUl.onmouseout = function(ev){
             var ev = ev || window.event;
             var target = ev.target || ev.srcElement;
             if(target.nodeName.toLowerCase() == 'li'){
                 target.style.background = "#fff";
             }           
         };

         //新增新節點
         oBtn.onclick = function(){
             num++;
             var oLi = document.createElement('li');
             oLi.innerHTML = 111*num;
             oUl.appendChild(oLi);
         };
     }
我們可以發現,當用事件委託的時候,根本就不需要去遍歷元素的子節點,只需要給父級元素新增事件就好了,其他的都是在js裡面的執行,這樣可以大大的減少dom操作,這才是事件委託的精髓所在。
 總結:
那什麼樣的事件可以用事件委託,什麼樣的事件不可以用呢? 
適合用事件委託的事件:click,mousedown,mouseup,keydown,keyup,keypress。  
值得注意的是,mouseover和mouseout雖然也有事件冒泡,但是處理它們的時候需要特別的注意,因為需要經常計算它們的位置,處理起來不太容易。  
不適合的就有很多了,舉個例子,mousemove,每次都要計算它的位置,非常不好把控,在不如說focus,blur之類的,本身就沒用冒泡的特性,自然就不能用事件委託了。

第二題:實現一維陣列就地逆序

 var arr1=new Array(1,2,3,4,5,6,7);
        function arrreverse(arr){
            var i=0;j=arr.length-1;len=arr.length;
            for(i;i<len/2;i++){
                var temp=arr[i];
                arr[i]=arr[j-i];
                arr[j-i]=temp;
            }
            console.log(arr);
        }
        arrreverse(arr1);

第三題:dom 的操作,常用的有哪些,如何建立、新增、移除、移動、複製、查詢節點?

建立:
createDocumentFragment();//建立一個DOM片段
createElement();//建立以一個具體的元素
createTextNode();//建立一個文字節點
新增:
appendChild();//用於新增新元素到尾部
insertBefore();//用於新元素新增到開始位置
移除已存在的元素:removeChild();//需要知道該元素的父元素。
替換:replaceChild(old, new);
複製:cloneNode(true)
查詢:
getElementsByTagName() //通過標籤名稱
getElementsByClassName() //通過標籤名稱
getElementsByName() //通過元素的Name屬性的值
getElementById() //通過元素Id,唯一性

本人在寫這篇部落格時候,也是借鑑了許多其他優秀的文章,非常感謝各位大神的分享。以上內容如有不正確的地方,還希望大家積極指正。謝謝啦
**本文章還會繼續更新哦**