前端面試題整理—ES6篇
一、es5和es6的區別,說一下你所知道的es6
ECMAScript5,即ES5,是ECMAScript的第五次修訂,于2009年完成標準化
ECMAScript6,即ES6,是ECMAScript的第六次修訂,于2015年完成,也稱ES2015
ES6是繼ES5之后的一次改進,相對于ES5更加簡潔,提高了開發效率
ES6新增的一些特性:
let聲明變量和const聲明常量,兩個都有塊級作用域
ES5中是沒有塊級作用域的,并且var有變量提升,在let中,使用的變量一定要進行聲明箭頭函數
ES6中的函數定義不再使用關鍵字function(),而是利用了()=>來進行定義模板字符串
模板字符串是增強版的字符串,用反引號(`)標識,可以當作普通字符串使用,也可以用來定義多行字符串解構賦值
ES6 允許按照一定模式,從數組和對象中提取值,對變量進行賦值for of循環
for...of循環可以遍歷數組、Set和Map結構、某些類似數組的對象、對象,以及字符串import、export導入導出
ES6標準中,Js原生支持模塊(module)。將JS代碼分割成不同功能的小塊進行模塊化,將不同功能的代碼分別寫在不同文件中,各模塊只需導出公共接口部分,然后通過模塊的導入的方式可以在其他地方使用set數據結構
Set數據結構,類似數組。所有的數據都是唯一的,沒有重復的值。它本身是一個構造函數... 展開運算符
可以將數組或對象里面的值展開;還可以將多個值收集為一個變量修飾器 @
decorator是一個函數,用來修改類甚至于是方法的行為。修飾器本質就是編譯時執行的函數class 類的繼承
ES6中不再像ES5一樣使用原型鏈實現繼承,而是引入Class這個概念async、await
使用 async/await, 搭配promise,可以通過編寫形似同步的代碼來處理異步流程, 提高代碼的簡潔性和可讀性
async 用于申明一個 function 是異步的,而 await 用于等待一個異步方法執行完成promise
Promise是異步編程的一種解決方案,比傳統的解決方案(回調函數和事件)更合理、強大Symbol
Symbol是一種基本類型。Symbol 通過調用symbol函數產生,它接收一個可選的名字參數,該函數返回的symbol是唯一的Proxy代理
使用代理(Proxy)監聽對象的操作,然后可以做一些相應事情
二、var、let、const之間的區別
- var聲明變量可以重復聲明,而let不可以重復聲明
- var是不受限于塊級的,而let是受限于塊級
- var會與window相映射(會掛一個屬性),而let不與window相映射
- var可以在聲明的上面訪問變量,而let有暫存死區,在聲明的上面訪問變量會報錯
- const聲明之后必須賦值,否則會報錯
- const定義不可變的量,改變了就會報錯
- const和let一樣不會與window相映射、支持塊級作用域、在聲明的上面訪問變量會報錯
三、使用箭頭函數應注意什么?
- 用了箭頭函數,this就不是指向window,而是父級(指向是可變的)
- 不能夠使用arguments對象
- 不能用作構造函數,這就是說不能夠使用new命令,否則會拋出一個錯誤
- 不可以使用yield命令,因此箭頭函數不能用作 Generator 函數
四、ES6的模板字符串有哪些新特性?并實現一個類模板字符串的功能
基本的字符串格式化。將表達式嵌入字符串中進行拼接。用${}
來界定
在ES5時我們通過反斜杠()來做多行字符串或者字符串一行行拼接。ES6反引號` `
就能解決
let name = 'web';
let age = 10;
let str = '你好,${name} 已經 ${age}歲了';
console.log(str);// 你好,web 已經 10歲了
五、介紹下 Set、Map的區別?
應用場景Set用于數據重組,Map用于數據儲存
Set:
- 成員不能重復
- 只有鍵值沒有鍵名,類似數組
- 可以遍歷,方法有add, delete,has
Map:
- 本質上是健值對的集合,類似集合
- 可以遍歷,可以跟各種數據格式轉換
六、ECMAScript 6 怎么寫 class ,為何會出現 class?
ES6的class可以看作是一個語法糖,它的絕大部分功能ES5都可以做到,新的class寫法只是讓對象原型的寫法更加清晰、更像面向對象編程的語法
//定義類
class Point {
constructor(x,y) {
//構造方法
this.x = x; //this關鍵字代表實例對象
this.y = y;
} toString() {
return '(' + this.x + ',' + this.y + ')';
}
}
七、Promise構造函數是同步執行還是異步執行,那么 then 方法呢?
promise構造函數是同步執行的,then方法是異步執行的
八、setTimeout、Promise、Async/Await 的區別
- 事件循環中分為宏任務隊列和微任務隊列。
- 其中setTimeout的回調函數放到宏任務隊列里,等到執行棧清空以后執行。
- promise.then里的回調函數會放到相應宏任務的微任務隊列里,等宏任務里面的同步代碼執行完再執行。
- async函數表示函數里面可能會有異步方法,await后面跟一個表達式。
- async方法執行時,遇到await會立即執行表達式,然后把表達式后面的代碼放到微任務隊列里,讓出執行棧讓同步代碼先執行。
九、promise有幾種狀態,什么時候會進入catch
1、三個狀態:pending、fulfilled、reject
2、兩個過程:padding -> fulfilled、padding -> rejected
3、當pending為rejectd時,會進入catch
十、下面的輸出結果是多少
const promise = new Promise((resolve, reject) => {
console.log(1);
resolve();
console.log(2);
})
promise.then(() => {
console.log(3);
})
console.log(4);
1 2 4 3
Promise 新建后立即執行,所以會先輸出 1,2,而 Promise.then() 內部的代碼在 當次 事件循環的 結尾 立刻執行 ,所以會繼續輸出4,最后輸出3
十一、使用結構賦值,實現兩個變量的值的交換
let a = 1;
let b = 2;
[a,b] = [b,a];
十二、設計一個對象,鍵名的類型至少包含一個symbol類型,并且實現遍歷所有key
let name = Symbol('name');
let product = {
[name]:"洗衣機",
"price":799
};
Reflect.ownKeys(product);
十三、下面Set結構,打印出的size值是多少
let s = new Set();
s.add([1]);
s.add([1]);console.log(s.size);
答案:2
兩個數組[1]并不是同一個值,它們分別定義的數組,在內存中分別對應著不同的存儲地址,因此并不是相同的值
都能存儲到Set結構中,所以size為2
十四、Promise 中reject 和 catch 處理上有什么區別
- reject 是用來拋出異常,catch 是用來處理異常
- reject 是 Promise 的方法,而 catch 是 Promise 實例的方法
- reject后的東西,一定會進入then中的第二個回調,如果then中沒有寫第二個回調,則進入catch
- 網絡異常(比如斷網),會直接進入catch而不會進入then的第二個回調
十五、使用class 手寫一個promise
//創建一個Promise的類
class Promise
{
//構造函數constructor里面是個執行器
constructor(executer)
{
this.status = 'pending';//默認的狀態 pending
this.value = undefined//成功的值默認undefined
this.reason = undefined//失敗的值默認undefined
//狀態只有在pending時候才能改變
let resolveFn = value =>
{
//判斷只有等待時才能resolve成功
if(this.status == pending)
{
this.status = 'resolve';
this.value = value;
}
}
//判斷只有等待時才能reject失敗
let rejectFn = reason =>
{
if(this.status == pending)
{
this.status = 'reject';
this.reason = reason;
}
}
try
{
// 把resolve和reject兩個函數傳給執行器executer
executer(resolve,reject);
}
catch(e)
{
reject(e);//失敗的話進catch
}
}
then(onFufilled,onReject)
{
//如果狀態成功調用onFufilled
if(this.status = 'resolve')
{
onFufilled(this.value);
}
//如果狀態失敗調用onReject
if(this.status = 'reject')
{
onReject(this.reason);
}
}
}
十六、如何使用Set去重
let arr = [12,43,23,43,68,12];
let item = [...new Set(arr)];
console.log(item); // [12, 43, 23, 68]
十七、將下面for循環改成for of形式
let arr = [11,22,33,44,55];
let sum = 0;
for(let i=0;i<arr.length;i++)
{
sum += arr[i];
}
答案:
let arr = [11,22,33,44,55];
let sum = 0;
for(value of arr)
{
sum += value;
}
十八、理解 async/await以及對Generator的優勢
async await 是用來解決異步的,async函數是Generator函數的語法糖
使用關鍵字async來表示,在函數內部使用 await 來表示異步
async函數返回一個 Promise 對象,可以使用then方法添加回調函數
當函數執行的時候,一旦遇到await就會先返回,等到異步操作完成,再接著執行函數體內后面的語句
async較Generator的優勢:
- 內置執行器。Generator 函數的執行必須依靠執行器,而 Aysnc 函數自帶執行器,調用方式跟普通函數的調用一樣
- 更好的語義。async 和 await 相較于 * 和 yield 更加語義化
- 更廣的適用性。yield命令后面只能是 Thunk 函數或 Promise對象,async函數的await后面可以是Promise也可以是原始類型的值
- 返回值是 Promise。async 函數返回的是 Promise 對象,比Generator函數返回的Iterator對象方便,可以直接使用 then() 方法進行調用
十九、forEach、for in、for of三者區別
forEach更多的用來遍歷數組
for in 一般常用來遍歷對象或json
for of數組對象都可以遍歷,遍歷對象需要通過和Object.keys()
for in循環出的是key,for of循環出的是value
二十、說一下es6的導入導出模塊
導入通過import關鍵字
// 只導入一個
import {sum} from "./example.js"
// 導入多個
import {sum,multiply,time} from "./exportExample.js"
// 導入一整個模塊
import * as example from "./exportExample.js"
導出通過export關鍵字
//可以將export放在任何變量,函數或類聲明的前面
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;
//也可以使用大括號指定所要輸出的一組變量
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export {firstName, lastName, year};
//使用export default時,對應的import語句不需要使用大括號
let bosh = function crs(){}
export default bosh;
import crc from 'crc';
//不使用export default時,對應的import語句需要使用大括號
let bosh = function crs(){}
export bosh;
import {crc} from 'crc';