一、問:ES6是什么械念,為什么要學習它,不學習ES6會怎么樣?
答: ES6是新一代的JS語言標準媒怯,對分JS語言核心內(nèi)容做了升級優(yōu)化订讼,規(guī)范了JS使用標準髓窜,新增了JS原生方法扇苞,使得JS使用更加規(guī)范,更加優(yōu)雅寄纵,更適合大型應(yīng)用的開發(fā)鳖敷。學習ES6是成為專業(yè)前端正規(guī)軍的必經(jīng)之路。不學習ES6也可以寫代碼打鬼子程拭,但是最多只能當個游擊隊長定踱。
二、問:ES5恃鞋、ES6和ES2015有什么區(qū)別?
答: ES2015特指在2015年發(fā)布的新一代JS語言標準崖媚,ES6泛指下一代JS語言標準,包含ES2015恤浪、ES2016畅哑、ES2017、ES2018等∷桑現(xiàn)階段在絕大部分場景下荠呐,ES2015默認等同ES6。ES5泛指上一代語言標準砂客。ES2015可以理解為ES5和ES6的時間分界線泥张。
三、問:babel是什么鞠值,有什么作用?
答:babel是一個 ES6 轉(zhuǎn)碼器媚创,可以將 ES6 代碼轉(zhuǎn)為 ES5 代碼,以便兼容那些還沒支持ES6的平臺彤恶。
四筝野、問:let有什么用晌姚,有了var為什么還要用let?
答: 在ES6之前歇竟,聲明變量只能用var挥唠,var方式聲明變量其實是很不合理的,準確的說焕议,是因為ES5里面沒有塊級作用域是很不合理的宝磨,甚至可以說是一個語言層面的bug(這也是很多c++、java開發(fā)人員看不懂盅安,也瞧不起JS語言的劣勢之一)唤锉。沒有塊級作用域回來帶很多難以理解的問題,比如for循環(huán)var變量泄露别瞭,變量覆蓋等問題窿祥。let 聲明的變量擁有自己的塊級作用域,且修復了var聲明變量帶來的變量提升問題蝙寨。
五晒衩、問:舉一些ES6對String字符串類型做的常用升級優(yōu)化?
答:
1、優(yōu)化部分:
ES6新增了字符串模板墙歪,在拼接大段字符串時听系,用反斜杠(`)取代以往的字符串相加的形式,能保留所有空格和換行虹菲,使得字符串拼接看起來更加直觀靠胜,更加優(yōu)雅。
2毕源、升級部分:
ES6在String原型上新增了includes()方法浪漠,用于取代傳統(tǒng)的只能用indexOf查找包含字符的方法(indexOf返回-1表示沒查到不如includes方法返回false更明確,語義更清晰), 此外還新增了startsWith(), endsWith(), padStart(),padEnd(),repeat()等方法霎褐,可方便的用于查找址愿,補全字符串。
六瘩欺、問:舉一些ES6對Array數(shù)組類型做的常用升級優(yōu)化?
答:
1必盖、優(yōu)化部分:
a. 數(shù)組解構(gòu)賦值。ES6可以直接以let [a,b,c] = [1,2,3]
形式進行變量賦值俱饿,在聲明較多變量時歌粥,不用再寫很多l(xiāng)et(var),且映射關(guān)系清晰,且支持賦默認值拍埠。
b. 擴展運算符失驶。ES6新增的擴展運算符(...)(重要),可以輕松的實現(xiàn)數(shù)組和松散序列的相互轉(zhuǎn)化,可以取代arguments對象和apply方法枣购,輕松獲取未知參數(shù)個數(shù)情況下的參數(shù)集合嬉探。(尤其是在ES5中擦耀,arguments并不是一個真正的數(shù)組,而是一個類數(shù)組的對象涩堤,但是擴展運算符的逆運算卻可以返回一個真正的數(shù)組)眷蜓。擴展運算符還可以輕松方便的實現(xiàn)數(shù)組的復制和解構(gòu)賦值(let a = [2,3,4]; let b = [...a]
)。
2胎围、升級部分:
ES6在Array原型上新增了find()方法吁系,用于取代傳統(tǒng)的只能用indexOf查找包含數(shù)組項目的方法,且修復了indexOf查找不到NaN的bug([NaN].indexOf(NaN) === -1
).此外還新增了copyWithin(), includes(), fill(),flat()等方法,可方便的用于字符串的查找白魂,補全,轉(zhuǎn)換等汽纤。
七、問:舉一些ES6對Number數(shù)字類型做的常用升級優(yōu)化?
答:
1福荸、優(yōu)化部分:
ES6在Number原型上新增了isFinite(), isNaN()方法蕴坪,用來取代傳統(tǒng)的全局isFinite(), isNaN()方法檢測數(shù)值是否有限、是否是NaN敬锐。ES5的isFinite(), isNaN()方法都會先將非數(shù)值類型的參數(shù)轉(zhuǎn)化為Number類型再做判斷背传,這其實是不合理的,最造成isNaN('NaN') === true
的奇怪行為--'NaN'是一個字符串滞造,但是isNaN卻說這就是NaN续室。而Number.isFinite()和Number.isNaN()則不會有此類問題(Number.isNaN('NaN') === false
)栋烤。(isFinite()同上)
2谒养、升級部分:
ES6在Math對象上新增了Math.cbrt(),trunc()明郭,hypot()等等較多的科學計數(shù)法運算方法买窟,可以更加全面的進行立方根、求和立方根等等科學計算薯定。
八始绍、問:舉一些ES6對Object類型做的常用升級優(yōu)化?(重要)
答:
1、優(yōu)化部分:
a. 對象屬性變量式聲明话侄。ES6可以直接以變量形式聲明對象屬性或者方法亏推,。比傳統(tǒng)的鍵值對形式聲明更加簡潔年堆,更加方便吞杭,語義更加清晰。
let [apple, orange] = ['red appe', 'yellow orange'];let myFruits = {apple, orange}; // let myFruits = {apple: 'red appe', orange: 'yellow orange'};復制代碼
尤其在對象解構(gòu)賦值(見優(yōu)化部分b.)或者模塊輸出變量時变丧,這種寫法的好處體現(xiàn)的最為明顯:
let {keys, values, entries} = Object;let MyOwnMethods = {keys, values, entries}; // let MyOwnMethods = {keys: keys, values: values, entries: entries}復制代碼
可以看到屬性變量式聲明屬性看起來更加簡潔明了芽狗。方法也可以采用簡潔寫法:
let es5Fun = { method: function(){}}; let es6Fun = { method(){}}復制代碼
b. 對象的解構(gòu)賦值。 ES6對象也可以像數(shù)組解構(gòu)賦值那樣痒蓬,進行變量的解構(gòu)賦值:
let {apple, orange} = {apple: 'red appe', orange: 'yellow orange'};復制代碼
c. 對象的擴展運算符(...)童擎。 ES6對象的擴展運算符和數(shù)組擴展運算符用法本質(zhì)上差別不大滴劲,畢竟數(shù)組也就是特殊的對象。對象的擴展運算符一個最最常用也最好用的用處就在于可以輕松的取出一個目標對象內(nèi)部全部或者部分的可遍歷屬性顾复,從而進行對象的合并和分解班挖。
let {apple, orange, ...otherFruits} = {apple: 'red apple', orange: 'yellow orange', grape: 'purple grape', peach: 'sweet peach'}; // otherFruits {grape: 'purple grape', peach: 'sweet peach'}// 注意: 對象的擴展運算符用在解構(gòu)賦值時,擴展運算符只能用在最有一個參數(shù)(otherFruits后面不能再跟其他參數(shù))let moreFruits = {watermelon: 'nice watermelon'};let allFruits = {apple, orange, ...otherFruits, ...moreFruits};復制代碼
d. super 關(guān)鍵字芯砸。ES6在Class類里新增了類似this的關(guān)鍵字super聪姿。同this總是指向當前函數(shù)所在的對象不同,super關(guān)鍵字總是指向當前函數(shù)所在對象的原型對象乙嘀。
2末购、升級部分:
a. ES6在Object原型上新增了is()方法,做兩個目標對象的相等比較虎谢,用來完善'==='方法盟榴。'==='方法中NaN === NaN //false
其實是不合理的,Object.is修復了這個小bug婴噩。(Object.is(NaN, NaN) // true
)
b. ES6在Object原型上新增了assign()方法擎场,用于對象新增屬性或者多個對象合并。
const target = { a: 1 };const source1 = { b: 2 };const source2 = { c: 3 };Object.assign(target, source1, source2);target // {a:1, b:2, c:3}復制代碼
注意: assign合并的對象target只能合并source1几莽、source2中的自身屬性迅办,并不會合并source1、source2中的繼承屬性章蚣,也不會合并不可枚舉的屬性站欺,且無法正確復制get和set屬性(會直接執(zhí)行g(shù)et/set函數(shù),取return的值)纤垂。
c. ES6在Object原型上新增了getOwnPropertyDescriptors()方法矾策,此方法增強了ES5中g(shù)etOwnPropertyDescriptor()方法,可以獲取指定對象所有自身屬性的描述對象峭沦。結(jié)合defineProperties()方法贾虽,可以完美復制對象,包括復制get和set屬性吼鱼。
d. ES6在Object原型上新增了getPrototypeOf()和setPrototypeOf()方法蓬豁,用來獲取或設(shè)置當前對象的prototype對象。這個方法存在的意義在于菇肃,ES5中獲取設(shè)置prototype對像是通過proto屬性來實現(xiàn)的地粪,然而proto屬性并不是ES規(guī)范中的明文規(guī)定的屬性,只是瀏覽器各大產(chǎn)商“私自”加上去的屬性巷送,只不過因為適用范圍廣而被默認使用了驶忌,再非瀏覽器環(huán)境中并不一定就可以使用,所以為了穩(wěn)妥起見,獲取或設(shè)置當前對象的prototype對象時付魔,都應(yīng)該采用ES6新增的標準用法聊品。
d. ES6在Object原型上還新增了Object.keys(),Object.values()几苍,Object.entries()方法翻屈,用來獲取對象的所有鍵、所有值和所有鍵值對數(shù)組妻坝。
九伸眶、問:舉一些ES6對Function函數(shù)類型做的常用升級優(yōu)化?(重要)
答:
1、優(yōu)化部分:
a. 箭頭函數(shù)(核心)刽宪。箭頭函數(shù)是ES6核心的升級項之一厘贼,箭頭函數(shù)里沒有自己的this,這改變了以往JS函數(shù)中最讓人難以理解的this運行機制。主要優(yōu)化點:
Ⅰ. 箭頭函數(shù)內(nèi)的this指向的是函數(shù)定義時所在的對象圣拄,而不是函數(shù)執(zhí)行時所在的對象嘴秸。ES5函數(shù)里的this總是指向函數(shù)執(zhí)行時所在的對象,這使得在很多情況下this的指向變得很難理解庇谆,尤其是非嚴格模式情況下岳掐,this有時候會指向全局對象,這甚至也可以歸結(jié)為語言層面的bug之一饭耳。ES6的箭頭函數(shù)優(yōu)化了這一點串述,它的內(nèi)部沒有自己的this,這也就導致了this總是指向上一層的this,如果上一層還是箭頭函數(shù)寞肖,則繼續(xù)向上指纲酗,直到指向到有自己this的函數(shù)為止,并作為自己的this逝淹。
Ⅱ. 箭頭函數(shù)不能用作構(gòu)造函數(shù)耕姊,因為它沒有自己的this桶唐,無法實例化栅葡。
Ⅲ. 也是因為箭頭函數(shù)沒有自己的this,所以箭頭函數(shù) 內(nèi)也不存在arguments對象。(可以用擴展運算符代替)
b. 函數(shù)默認賦值尤泽。ES6之前欣簇,函數(shù)的形參是無法給默認值得,只能在函數(shù)內(nèi)部通過變通方法實現(xiàn)坯约。ES6以更簡潔更明確的方式進行函數(shù)默認賦值熊咽。
function es6Fuc (x, y = 'default') { console.log(x, y);}es6Fuc(4) // 4, default復制代碼
2、升級部分:
ES6新增了雙冒號運算符闹丐,用來取代以往的bind横殴,call,和apply。
foo::bar;// 等同于bar.bind(foo); foo::bar(...arguments);// 等同于bar.apply(foo, arguments);復制代碼
十、問:Symbol是什么衫仑,有什么作用梨与?
答: Symbol是ES6引入的第七種原始數(shù)據(jù)類型,所有Symbol()生成的值都是獨一無二的文狱,可以從根本上解決對象屬性太多導致屬性名沖突覆蓋的問題粥鞋。對象中Symbol()屬性不能被for...in遍歷,但是也不是私有屬性瞄崇。
十一呻粹、問:Set是什么,有什么作用苏研?
答: Set是ES6引入的一種類似Array的新的數(shù)據(jù)結(jié)構(gòu)等浊,Set實例的成員類似于數(shù)組item成員,區(qū)別是Set實例的成員都是唯一摹蘑,不重復的凿掂。這個特性可以輕松地實現(xiàn)數(shù)組去重。
十二纹蝴、問:Map是什么庄萎,有什么作用?
答: Map是ES6引入的一種類似Object的新的數(shù)據(jù)結(jié)構(gòu)塘安,Map可以理解為是Object的超集糠涛,打破了以傳統(tǒng)鍵值對形式定義對象,對象的key不再局限于字符串兼犯,也可以是Object忍捡。可以更加全面的描述對象的屬性切黔。
十三砸脊、問:Proxy是什么,有什么作用纬霞?
答: Proxy是ES6新增的一個構(gòu)造函數(shù)凌埂,可以理解為JS語言的一個代理,用來改變JS默認的一些語言行為诗芜,包括攔截默認的get/set等底層方法瞳抓,使得JS的使用自由度更高,可以最大限度的滿足開發(fā)者的需求伏恐。比如通過攔截對象的get/set方法孩哑,可以輕松地定制自己想要的key或者value。下面的例子可以看到翠桦,隨便定義一個myOwnObj的key,都可以變成自己想要的函數(shù)横蜒。
function createMyOwnObj() { //想把所有的key都變成函數(shù),或者Promise,或者anything return new Proxy({}, { get(target, propKey, receiver) { return new Promise((resolve, reject) => { setTimeout(() => { let randomBoolean = Math.random() > 0.5; let Message; if (randomBoolean) { Message = `你的${propKey}運氣不錯,成功了`; resolve(Message); } else { Message = `你的${propKey}運氣不行丛晌,失敗了`; reject(Message); } }, 1000); }); } });} let myOwnObj = createMyOwnObj(); myOwnObj.hahaha.then(result => { console.log(result) //你的hahaha運氣不錯鹰霍,成功了}).catch(error => { console.log(error) //你的hahaha運氣不行,失敗了}) myOwnObj.wuwuwu.then(result => { console.log(result) //你的wuwuwu運氣不錯茵乱,成功了}).catch(error => { console.log(error) //你的wuwuwu運氣不行茂洒,失敗了})復制代碼
十四、問:Reflect是什么瓶竭,有什么作用督勺?
答: Reflect是ES6引入的一個新的對象,他的主要作用有兩點斤贰,一是將原生的一些零散分布在Object智哀、Function或者全局函數(shù)里的方法(如apply、delete荧恍、get瓷叫、set等等),統(tǒng)一整合到Reflect上送巡,這樣可以更加方便更加統(tǒng)一的管理一些原生API摹菠。其次就是因為Proxy可以改寫默認的原生API,如果一旦原生API別改寫可能就找不到了骗爆,所以Reflect也可以起到備份原生API的作用次氨,使得即使原生API被改寫了之后,也可以在被改寫之后的API用上默認的API摘投。
十五煮寡、問:Promise是什么,有什么作用犀呼?
答: Promise是ES6引入的一個新的對象幸撕,他的主要作用是用來解決JS異步機制里,回調(diào)機制產(chǎn)生的“回調(diào)地獄”外臂。它并不是什么突破性的API坐儿,只是封裝了異步回調(diào)形式,使得異步回調(diào)可以寫的更加優(yōu)雅专钉,可讀性更高挑童,而且可以鏈式調(diào)用。
十六跃须、問:Iterator是什么,有什么作用娃兽?(重要)
答: Iterator是ES6中一個很重要概念菇民,它并不是對象,也不是任何一種數(shù)據(jù)類型。因為ES6新增了Set第练、Map類型阔馋,他們和Array、Object類型很像娇掏,Array呕寝、Object都是可以遍歷的,但是Set婴梧、Map都不能用for循環(huán)遍歷下梢,解決這個問題有兩種方案,一種是為Set塞蹭、Map單獨新增一個用來遍歷的API孽江,另一種是為Set、Map番电、Array岗屏、Object新增一個統(tǒng)一的遍歷API,顯然漱办,第二種更好这刷,ES6也就順其自然的需要一種設(shè)計標準,來統(tǒng)一所有可遍歷類型的遍歷方式娩井。Iterator正是這樣一種標準崭歧。或者說是一種規(guī)范理念撞牢。
就好像JavaScript是ECMAScript標準的一種具體實現(xiàn)一樣率碾,Iterator標準的具體實現(xiàn)是Iterator遍歷器。Iterator標準規(guī)定屋彪,所有部署了key值為[Symbol.iterator]所宰,且[Symbol.iterator]的value是標準的Iterator接口函數(shù)(標準的Iterator接口函數(shù): 該函數(shù)必須返回一個對象,且對象中包含next方法畜挥,且執(zhí)行next()能返回包含value/done屬性的Iterator對象)的對象仔粥,都稱之為可遍歷對象,next()后返回的Iterator對象也就是Iterator遍歷器蟹但。
//obj就是可遍歷的躯泰,因為它遵循了Iterator標準,且包含[Symbol.iterator]方法华糖,方法函數(shù)也符合標準的Iterator接口規(guī)范麦向。//obj.[Symbol.iterator]() 就是Iterator遍歷器let obj = { data: [ 'hello', 'world' ], [Symbol.iterator]() { const self = this; let index = 0; return { next() { if (index < self.data.length) { return { value: self.data[index++], done: false }; } else { return { value: undefined, done: true }; } } }; }};復制代碼
ES6給Set、Map客叉、Array诵竭、String都加上了[Symbol.iterator]方法话告,且[Symbol.iterator]方法函數(shù)也符合標準的Iterator接口規(guī)范,所以Set卵慰、Map沙郭、Array、String默認都是可以遍歷的裳朋。
//Arraylet array = ['red', 'green', 'blue'];array[Symbol.iterator]() //Iterator遍歷器array[Symbol.iterator]().next() //{value: "red", done: false} //Stringlet string = '1122334455';string[Symbol.iterator]() //Iterator遍歷器string[Symbol.iterator]().next() //{value: "1", done: false} //setlet set = new Set(['red', 'green', 'blue']);set[Symbol.iterator]() //Iterator遍歷器set[Symbol.iterator]().next() //{value: "red", done: false} //Maplet map = new Map();let obj= {map: 'map'};map.set(obj, 'mapValue');map[Symbol.iterator]().next() {value: Array(2), done: false}復制代碼
十七病线、問:for...in 和for...of有什么區(qū)別?
答: 如果看到問題十六鲤嫡,那么就很好回答送挑。問題十六提到了ES6統(tǒng)一了遍歷標準,制定了可遍歷對象泛范,那么用什么方法去遍歷呢让虐?答案就是用for...of。ES6規(guī)定罢荡,有所部署了載了Iterator接口的對象(可遍歷對象)都可以通過for...of去遍歷赡突,而for..in僅僅可以遍歷對象。
這也就意味著区赵,數(shù)組也可以用for...of遍歷惭缰,這極大地方便了數(shù)組的取值,且避免了很多程序用for..in去遍歷數(shù)組的惡習笼才。
上面提到的擴展運算符本質(zhì)上也就是for..of循環(huán)的一種實現(xiàn)漱受。
十八、Generator函數(shù)是什么骡送,有什么作用昂羡?
答: 如果說JavaScript是ECMAScript標準的一種具體實現(xiàn)、Iterator遍歷器是Iterator的具體實現(xiàn)摔踱,那么Generator函數(shù)可以說是Iterator接口的具體實現(xiàn)方式虐先。
執(zhí)行Generator函數(shù)會返回一個遍歷器對象,每一次Generator函數(shù)里面的yield都相當一次遍歷器對象的next()方法派敷,并且可以通過next(value)方法傳入自定義的value,來改變Generator函數(shù)的行為蛹批。
Generator函數(shù)可以通過配合Thunk 函數(shù)更輕松更優(yōu)雅的實現(xiàn)異步編程和控制流管理。
十九篮愉、async函數(shù)是什么腐芍,有什么作用?
答: async函數(shù)可以理解為內(nèi)置自動執(zhí)行器的Generator函數(shù)語法糖试躏,它配合ES6的Promise近乎完美的實現(xiàn)了異步編程解決方案猪勇。
二十、Class冗酿、extends是什么埠对,有什么作用络断?
答: ES6 的class可以看作只是一個ES5生成實例對象的構(gòu)造函數(shù)的語法糖裁替。它參考了java語言项玛,定義了一個類的概念,讓對象原型寫法更加清晰弱判,對象實例化更像是一種面向?qū)ο缶幊探缶凇lass類可以通過extends實現(xiàn)繼承。它和ES5構(gòu)造函數(shù)的不同點:
a. 類的內(nèi)部定義的所有方法昌腰,都是不可枚舉的开伏。
///ES5function ES5Fun (x, y) { this.x = x; this.y = y;}ES5Fun.prototype.toString = function () { return '(' + this.x + ', ' + this.y + ')';}var p = new ES5Fun(1, 3);p.toString();Object.keys(ES5Fun.prototype); //['toString'] //ES6class ES6Fun { constructor (x, y) { this.x = x; this.y = y; } toString () { return '(' + this.x + ', ' + this.y + ')'; }} Object.keys(ES6Fun.prototype); //[]復制代碼
b.ES6的class類必須用new命令操作,而ES5的構(gòu)造函數(shù)不用new也可以執(zhí)行遭商。
c.ES6的class類不存在變量提升固灵,必須先定義class之后才能實例化,不像ES5中可以將構(gòu)造函數(shù)寫在實例化之后劫流。
d.ES5 的繼承巫玻,實質(zhì)是先創(chuàng)造子類的實例對象this,然后再將父類的方法添加到this上面祠汇。ES6 的繼承機制完全不同仍秤,實質(zhì)是先將父類實例對象的屬性和方法,加到this上面(所以必須先調(diào)用super方法)可很,然后再用子類的構(gòu)造函數(shù)修改this诗力。
二十一、module我抠、export苇本、import是什么,有什么作用菜拓?
答: module瓣窄、export、import是ES6用來統(tǒng)一前端模塊化方案的設(shè)計思路和實現(xiàn)方案尘惧。export康栈、import的出現(xiàn)統(tǒng)一了前端模塊化的實現(xiàn)方案,整合規(guī)范了瀏覽器/服務(wù)端的模塊化方法喷橙,用來取代傳統(tǒng)的AMD/CMD啥么、requireJS、seaJS贰逾、commondJS等等一系列前端模塊不同的實現(xiàn)方案悬荣,使前端模塊化更加統(tǒng)一規(guī)范,JS也能更加能實現(xiàn)大型的應(yīng)用程序開發(fā)疙剑。
import引入的模塊是靜態(tài)加載(編譯階段加載)而不是動態(tài)加載(運行時加載)氯迂。
import引入export導出的接口值是動態(tài)綁定關(guān)系践叠,即通過該接口,可以取到模塊內(nèi)部實時的值嚼蚀。
二十二禁灼、日常前端代碼開發(fā)中,有哪些值得用ES6去改進的編程優(yōu)化或者規(guī)范轿曙?
答:
1弄捕、常用箭頭函數(shù)來取代var self = this;
的做法。
2导帝、常用let取代var命令守谓。
3、常用數(shù)組/對象的結(jié)構(gòu)賦值來命名變量您单,結(jié)構(gòu)更清晰斋荞,語義更明確,可讀性更好虐秦。
4平酿、在長字符串多變量組合場合,用模板字符串來取代字符串累加羡疗,能取得更好地效果和閱讀體驗染服。
5、用Class類取代傳統(tǒng)的構(gòu)造函數(shù)叨恨,來生成實例化對象柳刮。
6、在大型應(yīng)用開發(fā)中痒钝,要保持module模塊化開發(fā)思維秉颗,分清模塊之間的關(guān)系,常用import送矩、export方法蚕甥。