前端常見JS問題總結


 

1. Call 和 Apply 的區別

語法:
function.call(thisObj [, arg1[, arg2[, [, ...argN]]]]);
function.apply(thisObj [, argArray] );

定義: call 和 apply 可以讓我們手動設置 this 指向
兩個參數: 第一個參數是 綁定 this 指向;第二個參數是 向將要執行的函數傳遞的參數
區別: 第二個參數, call 以一個一個的形式傳遞參數;apply 以數組的形式傳遞參數

var a = 10;
function sum(num1, num2) {
    console.log(this.a + num1 + num2);
}
var obj = {
    a: 20
}

sum(10, 10);    //30
sum.call(obj, 10, 10);       // 40
sum.apply(obj, [10, 10]);    // 40

 

2. 鍵盤事件屬性

event.keyCode;    // 獲取按下的鍵盤按鍵的鍵碼值(Unicode值)
event.ctrlKey;    // 獲取是否按下了ctrl鍵
event.shiftKey;   // 獲取是否按下了shift鍵
event.altKey;     // 獲取是否按下了alt鍵
event.metaKey;    // 獲取是否按下了meta鍵

 

3. 鼠標事件屬性

event.screenX/event.screenY     // 獲取鼠標基於屏幕的X軸/Y軸坐標
event.clientX/event.clientY     // 獲取鼠標基於瀏覽器窗口的X軸/Y軸坐標
event.pageX/event.pageY         // 獲取鼠標基於文檔的X軸/Y軸坐標

event.button   // 獲取鼠標按下的鍵。非IE瀏覽器中0為鼠標左鍵,1為鼠標中鍵,2為鼠標右鍵
event.which    // 獲取指定事件上哪個鍵盤鍵或鼠標按鈕被按下

 

4. addEventListener 和 attachEvent 區別

attachEvent方法適用於IE
attachEvent中的事件帶on, 而addEventListener中的事件不帶on
attachEvent 方法有兩個參數:第一個參數為事件名稱,第二個參數為接收事件處理的函數; addEventListener 方法有三個參數:第一個參數為事件名稱(不含 on,如 "click"),第二個參數為要接收事件處理的函數,第三個參數為一個bool值,默認為false

  1. 添加多個事件處理程序執行的順序不同

addEventListener: var btn=document.getElementById("myBtn");  
btn.addEventListener("click",function(){  
    alert(1);     
    },false);  
  
btn.addEventListener("click",function(){  
      alert(2);     
    },false); 

//執行結果 1 ,2
attachEvent: 
var btn=document.getElementById("myBtn");  
 btn.attachEvent("onclick",function(){  
     alert(1);     
   });  
 btn.attachEvent("onclick",function(){  
     alert(2);     
   });  

//執行結果 2 ,1

  2. 事件處理程序的作用域不同

DOM2級事件添加的事件處理程序,它的作用域是所屬的元素,而IE的事件處理程序會在全局作用域中運行。

addEventListener: var btn=document.getElementById("myBtn");  
btn.addEventListener("click",function(){  
    console.log(this.id);    // myBtn   
    },false);  
attachEvent: var btn=document.getElementById("myBtn");  
btn.attachEvent("onclick",function(){  
  alert(this===window);    // true   
  });  

  3. 移除綁定事件 removeEventListener() 和 detachEvent()

移除 addEventListener 事件:
element.removeEventListene(event, function, useCapture)
event: 事件名,注意不使用“on”前綴,如 click
function: 指定事件觸發時執行的函數
useCapture: 指定事件是否在捕獲或冒泡階段執行
true: 在捕獲階段執行
false: 在冒泡階段進行,默認值為false
如果添加時用的捕獲階段,那么在移除時也要用捕獲階段,否則無法移除它們
如果是同一個元素同一個調用函數同一個useCapture值綁定多次,在移除時只需要執行一次移除
移除 attachEvent 事件:
element.detachEvent(event, function)
event: 事件名,注意要使用“on”前綴,如 onclick
function: 指定事件觸發時執行的函數

 

 5. addEventListener 和 on 區別

<div id="box">addEventListener 和 on 區別</div>
window.onload = function(){
     var box = document.getElementById("box");
     box.onclick = function(){
         console.log("我是box1");
     }
     box.onclick = function(){
         console.log("我是box2");
     }
}

//運行結果:“我是box2”
 window.onload = function(){
     var box = document.getElementById("box");
     box.addEventListener("click", function(){
         console.log("我是box1");
     })
     box.addEventListener("click", function(){
         console.log("我是box2");
     })
}
運行結果:我是box1
     我是box2

第二個onclick會把第一個onclick給覆蓋了,雖然大部分情況我們用on就可以完成我們想要的結果,但是有時我們又需要執行多個相同的事件,很明顯如果用on完成不了我們想要的,而addEventListener可以多次綁定同一個事件並且不會覆蓋上一個事件。

 

6. HTML5 新增的事件

contextmenu事件
這個事件是當鼠標右擊的時候觸發的,但是觸發這個屬性的時候默認的行為也會被觸發,所以需要通過preventDefault()方法來阻止。

beforeunload事件
beforeunload在頁面卸載之前觸發,該事件會彈出一個對話框,詢問是否確定離開。

hashchange事件
該事件當URL中的hash值改變時觸發,通常用於Ajax應用中利用URL參數保存導航信息;這個在前端路由的制作中是非常有用得。

 

7. 阻止事件默認行為和阻止事件冒泡

<div id="wrap" style="width: 200px; height: 200px; background: gray;">
    <div id="btn" style="width: 100px; height: 100px; background: orangered;"></div>
    <a id="prevent" target="_blank" href="http://www.baidu.com">preventDefault</a>
</div>

標准瀏覽器的使用方法

preventDefault(): 用於阻止事件的默認行為;
比如: a 鏈接的跳轉行為和表單自動提交行為  

var prevent = document.getElementById("prevent");
    prevent.addEventListener("click", function(event){
        event.preventDefault();
    }, false);

//使用preventDefault()方法就阻止了a標簽打開新窗口的默認行為 

stopPropagation(): 用於阻止事件的進一步獲取和傳播;
比如:阻止事件繼續向上層冒泡

var btn = document.getElementById("btn"),
    wrap= document.getElementById("wrap");
    btn.addEventListener("click",function(event){
        alert("btn");
        event.stopPropagation();
    },false);
    wrap.addEventListener("click",function(){
        alert("wrap");
    },false);

//點擊btn時,這樣就阻止了id="btn"向上級id="wrap"冒泡,打印出來的結果是:彈窗僅彈出btn。否則,將會先彈出btn,然后彈出wrap。

低版本IE瀏覽器的使用方法

event.returnValue = false;   //阻止事件的默認行為;
event.cancelBubble = true;   //阻止事件的進一步獲取或者冒泡;

示例

function prevent(event) {
    event = event || window.event;
    if(event.preventDefault) {
        event.preventDefault();
    } else {
        event.returnValue = false; 
    }
}
//使用 if else 去判斷

 

8. 事件捕獲和事件冒泡

事件冒泡執行過程:從最具體的的元素(你單擊的那個元素)開始向上開始冒泡,下面的案例的順序是:content > wrap
事件捕獲執行過程:從最不具體的元素(最外面的那個盒子)開始向里面冒泡,下面的案例的順序是:wrap > content

<div id="wrap">
    <div id="content"></div>
</div>
(addEventListener第三個參數寫的是false, 默認為false)
 window.onload = function(){
     var wrap= document.getElementById("wrap");
     var content= document.getElementById("content");
     wrap.addEventListener("click", function(){
         console.log("我是wrap");
     }, false)
     content.addEventListener("click", function(){
         console.log("我是content");
     })
}
運行結果:我是content
     我是wrap
(addEventListener第三個參數寫的是true, 默認為false)
  window.onload = function(){
     var wrap= document.getElementById("wrap");
     var content= document.getElementById("content");
     wrap.addEventListener("click", function(){
         console.log("我是wrap");
     }, true)
     content.addEventListener("click", function(){
         console.log("我是content");
     })
}
運行結果:我是wrap
     我是content

第三個參數寫的是true,則按照事件捕獲的執行順序進行。

  

 9. 給 select 標簽 option 內容加鏈接

<select onchange="window.open(options[selectedIndex].value, '_self')">
    <option value="http://www.bj-hmk.com/">中文</option>
    <option value="http://en.bj-hmk.com/">English</option>
</select>

  

10. Null 和 Undefined

undefined 表示根本不存在定義
null 表示一個值被定義了,定義為“空值”

(1)變量被聲明了,但沒有賦值時,就等於undefined。
(2)調用函數時,應該提供的參數沒有提供,該參數等於undefined。
(3)對象沒有賦值的屬性,該屬性的值為undefined。
(4)函數沒有返回值時,默認返回undefined。

所以設置一個值為 null 是合理的,如
objA.valueA = null;

但設置一個值為 undefined 是不合理的,如
objA.valueA = undefined; // 應該直接使用 delete objA.valueA; 任何一個存在引用的變量值為undefined都是一件錯誤的事情。
這樣判斷一個值是否存在,就可以用
objA.valueA === undefined // 不應使用 null 因為 undefined == null,而 null 表示該值定義為空值。

 

11. 解決slideDown()和slideUp()鼠標快速移入移出,出現反復執行的問題

方法一:
$(".orderDivMain").hover(function () {
    if (!$(".orderDivId").is(":animated")) {
        $(this).find('.orderDivId').slideDown(500);
    }
}, function () {
    if (!$(".orderDivId").is(":animated")) {
        $(this).find('.orderDivId').slideUp(500);
    }
});

方法二:
$(".orderDivMain").hover(function () {
    $(".orderDivId").slideDown(500);
});
$(".orderDivId").mouseleave(function () {
    $(".orderDivId").slideUp(500);
});

 

12. web應用整體性能的考慮

12 13兩點 參考於 《JavaScript DOM編程藝術(第2版)》

盡量少訪問DOM和盡量減少標記

if(document.getElementsByTagName("a").length > 0){
    var links = document.getElementsByTagName("a");
    for(var i = 0; i < links.length; i++){
        something...
    }
}

上面這段代碼使用了兩次getElementsByTagName方法去執行相同的操作,浪費了一次搜索。更好的辦法是把第一次搜索的結果保存在一個變量中,然后重用該結果:

var links = document.getElementsByTagName("a");
if(links.length > 0){
    for(var i = 0; i < links.length; i++){
        something...
    }
}

合並和放置腳本

<script src="js/functionA.js"></script>
<script src="js/functionB.js"></script>
<script src="js/functionC.js"></script>
<script src="js/function.js"></script>

上面兩種做法,推薦的做法是把第一種functionA.js、functionB.js、functionC.js合並到一個腳本文件中。這樣就可以減少加載頁面時發送的請求數量,而減少請求數量通常都是性能優化時首先要考慮的。

位於<head>塊中的腳本會導致瀏覽器無法並行加載其他文件,把<script>標簽放在</body>標記之前,就可以讓頁面變的更快。  

 

13. 使你所寫的頁面能夠向后兼容、平穩退化

針對這一問題的最簡單的解決方案是,檢測瀏覽器對javascript的支持程度,即對象檢測。幾乎所有的東西(包括各種方法在內)都可以被當作對象來對待,這意味着我們可以很容易的把不支持某個特定的DOM方法的瀏覽器檢測出來:

if(method){
    statements
}

例如,檢測瀏覽器是否支持getElementById方法:

if(document.getElementById){
    statements using getElementById
}

但是如果需要檢測多個DOM方法或者屬性是否存在,那么最重要的語句可能會被深埋在一層又一層的花括號里,使得代碼將會很難閱讀和理解。

那么就可以把測試的條件改為“如果你不理解這個方法,請離開”則會變得簡單明了。

if(!document.getElementById){
    return false;
}

若需要測試多個方法或屬性是否支持,可以使用“邏輯或”操作符將其合並:

if(!document.getElementById || !document.getElementsByTagName){
    return false;
}

 

14. jQuery中attr和prop的區別

處理HTML元素本身就帶有的固有屬性時使用prop方法

處理HTML元素我們自己定義的Dom屬性時使用attr方法

<input class='check1' type='checkbox'>選擇1
<input class='check2' type='checkbox' checked>選擇2

checked屬於checkbox元素的固有屬性,讓我們來看看prop和attr的結果有什么不同:

prop方法:
$('.check1').prop('checked') -- false
$('.check2').prop('checked') -- true 
attr方法:
$('.check1').attr('checked') -- undefined 
$('.check2').attr('checked') -- 'checked'

 

15. 在選中的元素上綁定事件和通過代理綁定事件的區別

在選中的元素上綁定click事件:
$('a').on('click', function(){});
通過代理綁定click事件:
$(document).on('click', 'a', function(){});

在選中的元素上綁定事件只能為頁面現有的a元素綁定點擊事件,如果是動態生成的新的a元素是沒有事件的。

通過代理綁定事件是將指定的事件綁定在document上,新添加的a元素也能觸發此事件。

 

16. reload 方法,強迫瀏覽器刷新當前頁面。

語法:location.reload([falseOrTrue]) ;
參數: falseOrTrue, 可選參數。 默認為 false,從客戶端緩存里取當前頁。true,則以 GET 方式,從服務端取最新的頁面,相當於客戶端點擊 F5(“刷新”)。

<a href="javascript:location.reload();">點擊刷新頁面</a>
<span onclick="location.reload(true);">點擊刷新頁面</span>

 

17. 禁止頁面選取內容

適用於IE、Chrome瀏覽器,在 head 的 <script> 標簽里面添加 js 代碼

document.onselectstart = function (e) { return false; }
或者
document.onselectstart = new Function('event.returnValue = false;');

在firefox火狐瀏覽器中,禁止元素被選取可以采用 CSS 樣式在來控制

body{
    -moz-user-focus: ignore;  
    -moz-user-input: disabled; 
    -moz-user-select: none;
}

禁止鼠標右鍵

document.oncontextmenu = function(e){return false;}

 

18. 正則表達式驗證

//  驗證是否為手機號
function phone(num) {
    return /^1[34578]\d{9}$/.test(num);
}

//  驗證是否為郵箱
function email(e) {
    return /^(\w)+(\.\w+)*@(\w)+((\.\w+)+)$/.test(e);
}

 

19. 返回頂部

window.onscroll = function () {
    if (document.body.scrollTop || document.documentElement.scrollTop > 0) {
        document.getElementById('back_top').style.display = "block";
    } else {
        document.getElementById('back_top').style.display = "none";
    }
}
$('.back_top').click(function () {
    $("html,body").animate({ scrollTop: 0 }, 500);
    return false;
});

 

20. js 中 Error 錯誤

ReferenceError:作用域判別錯誤,通過作用域鏈的搜尋找不到相應的變量。

TypeError:可以通過作用域搜索到變量,但是對變量的操作不合法。

SyntaxError語法錯誤。


免責聲明!

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



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