ES2015(ES6)
ES2015 是2015年公布的ECMA Script(JS) 语言版本,也是第6个版本,所以也称之为ES6。在尔后ECMA Script每年公布一个大版本新减少一些重要个性,咱们称之为ES6+。
本文次要总结了ES2015-ES2019的次要个性,一个学习前端的童鞋应该是罕用且了解的一些个性。
ES2015 的次要作用:
- 解决原有语法的一些有余
- 对原有语法进行加强
全新的对象、全新的办法、全新的性能
Promise、Proxy、Object.assign等
全新的数据类型和数据结构
Symbol、Set、Map等
ES2015 罕用的环境反对状况
- nodejs查问:https://node.green/
- 浏览器查问:http://kangax.github.io/compa...
PC浏览器对ES2015的反对状况
- Chrome:51 版起便能够反对 97% 的 ES6 新个性。
- Firefox:53 版起便能够反对 97% 的 ES6 新个性。
- Safari:10 版起便能够反对 99% 的 ES6 新个性。
- Edge:Edge 15能够反对 96% 的 ES6 新个性。Edge 14 能够反对 93% 的 ES6 新个性。
- IE:IE7 ~ 11 根本不反对 ES6
挪动端浏览器对ES2015的反对状况
- iOS:10.0 版起便能够反对 99% 的 ES6 新个性。
- Android:根本不反对 ES6 新个性(5.1 仅反对 25%)
服务器对ES2015的反对状况,具体查看:https://node.green/
- Node.js:6.5 版起便能够反对 97% 的 ES6 新个性。(6.0 反对 92%)
var(比照let、const)
- 只有全局作用域、函数作用域,不存在严格的块级作用域
- 存在变量晋升
- 变量的申明和定义能够离开进行
- 变量能够反复申明
let(块级作用域)
- 存在块级作用域
- 不能变量晋升
- 变量的申明和定义能够离开进行
- 变量不能反复申明
const 常量
- 存在块级作用域
- 不能变量晋升
- 变量的申明和定义必须在同一个语句中
- 变量不能反复申明
- 不能批改申明过的变量值(例如:能够批改对象的属性值,不能批改对象地址)
- 最佳实际:不必var,主用const,配合let
数组解构
const [foo, bar, baz] = arrconsole.log(foo, bar, baz)const [, , baz] = arrconsole.log(baz)// 解构残余的数组元素// 只能在最初一个地位应用扩大运算符const [foo, ...rest] = arrconsole.log(rest)// 解构时元素较少,依照程序取元素const [foo] = arrconsole.log(foo)// 解构时设置默认值const [foo, bar, baz = 123, more = 'default value'] = arrconsole.log(bar, more)
对象解构
const obj = { name: 'zce', age: 18 }// 变量名反复时,能够重命名和设置默认值const name = 'tom'const { name: objName = 'jack' } = objconsole.log(objName)
模板字符串
- 反对换行符
- 反对嵌入变量、表达式
const name = 'tom'// 能够通过 ${} 插入表达式,表达式的执行后果将会输入到对应地位const msg = `hey, ${name} --- ${1 + 2} ---- ${Math.random()}`console.log(msg)
字符串的扩大办法
- includes 蕴含字符串
- startsWith 是否以某字符串结尾
- endsWith 是否以某字符串完结
const message = 'Error: foo is not defined.'console.log( // message.startsWith('Error') // message.endsWith('.') message.includes('foo'))
办法的参数默认值
- 在function参数前面应用=设置默认值
- 只有当形参传递是undefined或者没有传递值时,才会设置默认值(false也不会)
- 如果只有局部默认值,须要将设置默认值的代码放到前面;否则无奈失常应用
// 默认参数肯定是在形参列表的最初function foo (bar,enable = true) { console.log('foo invoked - enable: ') console.log(enable)}foo(false)
办法的残余参数
- 只能呈现在形参的最初一位
- 只能应用一次
- args是一个数组,区别于arguments是一个伪数组
function foo (first, ...args) { console.log(args)}foo(1, 2, 3, 4)
开展数组
const arr = ['foo', 'bar', 'baz']// console.log(// arr[0],// arr[1],// arr[2],// )// console.log.apply(console, arr)console.log(...arr)
箭头函数
插件:Fira Code字体将箭头画的更好看
const arr = [1, 2, 3, 4, 5, 6, 7]// arr.filter(function (item) {// return item % 2// })// 罕用场景,回调函数arr.filter(i => i % 2)
箭头函数的简写
function(value){return value} 等价于 value=>value
箭头函数的this指向
- 一般函数的this指向调用它办法的对象
- 箭头函数的this和它里面函数的this指向雷同,即:箭头函数不会扭转this的指向
// 箭头函数与 this// 箭头函数不会扭转 this 指向const person = { name: 'tom', // sayHi: function () { // console.log(`hi, my name is ${this.name}`)//tom,this指向该函数调用者 // } sayHi: () => { console.log(`hi, my name is ${this.name}`) //undefined,this和sayHi()里面的函数this雷同 }, sayHiAsync: function () { // const _this = this // setTimeout(function () { // console.log(_this.name) //这里的this为window,所以须要应用_this // }, 1000) console.log(this) setTimeout(() => { // console.log(this.name) //这里的this指向sayHiAsync里的this,即person console.log(this) }, 1000) }}person.sayHi()person.sayHiAsync()
对象字面量
- 如果属性名和值的变量名雷同,能够省略一个变量
- 办法的简写:能够省略“:function”
- 计算属性名:属性名能够在[]外面应用任意表达式
const bar = '345'const obj = { foo: 123, // bar: bar // 属性名与变量名雷同,能够省略 : bar bar, // method1: function () { // console.log('method111') // } // 办法能够省略 : function method1 () { console.log('method111') // 这种办法就是一般的函数,this 指向obj。 console.log(this) }, // Math.random(): 123 // 不容许,应用[]才行 // 通过 [] 让表达式的后果作为属性名 [bar]: 123}
Object.assign
Object.assign是不齐全的深拷贝?它到底拷贝了多少货色?
获取不到obj中的get、set信息
- 将源对象中的值赋值到指标对象
- 指标对象和返回值是同一个对象
- 如果指标对象中有雷同名字的属性,则笼罩该属性
- 能够传入多个源对象,依照程序顺次笼罩指标对象
const source1 = { a: 123, b: 123}const source2 = { b: 789, d: 789}const target = { a: 456, c: 456}const result = Object.assign(target, source1, source2)console.log(target)console.log(result === target) //true,指标对象和返回值是一个对象
Object.is
0 == false // => true0 === false // => false+0 === -0 // => trueNaN === NaN // => falseObject.is(+0, -0) // => falseObject.is(NaN, NaN) // => true
Proxy 和 Object.defineProperty
Proxy的作用
对Object属性变动进行监听
比照Object.defineProperty
参考笔记:https://gitee.com/ymcdhr/e-ta...
Reflect(对立的操作Object对象办法)
- Proxy属性的办法中默认调用了Reflect中的办法,例如:
const obj = { foo: '123', bar: '456'}const proxy = new Proxy(obj, { get (target, property) { console.log('watch logic~') // Proxy中如果不写,默认调用了此办法 return Reflect.get(target, property) }})
- Relect提供了对立的操作Object对象的办法,MDN上有残缺的13中办法:
https://developer.mozilla.org...
// console.log('name' in obj)// console.log(delete obj['age'])// console.log(Object.keys(obj))console.log(Reflect.has(obj, 'name'))console.log(Reflect.deleteProperty(obj, 'age'))console.log(Reflect.ownKeys(obj))
Promise
参考文档:js单线程机制与异步编程(Promise、Generator、Async、Await)
Class 类的根本语法
// class 关键词// function Person (name) {// this.name = name// }// Person.prototype.say = function () {// console.log(`hi, my name is ${this.name}`)// }class Person { // 构造函数 constructor (name) { this.name = name } // 成员变量 age = 18 // 成员函数 say () { console.log(`hi, my name is ${this.name}`) }}const p = new Person('tom')p.say()
Class 中的静态方法static
- 申明静态方法:static关键字
- 调用静态方法:Person.say
- 静态方法的this指向为类
// static 办法class Person { constructor (name) { this.name = name } say () { console.log(`hi, my name is ${this.name}`) } static create (name) { return new Person(name) }}const tom = Person.create('tom')tom.say()
Class 的继承
- 应用extends继承
- 留神super的应用,可能拜访父类;通常用来执行父类构造函数。
class Person { constructor (name) { this.name = name } say () { console.log(`hi, my name is ${this.name}`) }}class Student extends Person { constructor (name, number) { super(name) // 调用父类构造函数,否则name就没有赋值(重要) this.number = number } hello () { super.say() // 调用父类成员 console.log(`my school number is ${this.number}`) }}const s = new Student('jack', '100')s.hello()
Set、Map
Set 没有反复元素的数组汇合
罕用的成员办法
- s.add(item) 增加item,返回汇合自身,可链式调用
- s.size 获取Set的长度
- s.has(item)判断是否存在某个item
- s.delete(item)删除某个item
- s.clear()删除全副
const s = new Set()s.add(1).add(2).add(3).add(4).add(2)// console.log(s)// s.forEach(i => console.log(i)) //forEach、for...of 都能够用来遍历Set// for (let i of s) {// console.log(i)// }// console.log(s.size)// console.log(s.has(100))// console.log(s.delete(3))// console.log(s)// s.clear()// console.log(s)
罕用来数组去重
// 利用场景:数组去重const arr = [1, 2, 1, 3, 4, 1]const result1 = Array.from(new Set(arr))const result2 = [...new Set(arr)]console.log(result1,result2)
Map 能应用简单构造作为属性的对象汇合
以前的对象存储对象属性时,会将简单数据转换成字符串(toString()办法),如下:
const obj = {}obj[true] = 'value'obj[123] = 'value'obj[{ a: 1 }] = 'value'console.log(Object.keys(obj))//0: "123"//1: "true"//2: "[object Object]"
应用Map能够存储简单数据作为对象属性,罕用的办法有如下:
const m = new Map()const tom = { name: 'tom' }m.set(tom, 90)console.log(m)console.log(m.get(tom))// m.has()// m.delete()// m.clear()// forEach能够遍历Map中的itemm.forEach((value, key) => { console.log(value, key)})
Symbol
一个全新的根底数据类型,每次创立都是举世无双的值
let s = Symbol();typeof s// "symbol"let s1 = Symbol('foo');let s2 = Symbol('foo');s1 === s2 // false// for办法是创立的一样的值,参数会主动转换成字符串let s3 = Symbol.for('foo');let s4 = Symbol.for('foo');s3 === s4 // true
能够转换为字符串,通过description(ES2019提供的办法)
let s1 = Symbol('foo');let s2 = Symbol('foo');s1 // Symbol(foo)s2 // Symbol(foo)s1 === s2 // falses1.toString() // "Symbol(foo)"s2.toString() // "Symbol(foo)"s1.description // "foo" // ES2019提供的办法
能够作为对象的属性名,能够防止同名抵触
const obj = {}obj[Symbol()] = '123'obj[Symbol()] = '456'console.log(obj)//Symbol(): "123"//Symbol(): "456"
应用 Symbol 值定义属性时,Symbol 值必须放在方括号之中,而且不能应用点运算符
let s = Symbol();// 第一种写法let a = {};a[s] = 'Hello!';// 第二种写法let a = { [s]: 'Hello!'};// 以上写法都失去同样后果a[s] // "Hello!"
能够作为对象的公有成员,不能在内部间接拜访(因为每次拜访都不一样),只能通过外部this拜访
// 案例2:Symbol 模仿实现公有成员// a.js ======================================const name = Symbol()const person = { [name]: 'zce', say () { console.log(this[name]) }}// 只对外裸露 person// b.js =======================================// 因为无奈创立出一样的 Symbol 值,// 所以无奈间接拜访到 person 中的「公有」成员// person[Symbol()]person.say()
留神:for...in、Obeject.keys、Json.stringify都无奈在Symbol上应用
应用:Object.getOwnPropertySymbols,代替Obeject.keys办法用于Symbol
for...of 对立遍历办法
以前的 for...in 遍历键值对,forEach 存在局限性
- 能够用应用break终止遍历,forEach不能跳出循环
- 能够遍历Array数组、Set和Map对象
- 一般对象不能被间接 for...of 遍历,因为它没有Symbol.iterator属性
- 对象(Object)之所以没有默认部署 Iterator 接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,须要开发者手动指定。
- 所有能够应用 for...of 的对象都须要具备Symbol.iterator属性
// for...of 循环const arr = [100, 200, 300, 400]// for...of 循环能够代替 数组对象的 forEach 办法 但能够应用break跳出循环arr.forEach(item => { console.log(item)})for (const item of arr) { console.log(item) if (item > 100) { break }}// forEach 无奈跳出循环,必须应用 some 或者 every 办法// arr.forEach() // 不能跳出循环// arr.some()// arr.every()// 遍历 Set 与遍历数组雷同const s = new Set(['foo', 'bar'])for (const item of s) { console.log(item)}// 遍历 Map 能够配合数组构造语法,间接获取键值const m = new Map()m.set('foo', '123')m.set('bar', '345')for (const [key, value] of m) { console.log(key, value)}// 一般对象不能被间接 for...of 遍历const obj = { foo: 123, bar: 456 }for (const item of obj) { console.log(item)}
可迭代接口 iterator(次要给for...of应用)
- 一些数据结构的原型对象 proto 中含有Symbol.iterator办法
- iterator办法返回一个带next()办法的指针对象
- 每次执行next()办法,它都会返回下一个数据
具备 Symbol.iterator 属性的数据结构
Array、Map、Set、String、TypedArray、函数的 arguments 对象、NodeList 对象
iterator 的遍历过程是这样的。
- (1)创立一个指针对象,指向以后数据结构的起始地位。也就是说,遍历器对象实质上,就是一个指针对象。
- (2)第一次调用指针对象的next办法,能够将指针指向数据结构的第一个成员。
- (3)第二次调用指针对象的next办法,指针就指向数据结构的第二个成员。
- (4)一直调用指针对象的next办法,直到它指向数据结构的完结地位。
使对象可能应用 for...of
const obj = { // 应用计算属性,用[]存表达式属性名 // 1、Iterable,对象必须要有一个Symbol.iterator属性 [Symbol.iterator]: function () { return { // 2、Iterator,返回的对象有一个next()办法 next: function () { // 3、IterationResult,next()办法返回一个对象 return { value: 'zce', done: true } } } }}for (const item of obj) { console.log('循环体', item)}
使对象可能应用 for...of,残缺的代码
const obj = { store: ['foo', 'bar', 'baz'], [Symbol.iterator]: function () { let index = 0 const self = this return { next: function () { const result = { value: self.store[index], done: index >= self.store.length } index++ return result } } }}for (const item of obj) { console.log('循环体', item)}
迭代器模式(设计模式之一)
迭代器的另外一个主要用途:迭代器模式
Gernator 生成器
参考:js单线程机制与异步编程(Promise、Generator、Async、Await)
ES Modules
参考:工程化中的ES Modules/CommonJS/AMD/CMD
ES2016 新增个性
数组的includes办法
// Array.prototype.includes -----------------------------------const arr = ['foo', 1, NaN, false]// 找到返回元素下标console.log(arr.indexOf('foo'))// 找不到返回 -1console.log(arr.indexOf('bar'))// 无奈找到数组中的 NaNconsole.log(arr.indexOf(NaN))// 间接返回是否存在指定元素console.log(arr.includes('foo'))// 可能查找 NaNconsole.log(arr.includes(NaN))
指数运算符
// 指数运算符 ---------------------------------------------------console.log(Math.pow(2, 10))console.log(2 ** 10)
ES2017 新增个性
Object新增办法
Object.values —— 相似Object.keys,返回对象的值数组
Object.entries —— 以数组的模式返回对象中的键值对,联合for...of能够遍历obj
const obj = { foo: 'value1', bar: 'value2'}// Object.values -----------------------------------------------------------console.log(Object.values(obj))// Object.entries ----------------------------------------------------------console.log(Object.entries(obj))// 比iterator 更简略,间接先将obj转换成数组,再应用 for...offor (const [key, value] of Object.entries(obj)) { console.log(key, value)}console.log(new Map(Object.entries(obj)))
Object.getOwnPropertyDescriptors —— 获取对象属性的残缺信息,次要配合ES5的get、set应用
Object.assign 获取不到set、get信息
const p1 = { firstName: 'Lei', lastName: 'Wang', get fullName () { return this.firstName + ' ' + this.lastName }}// console.log(p1.fullName)// const p2 = Object.assign({}, p1)// p2.firstName = 'zce'// console.log(p2)const descriptors = Object.getOwnPropertyDescriptors(p1)// console.log(descriptors)const p2 = Object.defineProperties({}, descriptors)p2.firstName = 'zce'console.log(p2.fullName)
String新增办法
String.prototype.padStart / String.prototype.padEnd
const books = { html: 5, css: 16, javascript: 128}// for (const [name, count] of Object.entries(books)) {// console.log(name, count)// }for (const [name, count] of Object.entries(books)) { console.log(`${name.padEnd(16, '-')}|${count.toString().padStart(3, '0')}`)}
在函数参数中增加尾逗号
const arr = [ 100, 200, 300, 400,]const arr = [ 100, 200, 300]
新增Async/Await异步编程语法糖
参考资料:ecma6.0英文标准
来自于ES2017规范;async、await可能更不便的进行异步编程,且通常须要成对应用;
1、async、await绝对于generate函数降级晋升的中央:
- (1)内置执行器
- (2)更好的语义
- (3)更好的扩展器
- (4)返回值是promise
2、async、await的返回值
(1)async的返回值是promise对象;然而须要留神:
1、async函数返回一个 Promise 对象。
2、async函数外部return语句返回的值,会成为then办法回调函数的参数。
async function f() { return 'hello world';}f().then(v => console.log(v))// "hello world"
- (2)await返回值依据前面的参数不同而不同,有两种;
3、await 前面的参数
- (1)await前面跟一个promise对象;=> 返回promise对象的后果;
- (2)await前面跟一个值;=> 间接返回该值;
4、错误处理办法
如果await前面的promise异步操作出错,那么等同于async函数返回的 Promise 对象被reject。最好把await命令放在try...catch代码块中
async function f() { await new Promise(function (resolve, reject) { throw new Error('出错了'); });}f().then(v => console.log(v)).catch(e => console.log(e))async function myFunction() { try { await somethingThatReturnsAPromise(); } catch (err) { console.log(err); }}// 另一种写法async function myFunction() { await somethingThatReturnsAPromise() .catch(function (err) { console.log(err); });}
5、并发/循环异步申请的解决
(1)如果是串行执行异步申请,须要同步期待,会比拟耗时;
let foo = await getFoo();let bar = await getBar();// 1、循环外面的串行执行:async function dbFuc(db) { let docs = [{}, {}, {}]; for (let doc of docs) { await db.post(doc); }}// 2、谬误的串行执行:?why?思考?forEach外面的async应该是异步同时执行的,没有await?function dbFuc(db) { //这里不须要 async let docs = [{}, {}, {}]; // 可能失去谬误后果 docs.forEach(async function (doc) { await db.post(doc); });}
(2)并行执行——期待所有响应,再执行下一个步骤;
async function dbFuc(db) { let docs = [{}, {}, {}]; let promises = docs.map((doc) => db.post(doc)); let results = await Promise.all(promises); console.log(results);}// 或者应用上面的写法async function dbFuc(db) { let docs = [{}, {}, {}]; let promises = docs.map((doc) => db.post(doc)); let results = []; for (let promise of promises) { results.push(await promise); } console.log(results);}
(3)并行执行——不期待所有响应,回来一个回调一个;
// 能够不要在for外面await;也不要写成串行的回调;// 是在for外面写异步办法的调用?例如: let docs = [{}, {}, {}]; for (let doc of docs) { db.post(doc).then((res)=>{}); }
6、async、await原理(利用generator实现async、await)
async、await底层封装起来了看不见代码实现
能够利用iterator或者generator函数,进行封装实现;参考代码:(未完待续)
ES2019 前定义的数据类型:8种
6+1 种原始数据类型 + bigInt(下个版本)
- null
- undefined
- number
- string
- boolean
- Symbol(ES2015)
- BigInt(stage-4,下个版本出标准化)
1 种援用数据类型
Object
特地鸣谢:拉勾教育前端高薪训练营