常見前端面試題及答案(下)
51.你是如何組織自己的代碼?是使用模塊模式,還是使用經典繼承的方法?
請看文章-JavaScript之模塊化編程和Javascript之對象的繼承
52.請指出JavaScript宿主對象和原生對象的區別?
原生對象
ECMA-262 把本地對象(native object)定義為「獨立於宿主環境的 ECMAScript 實現提供的對象」。
「本地對象」包含哪些內容:Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、EvalError、RangeError、ReferenceError、SyntaxError、TypeError、URIError。
由此可以看出,簡單來說,本地對象就是 ECMA-262 定義的類(引用類型)。
內置對象
ECMA-262 把內置對象(built-in object)定義為「由 ECMAScript 實現提供的、獨立於宿主環境的所有對象,在 ECMAScript 程序開始執行時出現」。這意味著開發者不必明確實例化內置對象,它已被實例化了。
同樣是「獨立於宿主環境」。根據定義我們似乎很難分清「內置對象」與「本地對象」的區別。而ECMA-262 只定義了兩個內置對象,即 Global 和 Math (它們也是本地對象,根據定義,每個內置對象都是本地對象)。如此就可以理解了。內置對象是本地對象的一種。
宿主對象
何為「宿主對象」?主要在這個「宿主」的概念上,ECMAScript中的「宿主」當然就是我們網頁的運行環境,即「操作系統」和「瀏覽器」。
所有非本地對象都是宿主對象(host object),即由 ECMAScript 實現的宿主環境提供的對象。所有的BOM和DOM都是宿主對象。因為其對於不同的「宿主」環境所展示的內容不同。其實說白了就是,ECMAScript官方未定義的對象都屬於宿主對象,因為其未定義的對象大多數是自己通過ECMAScript程序創建的對象。
53.call和.apply的區別是什麼?
call方法:
語法:call(thisObj,Object)
定義:調用一個對象的一個方法,以另一個對象替換當前對象。
說明:call 方法可以用來代替另一個對象調用一個方法。call 方法可將一個函數的對象上下文從初始的上下文改變為由 thisObj 指定的新對象。 如果沒有提供 thisObj 參數,那麼 Global 對象被用作 thisObj。
apply方法:
語法:apply(thisObj,[argArray])
定義:應用某一對象的一個方法,用另一個對象替換當前對象。
說明:如果 argArray 不是一個有效的數組或者不是 arguments 對象,那麼將導致一個 TypeError。如果沒有提供 argArray 和 thisObj 任何一個參數,那麼 Global 對象將被用作 thisObj, 並且無法被傳遞任何參數。
對於apply和call兩者在作用上是相同的,但兩者在參數上有以下區別:
對於第一個參數意義都一樣,但對第二個參數:apply傳入的是一個參數數組,也就是將多個參數組合成為一個數組傳入,而call則作為call的參數傳入(從第二個參數開始)。如 func.call(func1,var1,var2,var3)對應的apply寫法為:func.apply(func1,[var1,var2,var3])同時使用apply的好處是可以直接將當前函數的arguments對象作為apply的第二個參數傳入。
54.請解釋Function.prototype.bind的作用?
55.你何時優化自己的代碼?
請看文章JavaScript之高效編程 及JavaScript編碼風格指南。
56.你能解釋一下JavaScript中的繼承是如何工作的嗎?
原型鏈等。
57.在什麼時候你會使用document.write()?
大多數生成的廣告代碼依舊使用document.write(),雖然這種用法會讓人很不爽。
58.請指出瀏覽器特性檢測,特性推斷和瀏覽器UA字元串嗅探的區別?
特性檢測:為特定瀏覽器的特性進行測試,並僅當特性存在時即可應用特性。
User-Agent檢測:最早的瀏覽器嗅探即用戶代理檢測,服務端(以及後來的客戶端)根據UA字元串屏蔽某些特定的瀏覽器查看網站內容。
特性推斷:嘗試使用多個特性但僅驗證了其中之一。根據一個特性的存在推斷另一個特性是否存在。問題是,推斷是假設並非事實,而且可能導致可維護性的問題。
59.請儘可能詳盡的解釋AJAX的工作原理。
請參考文章AJAX工作原理。
60.請解釋JSONP的工作原理,以及它為什麼不是真正的AJAX。
JSONP (JSON with Padding)是一個簡單高效的跨域方式,HTML中的script標籤可以載入並執行其他域的javascript,於是我們可以通過script標記來動態載入其他域的資源。例如我要從域A的頁面pageA載入域B的數據,那麼在域B的頁面pageB中我以JavaScript的形式聲明pageA需要的數據,然後在 pageA中用script標籤把pageB載入進來,那麼pageB中的腳本就會得以執行。JSONP在此基礎上加入了回調函數,pageB載入完之後會執行pageA中定義的函數,所需要的數據會以參數的形式傳遞給該函數。JSONP易於實現,但是也會存在一些安全隱患,如果第三方的腳本隨意地執行,那麼它就可以篡改頁面內容,截獲敏感數據。但是在受信任的雙方傳遞數據,JSONP是非常合適的選擇。
AJAX是不跨域的,而JSONP是一個是跨域的,還有就是二者接收參數形式不一樣!
61.你使用過JavaScript模板系統嗎?
如有使用過,請談談你都使用過哪些庫,比如Mustache.js,Handlebars等等。
62.請解釋變數聲明提升。
在JS里定義的變數,存在於作用域鏈里,而在函數執行時會先把變數的聲明進行提升,僅僅是把聲明進行了提升,而其值的定義還在原來位置。示例如下:
複製代碼
1 var test = function() {2 console.log(name); // 輸出:undefined3 var name = "jeri";4 console.log(name); // 輸出:jeri5 }6 7 test();
複製代碼
上述代碼與下述代碼等價。
複製代碼
1 var test = function() {2 var name;3 console.log(name); // 輸出:undefined4 name = "jeri";5 console.log(name); // 輸出:jeri6 }7 8 test();
複製代碼
由以上代碼可知,在函數執行時,把變數的聲明提升到了函數頂部,而其值定義依然在原來位置。
63.請描述下事件冒泡機制。
冒泡型事件:事件按照從最特定的事件目標到最不特定的事件目標(document對象)的順序觸發。
捕獲型事件:事件從最不精確的對象(document 對象)開始觸發,然後到最精確(也可以在窗口級別捕獲事件,不過必須由開發人員特別指定)。
支持W3C標準的瀏覽器在添加事件時用addEventListener(event,fn,useCapture)方法,基中第3個參數useCapture是一個Boolean值,用來設置事件是在事件捕獲時執行,還是事件冒泡時執行。而不兼容W3C的瀏覽器(IE)用attachEvent()方法,此方法沒有相關設置,不過IE的事件模型默認是在事件冒泡時執行的,也就是在useCapture等於false的時候執行,所以把在處理事件時把useCapture設置為false是比較安全,也實現兼容瀏覽器的效果。
64."attribute"和"property"的區別是什麼?
1. 定義
Property:屬性,所有的HTML元素都由HTMLElement類型表示,HTMLElement類型直接繼承自Element並添加了一些屬性,添加的這些屬性分別對應於每個HTML元素都有下面的這5個標準特性: id,title,lang,dir,className。DOM節點是一個對象,因此,他可以和其他的JavaScript對象一樣添加自定義的屬性以及方法。property的值可以是任何的數據類型,對大小寫敏感,自定義的property不會出現在html代碼中,只存在js中。
Attribute:特性,區別於property,attribute只能是字元串,大小寫不敏感,出現在innerHTML中,通過類數組attributes可以羅列所有的attribute。
2. 相同之處
標準的 DOM properties 與 attributes 是同步的。公認的(非自定義的)特性會被以屬性的形式添加到DOM對象中。如,id,align,style等,這時候操作property或者使用操作特性的DOM方法如getAttribute()都可以操作屬性。不過傳遞給getAttribute()的特性名與實際的特性名相同。因此對於class的特性值獲取的時候要傳入「class」。
3. 不同之處
1).對於有些標準的特性的操作,getAttribute與點號(.)獲取的值存在差異性。如href,src,value,style,onclick等事件處理程序。
2).href:getAttribute獲取的是href的實際值,而點號獲取的是完整的url,存在瀏覽器差異。
65.為什麼擴展JavaScript內置對象不是好的做法?
66.為什麼擴展JavaScript內置對象是好的做法?
67.請指出document.onload和document.ready兩個事件的區別。
頁面載入完成有兩種事件,一是ready,表示文檔結構已經載入完成(不包含圖片等非文字媒體文件),二是onload,指示頁面包含圖片等文件在內的所有元素都載入完成。
68.==和===有什麼不同?
首先,== equality 等同,=== identity 恆等。 ==, 兩邊值類型不同的時候,要先進行類型轉換,再比較。 ===,不做類型轉換,類型不同的一定不等。
先說 ===,這個比較簡單。下面的規則用來判斷兩個值是否===相等:
如果類型不同,就[不相等]
如果兩個都是數值,並且是同一個值,那麼[相等];(!例外)的是,如果其中至少一個是NaN,那麼[不相等]。(判斷一個值是否是NaN,只能用isNaN()來判斷)
如果兩個都是字元串,每個位置的字元都一樣,那麼[相等];否則[不相等]。
如果兩個值都是true,或者都是false,那麼[相等]。
如果兩個值都引用同一個對象或函數,那麼[相等];否則[不相等]。
如果兩個值都是null,或者都是undefined,那麼[相等]。
再說 ==,根據以下規則:
如果兩個值類型相同,進行 === 比較。
如果兩個值類型不同,他們可能相等。根據下面規則進行類型轉換再比較:
如果一個是null、一個是undefined,那麼[相等]。
如果一個是字元串,一個是數值,把字元串轉換成數值再進行比較。
如果任一值是 true,把它轉換成 1 再比較;如果任一值是 false,把它轉換成 0 再比較。
如果一個是對象,另一個是數值或字元串,把對象轉換成基礎類型的值再比較。對象轉換成基礎類型,利用它的toString或者valueOf方法。js核心內置類,會嘗試valueOf先於toString;例外的是Date,Date利用的是toString轉換。非js核心的對象,令說(比較麻煩,我也不大懂)
任何其他組合,都[不相等]。
69.你如何從瀏覽器的URL中獲取查詢字元串參數。
以下函數把獲取一個key的參數。
複製代碼
1 function parseQueryString ( name ){ 2 name = name.replace(/[[]/,"\["); 3 var regexS = "[\?&]"+name+"=([^&#]*)"; 4 var regex = new RegExp( regexS ); 5 var results = regex.exec( window.location.href ); 6 7 if(results == null) { 8 return ""; 9 } else {10 return results[1];11 }12 }
複製代碼
70.請解釋一下JavaScript的同源策略。
在客戶端編程語言中,如javascript和 ActionScript,同源策略是一個很重要的安全理念,它在保證數據的安全性方面有著重要的意義。同源策略規定跨域之間的腳本是隔離的,一個域的腳本不能訪問和操作另外一個域的絕大部分屬性和方法。那麼什麼叫相同域,什麼叫不同的域呢?當兩個域具有相同的協議, 相同的埠,相同的host,那麼我們就可以認為它們是相同的域。同源策略還應該對一些特殊情況做處理,比如限制file協議下腳本的訪問許可權。本地的HTML文件在瀏覽器中是通過file協議打開的,如果腳本能通過file協議訪問到硬碟上其它任意文件,就會出現安全隱患,目前IE8還有這樣的隱患。
71.請描述一下JavaScript的繼承模式。
關於繼承請看文章JavaScript之對象的繼承。
72.如何實現下列代碼:[1,2,3,4,5].duplicator();//[1,2,3,4,5,1,2,3,4,5]。
73.描述一種JavaScript中實現memoization(避免重複運算)的策略。
74.什麼是三元表達式?「三元」表示什麼意思?
三元表達式:? :。三元--三個操作對象。
在表達式boolean-exp ? value0 : value1 中,如果「布爾表達式」的結果為true,就計算「value0」,而且這個計算結果也就是操作符最終產生的值。如果「布爾表達式」的結果為false,就計算「value1」,同樣,它的結果也就成為了操作符最終產生的值。
75.JavaScript里函數參數arguments是數組嗎?
在函數代碼中,使用特殊對象 arguments,開發者無需明確指出參數名,通過使用下標就可以訪問相應的參數。
arguments雖然有一些數組的性質,但其並非真正的數組,只是一個類數組對象。其並沒有數組的很多方法,不能像真正的數組那樣調用.jion(),.concat(),.pop()等方法。
76.什麼是"use strict";?使用它的好處和壞處分別是什麼?
在代碼中出現表達式-"use strict"; 意味著代碼按照嚴格模式解析,這種模式使得Javascript在更嚴格的條件下運行。
好處:
消除Javascript語法的一些不合理、不嚴謹之處,減少一些怪異行為;
消除代碼運行的一些不安全之處,保證代碼運行的安全;
提高編譯器效率,增加運行速度;
為未來新版本的Javascript做好鋪墊。
壞處:
同樣的代碼,在"嚴格模式"中,可能會有不一樣的運行結果;一些在"正常模式"下可以運行的語句,在"嚴格模式"下將不能運行。
77.解釋"chaining"。
jQuery方法鏈接。直到現在,我們都是一次寫一條jQuery語句(一條接著另一條)。不過,有一種名為鏈接(chaining)的技術,允許我們在相同的元素上運行多條jQuery命令,一條接著另一條。
提示:這樣的話,瀏覽器就不必多次查找相同的元素。
如需鏈接一個動作,您只需簡單地把該動作追加到之前的動作上。
78.解釋"deferreds"。
開發網站的過程中,我們經常遇到某些耗時很長的javascript操作。其中,既有非同步的操作(比如ajax讀取伺服器數據),也有同步的操作(比如遍歷一個大型數組),它們都不是立即能得到結果的。
通常的做法是,為它們指定回調函數(callback)。即事先規定,一旦它們運行結束,應該調用哪些函數。
但是,在回調函數方面,jQuery的功能非常弱。為了改變這一點,jQuery開發團隊就設計了deferred對象。
簡單說,deferred對象就是jQuery的回調函數解決方案。在英語中,defer的意思是"延遲",所以deferred對象的含義就是"延遲"到未來某個點再執行。
79.你知道哪些針對jQuery的優化方法?
1.總是從ID選擇器開始繼承在jQuery中最快的選擇器是ID選擇器,因為它直接來自於JavaScript的getElementById()方法。
例如有一段HTML代碼:
複製代碼
1
217
複製代碼
比如需要選擇紅綠單選框,那麼可以使用一個tag name來限制(修飾)class,如下所示:var active_light=$(「input.on」);當然也可以結合就近的ID,如下所示:var active_light=$(「#traffic_light input.on」); 如果採用下面的選擇器,那麼效率是低效的。var traffic_button=$(「#content.button」);因為button已經有ID了,我們可以直接使用ID選擇器。如下所示:var traffic_button=$(「#traffic_button」);當然這只是對於單一的元素來講。如果你需要選擇多個元素,這必然會涉及到DOM遍歷和循環,為了提高性能,建議從最近的ID開始繼承。如下所示:var traffic_lights=$(「#traffic_light input」);
2.在class前使用tag(標籤名)在jQuery中第二快的選擇器是tag(標籤)選擇器(比如:$(「head」))。
跟ID選擇器累時,因為它來自原生的getElementsByTagName()方法。繼續看剛才那段HTML代碼:
在使用tag來修飾class的時候,我們需要注意以下幾點:(1)不要使用tag來修飾ID,如下所示:var content=$(「div#content」);這樣一來,選擇器會先遍歷所有的div元素,然後匹配#content。(好像jQuery從1.3.1開始改變了選擇器核心後,不存在這個問題了。暫時無法考證。)(2)不要畫蛇添足的使用ID來修飾ID,如下所示:var traffic_light=$(「#content#traffic_light」);
3.將jQuery對象緩存起來把jQuery對象緩存起來就是要告訴我們要養成將jQuery對象緩存進變數的習慣。
下面是一個jQuery新手寫的一段代碼:
1 $("#traffic_light input.on").bind("click",function(){});2 $("#traffic_light input.on").css("border","1px dashed yellow");3 $("#traffic_light input.on").css("background-color","orange");4 $("#traffic_light input.on").fadeIn("slow");
但切記不要這麼做。我們應該先將對象緩存進一個變數然後再操作,如下所示:
記住,永遠不要讓相同的選擇器在你的代碼里出現多次.註:(1)為了區分普通的JavaScript對象和jQuery對象,可以在變數首字母前加上$符號。(2)上面代碼可以使用jQuery的鏈式操作加以改善。如下所示:
複製代碼
1 var $active_light = $("#traffic_light input.on");2 3 $active_light.bind("click",function(){})4 .css("border","1px dashed yellow")5 .css("background-color","orange")6 .fadeIn("slow");
複製代碼
4.如果你打算在其他函數中使用jQuery對象,那麼你必須把它們緩存到全局環境中。
如下代碼所示:
複製代碼
1 // 在全局範圍定義一個對象(例如:window對象) 2 window.$my = { 3 head:$("head"), 4 trafficLight:$("#trafficLight"), 5 trafficButton:$("#trafficButton") 6 }; 7 8 function doSomething(){ 9 // 現在你可以引用存儲的結果並操作它們10 var script=document.createElement("script");11 $my.head.append(script);12 13 // 當你在函數內部操作是,可以繼續將查詢存入全局對象中去.14 $my.coolResults=$("#some_ul li");15 $my.otherResults=$("#some_table td");16 17 // 將全局函數作為一個普通的jquery對象去使用.18 $my.otherResults.css("border-color","red");19 $my.trafficLight.css("border-color","green");20 }21 // 你也可以在其他函數中使用它.
複製代碼
這裡的基本思想是在內存中建立你確實想要的東西,然後更新DOM。這並不是一個jQuery最佳實踐,但必須進行有效的JavaScript操作。直接的DOM操作速度很慢。例如,你想動態的創建一組列表元素,千萬不要這樣做,如下所示:對直接的DOM操作進行限制。
複製代碼
1 var top_100_list = [];// 假設這裡是100個獨一無二的字元串2 var $mylist = $("#mylist");// jQuery選擇到
元素3 4 for(var i = 0,l = top_100_list.length;i");6 }
複製代碼
我們應該將整套元素字元串在插入進dom中之前先全部創建好,如下所示:
1 $("#entryform input").bind("focus",function() {2 $(this).addClass("selected");3 }).bind("blur",function(){4 $(this).removeClass("selected");5 });
5.冒泡除非在特殊情況下,否則每一個js事件(例如:click,mouseover等.)都會冒泡到父級節點。
當我們需要給多個元素調用同個函數時這點會很有用。代替這種效率很差的多元素事件監聽的方法就是,你只需向它們的父節點綁定一次。比如,我們要為一個擁有很多輸入框的表單綁定這樣的行為:當輸入框被選中時為它添加一個class傳統的做法是,直接選中input,然後綁定focus等,如下所示:
複製代碼
1 $("#entryform").bind("focus",function(e) {2 var $cell = $(e.target); // e.target捕捉到觸發的目標元素3 $cell.addClass("selected");4 }).bind("blur",function(e) {5 var $cell = $(e.target);6 $cell.removeClass("selected");7 });
複製代碼
當然上面代碼能幫我們完成相應的任務,但如果你要尋求更高效的方法,請使用如下代碼:
通過在父級監聽獲取焦點和失去焦點的事件,對目標元素進行操作。在上面代碼中,父級元素扮演了一個調度員的角色,它可以基於目標元素綁定事件。如果你發現你給很多元素綁定了同一個事件監聽,那麼現在的你肯定知道哪裡做錯了。
6.推遲到$(window).load。
jQuery對於開發者來說有一個很誘人的東西,可以把任何東西掛到$(document).ready下。儘管$(document).rady確實很有用,它可以在頁面渲染時,其它元素還沒下載完成就執行。如果你發現你的頁面一直是載入中的狀態,很有可能就是$(document).ready函數引起的。你可以通過將jQuery函數綁定到$(window).load事件的方法來減少頁面載入時的cpu使用率。它會在所有的html(包括iframe)被下載完成後執行。一些特效的功能,例如拖放,視覺特效和動畫,預載入隱藏圖像等等,都是適合這種技術的場合。
7.壓縮JavaScript。
在線壓縮地址:http://dean.edwards.name/packer/壓縮之前,請保證你的代碼的規範性,否則可能失敗,導致Js錯誤。
8.盡量使用ID代替Class。
前面性能優化已經說過,ID選擇器的速度是最快的。所以在HTML代碼中,能使用ID的盡量使用ID來代替class。看下面的一個例子:
複製代碼
1 // 創建一個list 2 var $myList = $("#myList"); 3 var myListItems = "
"; 4 5 for(var i = 0; i < 1000;="" i="" ++)="" {="" 6="" ="" ="" mylistitems="" +="";11 $myList.html(myListItems);12 // 選擇每一個li13 14 for(var i = 0; i<1000; i++)="" {15="" ="" ="" var="" selecteditem="$(".listItem"" +="" i);16="">
複製代碼
在上段代碼中,選擇每個li總共只用了61毫秒,相比class的方式,將近快了100倍。 在代碼最後,選擇每個li的過程中,總共用了5066毫秒,超過5秒了。接著我們做一個對比,用ID代替class:
9.給選擇器一個上下文。
jQuery選擇器中有一個這樣的選擇器,它能指定上下文。jQuery(expression,context);通過它,能縮小選擇器在DOM中搜索的範圍,達到節省時間,提高效率。普通方式:$(『.myDiv』)改進方式:$(『.myDiv』,$(「#listItem」))。
10.慎用.live()方法(應該說盡量不要使用)。
這是jQuery1.3.1版本之後增加的方法,這個方法的功能就是為新增的DOM元素動態綁定事件。但對於效率來說,這個方法比較佔用資源。所以請盡量不要使用它。例如有這麼一段代碼:
複製代碼
1 13 14
this is first p
15 16複製代碼
運行後,你會發現新增的p元素,並沒用被綁定click事件。你可以改成.live(「click」)方式解決此問題,代碼如下:
複製代碼
1 $(function() { 2 $("p").live("click",function() { 3 // 改成live方式 4 alert($(this).text()); 5 }); 6 7 $("button").click(function() { 8 $("
this is second p
").appendTo("body"); 9 });10 })複製代碼
但我並不建議大家這麼做,我想用另一種方式去解決這個問題,代碼如下:
複製代碼
1 $(function() { 2 $("p").click(function() { 3 alert($(this).text()); 4 }); 5 6 $("button").click(function() { 7 $("
this is second p
").click(function() { 8 // 為新增的元素重新綁定一次 9 alert($(this).text());10 }).appendTo("body");11 });12 })複製代碼
雖然我把綁定事件重新寫了一次,代碼多了點,但這種方式的效率明顯高於live()方式,特別是在頻繁的DOM操作中,這點非常明顯。
80.請解釋.end()的用途。
在官方的API上是這樣描述end()方法的:「回到最近的一個"破壞性"操作之前。即,將匹配的元素列表變為前一次的狀態。」;看樣子好像是找到最後一次操作的元素的上一元素,在如下的例子中:html代碼:
複製代碼代碼如下:
1
測試內容1測試內容2jQuery代碼:
複製代碼代碼如下:
1 $("
新增內容
").appendTo("div").addClass("c1").end().addClass("c2");複製代碼代碼如下:
複製代碼
1
測試內容12新增內容
3 4 測試內容25新增內容
6複製代碼
這裡我就有一點不太明白了,怎麼只有第一個
標籤有兩個樣式,end()方法後返回的是什麼,在火狐里添加了監控,得到如下結果:1.$("
新增內容
").appendTo("div")返回的是:[p,p]對象數組,即新增後的兩個p標籤;2.$("新增內容
").appendTo("div").addClass("c1")返回的是:[p.c1,p.c1]對象數組,即添加了c1類樣式後的p對象數組;3.$("新增內容
").appendTo("div").addClass("c1").end()返回的是[p.c1],是第1個中的,在2操作中,最後「破壞」的是第2個
中的,所以他的前一次操作的對象是第1個
中的,返回的就是它;4.$("
新增內容
").appendTo("div").addClass("c1").end().addClass("c2")返回的仍然是第1個中的;現在算是有點明白了,關鍵是要搞清楚最後一次操作的元素的上一元素是什麼。
81.你如何給一個事件處理函數命名空間,為什麼要這樣做?
任何作為type參數的字元串都是合法的;如果一個字元串不是原生的JavaScript事件名,那麼這個事件處理函數會綁定到一個自定義事件上。這些自定義事件絕對不會由瀏覽器觸發,但可以通過使用.trigger()或者.triggerHandler()在其他代碼中手動觸發。如果type參數的字元串中包含一個點(.)字元,那麼這個事件就看做是有命名空間的了。這個點字元就用來分隔事件和他的命名空間。舉例來說,如果執行.bind("click.name",handler),那麼字元串中的click是事件類型,而字元串name就是命名空間。命名空間允許我們取消綁定或者觸發一些特定類型的事件,而不用觸發別的事件。參考unbind()來獲取更多信息。
jQuery的bind/unbind方法應該說使用很簡單,而且大多數時候可能並不會用到,取而代之的是直接用click/keydown之類的事件名風格的方法來做事件綁定操作。
但假設如下情況:需要在運行時根據用戶交互的結果進行不同click事件處理邏輯的綁定,因而理論上會無數次對某一個事件進行bind/unbind操作。但又希望unbind的時候只把自己綁上去的處理邏輯給釋放掉而不是所有其他地方有可能的額外的同一事件綁定邏輯。這時候如果直接用.click()/.bind("click")加上.unbind("click")來進行重複綁定的話,被unbind掉的將是所有綁定在元素上的click處理邏輯,潛在會影響到該元素其他第三方的行為。
當然如果在bind的時候是顯示定義了function變數的話,可以在unbind的時候提供function作為第二個參數來指定只unbind其中一個處理邏輯,但實際應用中很可能會碰到各種進行匿名函數綁定的情況。對於這種問題,jQuery的解決方案是使用事件綁定的命名空間。即在事件名稱後添加.something來區分自己這部分行為邏輯範圍。
比如用.bind("click.myCustomRoutine",function(){...});同樣是把匿名函數綁定到click事件(你可以用自己的命名空間多次綁定不同的行為方法上去),當unbind的時候用.unbind("click.myCustomRoutine")即可釋放所有綁定到.myCustomRoutine命名空間的click事件,而不會解除其他通過.bind("click")或另外的命名空間所綁定的事件行為。同時,使用命令空間還可以讓你一次性unbind所有此命名空間下的自定義事件綁定,通過.unbind(".myCustomRoutine")即可。要注意的是,jQuery的命名空間並不支持多級空間。
因為在jQuery裡面,如果用.unbind("click.myCustomRoutine.myCustomSubone"),解除的是命名空間分別為myCustomRoutine和myCustomSubone的兩個並列命名空間下的所有click事件,而不是"myCustomRoutine下的myCustomSubone子空間"。
82.請說出你可以傳遞給jQuery方法的四種不同值。
選擇器(字元串),HTML(字元串),回調函數,HTML元素,對象,數組,元素數組,jQuery對象等。
83.什麼是效果隊列?
jQuery中有個動畫隊列的機制。當我們對一個對象添加多次動畫效果時後添加的動作就會被放入這個動畫隊列中,等前面的動畫完成後再開始執行。可是用戶的操作往往都比動畫快,如果用戶對一個對象頻繁操作時不處理動畫隊列就會造成隊列堆積,影響到效果。jQuery中有stop這個方法可以停止當前執行的動畫,並且它有兩個布爾參數,默認值都為false。第一個參數為true時會清空動畫隊列,第二個參數為true時會瞬間完成掉當前動畫。所以,我們經常使用obj.stop(true,true)來停止動畫。但是這還不夠!正如jQuery文檔中的說法,即使第二個參數為true,也僅僅是把當前在執行的動畫跳轉到完成狀態。這時第一個參數如果也為true,後面的隊列就會被清空。如果一個效果需要多個動畫同時處理,我們僅完成其中的一個而把後面的隊列丟棄了,這就會出現意料之外的結果。
84.請指出.get(),[],eq()的區別。
eq:返回是一個jquery對象作用是將匹配的元素集合縮減為一個元素。這個元素在匹配元素集合中的位置變為0,而集合長度變成1。
get:是一個html對象數組作用是取得其中一個匹配的元素。num表示取得第幾個匹配的元素。
85.請指出.bind(),.live()和.delegate()的區別。
在操縱DOM的語境中,document是根節點。現在我們可以較容易地說明.bind()、.live()和.delegate()的不同之處了。
.bind()
1 $("a").bind("click", function() {alert("That tickles!")});
這是最簡單的綁定方法了。JQuery掃描文檔找出所有的$(『a』)元素,並把alert函數綁定到每個元素的click事件上。
.live()
1 $("a").live("click", function() {alert("That tickles!")});
JQuery把alert函數綁定到$(document)元素上,並使用』click』和』a』作為參數。任何時候只要有事件冒泡到document節點上,它就查看該事件是否是一個click事件,以及該事件的目標元素與』a』這一CSS選擇器是否匹配,如果都是的話,則執行函數。
live方法還可以被綁定到具體的元素(或context)而不是document上,像這樣:
1 $("a", $("#container")[0]).live(...);
.delegate()
1 $("#container").delegate("a", "click", function() {alert("That tickles!")});
JQuery掃描文檔查找$(『#container』),並使用click事件和』a』這一CSS選擇器作為參數把alert函數綁定到$(『#container』)上。任何時候只要有事件冒泡到$(『#container』)上,它就查看該事件是否是click事件,以及該事件的目標元素是否與CCS選擇器相匹配。如果兩種檢查的結果都為真的話,它就執行函數。
可以注意到,這一過程與.live()類似,但是其把處理程序綁定到具體的元素而非document這一根上。精明的JS』er們可能會做出這樣的結論,即$("a").live()==$(document).delegate("a"),是這樣嗎?嗯,不,不完全是。
為什麼.delegate()要比.live()好用?
基於幾個原因,人們通常更願意選用jQuery的delegate方法而不是live方法。考慮下面的例子:
1 $("a").live("click", function(){blah()}); // 或者2 $(document).delegate("a", "click", function(){blah()});
速度
後者實際上要快過前者,因為前者首先要掃描整個的文檔查找所有的$(『a』)元素,把它們存成jQuery對象。儘管live函數僅需要把』a』作為串參數傳遞以用做之後的判斷,但是$()函數並未知道被鏈接的方法將會是.live()。而另一方面,delegate方法僅需要查找並存儲$(document)元素。
一種尋求避開這一問題的方法是調用在$(document).ready()之外綁定的live,這樣它就會立即執行。在這種方式下,其會在DOM獲得填充之前運行,因此就不會查找元素或是創建jQuery對象了。
靈活性和鏈能力
live函數也挺令人費解的。想想看,它被鏈到$(『a』)對象集上,但其實際上是在$(document)對象上發生作用。由於這個原因,它能夠試圖以一種嚇死人的方式來把方法鏈到自身上。實際上,我想說的是,以$.live(『a』,…)這一形式作為一種全局性的jQuery方法,live方法會更具意義一些。
僅支持CSS選擇器
最後一點,live方法有一個非常大的缺點,那就是它僅能針對直接的CSS選擇器做操作,這使得它變得非常的不靈活。
為什麼選擇.live()或.delegate()而不是.bind()?
畢竟,bind看起來似乎更加的明確和直接,難道不是嗎?嗯,有兩個原因讓我們更願意選擇delegate或live而不是bind:
為了把處理程序附加到可能還未存在於DOM中的DOM元素之上。因為bind是直接把處理程序綁定到各個元素上,它不能把處理程序綁定到還未存在於頁面中的元素之上。
如果你運行了$(『a』).bind(…),而後新的鏈接經由AJAX加入到了頁面中,則你的bind處理程序對於這些新加入的鏈接來說是無效的。而另一方面live和delegate則是被綁定到另一個祖先節點上,因此其對於任何目前或是將來存在於該祖先元素之內的元素都是有效的。
或者為了把處理程序附加到單個元素上或是一小組元素之上,監聽後代元素上的事件而不是循環遍歷並把同一個函數逐個附加到DOM中的100個元素上。把處理程序附加到一個(或是一小組)祖先元素上而不是直接把處理程序附加到頁面中的所有元素上,這種做法帶來了性能上的好處。
停止傳播
最後一個我想做的提醒與事件傳播有關。通常情況下,我們可以通過使用這樣的事件方法來終止處理函數的執行:
1 $("a").bind("click", function(e) {2 e.preventDefault();3 // 或者 e.stopPropagation();4 });
不過,當我們使用live或是delegate方法的時候,處理函數實際上並沒有在運行,需要等到事件冒泡到處理程序實際綁定的元素上時函數才會運行。而到此時為止,我們的其他的來自.bind()的處理函數早已運行了。
86.請指出$和$.fn的區別,或者說出$.fn的用途。
Jquery為開發插件提供了兩個方法,分別是:
1 $.extend(obj);2 $.fn.extend(obj);
1.那麼這兩個分別是什麼意思?
$.extend(obj);是為了擴展jquery本身,為類添加新的方法。
$.fn.extend(obj);給JQUERY對象添加方法。
2.$.fn中的fn是什麼意思,其實是prototype,即$.fn=$.prototype;
具體用法請看下面的例子:
複製代碼
1 $.extend({2 3 add:function(a, b) {4 return a+b;5 }6 })7 8 $.add(5,8); // return 13
複製代碼
注意沒有,這邊的調用直接調用,前面不用任何對象。直接$.+方法名
$.fn.extend(obj);對prototype進行擴展,為jquery類添加成員函數,jquery類的實例可以使用這個成員函數。
複製代碼
1 $.fn.extend({ 2 3 clickwhile:function(){ 4 5 $(this).click(function(){ 6 alert($(this).val()) 7 }) 8 } 9 })10 11 $("input").clickwhile(); // 當點擊輸入框會彈出該對象的Value值
複製代碼
注意調用時候前面是有對象的。即$("input")這麼個東西。
87.請寫出一個函數實現N!的計算。N取很大的值時,該怎麼辦?
使用循環、遞歸都能寫出函數。
當N取值很大時,應該考慮把數值轉化為字元串再進行運算。大數乘法再轉化為大數加法運算,其具體演算法應該有不少C語言實現,可以參考一下。
88.modulo(12,5) //2 ;問題:實現滿足上述結果的modulo函數。
89."i"m a lasagna hog".split("").reverse().join("");問題:上面的語句的返回值是什麼?
答案:"goh angasal a m"i";
90.(window.foo||(window.foo="bar"));問題:window.foo的值是什麼?
答案:"bar"只有window.foo為假時的才是上面答案,否則就是它本身的值。
var foo="Hello";(function(){var bar="World";alert(foo+bar);})();alert(foo+bar);
91.問題:上面兩個alert的結果是什麼?
答案:"Hello World"和ReferenceError:bar is not defined
92.var foo=[];foo.push(1);foo.push(2);問題:foo.length的值是什麼?
答案:2
喜歡編程的寶寶可以加大牛微信 tang365666,備註數字2 ,即可免費獲取更多編程學習視頻,以及面試題,一定記得備註數字2推薦閱讀:
※人為什麼要努力?這是我見過的最好答案
※《朝花夕拾》填空題和答案
※金曲 | 答案在風中飄蕩
※馬年謎語大全及答案/謎底,馬年燈謎,有關馬年的謎語