高頻面試題 四問

一、對象創(chuàng)建的方式有哪些??
(1)第一種是工廠模式
????工廠模式的主要工作原理是用函數(shù)來封裝創(chuàng)建對象的細(xì)節(jié)
????從而通過調(diào)用函數(shù)來達(dá)到復(fù)用的目的
????但是它有一個很大的問題就是創(chuàng)建出來的對象無法和某個類型聯(lián)系起來
????它只是簡單的封裝了復(fù)用代碼
????而沒有建立起對象和類型間的關(guān)系
(2)第二種是構(gòu)造函數(shù)模式
????js 中每一個函數(shù)都可以作為構(gòu)造函數(shù)
????只要一個函數(shù)是通過 new 來調(diào)用的
????那么就可以把它稱為構(gòu)造函數(shù)
????執(zhí)行構(gòu)造函數(shù)首先會創(chuàng)建一個對象
????然后將對象的原型指向構(gòu)造函數(shù)的 prototype 屬性
????然后將執(zhí)行上下文中的 this 指向這個對象
????最后再執(zhí)行整個函數(shù)
????如果返回值不是對象
????則返回新建的對象
????因為 this 的值指向了新建的對象
????因此可以使用 this 給對象賦值
????構(gòu)造函數(shù)模式相對于工廠模式的優(yōu)點是
????所創(chuàng)建的對象和構(gòu)造函數(shù)建立起了聯(lián)系
????因此可以通過原型來識別對象的類型
????但是構(gòu)造函數(shù)存在一個缺點就是
????造成了不必要的函數(shù)對象的創(chuàng)建
????因為在 js 中函數(shù)也是一個對象
????因此如果對象屬性中如果包含函數(shù)的話
????那么每次都會新建一個函數(shù)對象
????浪費了不必要的內(nèi)存空間
????因為函數(shù)是所有的實例都可以通用的
(3)第三種模式是原型模式
????因為每一個函數(shù)都有一個 prototype 屬性
????這個屬性是一個對象
????它包含了通過構(gòu)造函數(shù)創(chuàng)建的所有實例都能共享的屬性和方法
????因此可以使用原型對象來添加公用屬性和方法
????從而實現(xiàn)代碼的復(fù)用
????這種方式相對于構(gòu)造函數(shù)模式來說
????解決了函數(shù)對象的復(fù)用問題
????但是這種模式也存在一些問題
????一個是沒有辦法通過傳入?yún)?shù)來初始化值
????另一個是如果存在一個引用類型如 Array 這樣的值
????那么所有的實例將共享一個對象
????一個實例對引用類型值的改變會影響所有的實例
(4)第四種模式是組合使用構(gòu)造函數(shù)模式和原型模式
????這是創(chuàng)建自定義類型的最常見方式
????因為構(gòu)造函數(shù)模式和原型模式分開使用都存在一些問題
????因此可以組合使用這兩種模式
????通過構(gòu)造函數(shù)來初始化對象的屬性
????通過原型對象來實現(xiàn)函數(shù)方法的復(fù)用
????這種方法很好的解決了兩種模式單獨使用時的缺點
????但是有一點不足的就是
????因為使用了兩種不同的模式
????所以對于代碼的封裝性不夠好
(5)第五種模式是動態(tài)原型模式
????這一種模式將原型方法賦值的創(chuàng)建過程移動到了構(gòu)造函數(shù)的內(nèi)部
????通過對屬性是否存在的判斷
????可以實現(xiàn)僅在第一次調(diào)用函數(shù)時對原型對象賦值一次的效果
????這一種方式很好地對上面的混合模式進行了封裝
(6)第六種模式是寄生構(gòu)造函數(shù)模式
????這一種模式和工廠模式的實現(xiàn)基本相同
????我對這個模式的理解是
????它主要是基于一個已有的類型
????在實例化時對實例化的對象進行擴展
????這樣既不用修改原來的構(gòu)造函數(shù)
????也達(dá)到了擴展對象的目的
????它的一個缺點和工廠模式一樣
????無法實現(xiàn)對象的識別
二、對象繼承的方式有哪些?
(1)第一種是以原型鏈的方式來實現(xiàn)繼承
????但是這種實現(xiàn)方式存在的缺點是
????在包含有引用類型的數(shù)據(jù)時
????會被所有的實例對象所共享
????容易造成修改的混亂
????還有就是在創(chuàng)建子類型的時候不能向超類型傳遞參數(shù)
(2)第二種方式是使用借用構(gòu)造函數(shù)的方式
????這種方式是通過在子類型的函數(shù)中調(diào)用超類型的構(gòu)造函數(shù)來實現(xiàn)的
????這一種方法解決了不能向超類型傳遞參數(shù)的缺點
????但是它存在的一個問題就是無法實現(xiàn)函數(shù)方法的復(fù)用
????并且超類型原型定義的方法子類型也沒有辦法訪問到
(3)第三種方式是組合繼承
????組合繼承是將原型鏈和借用構(gòu)造函數(shù)組合起來使用的一種方式
????通過借用構(gòu)造函數(shù)的方式來實現(xiàn)類型的屬性的繼承
????通過將子類型的原型設(shè)置為超類型的實例來實現(xiàn)方法的繼承
????這種方式解決了上面的兩種模式單獨使用時的問題
????但是由于我們是以超類型的實例來作為子類型的原型
????所以調(diào)用了兩次超類的構(gòu)造函數(shù)
????造成了子類型的原型中多了很多不必要的屬性
(4)第四種方式是原型式繼承
????原型式繼承的主要思路就是基于已有的對象來創(chuàng)建新的對象
????實現(xiàn)的原理是
????向函數(shù)中傳入一個對象
????然后返回一個以這個對象為原型的對象
????這種繼承的思路主要不是為了實現(xiàn)創(chuàng)造一種新的類型
????只是對某個對象實現(xiàn)一種簡單繼承
????ES5 中定義的 Object.create() 方法就是原型式繼承的實現(xiàn)
????缺點與原型鏈方式相同
(5)第五種方式是寄生式繼承
????寄生式繼承的思路是創(chuàng)建一個用于封裝繼承過程的函數(shù)
????通過傳入一個對象
????然后復(fù)制一個對象的副本
????然后對象進行擴展
????最后返回這個對象
????這個擴展的過程就可以理解是一種繼承
????這種繼承的優(yōu)點就是對一個簡單對象實現(xiàn)繼承
????如果這個對象不是自定義類型時
????缺點是沒有辦法實現(xiàn)函數(shù)的復(fù)用
(6)第六種方式是寄生式組合繼承
????組合繼承的缺點就是使用超類型的實例做為子類型的原型
????導(dǎo)致添加了不必要的原型屬性
????寄生式組合繼承的方式是使用超類型的原型的副本來作為子類型的原型
????這樣就避免了創(chuàng)建不必要的屬性
四、垃圾回收與內(nèi)存泄漏??
1、瀏覽器的垃圾回收機制??
????垃圾回收:
????JavaScript代碼運行時
????需要分配內(nèi)存空間來儲存變量和值
????當(dāng)變量不在參與運行時
????就需要系統(tǒng)收回被占用的內(nèi)存空間
????這就是垃圾回收
?????回收機制:
?????Javascript 具有自動垃圾回收機制
????會定期對那些不再使用的變量、對象所占用的內(nèi)存進行釋放
????原理就是找到不再使用的變量
????然后釋放掉其占用的內(nèi)存
?????JavaScript中存在兩種變量:
????局部變量和全局變量
????全局變量的生命周期會持續(xù)要頁面卸載;
????而局部變量聲明在函數(shù)中
????它的生命周期從函數(shù)執(zhí)行開始
????直到函數(shù)執(zhí)行結(jié)束
????在這個過程中
????局部變量會在堆或棧中存儲它們的值
????當(dāng)函數(shù)執(zhí)行結(jié)束后
????這些局部變量不再被使用
????它們所占有的空間就會被釋放
?????不過
????當(dāng)局部變量被外部函數(shù)使用時
????其中一種情況就是閉包
????在函數(shù)執(zhí)行結(jié)束后
????函數(shù)外部的變量依然指向函數(shù)內(nèi)部的局部變量
????此時局部變量依然在被使用
????所以不會回收
瀏覽器通常使用的垃圾回收方法有兩種:
????標(biāo)記清除
????引用計數(shù)
(1)標(biāo)記清除?標(biāo)記清除是瀏覽器常見的垃圾回收方式
????當(dāng)變量進入執(zhí)行環(huán)境時
????就標(biāo)記這個變量“進入環(huán)境”
????被標(biāo)記為“進入環(huán)境”的變量是不能被回收的
????因為他們正在被使用
????當(dāng)變量離開環(huán)境時
????就會被標(biāo)記為“離開環(huán)境”
????被標(biāo)記為“離開環(huán)境”的變量會被內(nèi)存釋放
?????垃圾收集器在運行的時候會給存儲在內(nèi)存中的所有變量都加上標(biāo)記
????然后
????它會去掉環(huán)境中的變量以及被環(huán)境中的變量引用的標(biāo)記
????而在此之后再被加上標(biāo)記的變量將被視為準(zhǔn)備刪除的變量
????原因是環(huán)境中的變量已經(jīng)無法訪問到這些變量了
????最后
????垃圾收集器完成內(nèi)存清除工作
????銷毀那些帶標(biāo)記的值
????并回收他們所占用的內(nèi)存空間
(2)引用計數(shù)?另外一種垃圾回收機制就是引用計數(shù)
????這個用的相對較少
????引用計數(shù)就是跟蹤記錄每個值被引用的次數(shù)
????當(dāng)聲明了一個變量并將一個引用類型賦值給該變量時
????則這個值的引用次數(shù)就是1
????相反
????如果包含對這個值引用的變量又取得了另外一個值
????則這個值的引用次數(shù)就減1
????當(dāng)這個引用次數(shù)變?yōu)?時
????說明這個變量已經(jīng)沒有價值
????因此
????在在機回收期下次再運行時
????這個變量所占有的內(nèi)存空間就會被釋放出來
?????這種方法會引起循環(huán)引用的問題
2、哪些情況會導(dǎo)致內(nèi)存泄漏 ?
?????以下四種情況會造成內(nèi)存的泄漏:
(1)意外的全局變量:
?????由于使用未聲明的變量
????而意外的創(chuàng)建了一個全局變量
????而使這個變量一直留在內(nèi)存中無法被回收
(2)被遺忘的計時器或回調(diào)函數(shù):
?????設(shè)置了 setInterval 定時器
????而忘記取消它
????如果循環(huán)函數(shù)有對外部變量的引用的話
????那么這個變量會被一直留在內(nèi)存中
????而無法被回收
(3)脫離 DOM 的引用:
?????獲取一個 DOM 元素的引用
????而后面這個元素被刪除
????由于一直保留了對這個元素的引用
????所以它也無法被回收
(4)閉包:
?????不合理的使用閉包
????從而導(dǎo)致某些變量一直被留在內(nèi)存當(dāng)中