js基礎(chǔ)
1.javaScript的數(shù)據(jù)類型有什么
基本數(shù)據(jù)類型:Undefined、Null、Boolean、Number、String
復(fù)雜數(shù)據(jù)類型:object,array,function
區(qū)別:基本數(shù)據(jù)類型把數(shù)據(jù)名和值直接存儲(chǔ)在棧當(dāng)中;復(fù)雜數(shù)據(jù)類型在棧中存儲(chǔ)數(shù)據(jù)名和一個(gè)堆的地址,在堆中存儲(chǔ)屬性及值,訪問時(shí)先從棧中獲取地址,再到堆中拿出相應(yīng)的值
2.檢測數(shù)據(jù)類型有什么方法
typeof
typeof xxx得到的值有以下幾種類型:undefined boolean number string object function、symbol ,比較簡單,不再一一演示了。
這里需要注意的有三點(diǎn):
typeof null結(jié)果是object ,實(shí)際這是typeof的一個(gè)bug,null是原始值,非引用類型
typeof [1, 2]結(jié)果是object,結(jié)果中沒有array這一項(xiàng),引用類型除了function其他的全部都是object
typeof Symbol() 用typeof獲取symbol類型的值得到的是symbol,這是 ES6 新增的知識(shí)點(diǎn)
instanceof
用于實(shí)例和構(gòu)造函數(shù)的對應(yīng)。例如判斷一個(gè)變量是否是數(shù)組,使用typeof無法判斷,但可以使用[1, 2] instanceof Array來判斷。因?yàn)?,[1, 2]是數(shù)組,它的構(gòu)造函數(shù)就是Array。
同理:
functionFoo(name) {
????this.name = name
?}
var foo =newFoo('bar’)
console.log(foo instanceof Foo) // true
3.介紹js有哪些內(nèi)置對象?
Object 是 JavaScript 中所有對象的父對象?
數(shù)據(jù)封裝類對象:Object、Array、Boolean、Number 和 String?
其他對象:Function、Arguments、Math、Date、RegEx、Error
4.如何區(qū)分?jǐn)?shù)組和對象?
(1)從原型入手,Array.prototype.isPrototypeOf(obj); ?利用isPrototypeOf()方法,判定Array是不是在obj的原型鏈中,如果是,則返回true,否則false。Array.prototype.isPrototype([]) //true?
(2)也可以從構(gòu)造函數(shù)入手,利用對向的constructor屬性?
(3)根據(jù)對象的class屬性(類屬性),跨原型鏈調(diào)用toString()方法。Object.prototype.toString.call(Window);?
(4)Array.isArray()方法。
5.null,undefined 的區(qū)別?
null ? ? ? ?表示一個(gè)對象被定義了,值為“空值”;?
undefined ? 表示不存在這個(gè)值。?
typeof undefined ? ? ? ? ? ? ? ? ? ? ?//"undefined"?
undefined :是一個(gè)表示"無"的原始值或者說表示"缺少值",就是此處應(yīng)該有一個(gè)值,但是還沒有定義。當(dāng)嘗試讀取時(shí)會(huì)返回 undefined;?
例如變量被聲明了,但沒有賦值時(shí),就等于undefined
typeof null ? ? ? ?//"object"?
null : 是一個(gè)對象(空對象, 沒有任何屬性和方法);?
例如作為函數(shù)的參數(shù),表示該函數(shù)的參數(shù)不是對象;
注意:
在驗(yàn)證null時(shí),一定要使用 === ,因?yàn)?== 無法分別 null 和 undefined?
undefined表示"缺少值",就是此處應(yīng)該有一個(gè)值,但是還沒有定義。典型用法是:?
1)變量被聲明了,但沒有賦值時(shí),就等于undefined。?
2) 調(diào)用函數(shù)時(shí),應(yīng)該提供的參數(shù)沒有提供,該參數(shù)等于undefined。?
3)對象沒有賦值的屬性,該屬性的值為undefined。?
4)函數(shù)沒有返回值時(shí),默認(rèn)返回undefined。
null表示"沒有對象",即該處不應(yīng)該有值。
典型用法是:?
1) 作為函數(shù)的參數(shù),表示該函數(shù)的參數(shù)不是對象。?
2) 作為對象原型鏈的終點(diǎn)。
6.聲明變量和聲明函數(shù)的提升有什么區(qū)別?
(1) 變量聲明提升:變量申明在進(jìn)入執(zhí)行上下文就完成了。?
只要變量在代碼中進(jìn)行了聲明,無論它在哪個(gè)位置上進(jìn)行聲明, js引擎都會(huì)將它的聲明放在范圍作用域的頂部;?
(2) 函數(shù)聲明提升:執(zhí)行代碼之前會(huì)先讀取函數(shù)聲明,意味著可以把函數(shù)申明放在調(diào)用它的語句后面。?
只要函數(shù)在代碼中進(jìn)行了聲明,無論它在哪個(gè)位置上進(jìn)行聲明, js引擎都會(huì)將它的聲明放在范圍作用域的頂部;?
(3) 變量or函數(shù)聲明:函數(shù)聲明會(huì)覆蓋變量聲明,但不會(huì)覆蓋變量賦值。?
同一個(gè)名稱標(biāo)識(shí)a,即有變量聲明var a,又有函數(shù)聲明function a() {},不管二者聲明的順序,函數(shù)聲明會(huì)覆蓋變量聲明,也就是說,此時(shí)a的值是聲明的函數(shù)function a() {}。注意:如果在變量聲明的同時(shí)初始化a,或是之后對a進(jìn)行賦值,此時(shí)a的值變量的值。
var a;
var c = 1;
a = 1;
function a() {
????????return true;
}
console.log(a);
原型,原型鏈
1.JavaScript原型,原型鏈 ? 有什么特點(diǎn)?
原型
每個(gè)對象都會(huì)在其內(nèi)部初始化一個(gè)屬性,就是prototype(原型)?
使用hasOwnProperty() 可以判斷這個(gè)屬性是不是對象本身的屬性
問題:Javascript中,有一個(gè)函數(shù),執(zhí)行時(shí)對象查找時(shí),永遠(yuǎn)不會(huì)去查找原型,這個(gè)函數(shù)是?
hasOwnProperty?
javaScript中hasOwnProperty函數(shù)方法是返回一個(gè)布爾值,指出一個(gè)對象是否具有指定名稱的屬性。此方法無法檢查該對象的原型鏈中是否具有該屬性;該屬性必須是對象本身的一個(gè)成員。
使用方法:?
object.hasOwnProperty(proName)?
其中參數(shù)object是必選項(xiàng)。一個(gè)對象的實(shí)例。?
proName是必選項(xiàng)。一個(gè)屬性名稱的字符串值。
如果 object 具有指定名稱的屬性,那么JavaScript中hasOwnProperty函數(shù)方法返回 true,反之則返回 false。
原型鏈
當(dāng)我們在訪問一個(gè)對象的屬性時(shí),如果這個(gè)對象內(nèi)部不存在這個(gè)屬性,那么他就會(huì)去prototype里找這個(gè)屬性,這個(gè)prototype又會(huì)有自己的prototype,于是就這樣一直找下去,找到Object.__proto__為止,找不到就返回unde也就是我們平時(shí)所說的原型鏈的概念。?
關(guān)系:instance.constructor.prototype = instance.__proto__?
特點(diǎn):?
JavaScript對象是通過引用來傳遞的,我們創(chuàng)建的每個(gè)新對象實(shí)體中并沒有一份屬于自己的原型副本。當(dāng)我們修改原型時(shí),與之相關(guān)的對象也會(huì)繼承這一改變。?
當(dāng)我們需要一個(gè)屬性的時(shí),Javascript引擎會(huì)先看當(dāng)前對象中是否有這個(gè)屬性, 如果沒有的話,就會(huì)查找他的Prototype對象是否有這個(gè)屬性,如此遞推下去,一直檢索到 Object 內(nèi)建對象。
所有的引用類型(數(shù)組、對象、函數(shù)),都具有對象特性,即可自由擴(kuò)展屬性(null除外)?
所有的引用類型(數(shù)組、對象、函數(shù)),都有一個(gè)__proto__屬性,屬性值是一個(gè)普通的對象?
所有的函數(shù),都有一個(gè)prototype屬性,屬性值也是一個(gè)普通的對象?
所有的引用類型(數(shù)組、對象、函數(shù)),__proto__屬性值指向它的構(gòu)造函數(shù)的prototype屬性值
原型鏈中的this
所有從原型或更高級原型中得到、執(zhí)行的方法,其中的this在執(zhí)行時(shí),就指向了當(dāng)前這個(gè)觸發(fā)事件執(zhí)行的對象。
閉包
閉包的形成與變量的作用域以及變量的生存周期有密切的關(guān)系
1.變量的作用域
在js中我們把作用域分為全局作用域和局部作用域,全局作用域就是window,在沒有塊級作用域概念的時(shí)候,每一個(gè)函數(shù)都是一個(gè)局部作用域。
其實(shí)變量的作用域,就說指變量的有效范圍。我們最長說的就是在函數(shù)中聲明的變量作用域。
當(dāng)在函數(shù)中聲明一個(gè)變量的時(shí)候,如果改變量沒有用var關(guān)鍵字去定義那么該變量就是一個(gè)全局變量,但是這樣做最容易造成命名沖突。
另一種情況就是使用var聲明的變量,這時(shí)候的變量就是局部變量,只有在該函數(shù)內(nèi)部可以訪問,在函數(shù)外面是訪問不到的
在javascript中,函數(shù)可以用來創(chuàng)造函數(shù)作用域。在函數(shù)中搜索變量的時(shí)候,如果該函數(shù)當(dāng)中沒有這個(gè)變量,那么這次搜索過程會(huì)隨著代碼執(zhí)行環(huán)境創(chuàng)建的作用域鏈往外層逐層搜索,一直搜索到window對象為止,找不到就會(huì)拋出一個(gè)為定義的錯(cuò)誤。而這種從內(nèi)到外逐層查找的關(guān)系在js中我們稱為作用域鏈
2.變量的生存周期
除了變量作用域之外,另外一個(gè)跟閉包有關(guān)的概念就是變量的生存周期,對于全局變量來說,全局變量的生存周期是永久的,除非我們主動(dòng)銷毀這個(gè)全局變量,而對于函數(shù)內(nèi)部的使用var聲明的變量來說,當(dāng)退出函數(shù)是,這些變量就會(huì)隨著函數(shù)的結(jié)束而銷毀。
3.閉包的形成
Javascript允許使用內(nèi)部函數(shù),可以將函數(shù)定義和函數(shù)表達(dá)式放在另一個(gè)函數(shù)的函數(shù)體內(nèi)。而且,內(nèi)部函數(shù)可以訪問它所在的外部函數(shù)聲明的局部變量、參數(shù)以及聲明的其他內(nèi)部函數(shù)。當(dāng)其中一個(gè)這樣的內(nèi)部函數(shù)在包含它們的外部函數(shù)之外被調(diào)用時(shí),就會(huì)形成閉包。常見的閉包寫法就是簡單的函數(shù)套函數(shù),通過另一個(gè)函數(shù)訪問這個(gè)函數(shù)的局部變量,利用閉包可以突破作用域鏈,將函數(shù)內(nèi)部的變量和方法傳遞到外部,延續(xù)變量的生命。使用閉包可以減少全局環(huán)境的污染,也可用延續(xù)變量的生命。
4.閉包的適用場景
閉包的適用場景非常廣泛,首先從閉包的優(yōu)點(diǎn)出發(fā)就是:?
減少全局環(huán)境的污染生成獨(dú)立的運(yùn)行環(huán)境
模塊化就是利用這個(gè)特點(diǎn)對不同的模塊都有自己獨(dú)立的運(yùn)行環(huán)境,不會(huì)和全局沖突,模塊和模塊之間通過拋出的接口進(jìn)行依賴使用?
以及像我們常用的jquery類庫(避免和全局沖突使用閉包實(shí)現(xiàn)自己獨(dú)立的環(huán)境)
可以通過返回其他函數(shù)的方式突破作用域鏈
可以利用這個(gè)功能做一些值的緩存工作,例如常見的設(shè)計(jì)模式(單例模式),以及現(xiàn)在比較火的框架vue中的計(jì)算屬性
其實(shí)當(dāng)遇到以下場景的時(shí)候都可以使用閉包?
1) 維護(hù)函數(shù)內(nèi)的變量安全,避免全局變量的污染。?
2) 維持一個(gè)變量不被回收。?
3) 封裝模塊
5.閉包的缺點(diǎn)
由于閉包會(huì)使得函數(shù)中的變量都被保存在內(nèi)存中,內(nèi)存消耗很大。所以在閉包不用之后,將不使用的局部變量刪除,使其被回收。在IE中可能導(dǎo)致內(nèi)存泄露,即無法回收駐留在內(nèi)存中的元素,這時(shí)候需要手動(dòng)釋放。
6.內(nèi)存泄露
內(nèi)存泄漏指一塊被分配的內(nèi)存既不能使用,又不能回收,直到瀏覽器進(jìn)程結(jié)束。
出現(xiàn)原因:
1) 循環(huán)引用:含有DOM對象的循環(huán)引用將導(dǎo)致大部分當(dāng)前主流瀏覽器內(nèi)存泄露。循環(huán) 引用,簡單來說假如a引用了b,b又引用了a,a和b就構(gòu)成了循環(huán)引用。?
2) JS閉包:閉包,函數(shù)返回了內(nèi)部函數(shù)還可以繼續(xù)訪問外部方法中定義的私有變量。?
3) Dom泄露,當(dāng)原有的DOM被移除時(shí),子結(jié)點(diǎn)引用沒有被移除則無法回收。
7.JavaScript垃圾回收機(jī)制
Javascript中,如果一個(gè)對象不再被引用,那么這個(gè)對象就會(huì)被GC(garbage collection)回收。如果兩個(gè)對象互相引用,而不再被第3者所引用,那么這兩個(gè)互相引用的對象也會(huì)被回收。垃圾回收不是時(shí)時(shí)的,因?yàn)槠溟_銷比較大,所以垃圾回收器會(huì)按照固定的時(shí)間間隔周期性的執(zhí)行。
函數(shù)a被b引用,b又被a外的c引用,這就是為什么函數(shù)a執(zhí)行后不會(huì)被回收的原因。
8.垃圾回收的兩個(gè)方法:
標(biāo)記清除法:
1) 垃圾回收機(jī)制給存儲(chǔ)在內(nèi)存中的所有變量加上標(biāo)記,然后去掉環(huán)境中的變量以及被環(huán)境中變量所引用的變量(閉包)。?
2) 操作1之后內(nèi)存中仍存在標(biāo)記的變量就是要?jiǎng)h除的變量,垃圾回收機(jī)制將這些帶有標(biāo)記的變量回收。
引用計(jì)數(shù)法:
1) 垃圾回收機(jī)制給一個(gè)變量一個(gè)引用次數(shù),當(dāng)聲明了一個(gè)變量并將一個(gè)引用類型賦值給該變量的時(shí)候這個(gè)值的引用次數(shù)就加1。?
2) 當(dāng)該變量的值變成了另外一個(gè)值,則這個(gè)值得引用次數(shù)減1。?
3) 當(dāng)這個(gè)值的引用次數(shù)變?yōu)?的時(shí)候,說明沒有變量在使用,垃圾回收機(jī)制會(huì)在運(yùn)行的時(shí)候清理掉引用次數(shù)為0的值占用的空間。
JS運(yùn)行機(jī)制
JavaScript引擎是單線程運(yùn)行的,瀏覽器無論在什么時(shí)候都只且只有一個(gè)線程在運(yùn)行JavaScript程序.瀏覽器的內(nèi)核是多線程的,它們在內(nèi)核制控下相互配合以保持同步,一個(gè)瀏覽器至少實(shí)現(xiàn)三個(gè)常駐線程:javascript引擎線程,GUI渲染線程,瀏覽器事件觸發(fā)線程。這些異步線程都會(huì)產(chǎn)生不同的異步的事件.
1) javascript引擎是基于事件驅(qū)動(dòng)單線程執(zhí)行的,JS引擎一直等待著任務(wù)隊(duì)列中任務(wù)的到來,然后加以處理,瀏覽器無論什么時(shí)候都只有一個(gè)JS線程在運(yùn)行JS程序。
2) GUI渲染線程負(fù)責(zé)渲染瀏覽器界面,當(dāng)界面需要重繪(Repaint)或由于某種操作引發(fā)回流(reflow)時(shí),該線程就會(huì)執(zhí)行。但需要注意 GUI渲染線程與JS引擎是互斥的,當(dāng)JS引擎執(zhí)行時(shí)GUI線程會(huì)被掛起,GUI更新會(huì)被保存在一個(gè)隊(duì)列中等到JS引擎空閑時(shí)立即被執(zhí)行。
3) 事件觸發(fā)線程,當(dāng)一個(gè)事件被觸發(fā)時(shí)該線程會(huì)把事件添加到待處理隊(duì)列的隊(duì)尾,等待JS引擎的處理。這些事件可來自JavaScript引擎當(dāng)前執(zhí)行的代碼塊如setTimeOut、也可來自瀏覽器內(nèi)核的其他線程如鼠標(biāo)點(diǎn)擊、AJAX異步請求等,但由于JS的單線程關(guān)系所有這些事件都得排隊(duì)等待JS引擎處理。(當(dāng)線程中沒有執(zhí)行任何同步代碼的前提下才會(huì)執(zhí)行異步代碼)
當(dāng)程序啟動(dòng)時(shí), 一個(gè)進(jìn)程被創(chuàng)建,同時(shí)也運(yùn)行一個(gè)線程, 即為主線程,js的運(yùn)行機(jī)制為單線程
程序中跑兩個(gè)線程,一個(gè)負(fù)責(zé)程序本身的運(yùn)行,作為主線程; 另一個(gè)負(fù)責(zé)主線程與其他線程的的通信,被稱為“Event Loop 線程" 。每當(dāng)遇到異步任務(wù),交給 EventLoop 線程,然后自己往后運(yùn)行,等到主線程運(yùn)行完后,再去 EventLoop 線程拿結(jié)果。
1)所有任務(wù)都在主線程上執(zhí)行,形成一個(gè)執(zhí)行棧(execution context stack)。
2)主線程之外,還存在一個(gè)"任務(wù)隊(duì)列"(task queue)。系統(tǒng)把異步任務(wù)放到"任務(wù)隊(duì)列"之中,然后繼續(xù)執(zhí)行后續(xù)的任務(wù)。
3)一旦"執(zhí)行棧"中的所有任務(wù)執(zhí)行完畢,系統(tǒng)就會(huì)讀取"任務(wù)隊(duì)列"。如果這個(gè)時(shí)候,異步任務(wù)已經(jīng)結(jié)束了等待狀態(tài),就會(huì)從"任務(wù)隊(duì)列"進(jìn)入執(zhí)行棧,恢復(fù)執(zhí)行。
4)主線程不斷重復(fù)上面的第三步。
"回調(diào)函數(shù)"(callback),就是那些會(huì)被主線程掛起來的代碼。異步任務(wù)必須指定回調(diào)函數(shù),當(dāng)異步任務(wù)從"任務(wù)隊(duì)列"回到執(zhí)行棧,回調(diào)函數(shù)就會(huì)執(zhí)行。"任務(wù)隊(duì)列"是一個(gè)先進(jìn)先出的數(shù)據(jù)結(jié)構(gòu),排在前面的事件,優(yōu)先返回主線程。主線程的讀取過程基本上是自動(dòng)的,只要執(zhí)行棧一清空,"任務(wù)隊(duì)列"上第一位的事件就自動(dòng)返回主線程。
主線程從"任務(wù)隊(duì)列"中讀取事件,這個(gè)過程是循環(huán)不斷的,所以整個(gè)的這種運(yùn)行機(jī)制又稱為Event Loop。
從主線程的角度看,一個(gè)異步過程包括下面兩個(gè)要素:
發(fā)起函數(shù)(或叫注冊函數(shù))A
回調(diào)函數(shù)callbackFn
它們都是在主線程上調(diào)用的,其中注冊函數(shù)用來發(fā)起異步過程,回調(diào)函數(shù)用來處理結(jié)果。
異步進(jìn)程有:
類似onclick等,由瀏覽器內(nèi)核的DOM binding模塊處理,事件觸發(fā)時(shí),回調(diào)函數(shù)添加到任務(wù)隊(duì)列中;
setTimeout等,由瀏覽器內(nèi)核的Timer模塊處理,時(shí)間到達(dá)時(shí),回調(diào)函數(shù)添加到任務(wù)隊(duì)列中;
Ajax,由瀏覽器內(nèi)核的Network模塊處理,網(wǎng)絡(luò)請求返回后,添加到任務(wù)隊(duì)列中。
例如setTimeout(fn, 1000),其中的setTimeout就是異步過程的發(fā)起函數(shù),fn是回調(diào)函數(shù)。用一句話概括:工作線程將消息放到消息隊(duì)列,主線程通過事件循環(huán)過程去取消息。
消息隊(duì)列:消息隊(duì)列是一個(gè)先進(jìn)先出的隊(duì)列,它里面存放著各種消息。
事件循環(huán):事件循環(huán)是指主線程重復(fù)從消息隊(duì)列中取消息、執(zhí)行的過程。
流程如下:
1) 主線程讀取js代碼, 形成相應(yīng)的堆和執(zhí)行棧, 執(zhí)行同步任務(wù)
2) 當(dāng)主線程遇到異步任務(wù),,指定給異步進(jìn)程處理, 同時(shí)繼續(xù)執(zhí)行同步任務(wù)
3) 當(dāng)異步進(jìn)程處理完畢后, 將相應(yīng)的異步任務(wù)推入到任務(wù)隊(duì)列首部
4) 主線程任務(wù)處理完畢后,,查詢?nèi)蝿?wù)隊(duì)列,則取出一個(gè)任務(wù)隊(duì)列推入到主線程的執(zhí)行棧
5) 重復(fù)執(zhí)行第2、3、4步,這就稱為事件循環(huán)
JS-Web-API 知識(shí)點(diǎn)與高頻考題解析
BOM
BOM(瀏覽器對象模型)是瀏覽器本身的一些信息的設(shè)置和獲取,例如獲取瀏覽器的寬度、高度,設(shè)置讓瀏覽器跳轉(zhuǎn)到哪個(gè)地址。?
navigator:?獲取瀏覽器特性(即俗稱的UA)然后識(shí)別客戶端?
location:?獲取網(wǎng)址、協(xié)議、path、參數(shù)、hash 等?
history: 操作瀏覽器的歷史紀(jì)錄,(前進(jìn),后退等功能)
1.什么是window對象? 什么是document對象?
window:它是一個(gè)頂層對象,而不是另一個(gè)對象的屬性,即瀏覽器的窗口。?
document:代表整個(gè)HTML 文檔,可用來訪問頁面中的所有元素?
Window 對象表示當(dāng)前瀏覽器的窗口,是JavaScript的頂級對象。我們創(chuàng)建的所有對象、函數(shù)、變量都是 Window 對象的成員。?
Window 對象的方法和屬性是在全局范圍內(nèi)有效的。?
Document 對象是 HTML 文檔的根節(jié)點(diǎn)與所有其他節(jié)點(diǎn)(元素節(jié)點(diǎn),文本節(jié)點(diǎn),屬性節(jié)點(diǎn), 注釋節(jié)點(diǎn))?
Document 對象使我們可以通過腳本對 HTML 頁面中的所有元素進(jìn)行訪問?
Document 對象是 Window 對象的一部分,可通過 window.document 屬性對其進(jìn)行訪問
2.事件是?IE與火狐的事件機(jī)制有什么區(qū)別? 如何阻止冒泡?
1) 我們在網(wǎng)頁中的某個(gè)操作(有的操作對應(yīng)多個(gè)事件)。例如:當(dāng)我們點(diǎn)擊一個(gè)按鈕就會(huì)產(chǎn)生一個(gè)事件。是可以被 JavaScript 偵測到的行為。?
2) 事件處理機(jī)制:IE是事件冒泡、Firefox同時(shí)支持兩種事件模型,也就是:捕獲型事件和冒泡型事件;?
3) ev.stopPropagation();(舊ie的方法 ev.cancelBubble = true;)
3.解釋一下事件代理
事件代理的原理其實(shí)就和作用域鏈的原理差不多,但是事件代理是利用事件的冒泡原理來實(shí)現(xiàn)的,事件代理就是通過給祖先元素添加事件,通過事件目標(biāo)對象開始向上查找找到匹配的子節(jié)點(diǎn)為止,如果找不到則到綁定事件的那個(gè)祖先元素為止,找到了就觸發(fā)事件,并且可以通過js中call和apply來改變觸發(fā)事件函數(shù)中的this為當(dāng)前綁定節(jié)點(diǎn),也是通過一層一層逐層向上的方式進(jìn)行匹配查找而觸發(fā)對應(yīng)事件,好處就是可以使后添加的dom元素也同樣有之前存在元素的事件,jquery中可以使用on,delegate,live實(shí)現(xiàn)的,不過在jquery1.7版本以后吧live給廢除了,原因就是live綁定事件的祖先元素是整個(gè)html頁面的根節(jié)點(diǎn),所以性能消耗比較大,在后邊的版本中給刪除了,使用on,delegate代替
優(yōu)點(diǎn):
使代碼簡潔?
減少瀏覽器的內(nèi)存占用
缺點(diǎn):
使用不當(dāng)會(huì)造成事件在不應(yīng)該觸發(fā)時(shí)觸發(fā)
function? bindEvent (elem, type, selector, fn) {
? ??????// 這樣處理,可接收兩種調(diào)用方式?bindEvent(div1, 'click', 'a', function () {...}) 和bindEvent(div1, 'click', function () {...}) 這兩種?
? ??????if(fn ==null) {
? ???????????fn = selector
? ???????????selector =null
? ??????}
? ??????// 綁定事件?
? ??????elem.addEventListener(type,function(e){
? ??????????var target
? ??????????if(selector) {
? ??????????????// 有 selector 說明需要做事件代理
? ???????????????// 獲取觸發(fā)時(shí)間的元素,即?
? ??????????????e.target target = e.target
? ??????????????// 看是否符合 selector 這個(gè)條件?
? ??????????????if(target.matches(selector)) {
? ???????????????????fn.call(target, e)
? ???????????????}
? ??? ? ? ???}else{
? ??????????????// 無 selector ,說明不需要事件代理
? ???????????????fn(e)
? ???????????}
? ???????})
? ???}
? ??// 使用代理,bindEvent 多一個(gè) 'a' 參數(shù)
?? ??var div1 =document.getElementById('div1')?
? ??bindEvent(div1,'click','a',function(e){
? ??????console.log(this.innerHTML)?
? ??})
? ??// 不使用代理?
? ??var a =document.getElementById('a1')?
? ??bindEvent(div1,'click',function(e){
? ??????console.log(a.innerHTML)
? ???})
4.offsetWidth/offsetHeight,clientWidth/clientHeight與scrollWidth/scrollHeight的區(qū)別
offsetWidth/offsetHeight返回值包含content + padding + border,效果與e.getBoundingClientRect()相同?
clientWidth/clientHeight返回值只包含content + padding,如果有滾動(dòng)條,也不包含滾動(dòng)條?
scrollWidth/scrollHeight返回值包含content + padding + 溢出內(nèi)容的尺寸
5.focus/blur與focusin/focusout的區(qū)別與聯(lián)系
focus/blur不冒泡,focusin/focusout冒泡?
focus/blur兼容性好,focusin/focusout在除FireFox外的瀏覽器下都保持良好兼容性,如需使用事件托管,可考慮在FireFox下使用事件捕獲elem.addEventListener('focus', handler, true)
可獲得焦點(diǎn)的元素:
window?
鏈接被點(diǎn)擊或鍵盤操作?
表單空間被點(diǎn)擊或鍵盤操作?
設(shè)置tabindex屬性的元素被點(diǎn)擊或鍵盤操作
6.mouseover/mouseout與mouseenter/mouseleave的區(qū)別與聯(lián)系
mouseover/mouseout是標(biāo)準(zhǔn)事件,所有瀏覽器都支持;mouseenter/mouseleave是IE5.5引入的特有事件后來被DOM3標(biāo)準(zhǔn)采納,現(xiàn)代標(biāo)準(zhǔn)瀏覽器也支持?
mouseover/mouseout是冒泡事件;mouseenter/mouseleave不冒泡。需要為多個(gè)元素監(jiān)聽鼠標(biāo)移入/出事件時(shí),推薦mouseover/mouseout托管,提高性能?
標(biāo)準(zhǔn)事件模型中event.target表示發(fā)生移入/出的元素,vent.relatedTarget對應(yīng)移出/如元素;在老IE中event.srcElement表示發(fā)生移入/出的元素,event.toElement表示移出的目標(biāo)元素,event.fromElement表示移入時(shí)的來源元素
7.介紹DOM0,DOM2,DOM3事件處理方式區(qū)別
DOM0級事件處理方式:
btn.onclick = func;?
btn.onclick = null;
DOM2級事件處理方式:
btn.addEventListener('click',func,false);
btn.removeEventListener('click',func,false);
btn.attachEvent("onclick",func);
btn.detachEvent("onclick",func);
DOM3級事件處理方式:
eventUtil.addListener(input, "textInput", func);?
eventUtil 是自定義對象,textInput 是DOM3級事件
8.事件的三個(gè)階段
捕獲、目標(biāo)、冒泡
js的冒泡(Bubbling Event)和捕獲(Capture Event)的區(qū)別
冒泡型事件:事件按照從最特定的事件目標(biāo)到最不特定的事件目標(biāo)(document對象)的順序觸發(fā)。?
捕獲型事件(event capturing):事件從最不精確的對象(document 對象)開始觸發(fā),然后到最精確(也可以在窗口級別捕獲事件,不過必須由開發(fā)人員特別指定)。?
DOM事件流:同時(shí)支持兩種事件模型:捕獲型事件和冒泡型事件,但是,捕獲型事件先發(fā)生。兩種事件流會(huì)觸及DOM中的所有對象,從document對象開始,也在document對象結(jié)束。
事件捕獲
當(dāng)你使用事件捕獲時(shí),父級元素先觸發(fā),子級元素后觸發(fā),即div先觸發(fā),p后觸發(fā)。
事件冒泡
當(dāng)你使用事件冒泡時(shí),子級元素先觸發(fā),父級元素后觸發(fā),即p先觸發(fā),div后觸發(fā)。
阻止冒泡
在W3c中,使用stopPropagation()方法
在IE下設(shè)置cancelBubble = true;
在捕獲的過程中stopPropagation();后,后面的冒泡過程也不會(huì)發(fā)生了。
阻止捕獲
阻止事件的默認(rèn)行為,例如click?后的跳轉(zhuǎn)
在W3c中,使用preventDefault()方法;
在IE下設(shè)置window.event.returnValue = false;
9.介紹事件“捕獲”和“冒泡”執(zhí)行順序和事件的執(zhí)行次數(shù)?
按照W3C標(biāo)準(zhǔn)的事件:首是進(jìn)入捕獲階段,直到達(dá)到目標(biāo)元素,再進(jìn)入冒泡階段?
事件執(zhí)行次數(shù)(DOM2-addEventListener):元素上綁定事件的個(gè)數(shù)?
注意1:前提是事件被確實(shí)觸發(fā)?
注意2:事件綁定幾次就算幾個(gè)事件,即使類型和功能完全一樣也不會(huì)“覆蓋”?
事件執(zhí)行順序:判斷的關(guān)鍵是否目標(biāo)元素?
非目標(biāo)元素:根據(jù)W3C的標(biāo)準(zhǔn)執(zhí)行:捕獲->目標(biāo)元素->冒泡(不依據(jù)事件綁定順序)?
目標(biāo)元素:依據(jù)事件綁定順序:先綁定的事件先執(zhí)行(不依據(jù)捕獲冒泡標(biāo)準(zhǔn))?
最終順序:父元素捕獲->目標(biāo)元素事件1->目標(biāo)元素事件2->子元素捕獲->子元素冒泡->父元素冒泡?
注意:子元素事件執(zhí)行前提 事件確實(shí)“落”到子元素布局區(qū)域上,而不是簡單的具有嵌套關(guān)系?
在一個(gè)DOM上同時(shí)綁定兩個(gè)點(diǎn)擊事件:一個(gè)用捕獲,一個(gè)用冒泡。事件會(huì)執(zhí)行幾次,先執(zhí)行冒泡還是捕獲?
該DOM上的事件如果被觸發(fā),會(huì)執(zhí)行兩次(執(zhí)行次數(shù)等于綁定次數(shù))?
如果該DOM是目標(biāo)元素,則按事件綁定順序執(zhí)行,不區(qū)分冒泡/捕獲?
如果該DOM是處于事件流中的非目標(biāo)元素,則先執(zhí)行捕獲,后執(zhí)行冒泡
10.window.onload 和 document.DOMContentLoaded ?(注:$(document).ready()) ?的區(qū)別?
一般情況下,DOMContentLoaded事件要在window.onload之前執(zhí)行,當(dāng)DOM樹構(gòu)建完成的時(shí)候就會(huì)執(zhí)行DOMContentLoaded事件,而window.onload是在頁面載入完成的時(shí)候,才執(zhí)行,這其中包括圖片等元素。大多數(shù)時(shí)候我們只是想在DOM樹構(gòu)建完成后,綁定事件到元素,我們并不需要圖片元素,加上有時(shí)候加載外域圖片的速度非常緩慢。
DOM
講 DOM 先從 HTML 講起,講 HTML 先從 XML 講起。XML 是一種可擴(kuò)展的標(biāo)記語言,所謂可擴(kuò)展就是它可以描述任何結(jié)構(gòu)化的數(shù)據(jù),它是一棵樹!
1.documen.write和 innerHTML的區(qū)別
document.write只能重繪整個(gè)頁面?
innerHTML可以重繪頁面的一部分
2.DOM操作——怎樣添加、移除、移動(dòng)、復(fù)制、創(chuàng)建和查找節(jié)點(diǎn)?
1)創(chuàng)建新節(jié)點(diǎn)
createDocumentFragment()//創(chuàng)建一個(gè)DOM片段 createElement()//創(chuàng)建一個(gè)具體的元素 createTextNode()//創(chuàng)建一個(gè)文本節(jié)點(diǎn)
2)添加、移除、替換、插入
appendChild()removeChild()replaceChild()insertBefore()//在已有的子節(jié)點(diǎn)前插入一個(gè)新的子節(jié)點(diǎn)
3)查找
getElementsByTagName()//通過標(biāo)簽名稱 getElementsByName()//通過元素的Name屬性的值(IE容錯(cuò)能力較強(qiáng),會(huì)得到一個(gè)數(shù)組,其中包括id等于name值的) getElementById()//通過元素Id,唯一性
3.attribute和property的區(qū)別是什么?
attribute是dom元素在文檔中作為html標(biāo)簽擁有的屬性;?
property就是dom元素在js中作為對象擁有的屬性。?
所以:?
對于html的標(biāo)準(zhǔn)屬性來說,attribute和property是同步的,是會(huì)自動(dòng)更新的,?
但是對于自定義的屬性來說,他們是不同步的,
4.src和href的區(qū)別
src用于替換當(dāng)前元素,href用于在當(dāng)前文檔和引用資源之間確立聯(lián)系。?
src是source的縮寫,指向外部資源的位置,指向的內(nèi)容將會(huì)嵌入到文檔中當(dāng)前標(biāo)簽所在位置;在請求src資源時(shí)會(huì)將其指向的資源下載并應(yīng)用到文檔內(nèi),當(dāng)瀏覽器解析到該元素時(shí),會(huì)暫停其他資源的下載和處理,直到將該資源加載、編譯、執(zhí)行完畢,圖片和框架等元素也如此,類似于將所指向資源嵌入當(dāng)前標(biāo)簽內(nèi)。這也是為什么將js腳本放在底部而不是頭部。?
Src source,指向外部資源的位置,如果我們添加瀏覽器會(huì)暫停其他資源的下載和處理,直到該資源加載,編譯,執(zhí)行完畢(圖片和框架也是如此),這也就是為什么js腳本要放在底部。?
src用于替換當(dāng)前元素,href用于在當(dāng)前文檔和引入資源之間建立聯(lián)系。