前端面試100問(1-10)

內容的起源來自於掘金上的一篇文章——《前端 100 問:能搞懂 80% 的請把簡歷給我》html

 

系列筆記:前端

 

 

題1:(滴滴、餓了麼)寫React/Vue項目時爲何要在列表組件中寫key,其做用是什麼?

答:(以Vue舉例回答)node

1.維護狀態。git

Vue默認使用「就地更新」策略,若是數據項的順序被改變,Vue將不會移動DOM元素來匹配數據項的順序。es6

這個默認的模式是高效的,可是隻適用於不依賴子組件狀態或臨時DOM狀態的列表渲染輸出。github

爲了給Vue一個提示,以便它能跟蹤每一個節點的身份,從而重用和從新排序現有元素,你須要爲每項提供一個惟一key屬性。面試

<div v-for="item in items" v-bind:key="item.id">
  <!-- 內容 -->
</div>

2.key的特殊屬性主要用在Vue的虛擬DOM算法,再新舊nodes對比時辨識VNodes。算法

使用key,它會基於key的變化從新排列元素順序,而且會移除key不存在的元素。數組

有相同父元素的子元素必須有獨特的key。重複的key會形成渲染錯誤。promise

 

它也能夠用於強制替換元素/組件而不是重複使用它。場景以下:

  • 完整地觸發組件的生命週期鉤子
  • 觸發過渡

例如:

<transition>
  <span :key="text">{{ text }}</span>
</transition>

當text發生改變時,<span>會隨時被更新,所以會觸發過渡。

 

 

題2:['1', '2', '3'].map(parseInt) what & why?

答:看到這題的時候,我快速按下f12打開開發者工具,console打印結果是[1, NaN, NaN],納尼~

當時我就懵了。因而我又去看了下map方法的文檔,沒毛病,經常使用的~等等,就在最下面,居然出現了和題目同樣的代碼~

MDN開發者文檔:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/map

見最下面的【使用技巧案例】

// 下面的語句返回什麼呢:
["1", "2", "3"].map(parseInt);
// 你可能覺的會是[1, 2, 3]
// 但實際的結果是 [1, NaN, NaN]

// 一般使用parseInt時,只須要傳遞一個參數.
// 但實際上,parseInt能夠有兩個參數.第二個參數是進制數.
// 能夠經過語句"alert(parseInt.length)===2"來驗證.
// map方法在調用callback函數時,會給它傳遞三個參數:當前正在遍歷的元素, 
// 元素索引, 原數組自己.
// 第三個參數parseInt會忽視, 但第二個參數不會,也就是說,
// parseInt把傳過來的索引值當成進制數來使用.從而返回了NaN.

 

 

題3:什麼是防抖和節流?有什麼區別?如何實現?

答:說真的,看到這題我是懵的。趕忙查了下什麼是防抖和節流。

研究了一天,準備單獨寫一篇防抖和節流。

相關文章:

一個防抖和節流的實用例子

一個Vue表單提交防抖的實用例子

 

 

題4:介紹下Set、Map、WeakSet和WeakMap的區別?

答:

Set 一種相似於數組但沒有重複值的數據結構

const s = new Set();

[2, 3, 5, 4, 2, 2].forEach(x => s.add(x));

for (let i of s) {
  console.log(i);  
}

// 2 3 5 4

詳細內容參見:阮一峯的《ECMAScript 6 入門》 http://es6.ruanyifeng.com/#docs/set-map

WeakSet 結構與Set相似,但有2個區別:

WeakSet的成員只能是對象,而不能是其餘類型的值,好比數值和Symbol

WeakSet中的對象都是弱引用

 

Map數據結構相似於對象,「鍵」的範圍不限於字符串,各類類型的值均可以看成鍵

Map結構提供了「值-值」的對應,是一種更完善的Hash結構實現

 

WeakMap結構與Map結構相似,也是用於生成鍵值對的集合。

WeakMap與Map的區別:

WeakMap只接受對象做爲鍵名(null除外),不接受其餘類型的值做爲鍵名

WeakMap的鍵名所指向的對象,不計入垃圾回收機制

(有點暈~)

 

題5:介紹下深度優先遍歷和廣度優先遍歷,如何實現?

題6:請分別用深度優先思想和廣度優先思想實現一個拷貝函數?

這兩題我看了好久,有點暈,先跳過

貼上木易楊說的答案:

題5答案:https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/9

題6答案:https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/10

 

題7:ES5/ES6的繼承除了寫法之外還有什麼區別?

答:

1.class聲明不會提高(有人說是會提高但不賦值)

2.class聲明內部會啓用嚴格模式

3.class的全部方法(包括靜態方法和實例方法)都是不可枚舉的

4.class的全部方法(包括靜態方法和實例方法)都沒有原型對象prototype

5.必須使用new調用class

6.class內部沒法重寫類名

//普通函數
function Bar() {
    Bar = 'Baz'; //沒問題
}

//
class Bar {
    constructor() {
        Bar = 'Baz'; // 錯誤
    }
}

7.由於this生成順序不一樣,因此子類的constructor中須要使用super()

答案摘自:https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/20

 

 

題8:setTimeout、Promise、Async/Await的區別?

答:那天首先花了一天時間去了解下什麼是JS事件循環、宏任務和微任務這些概念,整理成筆記以下:

 

學習筆記:初識JS事件循環機制

如下是來自github木易楊的blog的答案,原連接:https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/33

1.setTimeout

console.log('script start')
setTimeout(function () {
    console.log('settimeout')
})
console.log('script end')

// 輸出順序:script start -> script end -> settimeout

2.Promise

Promise自己是同步的當即執行函數。當在executor中執行resolve或者reject時是異步操做,會先執行then/cathc等,當主棧完成後,纔會去調用resolve/reject中存放的方法執行。

console.log('script start')
let promise1 = new Promise(function(resolve) {
    console.log('promise1')
    resolve()
    console.log('promise1 end')
}).then(function(){
    console.log('promise2')
})
setTimeout(function(){
    console.log('settimeout')
})
console.log('script end')

//輸出順序: script start -> promise1 -> promise1 end -> script end -> promise2 -> settimeout

當JS主線程執行到Promise對象時

  • promise1.then()的回調就是一個task
  • promise1是resolved或者rejected:那這個task就會放入當前事件循環回合的microtask queue
  • promise1是pending:這個task就會放入事件循環的將來的某個(可能下一個)回合的microtask queue中
  • setTimeout的回調也是個task,它會被放入microtask queue即便是0ms的狀況

 

3.async/await

async function async1 () {
    console.log('async1 start')
    await async2()
    console.log('async1 end')
}

async function async2 () {
    console.log('async2')
}

console.log('script start')
async1()
console.log('start end')

// 輸出順序:script start -> async1 start -> async2 -> script end -> async1 end

async函數返回一個Promise對象,當函數執行的時候,一旦遇到await就會先返回,等到觸發的異步操做完成,再執行函數體內後面的語句。能夠理解爲,是讓出了線程,跳出了async函數體。

舉個例子:

async function fn1 () {
    return 1
}
console.log(fn1())

 

fn1的運行結果是 一個Promise對象。由於也能夠用then來處理後續邏輯。

 

fn1().then(res => {
    console.log(res)
})

await的含義爲等待,也就是async函數須要等待await後的函數執行完成而且有了返回結果(Promise對象)以後,才能繼續執行下面的代碼。

await經過返回一個Promise對象來實現同步的效果。

 

await/async是經過Generator/function*來實現的。因此async/await的相關優點也來自於generator.

Generator是一個能夠暫停function.

function* generator(i) {
    console.log('inside before')
    yield i;
    yield i + 10;
    console.log('inside after')
}

var gen = generator(10)
console.log('outside before')
console.log(gen.next().value)
console.log(gen.next().value);
console.log('outside after')
gen.next();

//結果以下:
// outside before
// inside before
// 10
// 20
// outside after
// inside after

 

題9:Async/Await如何經過同步的方式實現異步?

答:

針對這個問題的學習筆記: 每日技術:Promise和Async/Await用法

 

 

 題10:異步筆試題

請寫出下面代碼的運行結果

async function async1() {
    console.log('async1 start');
    await async2();
    console.log('async1 end');
}
async function async2() {
    console.log('async2');
}
console.log('script start');
setTimeout(function() {
    console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
    console.log('promise1');
    resolve();
}).then(function() {
    console.log('promise2');
});
console.log('script end');

答:每日技術:關於promise,async,setTimeout的執行順序

相關文章
相關標籤/搜索