盘点ES6之后每次版本更新

盘点平常使用频繁,对开发者有重大意义的变更,无感的基本就没写,感兴趣的可以参考这篇 ES3到ES11都增加了什么

ES6

  • 1、let 和 const

新的申明变量的方式和变量的作用域

区别1var声明的变量会挂载在window上,而letconst声明的变量不会
区别2var声明的变量存在变量提升,而letconst不存在变量提升
区别3letconst声明形成快作用域
区别4:同一作用域下的letconst不能声明同名变量,而var可以
  • 2、字符串方法和模板字符串
// 模板字符串
const name = 'mySkey'
const str = `my name is ${name}`

// startsWith 判定字符串是否以另一个字符串开头,返回布尔值
console.log('hello wolrd'.startsWith('hello'))	// true

// endsWith	判定字符串是否以另一个字符串结尾,返回布尔值
console.log('hello wolrd'.endsWith('hello'))	// false

// includes	判定字符串是否以包含另一个字符串,返回布尔值
console.log('hello wolrd'.includes('hello'))	// true

// repeat 将字符串复制多次,参数就是被复制的次数
console.log('hello wolrd'.repeat(2))	// hello wolrdhello wolrd
  • 3、解构赋值

数组解构赋值是根据数组的下标来一一对应的,对象的赋值是根据对象的key来解构

//数组
let [a, b, c] =[1, 2, 3] 
//对象
let{ a, b, c} = { a: 1, b: 2, c: 3}
  • 4、数组方法

两个静态方法 of 和 from

// Array.of  解决了Array在接收参数时的BUG
console.log(Array.of(3))  // [3]

// Array.from  将类数组对象(之前称为集合的东西,有数组的特点,没数组的方法)转为数组,ES6之前,我们可以通过[].slice.call(arr)方式转为数组
console.log(Array.from(new Set([1, 2, 3])))

三个普通方法 find 、 findIndex 、copyWithin

const testArr = [
	{ name: 'ming', age: 23 },
    { name: 'dong', age: 23 }
]
// find  查询数组中的内容,首个满足条件的内容
console.log(testArr.find(item => item.age === 23))  // {name: "ming", age: 23}

// findIndex  与find一致,但是只返回下标
console.log(testArr.findIndex(item => item.age === 23))  // 0

// copyWithin  复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度
const array1 = ['a', 'b', 'c', 'd', 'e'];
console.log(array1.copyWithin(0, 3, 4));   // expected output: Array ["d", "b", "c", "d", "e"]
  • 5、对象两个方法 is 和 assign
// Object.is  用于比较两者是否全等
console.log(NaN === NaN) //false
console.log(Object.is(NaN,NaN) //true

 // Object.assign  用于对象属性的复制(浅复制)
var obj = {}
var obj1 = {sex :'女'}
Object.assign(obj, obj1)
  • 6、箭头函数

javascript中容易混淆作用域,一般都要利用词法作用域来传递 this,es6就解决了这个问题

// 一个参数时,可以不用()包含形参; 一句执行语句时,可以不用{}包含代码块; 一行代码时是有返回值的。
let fn = num=>console.log(num)

// 两个参数
let fn = (a,b)=>a+b

// 箭头函数中的this
function foo() {
  setTimeout(() => {
    console.log('id:', this.id);
  }, 100);
}

var id = 21;

foo.call({ id: 42 }); // id: 42

以下几点需要注意:

(1)函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。

(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。

(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

双冒号的使用,箭头函数可以绑定this对象,大大减少了显式绑定this对象的写法(call、apply、bind)。但是,箭头函数并不适用于所有场合,所以现在有一个提案,提出了“函数绑定”(function bind)运算符,用来取代call、apply、bind调用。

foo::bar;
// 等同于
bar.bind(foo);

foo::bar(...arguments);
// 等同于
bar.apply(foo, arguments);
  • 7、reset符的使用 …
// 函数参数中使用
let fn = (a,...arguments)=>console.log(...arguments)
fn(1,2,3,4) // 2,3,4

// 对象中使用
let person = {
  name: 'mySkey',
  age: 23
}

let me = {...person}
console.log(me) // { name: 'mySkey , age: 23}

let showInfo = ({name, age})=>{
  console.log(name +'`s age is '+ age)
}
showInfo({ ...person })

// 数组中使用
let arr = [1,2,3,4]
let arr1 = [0,...arr,5]
console.log(arr1)  // [0,1,2,3,4,5]
  • 8、Proxy

ES6中增加了一个Proxy代理类,他可以对指定的对象的访问操作和修改操作进行拦截,vue2.0是通过Object.defineProperty来拦截,要是开启深层拦截将很耗费性能,所以对于对象,数组的更改,无法数据动态响应;在vue3.0中将使用Proxy来进行拦截,将解决这一问题。

var proxy = new Proxy(原对象,{
	get:function(原对象,属性名){},
	set:function(原对象,属性名,属性值){},
})
  • 9、Set 和 WeakSet

Set 它类似于数组,但是成员的值都是唯一的,没有重复的值

使用场景并不多,但是用来做数组去重很方便

let removeSame = arr=>[...new Set(arr)]

既然可以做数组去重,那就可以做字符串去重

let removeSameStr = str=>[...new Set(str)].join('')

WeakSet 结构与 Set 类似,也是不重复的值的集合。但是,它与 Set 有两个区别。1、WeakSet 的成员只能是对象 2、WeakSet 中的对象都是弱引用,即垃圾回收机制不考虑 WeakSet 对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于 WeakSet 之中

const a = [[1, 2], [3, 4]];
const ws = new WeakSet(a);
// WeakSet {[1, 2], [3, 4]}
  • 10、Map 和 WeakMap

JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。

const map = new Map([
  ['name', '张三'],
  ['title', 'Author']
]);

map.size // 2
map.has('name') // true
map.get('name') // "张三"
map.has('title') // true
map.get('title') // "Author"

WeakMap 结构与Map结构类似,也是用于生成键值对的集合。WeakMap与Map的区别有两点:1、WeakMap只接受对象作为键名(null除外),不接受其他类型的值作为键名 2、WeakMap的键名所指向的对象,不计入垃圾回收机制

const wm = new WeakMap();
let key = {};
let obj = {foo: 1};

wm.set(key, obj);
obj = null;
wm.get(key)
// Object {foo: 1}
  • 11、Symbol

ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第六类型,前五是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)。

let mySymbol = Symbol();

// 第一种写法
let a = {};
a[mySymbol] = 'Hello!';

// 第二种写法
let a = {
  [mySymbol]: 'Hello!'
};

// 第三种写法
let a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });

// 以上写法都得到同样结果
a[mySymbol] // "Hello!"
  • 12、Promise

Promise是es6用来处理异步的对象,分为三种状态:pending、fulfilled、rejected。对象拥有resolve和reject两个方法,分别在里面处理正确情况和异常情况。

let getData = ()=>{
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      let data = { code: 404, msg: 'I am sleeping' }
      try{
        // throw('我非要出个错,来看一下catch有没有用')  // throw 强制产生一个错误,Promis的catch就能捕获到错误
        resolve(data)
      }catch(err){
        reject(err)
      }
    }, 3000)
  })
}

// 调用函数,在函数返回时使用数据
getData().then(res=>{
  console.log('后台说:' + res.msg)
}).catch(err=>{
  console.log('发生的错误是:' + err)
})
  • 13、Generator

Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。在node的中间件中使用广泛,中间件授权之类,vue的路由鉴权也有使用

let getData = ()=>{
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      let data = { code: 404, msg: 'I am sleeping' }
      resolve(data)
    }, 3000)
  })
}

// 调用函数,在函数返回时使用数据
(function* () {
  let data = yield getData();
  return data;
})().next().value.then(res=>{
  console.log(res)
})
  • 14、Iterator 和 for…of 循环

avaScript 原有的表示“集合”的数据结构,主要是数组(Array)和对象(Object),ES6 又添加了Map和Set。这样就有了四种数据集合,用户还可以组合使用它们,定义自己的数据结构,比如数组的成员是Map,Map的成员是对象。这样就需要一种统一的接口机制,来处理所有不同的数据结构。

遍历器(Iterator)就是这样一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署 Iterator 接口,就可以完成遍历操作(即依次处理该数据结构的所有成员)。遍历器可以直接遍历迭代器的结果,而不需要每次next

function* foo() {
  yield 1;
  yield 2;
  yield 3;
  yield 4;
  yield 5;
  return 6;
}

for (let v of foo()) {
  console.log(v);
}
// 1 2 3 4 5
  • 15、Class

class的本质是function,它可以看做是一个语法糖,让对象原型的写法更加清晰,更像面向对象编程的写法

class Person {
  constructor(props, name, age){
    super(props);
    this.name = name;
    this.age = age;
  }
  sing(){
    console.log('sing');
  }
  cry(){
    console.log('cry');
  }
}

Person.prototype = {
  talk: function(){
    console.log('talk')
  }
}
let mySkey = new Person('mySkey', 23)
mySkey.talk()

16、模块化

ES6 模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。比如,CommonJS 模块就是对象,输入时必须查找对象属性。

ES7

  • 1、Array.prototype.includes()

includes() 函数用来判断一个数组是否包含一个指定的值,如果包含则返回 true,否则返回false。

arr.includes(x)
// 相当于
arr.indexOf(x) >= 0
  • 2、指数操作符

在ES7中引入了指数运算符**,** 有与Math.pow(…)等效的计算结果。

console.log(2**10);// 输出1024

ES8

  • 1、async/await

async,await异步解决方案:优化回调地狱,ES6中的promise解决了回调地狱,但是要连续打点调用then,就会显得不清楚,所以引入了async函数,awiat表达式

async function process(array) {
  for await (let i of array) {
    doSomething(i);
  }
}
  • 2、Object.values()

Object.values()就是将对象的值合并到一个数组中, Object.keys() 是将对象的key合并到一个数组中

const obj = {a: 1, b: 2, c: 3};
console.log(Object.values(obj)) // [1, 2, 3]
  • 3、Object.entries()

Object.entries()函数返回一个给定对象自身可枚举属性的键值对的数组。

for(let [key,value] of Object.entries(obj1)){
	console.log(`key: ${key} value:${value}`)
}
//key:a value:1
//key:b value:2
//key:c value:3

4、string padStart() 和 padEnd

允许将空字符串或其他字符串添加到原始字符串的开头或结尾。

console.log('8'.padStart(2, '0'))

5、函数参数列表结尾允许逗号

主要作用是方便使用git进行多人协作开发时修改同一个函数减少不必要的行变更。

function add(
	a,
	b,
){
	return a + b
}

ES9

  • 1、异步迭代

在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);
  });
}

// 想要同步循环,需要以下写法
async function process(array) {
  for await (let i of array) {
    doSomething(i);
  }
}
  • 2、Promise.finally()

一个Promise调用链要么成功到达最后一个.then(),要么失败触发.catch()。在某些情况下,你想要在无论Promise运行成功还是失败,运行相同的代码,例如清除,删除对话,关闭数据库连接等。

function doSomething() {
  doSomething1()
  .then(doSomething2)
  .then(doSomething3)
  .catch(err => {
    console.log(err);
  })
  .finally(() => {
    // finish here!	// 清除loading之类的
  });
}
  • 3、Rest/Spread 属性

ES2015引入了Rest参数和扩展运算符。三个点(…)仅用于数组。Rest参数语法允许我们将一个不定数量的参数表示为一个数组。

function restParam({ a, ...x }) {
  // a = 1
  // x = { b: 2, c: 3 }
}
restParam({
  a: 1,
  b: 2,
  c: 3
});

const myObject = {
  a: 1,
  b: 2,
  c: 3
};
const { a, ...x } = myObject;

JavaScript正则表达式可以返回一个匹配的对象——一个包含匹配字符串的类数组,例如:以YYYY-MM-DD的格式解析日期:

const
  reDate = /([0-9]{4})-([0-9]{2})-([0-9]{2})/,
  match  = reDate.exec('2018-04-30'),
  year   = match[1], // 2018
  month  = match[2], // 04
  day    = match[3]; // 30

ES2018允许命名捕获组使用符号?<name>,在打开捕获括号(后立即命名,示例如下:

const
  reDate = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/,
  match  = reDate.exec('2018-04-30'),
  year   = match.groups.year,  // 2018
  month  = match.groups.month, // 04
  day    = match.groups.day;   // 30

命名捕获也可以使用在replace()方法中。例如将日期转换为美国的 MM-DD-YYYY 格式:

const
  reDate = /(?<year>[0-9]{4})-(?<month>[0-9]{2})-(?<day>[0-9]{2})/,
  d      = '2018-04-30',
  usDate = d.replace(reDate, '$<month>-$<day>-$<year>');

ES10

  • 1、Array的flat()方法和flatMap()方法

flat()和flatMap()本质上就是是归纳(reduce) 与 合并(concat)的操作。

// flat()方法最基本的作用就是数组降维
arr3.flat(Infinity);  /使用 Infinity 作为深度,展开任意深度的嵌套数组
// [1, 2, 3, 4, 5, 6]

// 可以利用flat()方法的特性来去除数组的空项
var arr4 = [1, 2, , 4, 5];
arr4.flat();
// [1, 2, 4, 5]

flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。它与 map 和 深度值1的 flat 几乎相同,但 flatMap 通常在合并成一种方法的效率稍微高一些。 这里我们拿map方法与flatMap方法做一个比较。

var arr1 = [1, 2, 3, 4];

arr1.map(x => [x * 2]); 
// [[2], [4], [6], [8]]

arr1.flatMap(x => [x * 2]);
// [2, 4, 6, 8]

// 只会将 flatMap 中的函数返回的数组 “压平” 一层
arr1.flatMap(x => [[x * 2]]);
// [[2], [4], [6], [8]]
  • 2、String的trimStart()方法和trimEnd()方法

分别是去除首位空白符的

  • 3、Object.fromEntries() 和 bject.entries()

Object.entries()方法的作用是返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for…in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环也枚举原型链中的属性)。而Object.fromEntries() 则是 Object.entries() 的反转。

const map = new Map([ ['foo', 'bar'], ['baz', 42] ]);
const obj = Object.fromEntries(map);
console.log(obj); // { foo: "bar", baz: 42 }

const arr = [ ['0', 'a'], ['1', 'b'], ['2', 'c'] ];
const obj = Object.fromEntries(arr);
console.log(obj); // { 0: "a", 1: "b", 2: "c" }
  • 4、Function.prototype.toString()

现在返回精确字符,包括空格和注释

  • 5、catch参数非必须
try {} catch {}
  • 6、Symbol.prototype.description

通过工厂函数Symbol()创建符号时,您可以选择通过参数提供字符串作为描述:

const sym = Symbol('The description');
assert.equal(sym.description, 'The description');

ES11

使用ES11需要安装的babel插件

plugins: [
  "@babel/plugin-proposal-nullish-coalescing-operator",
  "@babel/plugin-proposal-optional-chaining",
  "@babel/plugin-proposal-class-properties",
  "@babel/plugin-proposal-private-methods",
  "@babel/plugin-syntax-bigint"
]
  • 1、Nullish coalescing Operator(空值处理)

如果表达式在 ?? 的左侧 运算符求值为undefined或null,返回其右侧。

let user = {
    u1: 0,
    u2: false,
    u3: null,
    u4: undefined
    u5: '',
}
let u1 = user.u1 || '用户1'  // 用户1
let u2 = user.u2 || '用户2'  // 用户2
let u3 = user.u3 || '用户3'  // 用户3
let u4 = user.u4 || '用户4'  // 用户4
let u5 = user.u5 || '用户5'  // 用户5
// es11语法
let u1 = user.u1 ?? '用户1'  // 0
let u2 = user.u2 ?? '用户2'  // false
let u3 = user.u3 ?? '用户3'  // 用户3
let u4 = user.u4 ?? '用户4'  // 用户4
let u5 = user.u5 ?? '用户5'  // ''
  • 2、Optional chaining(可选链)

?. 用户检测不确定的中间节点,如果不存在中间节点则返回undefined。避免了程序报错直接导致整个应用挂掉,可以用lodash的 get 来处理这种链路不确定性

let person = {}
let age = person.info.age	// TypeError: Cannot read property 'name' of undefined 因为person的info属性为undefined,那么直接就报错了
let age = person.info?.age	// undefined

使用lodash
import _ from 'lodash'
let age = _.get(person, 'person.info.age', '')
  • 3、romise.allSettled

使用 Promise.all 来并发两个接口,如果其中任意一个异常,则两个区域都无法正常渲染。Promise.allSettled 则可以避免这个问题

Promise.all([
    new Promise.reject('a1'),
    new Promise.resolve('a2')
]).then((ret) => {
    // 不会执行
    console.log(ret)
}).catch((error) => {
    // 因为有一个promise返回为reject。所以程序只会走到这里
    // 输出:a1
    console.log(error) 
})

// 使用es11的Promise.allSettled
Promise.allSettled([
    new Promise.reject('a1'),
    new Promise.resolve('a2')
]).then((ret) => {
    // 输出 
    // 0: {status: "fulfilled", value: "a1"},
    // 1: {status: "rejected", value: "a2"}
    console.log(ret)
    
    // 这样可以过滤掉rejected,避免整段程序运行错乱
    handleFun(ret.filter(el => el.status !== 'rejected'))
})
  • 4、Dynamic import

动态引入,之前的import是静态引入

const util = './util.js'
import(util).then((module) => {
    module.fun1();
    module.fun2();
});

(async () => {
  const util = './util.js';
  const module = await import(util)
  const fun1 = module.fun1(1);
  const fun2 = module.fun1(2);
})();
  • 5、BigInt

BigInt是第7个基本类型,它是一个任意精度的整数。变量可以代表2⁵³不仅是在9007199254740992处的最大值。

// 创建方法一:在整数后面加 n
let bigInt = 9999999999999999n;
// 创建方法二:BigInt函数
let bigInt2 = BigInt(9999999999999999);
let bigInt3 = BigInt('9999999999999999');

// bigIng类型可以进行更大的值计算
let sum = bigInt + bigInt2 // 19999999999999999n
sum.toString() // 19999999999999999 使用toString可以去掉后面的n

// bigint是一种新的原始类型
typeof 9999999999999999n; // -> 'bigint
  • 6、String.protype.matchAll

原有的 match() 方法仅返回完整的匹配结果,却不会返回特定正则表达式组。而 matchAll()返回的迭代器不仅包括精确的匹配结果,还有全部的正则模式捕获结果

var str = 'From 2019.01.29 to 2019.01.30';
var allMatchs = str.matchAll(/(?<year>\d{4}).(?<month>\d{2}).(?<day>\d{2})/g);

for (const match of allMatchs) {
  console.log(match);
}
// [
//   [
//     '2019.01.29',
//     '2019',
//     '01',
//     '29',
//     index: 5,
//     input: 'From 2019.01.29 to 2019.01.30',
//     groups: [Object: null prototype] { year: '2019', month: '01', day: '29' }
//   ],
//   [
//     '2019.01.30',
//     '2019',
//     '01',
//     '30',
//     index: 19,
//     input: 'From 2019.01.29 to 2019.01.30',
//     groups: [Object: null prototype] { year: '2019', month: '01', day: '30' }
//   ]
// ]
  • 7、globalThis

全局this。在浏览器中它是 window, 在 worker 中它是 self, 在 Node.js 中它是global。有了globalThis后不管在哪个平台都可以用它来表示顶级的this

  • 8、import.meta

Domenic Denicola 提出的 import.meta 提议为当前运行的模块添加了一个特定 host 元数据对象。

console.log(import.meta.url)
// file:///Users/pawelgrzybek/main.js
  • 9、export * as ns from “mod”

这是对 ES 规范的有力补充,它允许开发者以新名称导出另一模块的命名空间外部对象。用于集成多个模块到一个文件

export * as ns from "mod"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值