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ū)別?
-
var定義的變量,作用域是整個(gè)封閉函數(shù),是全域的;
let定義的變量,作用域是在塊級(jí)或者字塊中;
-
變量提升:不論通過var聲明的變量處于當(dāng)前作用于的第幾行,都會(huì)提升到作用域的最頂部。
而let聲明的變量不會(huì)在頂部初始化,凡是在let聲明之前使用該變量都會(huì)報(bào)錯(cuò)(引用錯(cuò)誤ReferenceError);
只要塊級(jí)作用域內(nèi)存在
let,它所聲明的變量就會(huì)綁定在這個(gè)區(qū)域;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
⑦ let 與const關(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ò)誤的方法:
