前端面試基礎篇 二(附答案)

1.數組去重

答:

法一:indexOf循環去重

法二:ES6 Set去重;Array.from(new Set(array))

法三:Object 鍵值對去重;把數組的值存成 Object 的 key 值,比如 Object[value1] = true,在判斷另一個值的時候,如果 Object[value2]存在的話,就說明該值是重複的。

 

2.去除字符串首尾空格

答:

使用正則(^\s*)|(\s*$)即可

 

3.性能優化

答:

減少HTTP請求

使用內容發佈網絡(CDN)

添加本地緩存

壓縮資源文件

將CSS樣式表放在頂部,把javascript放在底部(瀏覽器的運行機制決定)

避免使用CSS表達式

減少DNS查詢

使用外部javascript和CSS

避免重定向

圖片lazyLoad

精靈圖

 

4.閉包 有什麼用

答:

(1)什麼是閉包:

閉包是指有權訪問另外一個函數作用域中的變量的函數。

閉包就是函數的局部變量集合,只是這些局部變量在函數返回後會繼續存在。閉包就是就是函數的“堆棧”在函數返回後並不釋放,我們也可以理解爲這些函數堆棧並不在棧上分配而是在堆上分配。當在一個函數內定義另外一個函數就會產生閉包。

(2)爲什麼要用:

匿名自執行函數:我們知道所有的變量,如果不加上var關鍵字,則默認的會添加到全局對象的屬性上去,這樣的臨時變量加入全局對象有很多壞處,比如:別的函數可能誤用這些變量;造成全局對象過於龐大,影響訪問速度(因爲變量的取值是需要從原型鏈上遍歷的)。除了每次使用變量都是用var關鍵字外,我們在實際情況下經常遇到這樣一種情況,即有的函數只需要執行一次,其內部變量無需維護,可以用閉包。

結果緩存:我們開發中會碰到很多情況,設想我們有一個處理過程很耗時的函數對象,每次調用都會花費很長時間,那麼我們就需要將計算出來的值存儲起來,當調用這個函數的時候,首先在緩存中查找,如果找不到,則進行計算,然後更新緩存並返回值,如果找到了,直接返回查找到的值即可。閉包正是可以做到這一點,因爲它不會釋放外部的引用,從而函數內部的值可以得以保留。

封裝:實現類和繼承等。

 

5.JS實現跨域

答:

JSONP:通過動態創建script,再請求一個帶參網址實現跨域通信。document.domain + iframe跨域:兩個頁面都通過js強制設置document.domain爲基礎主域,就實現了同域。

location.hash + iframe跨域:a欲與b跨域相互通信,通過中間頁c來實現。 三個頁面,不同域之間利用iframe的location.hash傳值,相同域之間直接js訪問來通信。

window.name + iframe跨域:通過iframe的src屬性由外域轉向本地域,跨域數據即由iframe的window.name從外域傳遞到本地域。

postMessage跨域:可以跨域操作的window屬性之一。

CORS:服務端設置Access-Control-Allow-Origin即可,前端無須設置,若要帶cookie請求,前後端都需要設置。

代理跨域:啓一個代理服務器,實現數據的轉發

參考https://segmentfault.com/a/1190000011145364

 

6.Js基本數據類型

答:

undefined、null、number、boolean、string、symbol

 

7.暫停死區

答:

使用let、const命令聲明變量之前,該變量都是不可用的。這在語法上,稱爲“暫時性死區”

 

8.ant-design優點和缺點

答:

優點:組件非常全面,樣式效果也都比較不錯。

缺點:框架自定義程度低,默認UI風格修改困難。

 

9.vue的生命週期

答:

Vue實例有一個完整的生命週期,也就是從開始創建、初始化數據、編譯模板、掛載Dom、渲染→更新→渲染、銷燬等一系列過程,我們稱這是Vue的生命週期。通俗說就是Vue實例從創建到銷燬的過程,就是生命週期。

每一個組件或者實例都會經歷一個完整的生命週期,總共分爲三個階段:初始化、運行中、銷燬。

實例、組件通過new Vue() 創建出來之後會初始化事件和生命週期,然後就會執行beforeCreate鉤子函數,這個時候,數據還沒有掛載呢,只是一個空殼,無法訪問到數據和真實的dom,一般不做操作

掛載數據,綁定事件等等,然後執行created函數,這個時候已經可以使用到數據,也可以更改數據,在這裏更改數據不會觸發updated函數,在這裏可以在渲染前倒數第二次更改數據的機會,不會觸發其他的鉤子函數,一般可以在這裏做初始數據的獲取

接下來開始找實例或者組件對應的模板,編譯模板爲虛擬dom放入到render函數中準備渲染,然後執行beforeMount鉤子函數,在這個函數中虛擬dom已經創建完成,馬上就要渲染,在這裏也可以更改數據,不會觸發updated,在這裏可以在渲染前最後一次更改數據的機會,不會觸發其他的鉤子函數,一般可以在這裏做初始數據的獲取

接下來開始render,渲染出真實dom,然後執行mounted鉤子函數,此時,組件已經出現在頁面中,數據、真實dom都已經處理好了,事件都已經掛載好了,可以在這裏操作真實dom等事情...

當組件或實例的數據更改之後,會立即執行beforeUpdate,然後vue的虛擬dom機制會重新構建虛擬dom與上一次的虛擬dom樹利用diff算法進行對比之後重新渲染,一般不做什麼事兒

當更新完成後,執行updated,數據已經更改完成,dom也重新render完成,可以操作更新後的虛擬dom

當經過某種途徑調用$destroy方法後,立即執行beforeDestroy,一般在這裏做一些善後工作,例如清除計時器、清除非指令綁定的事件等等

組件的數據綁定、監聽...去掉後只剩下dom空殼,這個時候,執行destroyed,在這裏做善後工作也可以

參考:https://segmentfault.com/a/1190000008010666

 

10.簡單介紹一下symbol

答:

Symbol是ES6 的新增屬性,代表用給定名稱作爲唯一標識,這種類型的值可以這樣創建,let id=symbol(“id”)

Symbl確保唯一,即使採用相同的名稱,也會產生不同的值,我們創建一個字段,僅爲知道對應symbol的人能訪問,使用symbol很有用,symbol並不是100%隱藏,有內置方法Object.getOwnPropertySymbols(obj)可以獲得所有的symbol。 
也有一個方法Reflect.ownKeys(obj)返回對象所有的鍵,包括symbol。

所以並不是真正隱藏。但大多數庫內置方法和語法結構遵循通用約定他們是隱藏的,

 

11.介紹一下promise,及其底層如何實現

答:

Promise是一個對象,保存着未來將要結束的事件,她有兩個特徵:

1、對象的狀態不受外部影響,Promise對象代表一個異步操作,有三種狀態,pending進行中,fulfilled已成功,rejected已失敗,只有異步操作的結果,纔可以決定當前是哪一種狀態,任何其他操作都無法改變這個狀態,這也就是promise名字的由來

2、一旦狀態改變,就不會再變,promise對象狀態改變只有兩種可能,從pending改到fulfilled或者從pending改到rejected,只要這兩種情況發生,狀態就凝固了,不會再改變,這個時候就稱爲定型resolved,

 

12.ES6箭頭函數的特性

答:

箭頭函數與普通函數的區別在於:

1、箭頭函數沒有this,所以需要通過查找作用域鏈來確定this的值,這就意味着如果箭頭函數被非箭頭函數包含,this綁定的就是最近一層非箭頭函數的this,

2、箭頭函數沒有自己的arguments對象,但是可以訪問外圍函數的arguments對象

3、不能通過new關鍵字調用,同樣也沒有new.target值和原型

 

13.給出以下代碼,輸出的結果是什麼?原因?

答:

for(var i=0;i<5;i++) { 
    setTimeout(function(){ 
        console.log(i);     //後輸出5次
    },1000); 
}
console.log(i)     //先輸出

//5   
//(5)5   5次

每次for循環的時候setTimeout都會執行,但是裏面的function則不會執行被放入任務隊列,因此放了5次;

for循環的5次執行完之後不到1000毫秒;   先輸出一個5

1000毫秒後全部執行任務隊列中的函數,再輸出5個5

 

14.js對象類型,基本對象類型以及引用對象類型的區別

答:

基本數據類型:按值訪問,可操作保存在變量中的實際的值。基本類型值指的是簡單的數據段。基本數據類型有這六種:undefined、null、string、number、boolean、symbol。

引用類型:當複製保存着對象的某個變量時,操作的是對象的引用,但在爲對象添加屬性時,操作的是實際的對象。引用類型值指那些可能爲多個值構成的對象。

引用類型有這幾種:Object、Array、RegExp、Date、Function、特殊的基本包裝類型(String、Number、Boolean)以及單體內置對象(Global、Math)。

 

15.怎麼實現一個計算一年中有多少周?

答:

首先你得知道是不是閏年,也就是一年是365還是366.

其次你得知道當年1月1號是周幾。假如是週五,一年365天把1號 2號3號減去,也就是把第一個不到一週的天數減去等於362
還得知道最後一天是周幾,加入是週五,需要把週一到週五減去,也就是362-5=357.正常情況 357這個數計算出來是7的倍數。357/7=51 。即爲週數。

 

16.面向對象的繼承方式

答:

原型鏈繼承

核心: 將父類的實例作爲子類的原型

特點:非常純粹的繼承關係,實例是子類的實例,也是父類的實例

父類新增原型方法/原型屬性,子類都能訪問到

簡單,易於實現

缺點:要想爲子類新增屬性和方法,不能放到構造器中

無法實現多繼承

來自原型對象的所有屬性被所有實例共享

創建子類實例時,無法向父類構造函數傳參

 

構造繼承

核心:使用父類的構造函數來增強子類實例,等於是複製父類的實例屬性給子類(沒用到原型)

特點:解決了子類實例共享父類引用屬性的問題

創建子類實例時,可以向父類傳遞參數

可以實現多繼承(call多個父類對象)

缺點:實例並不是父類的實例,只是子類的實例

只能繼承父類的實例屬性和方法,不能繼承原型屬性/方法

無法實現函數複用,每個子類都有父類實例函數的副本,影響性能

 

實例繼承

核心:爲父類實例添加新特性,作爲子類實例返回

特點:不限制調用方式,不管是new 子類()還是子類(),返回的對象具有相同的效果

缺點:實例是父類的實例,不是子類的實例

不支持多繼承

 

拷貝繼承

特點:

支持多繼承

缺點:

效率較低,內存佔用高(因爲要拷貝父類的屬性)

 

組合繼承

核心:通過調用父類構造,繼承父類的屬性並保留傳參的優點,然後通過將父類實例作爲子類原型,實現函數複用

特點:

可以繼承實例屬性/方法,也可以繼承原型屬性/方法

既是子類的實例,也是父類的實例

不存在引用屬性共享問題

可傳參

函數可複用

 

寄生組合繼承

核心:通過調用父類構造,繼承父類的屬性並保留傳參的優點,然後通過將父類實例作爲子類原型,實現函數複用

參考https://www.cnblogs.com/humin/p/4556820.html

 

17.class

答:

ES6提供了更接近傳統語言的寫法,引入了Class(類)這個概念,作爲對象的模板。通過class關鍵字,可以定義類。

 

 

前端面試基礎篇 一:https://blog.csdn.net/caoyan0829/article/details/89888629

前端面試核心篇 :https://blog.csdn.net/caoyan0829/article/details/90022103

 

此文章參考牛客面經彙總

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章