ECMAScript版本 | 发布时间 | 新增特性 |
---|---|---|
ECMAScript 2009(ES5) | 2009年11月 | 扩展了Object、Array、Function的功能等 |
ECMAScript 2015(ES6) | 2015年6月 | 类,模块化,箭头函数,函数参数默认值等 |
ECMAScript 2016(ES7) | 2016年3月 | includes,指数操作符 |
ECMAScript 2017(ES8) | 2017年6月 | sync/await,Object.values(),Object.entries(),String padding等 |
ECMAScript 2018(ES9) | 2018年 | Promise.finally(),Rest/Spread 属性等 |
ECMAScript 2019(ES10) | 2019年 | 新增了Array的flat()方法和flatMap()方法,Array.prototype.flat() 等 |
ES6是最重要的改变
类(class)(常用)
ES6 引入了class(类),让JavaScript的面向对象编程和工程化组件化变得更加简单和易于理解,方便于我们维护代码,和代码可读性。
import xxx from "./xxx"
class aaa extends xxx {
constructor(){
super()
}
//方法
static bbb
ccc(){
}
}
var let const(常用语法)
let,const具有块级作用域,不具有变量提升。
const 用于不能被重新赋值的变量,其实const并不是绝对意义上的不可以改变,当const一个数组时,我们可以改变数组内的内容。
模块化(Module)
ES5不支持原生的模块化,在ES6中模块作为重要的组成部分被添加进来。模块的功能主要由 export 和 import 组成。每一个模块都有自己单独的作用域,模块之间的相互调用关系是通过 export 来规定模块对外暴露的接口,通过import来引用其它模块提供的接口。同时还为模块创造了命名空间,防止函数的命名冲突。
// ES6的语法
import from
export default xxx
箭头(Arrow)函数(常用语法)
常用语法,他帮助我们更好的解决了this指向的问题,以及和bind的使用原理
模板字符串(``)(常用语法)
常用语法,使用模板字符串,字符串中可以直接使用{}
来写变量,这样简化了拼装字符串。
解构赋值(常用语法)
解构赋值语法是JavaScript的一种表达式,可以方便的从数组或者对象中快速提取值赋给定义的变量。
//语法
import {xxx} from './xxxxx'
延展操作符(Spread operator)(常用语法)
延展操作符…可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造对象时, 将对象表达式按key-value的方式展开。常用在数组的展开使用
语法
函数调用:
myFunction(...iterableObj); 复制代码
数组构造或字符串:
[...iterableObj, '4', ...'hello', 6]; 复制代码
构造对象时,进行克隆或者属性拷贝(ECMAScript 2018规范新增特性):
let objClone = { ...obj }; 复制代码
reactJS开发中常会用在redux中
对象属性简写(常用语法)
在ES6中允许我们在设置一个对象的属性的时候不指定属性名。
const name='Ming',age='18',city='Shanghai';
const student = { name:name, age:age, city:city }; //{name: "Ming", age: "18", city: "Shanghai"}
console.log(student);
const student = { name, age, city }; //{name: "Ming", age: "18", city: "Shanghai"}
Promise
Promise 是异步编程的一种解决方案,比传统的解决方案callback更加的优雅。它最早由社区提出和实现的,ES6 将其写进了语言标准,统一了用法,原生提供了Promise对象。(promise在真实开发中使用的较少,一般在封装一些异步操作时,或者封装插件,库的时候来使用,方便使用者来链式调用。
使用者直接使用.then来获取数据,同样可以使用async和await终级解决方案,阻塞式同步来获取异步数据。
参数默认值(常用)
定义函数或者方法时,可以直接在形参上设置默认值。
Proxy(参考连接)
代理对象
监视某个对象中的属性读写
在vue3.0中,使用了Proxy和映射来重写了双向数据绑定。Proxy我理解为Object.defineproperty()的封装。
var person = {
name:'tony',
age:20
}
//第一个参数是代理的处理对象,
const personProxy = new Proxy(person,{
//第一个参数代表目标对象,第二个是访问的属性名
get(target, property){//监视属性的访问
//console.log(target, property)
//return 100
return property in target ? target[property ] : 'default'
},
//第一个参数代表目标对象,第二个是写入的属性名称,第三个地表写入的值
set(target, property, value){//监视属性设置
//{name:'tony',age:20} gender true
//console.log(target, property, value)
if(property == 'age'){
if(!Number.isInteger(value)){/如果value不是Number类型报错
throw new Error (`${value} is not a int`)
}
}
target[property ] = value//给代理目标设置专门的属性
}
})
personProxy.gender = true
//{name:'tony',age:20} name
console.log(personProxy.name)//10
Proxy与Object.defineProperty的区别
Proxy的功能更为强大
Object.defineProperty只能监听对象属性的读写,而Proxy不仅能监听对象的读写
还能监听到更多对象操作,例如delete操作或者对象中方法的调用等
var person ={
name:'ceshi',
age:20
}
const proxy = new Proxy(person, {
deleteProperty(person, property){
console.log(person,property)
delete person[property]
}
})
delete proxy.name
console.log(person )
Proxy 更好支持数组对象的监视
let list = []
const listProxy = new Proxy(list,{
set(target, property, value){
console.log(target, property, value)
target[property] = value
return true
}
})
listProxy.push(100)
Proxy是以非侵入的方式监管对象的读写
已经定义好的对象,不需要对对象做任何的操作就可以实现监听
var person ={}
Object.defineProperty(person,'name',{
get(){
console.log('name被访问')
return person._name
},
set(value){
console.log('name被设置')
person._name = value
}
})
Object.defineProperty(person,'age',{
get(){
console.log('age被访问')
return person._age
},
set(value){
console.log('age被设置')
person._age = value
}
})
person.name = 'jack'
console.log(person)
Relect
ES6提供的一个静态类,是一个内置对象,统一对象操作Api
不能通过new构建一个实例对象,只能调用静态类里的静态方法Relect.get()去调用
内部封装了一系列对对象的底层操作(13个静态方法)
内部成员方法是Proxy处理对象的默认实现
const person = {
name:'tony',
age:20
}
const personProxy = new Proxy(person, {
get(target, property){
return Reflect.get(target, property)
}
})
console.log(personProxy.name)
const person = {
name:'tony',
age:20
}
console.log('name' in person)
console.log(Reflect.has(person,'name'))
console.log(delete person['name'])
console.log(Reflect.deletePorperty(person,'name'))
consoe.log(Obejct.keys(person))
consoe.log(Reflect.ownKeys(person))
set数据集合
常用于数组去重,一个没有重复的数据集合。
map
类似于object,但是键和值均可为任意类型,更加灵活方便,常用于多个if else中的条件数据集合。
Symbol
一种全新的数据类型,之前之前的字符串可以重复,从而导致冲突,一个不会重复的数据类型。
for of循环
for…of适用遍历数/数组对象/字符串/map/set等拥有迭代器对象的集合.但是不能遍历对象,因为没有迭代器对象.与forEach()不同的是,它可以正确响应break、continue和return语句
ES7
inclues
传统寻找数组是否函数某个元素使用indexOf
includes
const arr = [1,"string",NaN,undefined,null,Symbol(),true]
console.log(arr.indexOf(1))//但是不能用于NaN
console.log(arr.includes(NaN))//
指数运算符
const num = Math.pow(2,10)
console.log(num)//2的10次方
console.log(2 ** 10)//2的10次方
ES8
Object.values()
获取value 和 Object.keys()对应
Object.entries()
//有点类似于这个功能
const m = new Map()
m.set(‘foo’, ‘123’)
m.set(‘bar’, ‘456’)
for(const [key, val] in m){
console.log(key, val)//foo 123 bar 456
}
const obj = {
name:‘tony’,
age:20
}
for(const [key, val] in Object.entries(obj ){
console.log(key, val)//foo 123 bar 456
Async和Await
ES2018引入异步迭代器(asynchronous iterators),这就像常规迭代器,除了next()方法返回一个Promise。因此await可以和for…of循环一起使用,以串行的方式运行异步操作。异步解决方案
Object.values()
Object.values()是一个与Object.keys()类似的新函数,但返回的是Object自身属性的所有值,不包括继承的值。
Object.getOwnPropertyDescriptors()
Object.getOwnPropertyDescriptors()函数用来获取一个对象的所有自身属性的描述符,如果没有任何自身属性,则返回空对象。
ES9
异步迭代
在async/await的某些时刻,你可能尝试在同步循环中调用异步函数。例如:
async function process(array) { for (let i of array) { await doSomething(i); } }
这段代码不会正常运行,下面这段同样也不会:
async function process(array) { array.forEach(async i => { await doSomething(i); }); }
这段代码中,循环本身依旧保持同步,并在在内部异步函数之前全部调用完成。
ES2018引入异步迭代器(asynchronous iterators),这就像常规迭代器,除了next()方法返回一个Promise。因此await可以和for...of循环一起使用,以串行的方式运行异步操作。例如:
async function process(array) { for await (let i of array) { doSomething(i); } }
Promise.finally()
一个Promise调用链要么成功到达最后一个.then(),要么失败触发.catch()。在某些情况下,你想要在无论Promise运行成功还是失败,运行相同的代码,例如清除,删除对话,关闭数据库连接等。
.finally()允许你指定最终的逻辑:
function doSomething() {
doSomething1()
.then(doSomething2)
.then(doSomething3)
.catch(err => {
console.log(err);
})
.finally(() => { // finish here! }); }
正则表达式反向断言
目前JavaScript在正则表达式中支持先行断言(lookahead)。这意味着匹配会发生,但不会有任何捕获,并且断言没有包含在整个匹配字段中。例如从价格中捕获货币符号:
const reLookahead = /\D(?=\d+)/, match = reLookahead.exec('$123.89'); console.log( match[0] );
ES2018引入以相同方式工作但是匹配前面的反向断言(lookbehind),这样我就可以忽略货币符号,单纯的捕获价格的数字:
const reLookbehind = /(?<=\D)\d+/, match = reLookbehind.exec('$123.89'); console.log( match[0] ); // 123.89
以上是 肯定反向断言,非数字\D必须存在。同样的,还存在 否定反向断言,表示一个值必须不存在,例如:
const reLookbehindNeg = /(?<!\D)\d+/, match = reLookbehind.exec('$123.89'); console.log( match[0] ); // null
ES10
行分隔符(U + 2028)和段分隔符(U + 2029)符号现在允许在字符串文字中,与JSON匹配
以前,这些符号在字符串文字中被视为行终止符,因此使用它们会导致SyntaxError异常。
更加友好的 JSON.stringify
如果输入 Unicode 格式但是超出范围的字符,在原先JSON.stringify返回格式错误的Unicode字符串。现在实现了一个改变JSON.stringify的第3阶段提案,因此它为其输出转义序列,使其成为有效Unicode(并以UTF-8表示)
新增了Array的flat()方法和flatMap()方法
flat()和flatMap()本质上就是是归纳(reduce) 与 合并(concat)的操作。
const arr = ['a', 'b', ['c', 'd']];
const flattened = arr.flat();
console.log(flattened); // => ["a", "b", "c", "d"]
以前,我们经常使用reduce()或concat()来展平多维数组:
const arr = ['a', 'b', ['c', 'd']];
const flattend = [].concat.apply([], arr);
// or
// const flattened = [].concat(...arr);
console.log(flattened); // => ["a", "b", "c", "d"]
请注意,如果提供的数组中有空值,它们会被丢弃:
const arr = ['a', , , 'b', ['c', 'd']];
const flattened = arr.flat();
console.log(flattened); // => ["a", "b", "c", "d"]
flat() 还接受一个可选参数,该参数指定嵌套数组应该被展平的级别数。 如果未提供参数,则将使用默认值1:
const arr = [10, [20, [30]]];
console.log(arr.flat()); // => [10, 20, [30]]
console.log(arr.flat(1)); // => [10, 20, [30]]
console.log(arr.flat(2)); // => [10, 20, 30]
flatMap() 方法将map()和flat()组合成一个方法。 它首先使用提供的函数的返回值创建一个新数组,然后连接该数组的所有子数组元素。 来个例子:
const arr = [4.25, 19.99, 25.5];
console.log(arr.map(value => [Math.round(value)]));
// => [[4], [20], [26]]
console.log(arr.flatMap(value => [Math.round(value)]));
// => [4, 20, 26]
数组将被展平的深度级别为1.如果要从结果中删除项目,只需返回一个空数组:
const arr = [[7.1], [8.1], [9.1], [10.1], [11.1]];
// do not include items bigger than 9
arr.flatMap(value => {
if (value >= 10) {
return [];
} else {
return Math.round(value);
}
});
// returns:
// => [7, 8, 9]
除了正在处理的当前元素外,回调函数还将接收元素的索引和对数组本身的引用。flat()和flatMap()方法目前处于第4阶段。
BigInt(新数据类型,表示整数)
JavaScript 所有数字都保存成 64 位浮点数,这给数值的表示带来了两大限制。一是数值的精度只能到 53 个二进制位(相当于 16 个十进制位),大于这个范围的整数,JavaScript 是无法精确表示的,这使得 JavaScript 不适合进行科学和金融方面的精确计算。二是大于或等于 2 的 1024 次方的数值,JavaScript 无法表示,会返回 Infinity。
现在 ES10 引入了一种新的数据类型 BigInt(大整数),来解决这个问题。BigInt 只用来表示整数,没有位数的限制,任何位数的整数都可以精确表示。
创建 BigInt 类型的值也非常简单,只需要在数字后面加上 n 即可。例如,123 变为 123n。也可以使用全局方法 BigInt(value) 转化,入参 value 为数字或数字字符串。
阅读公众号: 程序员成长指北:
汇总JS语法 ES6、ES7、ES8、ES9、ES10、ES11、ES12新特性