近期在复习ES6,针对ES6新的知识点,以问答形式整理一个全面知识和问题汇总。(全干货,适合对ES6有必定理解的同窗复习,以及ES6面试。)前端
答: ES6是新一代的JS语言标准,对分JS语言核心内容作了升级优化,规范了JS使用标准,新增了JS原生方法,使得JS使用更加规范,更加优雅,更适合大型应用的开发。java
答:babel是一个 ES6 转码器,能够将 ES6 代码转为 ES5 代码,以便兼容那些还没支持ES6的平台。c++
答: 在ES6以前,声明变量只能用var,var方式声明变量实际上是很不合理的,准确的说,是由于ES5里面没有块级做用域是很不合理的,甚至能够说是一个语言层面的bug(这也是不少c++、java开发人员看不懂,也瞧不起JS语言的劣势之一)。没有块级做用域回来带不少难以理解的问题,好比for循环var变量泄露,变量覆盖等问题。let 声明的变量拥有本身的块级做用域,且修复了var声明变量带来的变量提高问题。es6
ES6新增了字符串模板,在拼接大段字符串时,用反斜杠(`)取代以往的字符串相加的形式,能保留全部空格和换行,使得字符串拼接看起来更加直观,更加优雅。面试
ES6在String原型上新增了includes()方法,用于取代传统的只能用indexOf查找包含字符的方法(indexOf返回-1表示没查到不如includes方法返回false更明确,语义更清晰), 此外还新增了startsWith(), endsWith(), padStart(),padEnd(),repeat()等方法,可方便的用于查找,补全字符串。编程
a. 数组解构赋值。ES6能够直接以let [a,b,c] = [1,2,3]
形式进行变量赋值,在声明较多变量时,不用再写不少let(var),且映射关系清晰,且支持赋默认值。数组
b. 扩展运算符。ES6新增的扩展运算符(...)(重要),能够轻松的实现数组和松散序列的相互转化,能够取代arguments对象和apply方法,轻松获取未知参数个数状况下的参数集合。(尤为是在ES5中,arguments并非一个真正的数组,而是一个类数组的对象,可是扩展运算符的逆运算却能够返回一个真正的数组)。扩展运算符还能够轻松方便的实现数组的复制和解构赋值(let a = [2,3,4]; let b = [...a]
)。浏览器
ES6在Array原型上新增了find()方法,用于取代传统的只能用indexOf查找包含数组项目的方法,且修复了indexOf查找不到NaN的bug([NaN].indexOf(NaN) === -1
).此外还新增了copyWithin(), includes(), fill(),flat()等方法,可方便的用于字符串的查找,补全,转换等。babel
ES6在Number原型上新增了isFinite(), isNaN()方法,用来取代传统的全局isFinite(), isNaN()方法检测数值是否有限、是不是NaN。ES5的isFinite(), isNaN()方法都会先将非数值类型的参数转化为Number类型再作判断,这实际上是不合理的,最形成isNaN('NaN') === true
的奇怪行为--'NaN'是一个字符串,可是isNaN却说这就是NaN。而Number.isFinite()和Number.isNaN()则不会有此类问题(Number.isNaN('NaN') === false
)。(isFinite()同上)数据结构
ES6在Math对象上新增了Math.cbrt(),trunc(),hypot()等等较多的科学计数法运算方法,能够更加全面的进行立方根、求和立方根等等科学计算。
a. 对象属性变量式声明。ES6能够直接以变量形式声明对象属性或者方法,。比传统的键值对形式声明更加简洁,更加方便,语义更加清晰。
let [apple, orange] = ['red appe', 'yellow orange']; let myFruits = {apple, orange}; // let myFruits = {apple: 'red appe', orange: 'yellow orange'};
尤为在对象解构赋值(见优化部分b.)或者模块输出变量时,这种写法的好处体现的最为明显:
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. 对象的解构赋值。 ES6对象也能够像数组解构赋值那样,进行变量的解构赋值:
let {apple, orange} = {apple: 'red appe', orange: 'yellow orange'};
c. 对象的扩展运算符(...)。 ES6对象的扩展运算符和数组扩展运算符用法本质上差异不大,毕竟数组也就是特殊的对象。对象的扩展运算符一个最经常使用也最好用的用处就在于能够轻松的取出一个目标对象内部所有或者部分的可遍历属性,从而进行对象的合并和分解。
let {apple, orange, ...otherFruits} = {apple: 'red apple', orange: 'yellow orange', grape: 'purple grape', peach: 'sweet peach'}; // otherFruits {grape: 'purple grape', peach: 'sweet peach'} // 注意: 对象的扩展运算符用在解构赋值时,扩展运算符只能用在最有一个参数(otherFruits后面不能再跟其余参数) let moreFruits = {watermelon: 'nice watermelon'}; let allFruits = {apple, orange, ...otherFruits, ...moreFruits};
d. super 关键字。ES6在Class类里新增了相似this的关键字super。同this老是指向当前函数所在的对象不一样,super关键字老是指向当前函数所在对象的原型对象。
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}
c. ES6在Object原型上新增了getOwnPropertyDescriptors()方法,此方法加强了ES5中getOwnPropertyDescriptor()方法,能够获取指定对象全部自身属性的描述对象。结合defineProperties()方法,能够完美复制对象,包括复制get和set属性。
d. ES6在Object原型上新增了getPrototypeOf()和setPrototypeOf()方法,用来获取或设置当前对象的prototype对象。这个方法存在的意义在于,ES5中获取设置prototype对像是经过__proto__属性来实现的,然而__proto__属性并非ES规范中的明文规定的属性,只是浏览器各大产商“私自”加上去的属性,只不过由于适用范围广而被默认使用了,再非浏览器环境中并不必定就可使用,因此为了稳妥起见,获取或设置当前对象的prototype对象时,都应该采用ES6新增的标准用法。
d. ES6在Object原型上还新增了Object.keys(),Object.values(),Object.entries()方法,用来获取对象的全部键、全部值和全部键值对数组。
a. 箭头函数(核心)。箭头函数是ES6核心的升级项之一,箭头函数里没有本身的this,这改变了以往JS函数中最让人难以理解的this运行机制。主要优化点:
Ⅰ. 箭头函数内的this指向的是函数定义时所在的对象,而不是函数执行时所在的对象。ES5函数里的this老是指向函数执行时所在的对象,这使得在不少状况下this的指向变得很难理解,尤为是非严格模式状况下,this有时候会指向全局对象,这甚至也能够归结为语言层面的bug之一。ES6的箭头函数优化了这一点,它的内部没有本身的this,这也就致使了this老是指向上一层的this,若是上一层仍是箭头函数,则继续向上指,直到指向到有本身this的函数为止,并做为本身的this。
Ⅱ. 箭头函数不能用做构造函数,由于它没有本身的this,没法实例化。
Ⅲ. 也是由于箭头函数没有本身的this,因此箭头函数 内也不存在arguments对象。(能够用扩展运算符代替)
b. 函数默认赋值。ES6以前,函数的形参是没法给默认值得,只能在函数内部经过变通方法实现。ES6以更简洁更明确的方式进行函数默认赋值
function es6Fuc (x, y = 'default') { console.log(x, y); } es6Fuc(4) // 4, default
ES6新增了双冒号运算符,用来取代以往的bind,call,和apply。(浏览器暂不支持,Babel已经支持转码)
foo::bar; // 等同于 bar.bind(foo); foo::bar(...arguments); // 等同于 bar.apply(foo, arguments);
答: Set是ES6引入的一种相似Array的新的数据结构,Set实例的成员相似于数组item成员,区别是Set实例的成员都是惟一,不重复的。这个特性能够轻松地实现数组去重。
答: Map是ES6引入的一种相似Object的新的数据结构,Map能够理解为是Object的超集,打破了以传统键值对形式定义对象,对象的key再也不局限于字符串,也能够是Object。能够更加全面的描述对象的属性。
答: Proxy是ES6新增的一个构造函数,能够理解为JS语言的一个代理,用来改变JS默认的一些语言行为,包括拦截默认的get/set等底层方法,使得JS的使用自由度更高,能够最大限度的知足开发者的需求。好比经过拦截对象的get/set方法,能够轻松地定制本身想要的key或者value。下面的例子能够看到,随便定义一个myOwnObj的key,均可以变成本身想要的函数。
function createMyOwnObj() { //想把全部的key都变成函数,或者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运气不行,失败了 })
答: Promise是ES6引入的一个新的对象,他的主要做用是用来解决JS异步机制里,回调机制产生的“回调地狱”。它并非什么突破性的API,只是封装了异步回调形式,使得异步回调能够写的更加优雅,可读性更高,并且能够链式调用。
答: 若是看到问题十六,那么就很好回答。问题十六提到了ES6统一了遍历标准,制定了可遍历对象,那么用什么方法去遍历呢?答案就是用for...of。ES6规定,有所部署了载了Iterator接口的对象(可遍历对象)均可以经过for...of去遍历,而for..in仅仅能够遍历对象。
这也就意味着,数组也能够用for...of遍历,这极大地方便了数组的取值,且避免了不少程序用for..in去遍历数组的恶习。
上面提到的扩展运算符本质上也就是for..of循环的一种实现。
答: async函数能够理解为内置自动执行器的Generator函数语法糖,它配合ES6的Promise近乎完美的实现了异步编程解决方案。
答: module、export、import是ES6用来统一前端模块化方案的设计思路和实现方案。export、import的出现统一了前端模块化的实现方案,整合规范了浏览器/服务端的模块化方法,用来取代传统的AMD/CMD、requireJS、seaJS、commondJS等等一系列前端模块不一样的实现方案,使前端模块化更加统一规范,JS也能更加能实现大型的应用程序开发。
import引入的模块是静态加载(编译阶段加载)而不是动态加载(运行时加载)。
import引入export导出的接口值是动态绑定关系,即经过该接口,能够取到模块内部实时的值。
答:
一、经常使用箭头函数来取代var self = this;
的作法。
二、经常使用let取代var命令。
三、经常使用数组/对象的结构赋值来命名变量,结构更清晰,语义更明确,可读性更好。
四、在长字符串多变量组合场合,用模板字符串来取代字符串累加,能取得更好地效果和阅读体验。
五、用Class类取代传统的构造函数,来生成实例化对象。
六、在大型应用开发中,要保持module模块化开发思惟,分清模块之间的关系,经常使用import、export方法。