前端工作面试问题(下)
?
?續(xù) “前端工作面試問(wèn)題(上)”
?
JS相關(guān)問(wèn)題:
- 解釋下事件代理。
? 在傳統(tǒng)的事件處理中,你按照需要為每一個(gè)元素添加或者是刪除事件處理器。然而,事件處理器將有可能導(dǎo)致內(nèi)存泄露或者是性能下降——你用得越多這種風(fēng)險(xiǎn)就越大。JavaScript事件代理則是一種簡(jiǎn)單的技巧,通過(guò)它你可以把事件處理器添加到一個(gè)父級(jí)元素上,這樣就避免了把事件處理器添加到多個(gè)子級(jí)元素上。
事件代理用到了兩個(gè)在JavaSciprt事件中常被忽略的特性:事件冒泡以及目標(biāo)元素。當(dāng)一個(gè)元素上的事件被觸發(fā)的時(shí)候,比如說(shuō)鼠標(biāo)點(diǎn)擊了一個(gè)按鈕,同樣的事件將會(huì)在那個(gè)元素的所有祖先元素中被觸發(fā)。這一過(guò)程被稱(chēng)為事件冒泡;這個(gè)事件從原始元素開(kāi)始一直冒泡到DOM樹(shù)的最上層。任何一個(gè)事件的目標(biāo)元素都是最開(kāi)始的那個(gè)元素,在我們的這個(gè)例子中也就是按鈕,并且它在我們的元素對(duì)象中以屬性的形式出現(xiàn)。使用事件代理,我們可以把事件處理器添加到一個(gè)元素上,等待一個(gè)事件從它的子級(jí)元素里冒泡上來(lái),并且可以得知這個(gè)事件是從哪個(gè)元素開(kāi)始的。
1 // 獲取父節(jié)點(diǎn),并為它添加一個(gè)click事件 2 document.getElementById("parent-list").addEventListener("click",function(e) { 3 // 檢查事件源e.targe是否為L(zhǎng)i 4 if(e.target && e.target.nodeName.toUpperCase == "LI") { 5 // 真正的處理過(guò)程在這里 6 console.log("List item ",e.target.id.replace("post-")," was clicked!"); 7 } 8 });這樣做的好處:那些需要?jiǎng)?chuàng)建的以及駐留在內(nèi)存中的事件處理器少了,這樣我們就提高了性能,并降低了崩潰的風(fēng)險(xiǎn)。在DOM更新后無(wú)須重新綁定事件處理器了。如果你的頁(yè)面是動(dòng)態(tài)生成的,比如說(shuō)通過(guò)Ajax,你不再需要在元素被載入或者卸載的時(shí)候來(lái)添加或者刪除事件處理器了。?
?
- 解釋下 JavaScript 中?this?是如何工作的。
? this 永遠(yuǎn)指向函數(shù)運(yùn)行時(shí)所在的對(duì)象,而不是函數(shù)被創(chuàng)建時(shí)所在的對(duì)象。匿名函數(shù)或不處于任何對(duì)象中的函數(shù)指向 window 。函數(shù)中的this的值取決于函數(shù)調(diào)用的模式:
方法調(diào)用模式
當(dāng)函數(shù)被保存為對(duì)象的一個(gè)屬性時(shí),成該函數(shù)為該對(duì)象的方法。函數(shù)中this的值為該對(duì)象。
var foo = {name: 'fooname',getName: function (){return this.name } } foo.getName(); // this => foo函數(shù)調(diào)用模式
當(dāng)函數(shù)并不是對(duì)象的屬性。函數(shù)中this的值為全局對(duì)象
note:某個(gè)方法中的內(nèi)部函數(shù)中的this的值也是全局對(duì)象,而非外部函數(shù)的this
構(gòu)造器調(diào)用模式
即使用new調(diào)用的函數(shù),則其中this將會(huì)被綁定到那個(gè)新構(gòu)造的對(duì)象。構(gòu)造器調(diào)用將一個(gè)全新的對(duì)象作為this變量的值,并隱式返回這個(gè)新對(duì)象作為調(diào)用結(jié)果。
如果你不是使用new來(lái)調(diào)用構(gòu)造器,那其實(shí)你就是在使用一個(gè)實(shí)函數(shù)。因此this就不會(huì)是你預(yù)期的值。在Sloppy模式中,this?指向的就是window?而你將會(huì)創(chuàng)建全局變量。不過(guò)如果使用的是strict模式,那你還是會(huì)得到警告(this===undefined)。
使用apply或call調(diào)用模式
該模式調(diào)用時(shí),函數(shù)中this被綁定到apply或call方法調(diào)用時(shí)接受的第一個(gè)參數(shù)。
在方法中this?的用法更傾向于傳統(tǒng)的面向?qū)ο笳Z(yǔ)言:this?指向的接收方,也就是包含有這個(gè)方法的對(duì)象。
?
?箭頭函數(shù)就是沒(méi)有自己的this?的函數(shù)。在這樣的函數(shù)中你可以隨便使用this,也不用擔(dān)心有沒(méi)有隱式的存在。下面提供了三種思路來(lái)解決這個(gè)問(wèn)題:
1)that=this,將this?賦值到一個(gè)變量上,這樣就把this?顯性地表現(xiàn)出來(lái)了(除了that,self?也是個(gè)很常見(jiàn)的用于存放this的變量名),之后就使用那個(gè)變量。
2)bind()。使用bind()來(lái)創(chuàng)建一個(gè)函數(shù),這個(gè)函數(shù)的this?總是存有你想要傳遞的值(下面這個(gè)例子中,方法的this):
this.friends.forEach(function (friend) {console.log(this.name+' knows '+friend);}.bind(this));3)用forEach的第二個(gè)參數(shù)。forEach的第二個(gè)參數(shù)會(huì)被傳入回調(diào)函數(shù)中,作為回調(diào)函數(shù)的this?來(lái)使用。
this.friends.forEach(function (friend) {console.log(this.name+' knows '+friend);}, this);?
- 解釋下原型繼承的原理。
? 在javascript中,類(lèi)(定義類(lèi)是模塊開(kāi)發(fā)和重用代碼的有效方式之一)的實(shí)現(xiàn)是基于其原型繼承機(jī)制的。如果兩個(gè)實(shí)例都從一個(gè)原型對(duì)象上繼承了屬性,我們說(shuō)它們是同一個(gè)類(lèi)的實(shí)例。如果兩個(gè)對(duì)象繼承自同一個(gè)原型,往往意味著(但不是絕對(duì))它們是由同一個(gè)構(gòu)造函數(shù)創(chuàng)建并初始化的。
1)類(lèi)和對(duì)象
在javascript中,類(lèi)的所有實(shí)例對(duì)象都從一個(gè)類(lèi)型對(duì)象上繼承屬性。因此,原型對(duì)象是類(lèi)的核心。
2)類(lèi)和構(gòu)造函數(shù)
構(gòu)造函數(shù)是用來(lái)初始化和創(chuàng)建對(duì)象的。使用new關(guān)鍵字來(lái)調(diào)用構(gòu)造函數(shù),創(chuàng)建一個(gè)新對(duì)象。調(diào)用構(gòu)造函數(shù)的一個(gè)重要特征是,構(gòu)造函數(shù)的prototype屬性被用做新對(duì)象的原型(var ?object.prototype = new Object())。這意味著通過(guò)同一個(gè)構(gòu)造函數(shù)創(chuàng)建的對(duì)象都是繼承自一個(gè)相同的對(duì)象,因此它們都是一個(gè)類(lèi)的成員。
javascript中的類(lèi)牽扯三種不同的對(duì)象,三種對(duì)象的屬性的行為和下面三種類(lèi)成員非常相似:
? ??構(gòu)造函數(shù)對(duì)象
? ? ? ? ?Js所有的函數(shù)都有一個(gè)prototype屬性,這個(gè)屬性引用了一個(gè)對(duì)象,即原型對(duì)象,也簡(jiǎn)稱(chēng)原型。這個(gè)函數(shù)包括構(gòu)造函數(shù)和普通函數(shù),判斷一個(gè)函數(shù)F是否是Object對(duì)象的實(shí)例:F.prototype instanceof Object //->true
? ??原型對(duì)象屬性被類(lèi)的所有實(shí)例所繼承,如果原型對(duì)象的屬性值是函數(shù)的話,這個(gè)函數(shù)就作為類(lèi)的實(shí)例方法來(lái)調(diào)用
? ??實(shí)例對(duì)象,類(lèi)的每個(gè)實(shí)例對(duì)象都是一個(gè)獨(dú)立的對(duì)象,直接 給這個(gè)實(shí)例定義的屬性是不會(huì)為所有實(shí)例對(duì)象鎖共享的。定義在實(shí)例上的非函數(shù)屬性,實(shí)際上是實(shí)例的字段。
在javascript中定義類(lèi)的步奏可以縮減為一個(gè)分三步的算法。第一步,先定義一個(gè)構(gòu)造函數(shù),并設(shè)置初始化新對(duì)象的實(shí)例屬性。第二步,給構(gòu)造函數(shù)的prototype對(duì)象定義實(shí)例的方法。第三步:給構(gòu)造函數(shù)定義類(lèi)字段和類(lèi)屬性。
? (面試官可能會(huì)問(wèn)到“javascript繼承和其他語(yǔ)言繼承的區(qū)別”,可以從基于對(duì)象和訪問(wèn)修飾符分析)
javascript中基于原型的繼承機(jī)制是動(dòng)態(tài)的:對(duì)象從其原型繼承屬性,如果創(chuàng)建對(duì)象之后原型的屬性發(fā)生改變,也會(huì)影響到繼承這個(gè)原型的所有實(shí)例對(duì)象。這意味著我們可以通過(guò)給原型對(duì)象添加新的方法來(lái)擴(kuò)充javascript類(lèi)。
?
- 你是如何測(cè)試 JavaScript 代碼的?
? 1)使用瀏覽器自帶的控制臺(tái)調(diào)試,詳細(xì)可參照“使用console進(jìn)行 性能測(cè)試 和 計(jì)算代碼運(yùn)行時(shí)間”
2)chrome的單步調(diào)試功能
JavaScript?斷點(diǎn)設(shè)置和調(diào)試功能和java編輯工具的調(diào)試方法類(lèi)似
Sources Panel 的左邊是內(nèi)容源,包括頁(yè)面中的各種資源;中間主區(qū)域用于展示左邊資源文件的內(nèi)容;右邊是調(diào)試功能區(qū),最上面的一排按鈕分別是暫停/繼續(xù)、單步執(zhí)行、單步跳入、單步跳出、禁用/啟用所有斷點(diǎn)。鼠標(biāo)點(diǎn)擊文件的行號(hào)就可以設(shè)置和刪除斷點(diǎn)。添加的每個(gè)斷點(diǎn)都會(huì)出現(xiàn)在右側(cè)調(diào)試區(qū)的 Breakpoints 列表中,點(diǎn)擊列表中斷點(diǎn)就會(huì)定位到內(nèi)容區(qū)的斷點(diǎn)上。Call Stack 列表的下方是 Scope Variables 列表,在這里可以查看此時(shí)局部變量和全局變量的值。
- *AMD vs. CommonJS?
CommonJs?是服務(wù)器端模塊的規(guī)范,Node.js采用了這個(gè)規(guī)范。根據(jù)CommonJS規(guī)范,一個(gè)單獨(dú)的文件就是一個(gè)模塊。加載模塊使用require方法,該方法讀取一個(gè)文件并執(zhí)行,最后返回文件內(nèi)部的exports對(duì)象。
//require方法默認(rèn)讀取js文件,所以可以省略js后綴 var test = require('./boobar').foobar;//test為boobar文件中的foobar對(duì)象的實(shí)例 test.bar(); //調(diào)用方法bar()CommonJS 加載模塊是同步的,所以只有加載完成才能執(zhí)行后面的操作。像Node.js主要用于服務(wù)器的編程,加載的模塊文件一般都已經(jīng)存在本地硬盤(pán),所以加載起來(lái)比較快,不用考慮異步加載的方式,所以CommonJS規(guī)范比較適用。?
AMD ?CMD?采用異步模式,方便瀏覽器環(huán)境要從服務(wù)器加載模塊。AMD 是 RequireJS 在推廣過(guò)程中對(duì)模塊定義的規(guī)范化產(chǎn)出。AMD異步加載模塊。它的模塊支持對(duì)象、函數(shù)、構(gòu)造器、字符串、JSON等各種類(lèi)型的模塊。適用AMD規(guī)范適用define方法定義模塊。
//通過(guò)數(shù)組引入依賴(lài) ,回調(diào)函數(shù)通過(guò)形參傳入依賴(lài) define(['someModule1', ‘someModule2’], function (someModule1, someModule2) {function foo () {/// something someModule1.test();}return {foo: foo} });本題內(nèi)容整理自:http://my.oschina.net/felumanman/blog/263330?p=1
?
- 什么是哈希表?
? 類(lèi)比數(shù)組,數(shù)組是編程上的哈希表,哈希表是一種數(shù)據(jù)結(jié)構(gòu),關(guān)鍵點(diǎn)就是用一個(gè)key值來(lái)取對(duì)應(yīng)數(shù)據(jù),就像數(shù)組的下標(biāo)。
? https://github.com/floraLam/dailyLearn/blob/master/dataStructure/31哈希表.html
?
- 解釋下為什么接下來(lái)這段代碼不是 IIFE(立即調(diào)用的函數(shù)表達(dá)式):function foo(){ }();.
? 而函數(shù)定義(語(yǔ)句以function關(guān)鍵字開(kāi)始)是不能被立即執(zhí)行的,這無(wú)疑會(huì)導(dǎo)致語(yǔ)法的錯(cuò)誤(SyntaxError)。當(dāng)函數(shù)定義代碼段包裹在括號(hào)內(nèi),使解析器可以將之識(shí)別為函數(shù)表達(dá)式,然后調(diào)用。IIFE:(function foo(){})()
之前面試,遇到問(wèn)題,區(qū)分(function(){})();和(function(){}());其實(shí)兩者實(shí)現(xiàn)效果一樣。函數(shù)字面量:首先聲明一個(gè)函數(shù)對(duì)象,然后執(zhí)行它。(function () { alert(1); })(); 優(yōu)先表達(dá)式:由于Javascript執(zhí)行表達(dá)式是從圓括號(hào)里面到外面,所以可以用圓括號(hào)強(qiáng)制執(zhí)行聲明的函數(shù)。(function () { alert(2); }());
?
- 描述以下變量的區(qū)別:null,undefined?或?undeclared?
? ?'undefined'是未定義,在變量沒(méi)有賦值的時(shí)候的值即為undefined。"缺少值",就是此處應(yīng)該有一個(gè)值,但是還沒(méi)有定義。
'underclared'即為被污染的命名,訪問(wèn)沒(méi)有被聲明的變量,會(huì)拋出異常,終止執(zhí)行。
'null'是一個(gè)空的對(duì)象引用。"沒(méi)有對(duì)象",即該處不應(yīng)該有值
undefined和null在if語(yǔ)句中,都會(huì)被自動(dòng)轉(zhuǎn)為false,相等運(yùn)算符甚至直接報(bào)告兩者相等。typeof undefined會(huì)返回undefined ,而typeof null?總返回?object(typeof有六種可能:"number"、"string"、"boolean"、"object"、"function"、"undefined")
false == undefined;//false false == null;//false null == undefined;//true?
- 什么是閉包,如何使用它,為什么要使用它?
當(dāng)某個(gè)函數(shù)調(diào)用時(shí)會(huì)創(chuàng)建一個(gè)執(zhí)行環(huán)境以及作用域鏈,然后根據(jù)arguments和其它命名參數(shù)初始化形成活動(dòng)對(duì)象。在外部函數(shù)調(diào)用結(jié)束后,其執(zhí)行環(huán)境與作用域鏈被銷(xiāo)毀,但是其活動(dòng)對(duì)象保存在了閉包之中,最后在閉包函數(shù)調(diào)用結(jié)束后才銷(xiāo)毀。簡(jiǎn)單的說(shuō),閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。
由于在Javascript語(yǔ)言中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量,因此可以把閉包簡(jiǎn)單理解成“定義在一個(gè)函數(shù)內(nèi)部的函數(shù)”。
注意:
1)由于閉包會(huì)使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大,所以不能濫用閉包,否則會(huì)造成網(wǎng)頁(yè)的性能問(wèn)題,在IE中可能導(dǎo)致內(nèi)存泄露。解決方法是,在退出函數(shù)之前,將不使用的局部變量全部刪除。
2)閉包會(huì)在父函數(shù)外部,改變父函數(shù)內(nèi)部變量的值。所以,如果你把父函數(shù)當(dāng)作對(duì)象(object)使用,把閉包當(dāng)作它的公用方法(Public Method),把內(nèi)部變量當(dāng)作它的私有屬性(private value),這時(shí)一定要小心,不要隨便改變父函數(shù)內(nèi)部變量的值。
閉包可以用在許多地方。它的最大用處有兩個(gè),一個(gè)是前面提到的可以讀取函數(shù)內(nèi)部的變量,另一個(gè)就是讓這些變量的值始終保持在內(nèi)存中。
用法
//第1種寫(xiě)法 :這種寫(xiě)法沒(méi)什么特別的,只是給函數(shù)添加一些屬性。 function Circle(r) { this.r = r; } Circle.PI = 3.14159; Circle.prototype.area = function() { return Circle.PI * this.r * this.r; } var c = new Circle(1.0); alert(c.area()); //第2種寫(xiě)法 :這種寫(xiě)法是聲明一個(gè)變量,將一個(gè)函數(shù)當(dāng)作值賦給變量。 var Circle = function() { var obj = new Object(); obj.PI = 3.14159; obj.area = function( r ) { return this.PI * r * r; } return obj; } var c = new Circle(); alert( c.area( 1.0 ) ); //第3種寫(xiě)法 :這種方法最好理解,就是new 一個(gè)對(duì)象,然后給對(duì)象添加屬性和方法。 var Circle = new Object(); Circle.PI = 3.14159; Circle.Area = function( r ) { return this.PI * r * r; } alert( Circle.Area( 1.0 ) ); //第4種寫(xiě)法 :這種方法使用較多,也最為方便。var obj = {}就是聲明一個(gè)空的對(duì)象。 var Circle={ "PI":3.14159, "area":function(r){ return this.PI * r * r; } }; alert( Circle.area(1.0) );閉包的用途????
事實(shí)上,通過(guò)使用閉包,我們可以做很多事情。比如模擬面向?qū)ο蟮拇a風(fēng)格;更優(yōu)雅,更簡(jiǎn)潔的表達(dá)出代碼;在某些方面提升代碼的執(zhí)行效率。
1)匿名自執(zhí)行函數(shù)
全局對(duì)象過(guò)于龐大,影響訪問(wèn)速度(因?yàn)樽兞康娜≈凳切枰獜脑玩溕媳闅v的)。
除了每次使用變量都是用var關(guān)鍵字外,我們?cè)趯?shí)際情況下經(jīng)常遇到這樣一種情況,即有的函數(shù)只需要執(zhí)行一次,其內(nèi)部變量無(wú)需維護(hù),我們可以使用閉包。
我們創(chuàng)建了一個(gè)匿名的函數(shù),并立即執(zhí)行它,由于外部無(wú)法引用它內(nèi)部的變量,因此在函數(shù)執(zhí)行完后會(huì)立刻釋放資源,關(guān)鍵是不污染全局對(duì)象。
2)結(jié)果緩存
我們開(kāi)發(fā)中會(huì)碰到很多情況,設(shè)想我們有一個(gè)處理過(guò)程很耗時(shí)的函數(shù)對(duì)象,每次調(diào)用都會(huì)花費(fèi)很長(zhǎng)時(shí)間,那么我們就需要將計(jì)算出來(lái)的值存儲(chǔ)起來(lái),當(dāng)調(diào)用這個(gè)函數(shù)的時(shí)候,首先在緩存中查找,如果找不到,則進(jìn)行計(jì)算,然后更新緩存并返回值,如果找到了,直接返回查找到的值即可。閉包正是可以做到這一點(diǎn),因?yàn)樗粫?huì)釋放外部的引用,從而函數(shù)內(nèi)部的值可以得以保留。
3)封裝
4)實(shí)現(xiàn)類(lèi)和繼承
- 你喜歡的使用閉包的模式是什么?兩種模式用在不同場(chǎng)合。參見(jiàn)jQuery源碼,立即調(diào)用模式,把$的jQuery源碼放在了全局作用域下。返回函數(shù)類(lèi)型的,制作一個(gè)隨時(shí)可以使用的函數(shù)。
?
- 請(qǐng)舉出一個(gè)匿名函數(shù)的典型用例?
? $.("input").each(function(e){this.val('OK')});
- ------------------------------解釋 “JavaScript 模塊模式” 以及你在何時(shí)使用它。
? 我們?cè)谧鰎adf庫(kù)的時(shí)候,把所有的函數(shù)寫(xiě)在var function = ?radf(){}里,為的是在全局作用域下,只有一個(gè)radf對(duì)象,所有的屬性和方法全在radf命名空間下面。這樣就是一個(gè)無(wú)污染的環(huán)境。
- 如果有提到無(wú)污染的命名空間,可以考慮加分。
- 如果你的模塊沒(méi)有自己的命名空間會(huì)怎么樣?
- 與其它庫(kù)或內(nèi)容造成沖突。
- 如果有提到無(wú)污染的命名空間,可以考慮加分。
- 如果你的模塊沒(méi)有自己的命名空間會(huì)怎么樣?
?
- 你是如何組織自己的代碼?是使用模塊模式,還是使用經(jīng)典繼承的方法?
? 在模塊模式中使用繼承。例如我們的庫(kù)中有pannel布局型組件和data型組件,其余都依照這兩個(gè)基本組件繼承而來(lái)。
具體可以參考 ExtJS4 便捷三層開(kāi)發(fā)模式?
?
- 請(qǐng)指出 JavaScript 宿主對(duì)象和原生對(duì)象的區(qū)別?
原生對(duì)象,獨(dú)立于宿主環(huán)境的 ECMAScript 實(shí)現(xiàn)提供的對(duì)象。為array obj regexp date function等可以new實(shí)例化的對(duì)象。
內(nèi)置對(duì)象為gload Math 等,開(kāi)發(fā)者不必明確實(shí)例化內(nèi)置對(duì)象,它已被實(shí)例化了。類(lèi)似于isNaN()、parseInt()和parseFloat()方法等,看起來(lái)都是函數(shù),而實(shí)際上,它們都是Global對(duì)象的方法。具體可以參考?JavaScript 全局對(duì)象
宿主對(duì)象。即由 ECMAScript 實(shí)現(xiàn)的宿主環(huán)境(操作系統(tǒng)和瀏覽器)提供的對(duì)象。所有的BOM和DOM對(duì)象都是宿主對(duì)象。因?yàn)槠鋵?duì)于不同的“宿主”環(huán)境所展示的內(nèi)容不同(這就是兼容性和特性檢測(cè)的緣由)。ECMAScript官方未定義的對(duì)象都屬于宿主對(duì)象。
?
- 指出下列代碼的區(qū)別:
function Person(){}
var person = Person();
var person = new Person();
1、定義一個(gè)函數(shù)為Person()2、定義一個(gè)匿名函數(shù)指向person
3、實(shí)例化一個(gè)person、原型來(lái)自于函數(shù)Person
- .call?和?.apply?的區(qū)別是什么??
call和apply都是調(diào)用一個(gè)對(duì)象的一個(gè)方法,以另一個(gè)對(duì)象替換當(dāng)前對(duì)象。它們都屬于Function.prototype的一個(gè)方法,所以每個(gè)function實(shí)例都有call和apply屬性。這兩個(gè)方法可以用來(lái)代替另一個(gè)對(duì)象調(diào)用一個(gè)方法,可將一個(gè)函數(shù)的對(duì)象上下文從初始的上下文改變?yōu)橛?thisObj 指定的新對(duì)象。
區(qū)別在于,兩者傳遞的參數(shù)不同,雖然函數(shù)第一個(gè)參數(shù)都是要傳入給當(dāng)前對(duì)象的對(duì)象,但是,apply的第二個(gè)參數(shù)是一個(gè)參數(shù)數(shù)組,將多個(gè)參數(shù)組合成為一個(gè)數(shù)組傳入;而call第二個(gè)參數(shù)則是直接的參數(shù)列表。
?
- 請(qǐng)解釋?Function.prototype.bind?
?Function.prototype.bind()其實(shí)就是函數(shù)綁定。函數(shù)的接收者取決于他是如何被調(diào)用,可以通過(guò)調(diào)用.bind()給函數(shù)綁定作用域上下文,即函數(shù)的接收者。
var foo = { x: 3} var bar = function(){console.log(this.x);}bar(); // undefined var boundFunc = bar.bind(foo);//隱式看作是在foo作用域里調(diào)用bar方法 boundFunc(); // 3我們創(chuàng)建了一個(gè)新的函數(shù),當(dāng)它被執(zhí)行的時(shí)候,它的 this 會(huì)被設(shè)置成 foo —— 而不是像我們調(diào)用 bar() 時(shí)的全局作用域。
對(duì)于改變上下文作用域(具體可以查看上題“解釋下 JavaScript 中?this?是如何工作的”),可以將this設(shè)置到一個(gè)變量上,這樣改變了上下文之后繼續(xù)引用到它。同時(shí)可以選擇 self, _this 或者 context 作為變量名稱(chēng)(也有人使用 that)。
.bind()創(chuàng)建了一個(gè)函數(shù),當(dāng)這個(gè)函數(shù)在被調(diào)用的時(shí)候,它的 this 關(guān)鍵詞會(huì)被設(shè)置成被傳入的值(這里指調(diào)用bind()時(shí)傳入的參數(shù))也就是我們傳入想要的上下文。
簡(jiǎn)單的用法:
關(guān)于 Function.prototype.bind() 內(nèi)部,這里有個(gè)非常簡(jiǎn)單的例子:
Function.prototype.bind = function (scope) {var fn = this;return function () {return fn.apply(scope);//使用call效果一樣}; }?? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
- 你何時(shí)優(yōu)化自己的代碼?
優(yōu)化代碼是在不改變程序行為的基礎(chǔ)上進(jìn)行小的改動(dòng),是代碼逐漸改善的過(guò)程。移除長(zhǎng)期累積下來(lái)的爛碼,以得到更清晰和更容易維護(hù),除錯(cuò)以及添加新功能的代碼,這做法不能單純只出現(xiàn)在編碼的后期,甚至是你意識(shí)到你的代碼已經(jīng)無(wú)從再下手非重寫(xiě)不可的時(shí)候,而是從開(kāi)始開(kāi)發(fā)起,逐漸積累,逐漸修改。以前因?yàn)槿粘>幋a的隨意性,導(dǎo)致問(wèn)題日益積累,逐步擴(kuò)散,最后只能推倒重來(lái)。如果時(shí)間經(jīng)受不起推倒重來(lái),你別無(wú)選擇,唯一實(shí)現(xiàn)的選擇就是重構(gòu)。整體的優(yōu)化設(shè)計(jì)雖然惹人注目令人難忘,但沒(méi)有平日的積累,何以收獲龐大的成就?你的目標(biāo)應(yīng)該是讓代碼每天都有新變化。堅(jiān)持幾個(gè)月,我相信我們都能擁有驕傲地,清晰代碼。
?
- 在什么時(shí)候你會(huì)使用?document.write()?
記住,在載入頁(yè)面后,瀏覽器輸出流自動(dòng)關(guān)閉。在此之后,任何一個(gè)對(duì)當(dāng)前頁(yè)面進(jìn)行操作的document.write()方法將打開(kāi)—個(gè)新的輸出流,它將清除當(dāng)前頁(yè)面內(nèi)容(包括源文檔的任何變量或值)。因此,假如希望用腳本生成的HTML替換當(dāng)前頁(yè)面,就必須把HTML內(nèi)容連接起來(lái)賦給一個(gè)變量,使用一個(gè)document.write()方法完成寫(xiě)操作。不必清除文檔并打開(kāi)一個(gè)新數(shù)據(jù)流,一個(gè)document.write()調(diào)用就可完成所有的操作。
關(guān)于document.write()方法還有一點(diǎn)要說(shuō)明的是它的相關(guān)方法document.close()。腳本向窗口(不管是本窗口或其他窗口)寫(xiě)完內(nèi)容后,必須關(guān)閉輸出流。在延時(shí)腳本的最后一個(gè)document.write()方法后面,必須確保含有document.close()方法,不這樣做就不能顯示圖像和表單。并且,任何后面調(diào)用的document.write()方法只會(huì)把內(nèi)容追加到頁(yè)面后,而不會(huì)清除現(xiàn)有內(nèi)容來(lái)寫(xiě)入新值。為了演示document.write()方法,我們提供了同一個(gè)應(yīng)用程序的兩個(gè)版本。
- 大多數(shù)生成的廣告代碼依舊使用?document.write(),雖然這種用法會(huì)讓人很不爽。
?
- 請(qǐng)指出瀏覽器特性檢測(cè),特性推斷和瀏覽器 UA 字符串嗅探的區(qū)別?
檢測(cè)瀏覽器的特殊名稱(chēng)和版本(用戶(hù)代理檢測(cè))即瀏覽器UA字符串嗅探。瀏覽器嗅探技術(shù)可以快捷的將代碼進(jìn)行分支,以便針對(duì)不同的瀏覽器應(yīng)用不同的指令;針對(duì)特定瀏覽器的特定版本,超出范圍之外都是不可靠的
if (navigator.userAgent.indexOf("MSIE 7") > -1){
//do something
}
檢測(cè)瀏覽器的特性(特性檢測(cè))
if(document.all){?
//do something?
}?
另外IE獨(dú)有children,parentElement,innerText,outerText,outerHTML,FF沒(méi)有;
直接進(jìn)行特性檢測(cè)是個(gè)很好的方法,并且大部分情況下能滿(mǎn)足需求。一般只要在檢測(cè)前知道這個(gè)特性是否被實(shí)現(xiàn)即可,而不會(huì)去考慮它們之間的關(guān)系。?
另外,針對(duì)CSS3中新特性@font-face、border-radius、 border-image、box-shadow、rgba() 等,HTML5的特性——比如audio、video、本地儲(chǔ)存、和新的 <input>標(biāo)簽的類(lèi)型和屬性等,必要時(shí)要進(jìn)行優(yōu)雅降級(jí)。
?
?
?
- 請(qǐng)盡可能詳盡的解釋 AJAX 的工作原理。
? 非ajax是把要提交的內(nèi)容放在submit里面,瀏覽器刷新提交數(shù)據(jù)。ajax即異步數(shù)據(jù)刷新,將要提交的數(shù)據(jù)與服務(wù)器接口交換數(shù)據(jù),將得到的數(shù)據(jù)返回用于重組dom元素,以及改變一些頁(yè)面效果。
Ajax的原理簡(jiǎn)單來(lái)說(shuō)通過(guò)XmlHttpRequest對(duì)象來(lái)向服務(wù)器發(fā)異步請(qǐng)求,從服務(wù)器獲得數(shù)據(jù),然后用javascript來(lái)操作DOM而更新頁(yè)面。這其中最關(guān)鍵的一步就是從服務(wù)器獲得請(qǐng)求數(shù)據(jù)。
?XMLHttpRequest是ajax的核心機(jī)制,它是在IE5中首先引入的,是一種支持異步請(qǐng)求的技術(shù)。簡(jiǎn)單的說(shuō),也就是javascript可以及時(shí)向服務(wù)器提出請(qǐng)求和處理響應(yīng),而不阻塞用戶(hù)。達(dá)到無(wú)刷新的效果。
?? 簡(jiǎn)單地說(shuō),我們可以把服務(wù)器端看成一個(gè)數(shù)據(jù)接口,它返回的是一個(gè)純文本流,當(dāng)然,這個(gè)文本流可以是XML格式,可以是Html,可以是Javascript代碼,也可以只是一個(gè)字符串。這時(shí)候,XMLHttpRequest向服務(wù)器端請(qǐng)求這個(gè)頁(yè)面,服務(wù)器端將文本的結(jié)果寫(xiě)入頁(yè)面,這和普通的web開(kāi)發(fā)流程是一樣的,不同的是,客戶(hù)端在異步獲取這個(gè)結(jié)果后,不是直接顯示在頁(yè)面,而是先由javascript來(lái)處理,然后再顯示在頁(yè)面。
?
- 請(qǐng)解釋 JSONP 的工作原理,以及它為什么不是真正的 AJAX。
JSONP動(dòng)態(tài)創(chuàng)建script標(biāo)簽,回調(diào)函數(shù)。Ajax是頁(yè)面無(wú)刷新請(qǐng)求數(shù)據(jù)操作
動(dòng)態(tài)添加一個(gè)<script>標(biāo)簽,而script標(biāo)簽的src屬性是沒(méi)有跨域的限制的。這樣說(shuō)來(lái),這種跨域方式其實(shí)與ajax XmlHttpRequest協(xié)議無(wú)關(guān)了。當(dāng)GET請(qǐng)求從被調(diào)用頁(yè)面返回時(shí),可以返回一段JavaScript代碼,這段代碼會(huì)自動(dòng)調(diào)用主頁(yè)面中的一個(gè)callback函數(shù)。
Jsonp優(yōu)點(diǎn)不受同源策略的影響,它的兼容性更好,在更加古老的瀏覽器中都可以運(yùn)行,不需要XMLHttpRequest或ActiveX的支持;并且在請(qǐng)求完畢后可以通過(guò)調(diào)用callback的方式回傳結(jié)果
Jsonp缺點(diǎn),它只支持GET請(qǐng)求而不支持POST等其它類(lèi)型的HTTP請(qǐng)求;它只支持跨域HTTP請(qǐng)求這種情況,不能解決不同域的兩個(gè)頁(yè)面之間如何進(jìn)行JavaScript調(diào)用的問(wèn)題。
?
- 你使用過(guò) JavaScript 模板系統(tǒng)嗎?
?沒(méi)用過(guò),但是知道:在生成各種頁(yè)面內(nèi)容結(jié)合javascript模板技術(shù),能讓邏輯和數(shù)據(jù)之間更加清晰。邏輯是寫(xiě)在"<%"與"%>"之間,如果是注釋,則用"<%#"與"%>",后臺(tái)傳過(guò)來(lái)的變量使用@來(lái)標(biāo)記。
- 如有使用過(guò),請(qǐng)談?wù)勀愣际褂眠^(guò)哪些庫(kù),比如 Mustache.js,Handlebars 等等。
?
- 請(qǐng)解釋變量聲明提升。
? javascript不支持塊級(jí)作用域,即變量定義的作用域并不是離其最近的封閉語(yǔ)句或代碼塊,而是包含它的函數(shù):
var foo = 1; function bar() {if (!foo) {var foo = 10;}alert(foo);//10 } bar();?
var a = 1; function b() {a = 10;return;function a() {}} b();alert(a);//1對(duì)于被函數(shù)作用域包圍的變量的作用域?yàn)楹瘮?shù),函數(shù)內(nèi)部訪問(wèn)變量,將會(huì)返回函數(shù)體內(nèi)最近的變量值;函數(shù)外部訪問(wèn)變量將會(huì)函數(shù)體外所聲明的變量值。
也但是,對(duì)于被if語(yǔ)句包裹的代碼段,不能看作是另外一個(gè)獨(dú)立的作用域,也就是說(shuō),對(duì)于被非函數(shù)的{}所包圍的代碼段內(nèi)所定義的變量,變量的聲明將會(huì)提升到{}所在的作用域。
function f(){{var x =0;}}等同于function f(){var x ;{x =0;}}
function foo() {bar();var x = 1;}會(huì)被解釋為function foo() {var x;bar();x = 1;}
變量賦值并沒(méi)有被提升,只是聲明被提升了。但是,函數(shù)的聲明有點(diǎn)不一樣,函數(shù)體也會(huì)一同被提升。但是請(qǐng)注意,函數(shù)的聲明有兩種方式:
function test() {foo(); // TypeError "foo is not a function"bar(); // "this will run!"var foo = function () { // 變量指向函數(shù)表達(dá)式alert("this won't run!");}function bar() { // 函數(shù)聲明 函數(shù)名為baralert("this will run!");} } test();對(duì)于var?a=1; ?function?a(){ } ?alert(a);function?a(){ ?} var?a=1; ?alert(a);都是會(huì)打印出1 ?
對(duì)于全局作用于范圍的變量,var與不var是有區(qū)別的.?沒(méi)有var的寫(xiě)法,其變量不會(huì)被提升。比如下面的程序會(huì)報(bào)錯(cuò):alert(a);a=1;
eval中創(chuàng)建的局部變量是不會(huì)被提升var a = 1;function t(){console.info(a);eval('var a = 2');console.info(a);}t();console.info(a);結(jié)果按照順序?yàn)?,2,1
?
- 請(qǐng)描述下事件冒泡機(jī)制。
? 從目標(biāo)元素開(kāi)始,往頂層元素傳播。途中如果有節(jié)點(diǎn)綁定了相應(yīng)的事件處理函數(shù),這些函數(shù)都會(huì)被一次觸發(fā)。如果想阻止事件起泡,可以使用e.stopPropagation()(Firefox)或者e.cancelBubble=true(IE)來(lái)組織事件的冒泡傳播。
?
- "attribute" 和 "property" 的區(qū)別是什么?
DOM元素的attribute和property兩者是不同的東西。attribute翻譯為“特性”,property翻譯為“屬性”。
attribute是一個(gè)特性節(jié)點(diǎn),每個(gè)DOM元素都有一個(gè)對(duì)應(yīng)的attributes屬性來(lái)存放所有的attribute節(jié)點(diǎn),attributes是一個(gè)類(lèi)數(shù)組的容器,說(shuō)得準(zhǔn)確點(diǎn)就是NameNodeMap,不繼承于Array.prototype,不能直接調(diào)用Array的方法。attributes的每個(gè)數(shù)字索引以名值對(duì)(name=”value”)的形式存放了一個(gè)attribute節(jié)點(diǎn)。<div class="box" id="box" gameid="880">hello</div>
property就是一個(gè)屬性,如果把DOM元素看成是一個(gè)普通的Object對(duì)象,那么property就是一個(gè)以名值對(duì)(name=”value”)的形式存放在Object中的屬性。要添加和刪除property和普通的對(duì)象類(lèi)似。
很多attribute節(jié)點(diǎn)還有一個(gè)相對(duì)應(yīng)的property屬性,比如上面的div元素的id和class既是attribute,也有對(duì)應(yīng)的property,不管使用哪種方法都可以訪問(wèn)和修改。
總之,attribute節(jié)點(diǎn)都是在HTML代碼中可見(jiàn)的,而property只是一個(gè)普通的名值對(duì)屬性。
?
- 為什么擴(kuò)展 JavaScript 內(nèi)置對(duì)象不是好的做法?
需要給Array原型添加一個(gè)distinct的方法,最好檢查是否存在同名的方法,避免自定義方法覆蓋原生方法:
Arrray.prototype.distinct = Arrray.prototype.distinct || function(){/*.....*/} ?
- 請(qǐng)指出 document load 和 document ready 兩個(gè)事件的區(qū)別。
jQuery中$(function(){/* do something*/});他的作用或者意義就是:在DOM加載完成后就可以可以對(duì)DOM進(jìn)行操作。一般情況先一個(gè)頁(yè)面響應(yīng)加載的順序是,域名解析-加載html-加載js和css-加載圖片等其他信息。
- ==?和?===?有什么不同?
注意:
1)如果兩個(gè)值的類(lèi)型不同,它們就不相同。
2)如果兩個(gè)值是數(shù)字,而且值相同,那么除非其中一個(gè)或兩個(gè)都是NaN(這種情況它們不是等同的),否則它們是等同的。值NaN永遠(yuǎn)不會(huì)與其他任何值等同,包括它自身(奇怪的家伙),要檢測(cè)一個(gè)值是否是NaN,可以使用全局函數(shù)isNaN()。
3)如果兩個(gè)值都是字符串,而且在串中同一位置上的字符完全相同,那么它們就完全等同。如果字符串的長(zhǎng)度或內(nèi)容不同,它們就不是等同的。
4)如果兩個(gè)值都是布爾型true,或者兩個(gè)值都是布爾型false,那么它們等同。
5)如果兩個(gè)值引用的是同一個(gè)對(duì)象、數(shù)組或函數(shù),那么它們完全等同。如果它們引用的是不同的對(duì)象(數(shù)組或函數(shù)),它們就不完全等同,即使這兩個(gè)對(duì)象具有完全相同的屬性,或兩個(gè)數(shù)組具有完全相同的元素。
6)如果兩個(gè)值都是null或都是undefined,“==”返回true,“===”返回false。
- 請(qǐng)解釋一下 JavaScript 的同源策略。
? 同源策略是客戶(hù)端腳本(尤其是Javascript)的重要的安全度量標(biāo)準(zhǔn)。所謂同源是指,域名,協(xié)議,端口相同。如果我們又想利用XMLHTTP的無(wú)刷新異步交互能力,又不愿意公然突破Javascript的安全策略,可以選擇的方案就是給XMLHTTP加上嚴(yán)格的同源限制。
同源策略阻止從一個(gè)源加載的文檔或腳本獲取或設(shè)置另一個(gè)源加載的文檔的屬性。
處理跨域方法:
? 1)document.domain+iframe的設(shè)置
2)動(dòng)態(tài)創(chuàng)建script
3)利用iframe和location.hash
4)window.name實(shí)現(xiàn)的跨域數(shù)據(jù)傳輸
5)使用HTML5 postMessage
?
- 如何實(shí)現(xiàn)下列代碼:
[1,2,3,4,5].duplicator(); // [1,2,3,4,5,1,2,3,4,5]
Array.prototype.duplicator = function(){var l = this.length,i;
for(i=0;i<l;i++){
this.push(this[i])
}
}
- 什么是三元表達(dá)式?“三元” 表示什么意思?
三元運(yùn)算符需要三個(gè)操作數(shù)。
語(yǔ)法是?條件 ? 結(jié)果1 : 結(jié)果2;. 這里你把條件寫(xiě)在問(wèn)號(hào)(?)的前面后面跟著用冒號(hào)(:)分隔的結(jié)果1和結(jié)果2。滿(mǎn)足條件時(shí)結(jié)果1否則結(jié)果2。
- 什么是?"use strict";?? 使用它的好處和壞處分別是什么?
在所有的函數(shù) (或者所有最外層函數(shù)) 的開(kāi)始處加入 "use strict"; 指令啟動(dòng)嚴(yán)格模式。
"嚴(yán)格模式"有兩種調(diào)用方法
?
1)將"use strict"放在腳本文件的第一行,則整個(gè)腳本都將以"嚴(yán)格模式"運(yùn)行。如果這行語(yǔ)句不在第一行,則無(wú)效,整個(gè)腳本以"正常模式"運(yùn)行。如果不同模式的代碼文件合并成一個(gè)文件,這一點(diǎn)需要特別注意。
?
2)將整個(gè)腳本文件放在一個(gè)立即執(zhí)行的匿名函數(shù)之中。
?
? 好處
- 消除Javascript語(yǔ)法的一些不合理、不嚴(yán)謹(jǐn)之處,減少一些怪異行為;
- 消除代碼運(yùn)行的一些不安全之處,保證代碼運(yùn)行的安全;
- 提高編譯器效率,增加運(yùn)行速度;
- 為未來(lái)新版本的Javascript做好鋪墊。
壞處
同樣的代碼,在"嚴(yán)格模式"中,可能會(huì)有不一樣的運(yùn)行結(jié)果;一些在"正常模式"下可以運(yùn)行的語(yǔ)句,在"嚴(yán)格模式"下將不能運(yùn)行
?
jQuery?相關(guān)問(wèn)題:
?
- 解釋"chaining"。
Chaining 允許我們?cè)谝粭l語(yǔ)句中允許多個(gè) jQuery 方法(在相同的元素上)。這樣的話,瀏覽器就不必多次查找相同的元素。鏈?zhǔn)秸{(diào)用,這是因?yàn)閖Query內(nèi)部在方法調(diào)用之后,都返回本身(在無(wú)狀態(tài)的方法中返回新對(duì)象來(lái)支持方法鏈,有狀態(tài)的方法中返回this來(lái)支持方法鏈)。雖然如此,但是如果直接把全部代碼都寫(xiě)在一行,可讀性會(huì)變差,不利于維護(hù),因此要加上必要的縮進(jìn)和換行。
$("#p1").css("color","red").slideUp(2000).slideDown(2000);- 解釋"deferreds"。
deferred對(duì)象就是jQuery的回調(diào)函數(shù)解決方案。deferred對(duì)象的含義就是"延遲"到未來(lái)某個(gè)點(diǎn)再執(zhí)行。
對(duì)于那些某些耗時(shí)很長(zhǎng)的javascript操作比如異步的操作(比如ajax讀取服務(wù)器數(shù)據(jù)),和同步的操作(比如遍歷一個(gè)大型數(shù)組),并不是馬上能夠得到結(jié)果,因此,為它們指定回調(diào)函數(shù)(callback)。
? $.ajax("test.html").done(function(){ alert("成功!"); }).fail(function(){ alert("出錯(cuò)!"); });同時(shí)回調(diào)函數(shù)可以添加任意多個(gè),它們按照添加順序執(zhí)行。
?
- 你知道哪些針對(duì) jQuery 的優(yōu)化方法。
1)總是從ID選擇器開(kāi)始繼承
在jQuery中最快的選擇器是ID選擇器,因?yàn)樗苯觼?lái)自于JavaScript的getElementById()方法。當(dāng)然 這只是對(duì)于單一的元素來(lái)講。如果你需要選擇多個(gè)元素,這必然會(huì)涉及到 DOM遍歷和循環(huán),為了提高性能,建議從最近的ID開(kāi)始繼承。如下所示:var traffic_lights = $(“#traffic_light input”)
可以使用console測(cè)試程序性能,比較id選擇器和class選擇器的效率。
2)在class前使用tag(標(biāo)簽名)
在jQuery中第二快的選擇器是tag(標(biāo)簽)選擇器( 比如:$(“head”) ),因?yàn)樗鼇?lái)自原生的getElementsByTagName() 方法。
在使用tag來(lái)修飾class的時(shí)候,我們需要注意以下幾點(diǎn):
(1) 不要使用tag來(lái)修飾ID,如下所示:var content = $(“div#content”);這樣一來(lái),選擇器會(huì)先遍歷所有的div元素,然后匹配#content。
(2)不要使用ID來(lái)修飾ID,如下所示:var traffic_light = $(“#content #traffic_light”);
3)將jQuery對(duì)象緩存起來(lái)
把jQuery對(duì)象緩存起來(lái),不要讓相同的選擇器在你的代碼里出現(xiàn)多次。
注意:(1)為了區(qū)分普通的JavaScript對(duì)象和jQuery對(duì)象,可以在變量首字母前加上 $ 符號(hào)。
??(2)代碼可以使用jQuery的鏈?zhǔn)讲僮骷右愿纳啤?/span>
4)對(duì)直接的DOM操作進(jìn)行限制
這里的基本思想是在內(nèi)存中建立你確實(shí)想要的東西,然后更新DOM ,因?yàn)橹苯拥腄OM操作速度很慢。例如,動(dòng)態(tài)的創(chuàng)建一組列表元素,盡量不要在循環(huán)中,調(diào)用append:? ??
for?(var?i=0,?l=top_100_list.length;?i<l;?i++){?$mylist.append("<li>"?+?top_100_list[i]?+?"</li>");}
而應(yīng)該將整套元素字符串創(chuàng)建完畢后,再在插入進(jìn)dom中
for?(var?i=0,?l=top_100_list.length;?i<l;?i++){top_100_li?+=?"<li>"?+?top_100_list[i]?+?"</li>";}? ?$mylist.html(top_100_li);
5)冒泡
除非在特殊情況下, 否則每一個(gè)js事件(例如:click, mouseover等.)都會(huì)冒泡到父級(jí)節(jié)點(diǎn)。當(dāng)我們需要給多個(gè)元素調(diào)用同個(gè)函數(shù)時(shí)這點(diǎn)會(huì)很有用。代替這種效率很差的多元素事件監(jiān)聽(tīng)的方法就是, 你只需向它們的父節(jié)點(diǎn)綁定一次。
6)推遲到 $(window).load
$(document).rady 確實(shí)很有用, 它可以在頁(yè)面渲染時(shí),其它元素還沒(méi)下載完成就執(zhí)行。其實(shí)可以通過(guò)將jQuery函數(shù)綁定到$(window).load 事件的方法來(lái)減少頁(yè)面載入時(shí)的cpu使用率。它會(huì)在所有的html(包括iframe)被下載完成后執(zhí)行。一些特效的功能,例如拖放, 視覺(jué)特效和動(dòng)畫(huà), 預(yù)載入隱藏圖像等等,都是適合這種技術(shù)的場(chǎng)合。
7)壓縮JavaScript
壓縮之前,請(qǐng)保證你的代碼的規(guī)范性(語(yǔ)句執(zhí)行結(jié)束后添加分號(hào)),否則可能失敗,導(dǎo)致Js錯(cuò)誤。
8)給選擇器一個(gè)上下文
jQuery選擇器中有一個(gè)這樣的選擇器,它能指定上下文。jQuery( expression, context );
通過(guò)它,能縮小選擇器在DOM中搜索的范圍,達(dá)到節(jié)省時(shí)間,提高效率。
普通方式:$(‘.myDiv’)改進(jìn)方式:$(‘.myDiv’ , $(“#listItem”) )
?
- 請(qǐng)解釋?.end()?的用途。
? end() 方法結(jié)束當(dāng)前鏈條中的最近的篩選操作,并將匹配元素集還原為之前的狀態(tài)。
大多數(shù) jQuery 的遍歷方法會(huì)操作一個(gè) jQuery 對(duì)象實(shí)例,并生成一個(gè)匹配不同 DOM 元素集的新對(duì)象。當(dāng)發(fā)生這種情況時(shí),應(yīng)該會(huì)把新的元素集推入維持在對(duì)象中的堆棧內(nèi)。每次成功的篩選方法調(diào)用都會(huì)把新元素推入堆棧中。如果我們需要老的元素集,可以使用 end() 從堆棧中彈出新集合。但由于進(jìn)行了額外的調(diào)用,會(huì)有一點(diǎn)點(diǎn)性能損失。
?
- 你如何給一個(gè)事件處理函數(shù)命名空間,為什么要這樣做?
? 用 .bind('click.myCustomRoutine',function(){...}); 把匿名函數(shù)綁定到 click 事件(使用命名空間多次綁定不同的行為方法);使用.unbind('click.myCustomRoutine') 即可 釋放所有綁定到 .myCustomRoutine 命名空間的 click 事件,而不會(huì)解除其他通過(guò) .bind('click') 或另外的命名 空間所綁定的事件行為。?
但是,考慮一種情況就是:需要在運(yùn)行時(shí)根據(jù)用戶(hù)交互的結(jié)果進(jìn)行不同click事件處理邏輯的綁定,因而理論 上會(huì)無(wú)數(shù)次對(duì)某一個(gè)事件進(jìn)行 bind / unbind 操作。但又希望 unbind 的時(shí)候只把自己綁上去的處理邏輯給釋放掉而不是所有其他地方有 可能的額外的同一事件綁定邏輯。?
這時(shí)候如果直接用 .click() / .bind('click') 加 上 .unbind('click') 來(lái)進(jìn)行重復(fù)綁定的話,被unbind 掉的將是所有綁定在元素上的 click 處理邏輯,潛在會(huì)影響到該元素 其他第三方的行為。
對(duì)于這種問(wèn)題,jQuery的解決方案是使用事件綁定的命名空間。即在事件名稱(chēng)后添加.something 來(lái)區(qū)分自己這部分行為邏輯范圍。??
- 請(qǐng)說(shuō)出你可以傳遞給 jQuery 方法的四種不同值。
選擇器(字符串),HTML(字符串),回調(diào)函數(shù),HTML元素,對(duì)象,數(shù)組,元素?cái)?shù)組,jQuery對(duì)象等。
?
- 什么是效果隊(duì)列?
? jQuery中有個(gè)動(dòng)畫(huà)隊(duì)列的機(jī)制。當(dāng)對(duì)一個(gè)對(duì)象添加多次動(dòng)畫(huà)效果時(shí)后添加的動(dòng)作就會(huì)被放入這個(gè)動(dòng)畫(huà)隊(duì)列中,等前面的動(dòng)畫(huà)完成后再開(kāi)始執(zhí)行。可是用戶(hù)的操作往往都比動(dòng)畫(huà)快,如果用戶(hù)對(duì)一個(gè)對(duì)象頻繁操作時(shí)不處理動(dòng)畫(huà)隊(duì)列就會(huì)造成隊(duì)列堆積,影響到效果。
jQuery中有stop這個(gè)方法可以停止當(dāng)前執(zhí)行的動(dòng)畫(huà),并且它有兩個(gè)布爾參數(shù),默認(rèn)值都為false。第一個(gè)參數(shù)為true時(shí)會(huì)清空動(dòng)畫(huà)隊(duì)列,第二個(gè)參數(shù)為true時(shí)會(huì)瞬間完成掉當(dāng)前動(dòng)畫(huà)。;第二個(gè)參數(shù)為true,把當(dāng)前在執(zhí)行的動(dòng)畫(huà)跳轉(zhuǎn)到完成狀態(tài)。這時(shí)第一個(gè)參數(shù)如果也為true,后面的隊(duì)列就會(huì)被清空。
?
- 請(qǐng)指出?.get(),[],eq()?的區(qū)別。
進(jìn)一步說(shuō),返回的是jQuery對(duì)象,就可以繼續(xù)調(diào)用其他方法,返回的是html數(shù)組就不能調(diào)用jQuery的其他方法,例如:
$("ul li").eq(1).css("color", "red"); //這個(gè)是正確的 $("ul li").get(1).css("color", "red"); //這個(gè)是錯(cuò)誤的
當(dāng)$()所獲取的對(duì)象不存在,即為[]時(shí),get()返回undefined,而eq()返回m.fn.init[0],jQuery文檔對(duì)象。
- 請(qǐng)指出?.bind(),.live()?和?.delegate()?的區(qū)別。
? 對(duì)于bind():$('a').bind('click',function(){alert('That tickles!');})jQuery掃描文檔找出所有的$(‘a(chǎn)')元素,并把a(bǔ)lert函數(shù)綁定到每個(gè)元素的click事件上。?
對(duì)于live():$('a').live('click',function(){alert('That tickles!')})jQuery把a(bǔ)lert函數(shù)綁定到$(document)元素上,并使用'click'和'a'作為參數(shù)。任何時(shí)候只要有事件冒泡到document節(jié)點(diǎn)上,它就查看該事件是否是一個(gè)click事件,以及該事件的目標(biāo)元素與'a'這一CSS選擇器是否匹配,如果都是的話,則執(zhí)行函數(shù)。?
對(duì)于.delegate() :$('#container').delegate('a','click',function(){alert('That tickles!')})jQuery掃描文檔查找$('#container'),并使用click事件和'a'這一CSS選擇器作為參數(shù)把a(bǔ)lert函數(shù)綁定到$('#container')上。任何時(shí)候只要有事件冒泡到$('#container')上,它就查看該事件是否是click事件,以及該事件的目標(biāo)元素是否與CSS選擇器相匹配。如果兩種檢查的結(jié)果都為真的話,它就執(zhí)行函數(shù)。?
bind看上去更加明確直接,但是delegate和live執(zhí)行的效率會(huì)更高。
bind首先要掃描整個(gè)的文檔查找所有的$(‘a(chǎn)')元素,把它們存成jQuery對(duì)象。盡管live函數(shù)僅需要把'a'作為串參數(shù)傳遞以用做之后的判斷,但是$()函數(shù)并未“知道”被鏈接的方法將會(huì)是.live()。
delegate方法僅需要查找并存儲(chǔ)$(document)元素。?一種尋求避開(kāi)這一問(wèn)題的方法是調(diào)用在$(document).ready()之外綁定的live,這樣它就會(huì)立即執(zhí)行。在這種方式下,其會(huì)在DOM獲得填充之前運(yùn)行,因此就不會(huì)查找元素或是創(chuàng)建jQuery對(duì)象了。?
?
- 請(qǐng)指出?$?和?$.fn?的區(qū)別,或者說(shuō)出?$.fn?的用途。
jQuery對(duì)方法的拓展,從調(diào)用聲明創(chuàng)建方法的方式來(lái)看,可以歸結(jié)為兩類(lèi):一類(lèi)直接由$符調(diào)用;另一類(lèi)由$("")來(lái)調(diào)用。$拓展的方法是靜態(tài)方法,可以使用$直接調(diào)用,其拓展的方式一般使用$.extend({});;而$.fn拓展的方法是實(shí)例方法,必須由“對(duì)象”$("")來(lái)調(diào)用,一般使用$.fn.extend({?})。
$.fn是指jquery的命名空間,加上fn上的方法及屬性,會(huì)對(duì)jquery實(shí)例每一個(gè)有效。?如擴(kuò)展$.fn.abc() ;使用:$("#div").abc(); 。
?
- 請(qǐng)優(yōu)化下列選擇器:
$(".foo div#bar:eq(0)")->$(".foo #bar:first-child")
?
代碼相關(guān)的問(wèn)題:
modulo(12, 5) // 2
問(wèn)題:實(shí)現(xiàn)滿(mǎn)足上述結(jié)果的modulo函數(shù)
1 (function module(a,b){ 2 var r; 3 if( !isNaN(a) && !isNaN(b)){ 4 (a>b)?(r= a%b):(r= b%a); 5 return r; 6 }else{ 7 throw new Error("arguments are not numbers"); 8 } 9 })(12,5);實(shí)際上就是求模運(yùn)算。注意:檢查參數(shù)的合理性(數(shù)字且長(zhǎng)度為2)否則拋出異常
?
"i'm a lasagna hog".split("").reverse().join("");
問(wèn)題:上面的語(yǔ)句的返回值是什么??答案:"goh angasal a m'i"
這道題目提醒了一點(diǎn):"i'm a lasagna hog"不繼承于Array.prototype不能直接調(diào)用Array的reverse()方法。因此先要使用split("")將字符串轉(zhuǎn)變?yōu)閿?shù)組,最后使用join("")將已經(jīng)逆序的結(jié)果轉(zhuǎn)換為字符串。
博主想補(bǔ)充一點(diǎn)是:通過(guò)dom操作(ducument.getElementByTayName和document.getByClassName)獲取的NodeList和函數(shù)中的arguments對(duì)象都是偽數(shù)組,不能不繼承Array.prototype,不能直接調(diào)用Array的方法。可以使用遍歷,將偽數(shù)組中的元素push到新數(shù)組中或使用[].slice.call(arguments)將偽數(shù)組轉(zhuǎn)換為數(shù)組。
?
( window.foo || ( window.foo = "bar" ) );
問(wèn)題:window.foo 的值是什么??答案:"bar"?只有 window.foo 為假(定義的值類(lèi)型轉(zhuǎn)換為false或者沒(méi)定義,即為undefined)時(shí)的才是上面答案,否則就是它本身的值(提前聲明定義的值)。
?
var foo = "Hello"; (function() { var bar = " World"; alert(foo + bar); })(); alert(foo + bar);
問(wèn)題:上面兩個(gè) alert 的結(jié)果是什么?答案: "Hello World"?和?ReferenceError: bar is not defined
var foo = "Hello"; (function() { var bar = " World"; console.info(foo + bar); //代碼段包裹在“立即調(diào)用函數(shù)”中,獲取全局的foo和函數(shù)內(nèi)的bar })(); console.info(foo + bar);//“立即調(diào)用函數(shù)”執(zhí)行完畢后,外部無(wú)法訪問(wèn)其內(nèi)部的局部變量,因此,在此作用域內(nèi)的bar未定義?
var foo = [];
foo.push(1);
foo.push(2);
問(wèn)題:foo.length 的值是什么??答案:2
個(gè)人感覺(jué)這道題目考得太簡(jiǎn)單了,最后,大家思考一下這道題目:
var array1 = [1,2]; var array2 = array1; array1[0] = array2[1]; array2.push(3); console.log(array1); console.log(array2);array2 = array1將array2和array1引用同一片存儲(chǔ)區(qū)域,對(duì)其中一個(gè)變量進(jìn)行賦值和修改操作都會(huì)影響到另外一個(gè)變量的值。?
因此答案是:Array1的值為[2,2,3];Array2的值為[2,2,3]
轉(zhuǎn)載于:https://www.cnblogs.com/0603ljx/p/4334228.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的前端工作面试问题(下)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 2018.08.09洛谷P3959 宝藏
- 下一篇: 作业三--阅读《构建之法》1-5章