【半月刊 4】前端高頻面試題及答案彙總

更新:謝謝你們的支持,最近折騰了一個博客官網出來,方便你們系統閱讀,後續會有更多內容和更多優化,猛戳這裏查看css

------ 如下是正文 ------html

引言

半月刊第四期來啦,這段時間 Daily-Interview-Question 新增了 14 道高頻面試題,今天就把最近半月彙總的面試題和部分答案發給你們,幫助你們查漏補缺,歡迎 加羣 互相學習。前端

更多更全的面試題和答案彙總在下面的項目中,點擊查看。vue

項目地址:Daily-Interview-Questiongit

第 40 題:在 Vue 中,子組件爲什麼不能夠修改父組件傳遞的 Prop

若是修改了,Vue 是如何監控到屬性的修改並給出警告的。github

解析:面試

  1. 子組件爲什麼不能夠修改父組件傳遞的 Prop 單向數據流,易於監測數據的流動,出現了錯誤能夠更加迅速的定位到錯誤發生的位置。
  2. 若是修改了,Vue 是如何監控到屬性的修改並給出警告的。
if (process.env.NODE_ENV !== 'production') {
      var hyphenatedKey = hyphenate(key);
      if (isReservedAttribute(hyphenatedKey) ||
          config.isReservedAttr(hyphenatedKey)) {
        warn(
          ("\"" + hyphenatedKey + "\" is a reserved attribute and cannot be used as component prop."),
          vm
        );
      }
      defineReactive$$1(props, key, value, function () {
        if (!isRoot && !isUpdatingChildComponent) {
          warn(
            "Avoid mutating a prop directly since the value will be " +
            "overwritten whenever the parent component re-renders. " +
            "Instead, use a data or computed property based on the prop's " +
            "value. Prop being mutated: \"" + key + "\"",
            vm
          );
        }
      });
    }
複製代碼

在initProps的時候,在defineReactive時經過判斷是否在開發環境,若是是開發環境,會在觸發set的時候判斷是否此key是否處於updatingChildren中被修改,若是不是,說明此修改來自子組件,觸發warning提示。vuex

須要特別注意的是,當你從子組件修改的prop屬於基礎類型時會觸發提示。 這種狀況下,你是沒法修改父組件的數據源的, 由於基礎類型賦值時是值拷貝。你直接將另外一個非基礎類型(Object, array)賦值到此key時也會觸發提示(但實際上不會影響父組件的數據源), 當你修改object的屬性時不會觸發提示,而且會修改父組件數據源的數據。segmentfault

未完待續,點擊查看更多細節:第 40 題跨域

第 41 題:下面代碼輸出什麼

var a = 10;
(function () {
    console.log(a)
    a = 5
    console.log(window.a)
    var a = 20;
    console.log(a)
})()
複製代碼

解析:

依次輸出:undefined -> 10 -> 20

在當即執行函數中,var a = 20; 語句定義了一個局部變量 a,因爲js的變量聲明提高機制,局部變量a的聲明會被提高至當即執行函數的函數體最上方,且因爲這樣的提高並不包括賦值,所以第一條打印語句會打印undefined,最後一條語句會打印20

因爲變量聲明提高,a = 5; 這條語句執行時,局部的變量a已經聲明,所以它產生的效果是對局部的變量a賦值,此時window.a 依舊是最開始賦值的10

未完待續,點擊查看更多細節:第 41題

第 42 題:實現一個 sleep 函數

好比 sleep(1000) 意味着等待1000毫秒,可從 Promise、Generator、Async/Await 等角度實現。

解析:4 種方式

//Promise
const sleep = time => {
  return new Promise(resolve => setTimeout(resolve,time))
}
sleep(1000).then(()=>{
  console.log(1)
})

//Generator
function* sleepGenerator(time) {
  yield new Promise(function(resolve,reject){
    setTimeout(resolve,time);
  })
}
sleepGenerator(1000).next().value.then(()=>{console.log(1)})

//async
function sleep(time) {
  return new Promise(resolve => setTimeout(resolve,time))
}
async function output() {
  let out = await sleep(1000);
  console.log(1);
  return out;
}
output();

//ES5
function sleep(callback,time) {
  if(typeof callback === 'function')
    setTimeout(callback,time)
}

function output(){
  console.log(1);
}
sleep(output,1000);
複製代碼

未完待續,點擊查看更多細節:第 42 題

第 43 題:使用 sort() 對數組 [3, 15, 8, 29, 102, 22] 進行排序,輸出結果

解析:

sort 函數,能夠接收一個函數,返回值是比較兩個數的相對順序的值

  1. 默認沒有函數 是按照 UTF-16 排序的,對於字母數字 你能夠利用 ASCII 進行記憶
[3, 15, 8, 29, 102, 22].sort();

// [102, 15, 22, 29, 3, 8]
複製代碼
  1. 帶函數的比較
[3, 15, 8, 29, 102, 22].sort((a,b) => {return a - b});
複製代碼
  • 返回值大於0 即a-b > 0 , a 和 b 交換位置
  • 返回值小於0 即a-b < 0 , a 和 b 位置不變
  • 返回值等於0 即a-b = 0 , a 和 b 位置不變

對於函數體返回 b-a 能夠類比上面的返回值進行交換位置

未完待續,點擊查看更多細節:第 43 題

第 44 題:介紹 HTTPS 握手過程

解析:

開始加密通訊以前,客戶端和服務器首先必須創建鏈接和交換參數,這個過程叫作握手(handshake)。

假定客戶端叫作愛麗絲,服務器叫作鮑勃,整個握手過程能夠用下圖說明。

img

握手階段分紅五步。

第一步,愛麗絲給出協議版本號、一個客戶端生成的隨機數(Client random),以及客戶端支持的加密方法。

第二步,鮑勃確認雙方使用的加密方法,並給出數字證書、以及一個服務器生成的隨機數(Server random)。

第三步,愛麗絲確認數字證書有效,而後生成一個新的隨機數(Premaster secret),並使用數字證書中的公鑰,加密這個隨機數,發給鮑勃。

第四步,鮑勃使用本身的私鑰,獲取愛麗絲髮來的隨機數(即Premaster secret)。

第五步,愛麗絲和鮑勃根據約定的加密方法,使用前面的三個隨機數,生成"對話密鑰"(session key),用來加密接下來的整個對話過程。

參考:

圖解SSL/TLS協議

SSL/TLS協議運行機制的概述

未完待續,點擊查看更多細節:第 44 題

第 45 題:HTTPS 握手過程當中,客戶端如何驗證證書的合法性

解析:

  • 一、首先什麼是HTTP協議? http協議是超文本傳輸協議,位於tcp/ip四層模型中的應用層;經過請求/響應的方式在客戶端和服務器之間進行通訊;可是缺乏安全性,http協議信息傳輸是經過明文的方式傳輸,不作任何加密,至關於在網絡上裸奔;容易被中間人惡意篡改,這種行爲叫作中間人攻擊;

  • 二、加密通訊: 爲了安全性,雙方可使用對稱加密的方式key進行信息交流,可是這種方式對稱加密祕鑰也會被攔截,也不夠安全,進而仍是存在被中間人攻擊風險; 因而人們又想出來另一種方式,使用非對稱加密的方式;使用公鑰/私鑰加解密;通訊方A發起通訊並攜帶本身的公鑰,接收方B經過公鑰來加密對稱祕鑰;而後發送給發起方A;A經過私鑰解密;雙發接下來經過對稱祕鑰來進行加密通訊;可是這種方式仍是會存在一種安全性;中間人雖然不知道發起方A的私鑰,可是能夠作到偷天換日,將攔截髮起方的公鑰key;並將本身生成的一對公/私鑰的公鑰發送給B;接收方B並不知道公鑰已經被偷偷換過;按照以前的流程,B經過公鑰加密本身生成的對稱加密祕鑰key2;發送給A; 此次通訊再次被中間人攔截,儘管後面的通訊,二者仍是用key2通訊,可是中間人已經掌握了Key2;能夠進行輕鬆的加解密;仍是存在被中間人攻擊風險;

  • 三、解決困境:權威的證書頒發機構CA來解決;

    • 3.1製做證書:做爲服務端的A,首先把本身的公鑰key1發給證書頒發機構,向證書頒發機構進行申請證書;證書頒發機構有一套本身的公私鑰,CA經過本身的私鑰來加密key1,而且經過服務端網址等信息生成一個證書籤名,證書籤名一樣使用機構的私鑰進行加密;製做完成後,機構將證書發給A;
    • 3.2校驗證書真僞:當B向服務端A發起請求通訊的時候,A再也不直接返回本身的公鑰,而是返回一個證書; 說明:各大瀏覽器和操做系統已經維護了全部的權威證書機構的名稱和公鑰。B只須要知道是哪一個權威機構發的證書,使用對應的機構公鑰,就能夠解密出證書籤名;接下來,B使用一樣的規則,生成本身的證書籤名,若是兩個簽名是一致的,說明證書是有效的; 簽名驗證成功後,B就能夠再次利用機構的公鑰,解密出A的公鑰key1;接下來的操做,就是和以前同樣的流程了;
    • 3.3:中間人是否會攔截髮送假證書到B呢? 由於證書的簽名是由服務器端網址等信息生成的,而且經過第三方機構的私鑰加密中間人沒法篡改; 因此最關鍵的問題是證書籤名的真僞;
  • 四、https主要的思想是在http基礎上增長了ssl安全層,即以上認證過程。

未完待續,點擊查看更多細節:第 45 題

第 46 題:輸出如下代碼執行的結果並解釋爲何

var obj = {
    '2': 3,
    '3': 4,
    'length': 2,
    'splice': Array.prototype.splice,
    'push': Array.prototype.push
}
obj.push(1)
obj.push(2)
console.log(obj)
複製代碼

解析:

涉及知識點:

  • 類數組(ArrayLike):

一組數據,由數組來存,可是若是要對這組數據進行擴展,會影響到數組原型,ArrayLike的出現則提供了一箇中間數據橋樑,ArrayLike有數組的特性, 可是對ArrayLike的擴展並不會影響到原生的數組。

  • push方法:

push 方法有意具備通用性。該方法和 call() 或 apply() 一塊兒使用時,可應用在相似數組的對象上。push 方法根據 length 屬性來決定從哪裏開始插入給定的值。若是 length 不能被轉成一個數值,則插入的元素索引爲 0,包括 length 不存在時。當 length 不存在時,將會建立它。 惟一的原生類數組(array-like)對象是 Strings,儘管如此,它們並不適用該方法,由於字符串是不可改變的。

  • 對象轉數組的方式:

Array.from()、splice()、concat()等。

題分析: 這個obj中定義了兩個key值,分別爲splice和push分別對應數組原型中的splice和push方法,所以這個obj能夠調用數組中的push和splice方法,調用對象的push方法:push(1),由於此時obj中定義length爲2,因此從數組中的第二項開始插入,也就是數組的第三項(下表爲2的那一項),由於數組是從第0項開始的,這時已經定義了下標爲2和3這兩項,因此它會替換第三項也就是下標爲2的值,第一次執行push完,此時key爲2的屬性值爲1,同理:第二次執行push方法,key爲3的屬性值爲2。此時的輸出結果就是:

Object(4) [empty × 2, 1, 2, splice: ƒ, push: ƒ]---->
[
  2: 1,
  3: 2,
  length: 4,
  push: ƒ push(),
  splice: ƒ splice()
]
複製代碼

由於只是定義了2和3兩項,沒有定義0和1這兩項,因此前面會是empty。 若是講這道題改成:

var obj = {
    '2': 3,
    '3': 4,
    'length': 0,
    'splice': Array.prototype.splice,
    'push': Array.prototype.push
}
obj.push(1)
obj.push(2)
console.log(obj)
複製代碼

此時的打印結果就是:

Object(2) [1, 2, 2: 3, 3: 4, splice: ƒ, push: ƒ]---->
[
  0: 1,
  1: 2,
  2: 3,
  3: 4,
  length: 2,
  push: ƒ push(),
  splice: ƒ splice()
]
複製代碼

原理:此時length長度設置爲0,push方法從第0項開始插入,因此填充了第0項的empty 至於爲何對象添加了splice屬性後並無調用就會變成類數組對象這個問題,這是控制檯中 DevTools 猜想類數組的一個方式: github.com/ChromeDevTo…

未完待續,點擊查看更多細節:第 46 題

第 47 題:雙向綁定和 vuex 是否衝突

解析:

當在嚴格模式中使用 Vuex 時,在屬於 Vuex 的 state 上使用 v-model 會比較棘手:

<input v-model="obj.message">
複製代碼

假設這裏的 obj 是在計算屬性中返回的一個屬於 Vuex store 的對象,在用戶輸入時,v-model 會試圖直接修改 obj.message。在嚴格模式中,因爲這個修改不是在 mutation 函數中執行的, 這裏會拋出一個錯誤。

用「Vuex 的思惟」去解決這個問題的方法是:給 <input> 中綁定 value,而後偵聽 input 或者 change 事件,在事件回調中調用 action:

<input :value="message" @input="updateMessage">
複製代碼
// ...
computed: {
  ...mapState({
    message: state => state.obj.message
  })
},
methods: {
  updateMessage (e) {
    this.$store.commit('updateMessage', e.target.value)
  }
}
複製代碼

下面是 mutation 函數:

// ...
mutations: {
  updateMessage (state, message) {
    state.obj.message = message
  }
}
複製代碼

雙向綁定的計算屬性

必須認可,這樣作比簡單地使用「v-model + 局部狀態」要囉嗦得多,而且也損失了一些 v-model 中頗有用的特性。另外一個方法是使用帶有 setter 的雙向綁定計算屬性:

<input v-model="message">
複製代碼
// ...
computed: {
  message: {
    get () {
      return this.$store.state.obj.message
    },
    set (value) {
      this.$store.commit('updateMessage', value)
    }
  }
}
複製代碼

未完待續,點擊查看更多細節:第 47 題

第 48 題:call 和 apply 的區別是什麼,哪一個性能更好一些

解析:

  1. Function.prototype.apply和Function.prototype.call 的做用是同樣的,區別在於傳入參數的不一樣;
  2. 第一個參數都是,指定函數體內this的指向;
  3. 第二個參數開始不一樣,apply是傳入帶下標的集合,數組或者類數組,apply把它傳給函數做爲參數,call從第二個開始傳入的參數是不固定的,都會傳給函數做爲參數。
  4. call比apply的性能要好,日常能夠多用call, call傳入參數的格式正是內部所須要的格式,參考 call和apply的性能對比

未完待續,點擊查看更多細節:第 48 題

第 49 題:爲何一般在發送數據埋點請求的時候使用的是 1x1 像素的透明 gif 圖片?

解析:

  1. 可以完成整個 HTTP 請求+響應(儘管不須要響應內容)
  2. 觸發 GET 請求以後不須要獲取和處理數據、服務器也不須要發送數據
  3. 跨域友好
  4. 執行過程無阻塞
  5. 相比 XMLHttpRequest 對象發送 GET 請求,性能上更好
  6. GIF的最低合法體積最小(最小的BMP文件須要74個字節,PNG須要67個字節,而合法的GIF,只須要43個字節)
  7. 不會阻塞頁面加載,影響用戶的體驗,只要new Image對象就行了;(排除JS/CSS文件資源方式上報)

未完待續,點擊查看更多細節:第 49 題

第 50 題:實現 (5).add(3).minus(2) 功能。

例: 5 + 3 - 2,結果爲 6

解析:

Number.prototype.add = function(n) {
  return this.valueOf() + n;
};
Number.prototype.minus = function(n) {
  return this.valueOf() - n;
};
複製代碼

未完待續,點擊查看更多細節:第 50 題

第 51 題:Vue 的響應式原理中 Object.defineProperty 有什麼缺陷?

爲何在 Vue3.0 採用了 Proxy,拋棄了 Object.defineProperty?

解析:

Object.defineProperty自己有必定的監控到數組下標變化的能力: Object.defineProperty自己是能夠監控到數組下標的變化的,可是在 Vue 中,從性能/體驗的性價比考慮,尤大大就棄用了這個特性。具體咱們能夠參考 《記一次思否問答的問題思考:Vue爲何不能檢測數組變更》這篇文章,文章底部配圖中有尤大大的嚴肅回覆截圖; 下方的討論區也很值得你們下去看一看,有對於 for / forEach / for .. in .. 幾個循環方式的討論。

關於 Vue 3.0 的其餘信息咱們能夠參考 尤大大發布的 Vue 3.0 新特性預覽PPT

直接經過數組的下標給數組設置值,不能實時響應。 爲了解決這個問題,通過vue內部處理後可使用如下幾種方法來監聽數組

push()
pop()
shift()
unshift()
splice()
sort()
reverse()
複製代碼

因爲只針對了以上幾種方法進行了hack處理,因此其餘數組的屬性也是檢測不到的,仍是具備必定的侷限性。

Object.defineProperty只能劫持對象的屬性,所以咱們須要對每一個對象的每一個屬性進行遍歷。Vue 2.x裏,是經過 遞歸 + 遍歷 data 對象來實現對數據的監控的,若是屬性值也是對象那麼須要深度遍歷,顯然若是能劫持一個完整的對象是纔是更好的選擇。

而要取代它的Proxy有如下兩個優勢;

能夠劫持整個對象,並返回一個新對象 有13種劫持操做

未完待續,點擊查看更多細節:第 51 題

第 52 題:怎麼讓一個 div 水平垂直居中

解析:

<div class="parent">
  <div class="child"></div>
</div>
複製代碼
div.parent {
    display: flex;
    justify-content: center;
    align-items: center;
}
複製代碼
div.parent {
    position: relative; 
}
div.child {
    position: absolute; 
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);  
}
/* 或者 */
div.child {
    width: 50px;
    height: 10px;
    position: absolute;
    top: 50%;
    left: 50%;
    margin-left: -25px;
    margin-top: -5px;
}
/* 或 */
div.child {
    width: 50px;
    height: 10px;
    position: absolute;
    left: 0;
    top: 0;
    right: 0;
    bottom: 0;
    margin: auto;
}
複製代碼
div.parent {
    display: grid;
}
div.child {
    justify-self: center;
    align-self: center;
}
複製代碼
div.parent {
    font-size: 0;
    text-align: center;
    &::before {
        content: "";
        display: inline-block;
        width: 0;
        height: 100%;
        vertical-align: middle;
    }
}
div.parent{
  display: inline-block;
  vertical-align: middle;
}
複製代碼

未完待續,點擊查看更多細節:第 52 題

第 53 題:輸出如下代碼的執行結果並解釋爲何

var a = {n: 1};
var b = a;
a.x = a = {n: 2};

console.log(a.x) 	
console.log(b.x)
複製代碼

解析:

var a = {n: 1};
var b = a;
a.x = a = {n: 2};

a.x 	// --> undefined
b.x 	// --> {n: 2}
複製代碼

答案已經寫上面了,這道題的關鍵在於

  • 一、優先級。.的優先級高於=,因此先執行a.x,堆內存中的{n: 1}就會變成{n: 1, x: undefined},改變以後相應的b.x也變化了,由於指向的是同一個對象。
  • 二、賦值操做是從右到左,因此先執行a = {n: 2}a的引用就被改變了,而後這個返回值又賦值給了a.x須要注意的是這時候a.x是第一步中的{n: 1, x: undefined}那個對象,其實就是b.x,至關於b.x = {n: 2}

img

未完待續,點擊查看更多細節:第 53 題


交流

進階系列文章彙總以下,以爲不錯點個 Star,歡迎 加羣 互相學習。

github.com/yygmind/blo…

我是木易楊,公衆號「高級前端進階」做者,跟着我每週重點攻克一個前端面試重難點。接下來讓我帶你走進高級前端的世界,在進階的路上,共勉!

相關文章
相關標籤/搜索