ES6面試題

1.箭頭函數(shù)中的this指向定義時(shí)當(dāng)前周圍的作用域;

2.如果使用標(biāo)記模板字面量,第一個(gè)參數(shù)的值總是字符串的數(shù)組。其余的參數(shù)獲取的是傳遞的表達(dá)式的值;

3. es6中和原型一樣用來(lái)繼承的class和繼承是怎么實(shí)現(xiàn)的?

貼上

class Point {
  // ...
}
typeof Point // "function",類的數(shù)據(jù)類型就是函數(shù)
Point === Point.prototype.constructor // true,類本身就指向構(gòu)造函數(shù)

使用的時(shí)候,也是直接對(duì)類使用new命令,跟構(gòu)造函數(shù)的用法完全一致,不使用new會(huì)報(bào)錯(cuò)。

類的所有方法都定義在類的prototype屬性上面。

class Point {
  constructor() {    // ...  }
  toString() {    // ...  }
  toValue() {    // ...  }
}
// 等同于
Point.prototype = {
  constructor() {},
  toString() {},
  toValue() {},
};

//Object.assign方法可以很方便地一次向類添加多個(gè)方法
Object.assign(Point.prototype, {
  toString(){},
  toValue(){}
});

類不存在變量提升(hoist),這一點(diǎn)與 ES5 完全不同。

Class 可以通過extends關(guān)鍵字實(shí)現(xiàn)繼承。

class ColorPoint extends Point {}//ColorPoint繼承了Point類所有的屬性和方法

super關(guān)鍵字,表示父類的構(gòu)造函數(shù),用來(lái)新建父類的this對(duì)象。

子類必須在constructor方法中調(diào)用super方法,否則新建實(shí)例時(shí)會(huì)報(bào)錯(cuò),只有調(diào)用super之后,才可以使用this關(guān)鍵字。

區(qū)別:

ES5 的繼承,實(shí)質(zhì)是先創(chuàng)造子類的實(shí)例對(duì)象this,然后再將父類的方法添加到this上面Parent.apply(this))。

ES6 的繼承機(jī)制完全不同,實(shí)質(zhì)是先將父類實(shí)例對(duì)象的屬性和方法,加到this上面(所以必須先調(diào)用super方法),然后再用子類的構(gòu)造函數(shù)修改this。

Class 作為構(gòu)造函數(shù)的語(yǔ)法糖,同時(shí)有prototype屬性和__proto__屬性,因此同時(shí)存在兩條繼承鏈。

(1)子類的_proto_屬性,表示構(gòu)造函數(shù)的繼承,總是指向父類。

(2)子類prototype屬性的_proto_屬性,表示方法的繼承,總是指向父類的prototype屬性。

子類實(shí)例的__proto__屬性的__proto__屬性,指向父類實(shí)例的__proto__屬性。也就是說(shuō),子類的原型的原型,是父類的原型。

Object.getPrototypeOf方法判斷,一個(gè)類是否繼承了另一個(gè)類。

4. es6中const、let、var之間的區(qū)別?

  1. var定義的變量,作用域是整個(gè)封閉函數(shù),是全域的;

    let定義的變量,作用域是在塊級(jí)或者字塊中;

  2. 變量提升:不論通過var聲明的變量處于當(dāng)前作用于的第幾行,都會(huì)提升到作用域的最頂部。

    而let聲明的變量不會(huì)在頂部初始化,凡是在let聲明之前使用該變量都會(huì)報(bào)錯(cuò)(引用錯(cuò)誤ReferenceError);

  3. 只要塊級(jí)作用域內(nèi)存在let,它所聲明的變量就會(huì)綁定在這個(gè)區(qū)域;

  4. let不允許在相同作用域內(nèi)重復(fù)聲明(報(bào)錯(cuò)同時(shí)使用var和let,兩個(gè)let)

const用來(lái)專門聲明一個(gè)常量,它跟let一樣作用于塊級(jí)作用域沒有變量提升,重復(fù)聲明會(huì)報(bào)錯(cuò),不同的是const聲明的常量不可改變,聲明時(shí)必須初始化(賦值),const定義的對(duì)象可變。

const使用場(chǎng)景很廣,包括常量、配置項(xiàng)以及引用的組件、定義的 “大部分” 中間變量等,都應(yīng)該以cosnt做定義。反之就 let 而言,他的使用場(chǎng)景應(yīng)該是相對(duì)較少的,我們只會(huì)在 loop(for,while 循環(huán))及少量必須重定義的變量上用到他。

5. 大致講一下ES6新特性;

箭頭函數(shù);

② 增加了對(duì)類的支持class關(guān)鍵字;繼承:class Programmer extends Animal

③ 增強(qiáng)了對(duì)象字面量:可以在對(duì)象字面量里面定義原型

__proto__: human, //設(shè)置此對(duì)象的原型為human,相當(dāng)于繼承human;

定義方法可以不用function關(guān)鍵字

work() {console.log('working...'); };

字符串模板:反引號(hào) ` 來(lái)創(chuàng)建字符串;

解構(gòu):[name,age]=[Alice,’male’,’secrect’];//數(shù)組解構(gòu);

⑥ 參數(shù)默認(rèn)值,不定參數(shù),拓展參數(shù):

? 參數(shù)默認(rèn)值:在定義函數(shù)的時(shí)候指定參數(shù)的默認(rèn)值

function sayHello2(name='dude'){
    console.log(`Hello ${name}`);
}

? 不定參數(shù):在函數(shù)中使用命名參數(shù)同時(shí)接收不定數(shù)量的未命名參數(shù),三個(gè)句點(diǎn)后跟代表所有不定參數(shù)的變量名。

function add(...x){
    return x.reduce((m,n)=>m+n);
}

? 拓展參數(shù):允許傳遞數(shù)組或者類數(shù)組直接做為函數(shù)的參數(shù)而不用通過apply。

var people=['Wayou','John','Sherlock'];
sayHello(...people);//輸出:Hello Wayou,John,Sherlock

letconst關(guān)鍵字

for of值遍歷:for in 循環(huán)用于遍歷數(shù)組,類數(shù)組或?qū)ο?,for of循環(huán)功能相似,不同的是每次循環(huán)它提供的不是序號(hào)而是值。

for…of 循環(huán)的i代表的是value(多用于數(shù)組),for…in 循環(huán)的是key(多用于對(duì)象

⑨ iterator, generator:iterator擁有一個(gè)next方法;generator是一種特殊的iterator,通過function來(lái)聲明的,yield 關(guān)鍵字*可以暫停函數(shù)的執(zhí)行,隨后可以再進(jìn)進(jìn)入函數(shù)繼續(xù)執(zhí)行。

模塊module

// point.js
module "point" {
    export class Point {
        constructor (x, y) {
            public x = x;
            public y = y;
        } 
    }
}

// myapp.js
module point from "/point.js";  //聲明引用的模塊
import Point from "point";      //可以看出,盡管聲明了引用的模塊,還是可以通過指定需要的部分進(jìn)行導(dǎo)入
var origin = new Point(0, 0);
console.log(origin);

Map,Set 和 WeakMap,WeakSet:提供了更加方便的獲取屬性值的方法,不用像以前一樣用hasOwnProperty來(lái)檢查某個(gè)屬性是屬于原型鏈上還是當(dāng)前對(duì)象的。同時(shí),在進(jìn)行屬性值添加與獲取時(shí)有專門的get,set 方法。WeakMap,WeakSet更加安全,作為屬性鍵的對(duì)象如果沒有別的變量在引用它們,則會(huì)被回收釋放掉。

② Proxies:監(jiān)聽對(duì)象身上發(fā)生了什么事情,并在這些事情發(fā)生后執(zhí)行一些相應(yīng)的操作。

③ Symbols:是一種基本類型,不是一個(gè)對(duì)象。可以用symbol這種值來(lái)做為對(duì)象的鍵。

④ Math,Number,String,Object 的新API;

⑤ Promises:處理異步操作的一種模式,then()

6.Object.assign淺拷貝

Object.assign方法用來(lái)將源對(duì)象(source)的所有可枚舉屬性,復(fù)制到目標(biāo)對(duì)象(target)。

Object.assign方法實(shí)行的是淺拷貝,而不是深拷貝。

參數(shù)

? 它至少需要兩個(gè)對(duì)象作為參數(shù),第一個(gè)參數(shù)是目標(biāo)對(duì)象,后面的參數(shù)都是源對(duì)象。

? 如果只有一個(gè)參數(shù),Object.assign會(huì)直接返回該參數(shù)。

? 如果該參數(shù)不是對(duì)象,則會(huì)先轉(zhuǎn)成對(duì)象,然后返回

? 由于undefined和null無(wú)法轉(zhuǎn)成對(duì)象,所以如果它們作為參數(shù),就會(huì)報(bào)錯(cuò)

注:如果目標(biāo)對(duì)象與源對(duì)象有同名屬性,或多個(gè)源對(duì)象有同名屬性,則后面的屬性會(huì)覆蓋前面的屬性。

注意:如果非對(duì)象參數(shù)出現(xiàn)在源對(duì)象的位置(即非首參數(shù)),那么處理規(guī)則有所不同。首先,這些參數(shù)都會(huì)轉(zhuǎn)成對(duì)象,如果無(wú)法轉(zhuǎn)成對(duì)象,就會(huì)跳過。這意味著, 如果undefined和null不在首參數(shù),就不會(huì)報(bào)錯(cuò)。其他類型的值(即數(shù)值、字符串和布爾值)不在首參數(shù),也不會(huì)報(bào)錯(cuò)。但是,除了字符串會(huì)以數(shù)組形式,拷貝入目標(biāo)對(duì)象,其他值都不會(huì)產(chǎn)生效果。

對(duì)于嵌套的對(duì)象,Object.assign的處理方法是替換,而不是添加。

var target = { a: { b: 'c', d: 'e' } }
var source = { a: { b: 'hello' } } 
Object.assign(target, source); /*{ a: { b: 'hello' } } */

注意,Object.assign可以用來(lái)處理數(shù)組,但是會(huì)把數(shù)組視為對(duì)象。

console.log(Object.assign([1, 2, 3], [4, 5]));
/*[4,5,3] 4覆蓋1,5覆蓋2,因?yàn)樗鼈冊(cè)跀?shù)組的同一位置,所以就對(duì)應(yīng)位置覆蓋了*/

如果源對(duì)象某個(gè)屬性的值是對(duì)象,那么目標(biāo)對(duì)象拷貝得到的是這個(gè)對(duì)象的引用。

var object1 = { a: { b: 1 } };
var object2 = Object.assign({}, object1); 
object1.a.b = 2; 
console.log(object2.a.b);

用途

為對(duì)象添加屬性;為對(duì)象添加方法;克隆對(duì)象;合并多個(gè)對(duì)象;為屬性指定默認(rèn)值

//克隆對(duì)象:將原始對(duì)象拷貝到一個(gè)空對(duì)象,就得到了原始對(duì)象的克隆
function copyFnc(origin) {
    return Object.assign({}, origin)
} 
var sur = { a: 1, b: 2 };
console.log(copyFnc(sur));

采用這種方法克隆,只能克隆原始對(duì)象自身的值,不能克隆它繼承的值。如果想要保持繼承鏈,可以采用下面的代碼。

/*克隆對(duì)象:在JS里子類利用Object.getPrototypeOf去調(diào)用父類方法,用來(lái)獲取對(duì)象的原型*/
function clone(origin) {
    let originProto = Object.getPrototypeOf(origin);
    return Object.assign(Object.create(originProto), origin);
}

//多個(gè)對(duì)象合并到某個(gè)對(duì)象
const merge = (target, ...sources) => Object.assign(target, ...sources);
//多個(gè)對(duì)象合并到新對(duì)象
const merge = (...sources) => Object.assign({}, ...sources);

const o1 = { a: 1 };
const o2 = { b: 2 };
const o3 = { c: 3 };
const obj = Object.assign(o1, o2, o3);// { a: 1, b: 2, c: 3 }

7.箭頭函數(shù)和一般函數(shù)有什么區(qū)別?

定義箭頭函在數(shù)語(yǔ)法上要比普通函數(shù)簡(jiǎn)潔得多。箭頭函數(shù)省去了function關(guān)鍵字,采用箭頭=>來(lái)定義函數(shù)。

基本語(yǔ)法:關(guān)于箭頭函數(shù)的參數(shù):

① 如果箭頭函數(shù)沒有參數(shù),直接寫一個(gè)空括號(hào)即可。

② 如果箭頭函數(shù)的參數(shù)只有一個(gè),也可以省去包裹參數(shù)的括號(hào)。

③ 如果箭頭函數(shù)有多個(gè)參數(shù),將參數(shù)依次用逗號(hào)(,)分隔,包裹在括號(hào)中即可。

基本語(yǔ)法:關(guān)于箭頭函數(shù)的函數(shù)體:

① 如果箭頭函數(shù)的函數(shù)體只有一句代碼,就是簡(jiǎn)單返回某個(gè)變量或者返回一個(gè)簡(jiǎn)單的JS表達(dá)式,可以省去函數(shù)體的大括號(hào){ }。

② 如果箭頭函數(shù)的函數(shù)體只有一句代碼,就是返回一個(gè)對(duì)象,用小括號(hào)包裹要返回的對(duì)象,不報(bào)錯(cuò)

let getTempItem = id => ({ id: id, name: "Temp" });

③ 如果箭頭函數(shù)的函數(shù)體只有一條語(yǔ)句并且不需要返回值(最常見是調(diào)用一個(gè)函數(shù)),可以給這條語(yǔ)句前面加一個(gè)void關(guān)鍵字

let fn = () => void doesNotReturn();
//用來(lái)簡(jiǎn)化回調(diào)函數(shù):
[1,2,3].map(function (x) {return x * x;});// 正常函數(shù)寫法
[1,2,3].map(x => x * x);// 箭頭函數(shù)寫法
var result = [2, 5, 1, 4, 3].sort(function (a, b) {  return a - b;});// 正常函數(shù)寫法
var result = [2, 5, 1, 4, 3].sort((a, b) => a - b);// 箭頭函數(shù)寫法

區(qū)別

1、語(yǔ)法更加簡(jiǎn)潔、清晰

2、箭頭函數(shù)不會(huì)創(chuàng)建自己的this,它會(huì)捕獲自己在定義時(shí)(注意,是定義時(shí),不是調(diào)用時(shí))所處的外層執(zhí)行環(huán)境的this,并繼承這個(gè)this值。所以,箭頭函數(shù)中this的指向在它被定義的時(shí)候就已經(jīng)確定了,之后永遠(yuǎn)不會(huì)改變。

3、箭頭函數(shù)繼承而來(lái)的this指向永遠(yuǎn)不變

4、.call()/.apply()/.bind()無(wú)法改變箭頭函數(shù)中this的指向(但是也不會(huì)報(bào)錯(cuò))

5、箭頭函數(shù)不能作為構(gòu)造函數(shù)使用:因?yàn)榧^函數(shù)沒有自己的this,它的this其實(shí)是繼承了外層執(zhí)行環(huán)境中的this,且this指向永遠(yuǎn)不會(huì)隨在哪里調(diào)用、被誰(shuí)調(diào)用而改變,所以箭頭函數(shù)不能作為構(gòu)造函數(shù)使用,或者說(shuō)構(gòu)造函數(shù)不能定義成箭頭函數(shù),否則用new調(diào)用時(shí)會(huì)報(bào)錯(cuò)!

6、箭頭函數(shù)沒有自己的arguments:在箭頭函數(shù)中訪問arguments實(shí)際上獲得的是外層局部(函數(shù))執(zhí)行環(huán)境中的值。可以在箭頭函數(shù)中使用rest參數(shù)代替arguments對(duì)象,來(lái)訪問箭頭函數(shù)的參數(shù)列表

7、箭頭函數(shù)沒有原型prototype

let sayHi = () => {    console.log('Hello World !')};
console.log(sayHi.prototype); // undefined

8.Promise、async await 的使用?

promise和async/await都是異步方案,promise是es6的新特性,而async/await是es7新出的特性。

Promise是一個(gè)對(duì)象,可以實(shí)現(xiàn)鏈?zhǔn)降膶懛?/strong>來(lái)實(shí)現(xiàn)同步異步操作,

then()…catch()…,then表示上一個(gè)promise執(zhí)行完后執(zhí)行,如果出現(xiàn)錯(cuò)誤就會(huì)傳入catch里面,通常這么寫:

var pro = new promise (function(resolve,reject){
    resolve("success");
    console.log("afterresolve");
    reject("error");
});
pro.then(result=>{
    console.log(result);
});
pro.catch(result=>{
    console.log(result);
})
//afterresolve success

resolve下面的語(yǔ)句其實(shí)是可以執(zhí)行的,那么為什么reject的狀態(tài)信息在下面沒有接受到呢?

這就是因?yàn)镻romise對(duì)象的特點(diǎn):狀態(tài)的凝固。new出一個(gè)Promise對(duì)象時(shí),這個(gè)對(duì)象的起始狀態(tài)就是Pending狀態(tài),在根據(jù)resolve或reject返回Fulfilled狀態(tài)/Rejected狀態(tài)。

new Promise((resolve, reject) => {
    var param = 'Promise 執(zhí)行完后返回的數(shù)據(jù)';
    var error = 'Promise 異步執(zhí)行異常';
    if( error ) {
        reject(new Error('Promise 異步執(zhí)行異常'));
    } else {
        resolve(param);
    }
}).then((res) => {
//  這里res就是Promise中的param參數(shù)
    console.log(res);  //  Promise 執(zhí)行完后返回的數(shù)據(jù)
    var param = '第一個(gè)then 執(zhí)行完后返回的數(shù)據(jù)';
    return param;
}).then((res) => {
//  這里的res就不是Promise中resolve的param參數(shù)了,而是上一個(gè)then中的返回值
    console.log(res);  //  第一個(gè)then 執(zhí)行完后返回的數(shù)據(jù)
}).catch((error) => {
//  這里是Promise執(zhí)行reject方法中的參數(shù)
    console.log(error); //  Promise 異步執(zhí)行異常
});

第一個(gè)then()觸發(fā)條件:是 Promise() 實(shí)例化時(shí)resolve()觸發(fā),resolve(param);

第二個(gè)及以后的then() 觸發(fā)條件是第一個(gè)then()執(zhí)行完成,并且將return值作為下一個(gè)then的參數(shù);

catch()觸發(fā)條件是執(zhí)行了reject(),用于指定發(fā)生錯(cuò)誤的時(shí)候的回調(diào)函數(shù)。

需要注意的是resolve與reject只能執(zhí)行一個(gè)。也就是說(shuō)如果不加入判斷的話,某一個(gè)先執(zhí)行了,后面的就自動(dòng)忽略了。

對(duì)于async/await來(lái)說(shuō)是基于promise的,他可以讓我們更加優(yōu)雅的寫出代碼,而替代then()的寫法;

需要注意的就是await是強(qiáng)制把異步變成了同步,這一句代碼執(zhí)行完,才會(huì)執(zhí)行下一句

await必須用在async方法中;處理錯(cuò)誤的方法:

1572012187509
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容