一. ES7新增特性
1. Array.prototype.includes()
在
ES7
之前,如果我们想判断一个数组中是否包含某个元素,需要通过indexOf
获取结果,并且判断是否为-1
在
ES7
中,我们可以通过includes
来判断一个数组中是否包含一个指定的元素,根据情况,如果包含则返回true
,否则返回false
Array.prototype.includes(searchElement, fromIndex)
searchElement
:需要查找的元素值fromIndex
(可选):从fromIndex
索引处开始查找valueToFind
,默认为0
jsconst names = ['aaa', 'bbb', 'later'] names.indexOf('later') // 2 names.includes('later') // true names.includes('ccc') // false
2. 指数exponentiation运算符
在
ES7
之前,计算数字的乘方需要通过Math.pow()
方法来完成在
ES7
中,增加了**
运算符,可以对数字来计算乘方js// es7之前 Math.pow(3, 2) // 9 // es7 3**2 // 9
二. ES8新增特性
1. Object.values()
之前我们可以通过
Object.keys()
获取一个对象所有的key
(除Symbol
以外)在
ES8
中提供了Object.values()
来获取所有的value
值(除Symbol
以外):jsconst obj = { name: 'later', age: 18, height: 1.88, [Symbol('aaa')]: 'ccc' } obj // {name: 'later', age: 18, height: 1.88, Symbol(aaa): 'ccc'} Object.keys(obj) // ['name', 'age', 'height'] Object.values(obj) // ['later', 18, 1.88] Object.getOwnPropertySymbols(obj) // [Symbol(aaa)] Object.values('abc') // ['a', 'b', 'c'] Object.keys('abc') // ['0', '1', '2']
2. Object.entries()
通过
Object.entries()
可以获取到一个数组,数组中会存放可枚举属性的键值对数组- 可以针对对象、数组、字符串进行操作,返回一个数组
jsconst obj = { name: 'later', age: 18, height: 1.88, [Symbol('aaa')]: 'ccc' } Object.entries(obj) // [['name', 'later'], ['age', 18], ['height', 1.88]] for (const item of Object.entries(obj)) { const [key, value] = item console.log(key, value) } // name later // age 18 // height 1.88 // 数组 Object.entries(['a', 'b']) // [['0', 'a'], ['1', 'b']] // 字符串 Object.entries('abc') // [['0', 'a'], ['1', 'b'], ['2', 'c']]
3. String.prototype.padStart()、padEnd()
某些字符串我们需要对其进行前后的填充,来实现某种格式化效果
ES8
中增加了padStart()
和padEnd()
方法,分别是对字符串的首尾进行填充jsconst minute = '5' const second = '6' // 应用场景一:对时间进行格式化 console.log(minute.padStart(2, '0'), ":", second.padStart(2, '0')) // 05 : 06
我们简单举一个应用场景:比如需要对身份证、银行卡的前面位数进行隐藏:
jsconst minute = '5' const second = '6' // 应用场景二:对一些敏感数据进行脱敏处理 let cardNum = '430521199910102233' cardNum.slice(-4).padStart(18, '*') // **************2233
4. Trailing Commas
在
ES8
中,我们允许在函数定义和调用时多加一个逗号:- 早期这种写法是不会被支持的,不推荐使用,了解即可
jsfunction foo(a, b,) { console.log(a, b) } foo(1, 2,)
5. Object.getOwnPropertyDescriptors()
Object.getOwnPropertyDescriptors():
- 用来获取一个对象的所有自身属性的描述符
Async Function:async、await
- 后续讲
Promise
讲解
- 后续讲
三. ES9新增特性
Async iterators
:后续迭代器讲解Object spread operators
:就是允许在构造对象字面量时,使用展开语法对某个对象进行语法层面的展开Promise finally
:后续讲Promise
讲解
四. ES10新增特性
1. Array.prototype.flat()、flatMap()
flat()
方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回js// flat的使用: const nums = [10, 20, [111, 222], [333, 444], [[123, 321], [231, 312]]] const newNums1 = nums.flat(1) console.log(newNums1) // [10, 20, 111, 222, 333, 444, [123, 321], [231, 312]] const newNums2 = nums.flat(2) console.log(newNums2) // [10, 20, 111, 222, 333, 444, 123, 321, 231, 312]
flatMap()
方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组- 注意一:
flatMap
是先进行map
操作,再做flat
的操作 - 注意二:
flatMap
中的flat
相当于深度为1
js// flatMap的使用: // 对数组中每一个元素应用一次传入的map对应的函数 const messages = [ "Hello World aaaaa", "Hello Coderwhy", "你好啊 李银河" ] // 1.for循环的方式: let newInfos = [] for (const item of messages) { const infos = item.split(" ") for (const info of infos) { newInfos.push(info) } newInfos = [...newInfos, ...infos] // newInfos = newInfos.concat(infos) } console.log(newInfos) // ['Hello', 'World', 'aaaaa', 'Hello', 'Coderwhy', '你好啊', '李银河'] // 2.先进行map, 再进行flat操作 const newMessages = messages.map(item => item.split(" ")) const finalMessages = newMessages.flat(1) console.log(finalMessages) // ['Hello', 'World', 'aaaaa', 'Hello', 'Coderwhy', '你好啊', '李银河'] // 3.flatMap const finalMessages = messages.flatMap(item => item.split(" ")) console.log(finalMessages) // ['Hello', 'World', 'aaaaa', 'Hello', 'Coderwhy', '你好啊', '李银河']
- 注意一:
2. Object.fromEntries()
在前面,我们可以通过
Object.entries()
将一个对象转换成自身可枚举属性的键值对数组那么如果我们有一个
entries
了,如何将其转换成对象呢?ES10
提供了Object.formEntries()
来完成转换
那么这个方法有什么应用场景呢?
js// 1.对象 const obj = { name: "why", age: 18, height: 1.88 } const entries = Object.entries(obj) const info = Object.fromEntries(entries) console.log(info) // {name: 'why', age: 18, height: 1.88} // 2.应用 const searchString = "?name=later&age=18&height=1.88" const params = new URLSearchParams(searchString) console.log(params.get("name")) // later console.log(params.get("age")) // 18 console.log(params.entries()) // Iterator {} for (const item of params.entries()) { console.log(item) } // ['name', 'later'] // ['age', '18'] // ['height', '1.88'] const paramObj = Object.fromEntries(params) console.log(paramObj) // {name: 'later', age: '18', height: '1.88'}
3. trimStart、trimEnd
去除一个字符串首尾的空格,我们可以通过
trim
方法,如果单独去除前面或者后面呢?ES10
中给我们提供了trimStart
和trimEnd
jsconst msg = ' hello world ' msg.trimStart() // 'hello world ' msg.trimEnd() // ' hello world'
4. 其他知识点
Symbol description
:已经讲过了Optional catch binding
:后面讲解try...cach
讲解
五. ES11新增特性
1. BigInt
在早期的
JavaScript
中,我们不能正确的表示过大的数字:大于
MAX_SAFE_INTEGER
的数值,表示的可能是不正确的jsNumber.MAX_SAFE_INTEGER // 9007199254740991 const num1 = 9007199254740991 + 1 const num2 = 9007199254740991 + 2 console.log(num1, num2) // 9007199254740992 9007199254740992
那么
ES11
中,引入了新的数据类型BigInt
,用于表示大的整数:BitInt
的表示方法是在数值的后面加上n
jsNumber.MAX_SAFE_INTEGER // 9007199254740991 const num1 = 9007199254740992n const num2 = 9007199254740993n console.log(num1, num2) // 9007199254740992n 9007199254740993n
2. Nullish Coalescing Operator
ES11
,Nullish Coalescing Operator
增加了空值合并操作符:||
:只要值为假,一律使用默认值??
:只有值为null
或undefined
的时候,才会使用默认值
js// '||'逻辑或 只要值为假,一律使用默认值 let info = '' // info = info || "默认值" // console.log(info) // '默认值' // ??: 空值合并运算符 info = info ?? "默认值" console.log(info) // ''
3. Optional chaining 可选链
可选链也是
ES11
中新增一个特性,主要作用是让我们的代码在进行null
和undefined
判断时更加清晰和简洁:obj?.prop
obj?.[expr]
arr?.[index]
func?.(args)
jsconst obj = { name: "why", friend: { name: "kobe", // running: function() { // console.log("running~") // } } } // 1.直接调用: 非常危险 // obj.friend.running() // 2.if判断,&&逻辑与: 麻烦/不够简洁 // if (obj.friend && obj.friend.running) { // obj.friend.running() // } // obj&&obj.friend&&obj.friend.running&&obj.friend.running() // 3.可选链的用法: ?. obj?.friend?.running?.()
4. globalThis关键字
在之前我们希望获取
JavaScript
环境的全局对象,不同的环境获取的方式是不一样的- 比如在浏览器中可以通过
this
、window
来获取 - 比如在
Node
中我们需要通过global
来获取
- 比如在浏览器中可以通过
在
ES11
中对获取全局对象进行了统一的规范:globalThis
jsconsole.log(window) // 浏览器上 console.log(global) // Node中 console.log(globalThis == window) // true
5. for .. in 标准化
在
ES11
之前,虽然很多浏览器支持for...in
来遍历对象类型,但是并没有被ECMA
标准化在
ES11
中,对其进行了标准化,for...in
是用于遍历对象的key
的:jsconst obj = { name: 'later', age: 18 } for (const key in obj) { console.log(key) } // name age
6. 其他知识点
Dynamic Import
:后续ES Module
模块化中讲解Promise.allSettled
:后续讲Promise
的时候讲解import meta
:后续ES Module
模块化中讲解
六. ES12新增特性
1. FinalizationRegister
FinalizationRegistry
对象可以让你在对象被垃圾回收时请求一个回调FinalizationRegistry
提供了这样的一种方法:当一个在注册表中注册的对象被回收时,请求在某个时间点上调用一个清理回调。(清理回调有时被称为finalizer
)- 你可以通过调用
register
方法,注册任何你想要清理回调的对象,传入该对象和所含的值register()
方法用FinalizationRegistry
实例注册一个对象,这样如果对象被垃圾回收,注册表的回调函数就会被调用
registry
不保留对注册对象的强引用,因为这将破坏目的(如果注册中心保留强引用,对象将永远不会被回收)- 如果对象被回收,你的清理回调可能会在某些时候调用你为它提供的持有值(
registry
方法所传入的第二个参数)。被保存的值可以是任何你喜欢的值:一个原始值或者一个对象,甚至是undefined
的。如果持有的值是一个对象,registry
保持对它的强引用(所以它可以把它传递给你的清理回调)
验证
WeakSet、WeatMap
的弱引用jslet obj = { name: "later", age: 18 } const finalRegistry = new FinalizationRegistry((value) => { console.log("某一个对象被回收了:", value) }) finalRegistry.register(obj, 'later') obj = null let obj2 = {} const weakSet = new WeakSet() weakSet.add(obj2) // 弱引用 会被回收掉 // const set = new Set() // set.add(obj2) // 强引用 不会被回收 finalRegistry.register(obj2, 'obj2') obj2 = null let obj3 = {} const weakMap = new WeakMap() weakMap.set(obj3, 'obj3') // 弱引用 会被回收掉 // const map = new Map() // map.set(obj3, 'obj3') // 强引用 不会被回收 finalRegistry.register(obj3, 'obj3') obj3 = null
2. WeakRef
如果我们默认将一个对象赋值给另外一个引用,那么这个引用是一个强引用:
- 如果我们希望是一个弱引用的话,可以使用
WeakRef
WeakRef
对象允许您保留对另一个对象的弱引用,而不会阻止被弱引用对象被GC
回收
jslet obj = { name: 'later' } // let obj2 = obj // 这里产生强引用,即使Obj=null,{}也不会被回收 const objWeakRef = new WeakRef(obj) // console.log(objWeakRef.deref()) // 这里不会被回收,mdn上解释有做特殊处理 console.log(objWeakRef.deref().name) // later const finalRegistry = new FinalizationRegistry(value => { console.log(value, '对象被回收了') }) finalRegistry.register(obj, 'obj') obj = null
- 如果我们希望是一个弱引用的话,可以使用
3. logical assignment operators
逻辑赋值运算符
a ||= b
:a = a || b
a ??= b
:a = a ?? b
a &&= b
:a = a && b
js// 赋值运算符 // const foo = "foo" let counter = 100 counter = counter + 100 counter += 50 // 逻辑赋值运算符 function foo(message) { // 1.||逻辑赋值运算符 // message = message || "默认值" // message ||= "默认值" // 就是上面这种写法的另外一种简写吧(个人认为就是语法糖) // 2.??逻辑赋值运算符 // message = message ?? "默认值" message ??= "默认值" // 就是上面这种写法的另外一种简写吧(个人认为就是语法糖) console.log(message) } foo("abc") // abc foo() // 默认值 // 3.&&逻辑赋值运算符 let obj = { name: "later", running: function() { console.log("running~") } } // 3.1.&&一般的应用场景 // obj && obj.running && obj.running() // obj = obj && obj.name obj &&= obj.name // 就是上面这种写法的另外一种简写吧(个人认为就是语法糖) console.log(obj) // later
4. 其他知识点
Numeric Separator
:讲过了jsconst num1 = 100_200_3000
String.prototype.replaceAll
:字符串替换jsconst str1 = 'later later Later' // 区分大小写 str1.replaceAll('later', 'aaa') // aaa aaa Later str1.replaceAll(/later/ig, 'bbb') // bbb bbb bbb
七. ES13新增特性
1. String / Array.prototype.at()
前面我们有学过字符串、数组的
at
方法,它们是作为ES13
中的新特性加入的:- -0 等价于 0
js// 数组 const arr = [1, 2, 3] console.log(arr.at(0), arr.at(-1)) // 1 3 // 字符串 const str = '123' console.log(str.at(0), str.at(-1)) // 1 3
2. Object.hasOwn(obj, propKey)
Object
构造函数中新增了一个静态方法(类方法):hasOwn(obj, propKey)
- 该方法用于判断一个对象中是否有某个自己的属性
Object.hasOwn()
是用来替换Object.prototype.hasOwnProperty()
的
那么和之前学习的
Object.prototype.hasOwnProperty
有什么区别呢?- 区别一:防止对象内部有重写
hasOwnProperty
- 因为
hasOwnProperty
方法是基于实例对象的原型对象进行调用的,如果对象内部自己有重写一个hasOwnProperty
,就会优先调用自己的
- 因为
- 区别二:对于隐式原型指向
null
的对象,hasOwnProperty
无法进行判断- 因为
hasOwnProperty
方法是存在于Object
构造函数的显式原型上的,如果某个对象隐式原型指向null
,而不是Object.prototype
,null
上是不存在hasOwnProperty
方法的
- 因为
- 区别一:防止对象内部有重写
3. New members of classes
在
ES13
中,新增了定义class
类中成员字段(field
)的其他方式:Instance public fields
: 实例公共字段Static public fields
:静态公共字段Instance private fields
:实例私有字段static private fields
:静态私有字段static block
:静态代码块
jsclass Person { // 1.实例属性 // 对象属性: public 公共 -> public instance fields height = 1.88 foo = () => {} // 对象属性: private 私有: 程序员之间的约定 // _intro = "name is why" // ES13对象属性: private 私有属性 只能在class内部使用 #intro = "hello" // 2.类属性(static) // 类属性: public static totalCount = "70亿" // 类属性: private 私有类方法 只能在class内部使用 static #maleTotalCount = "20亿" constructor(name, age) { // 对象中的属性: 在constructor通过this设置 this.name = name this.age = age } // 3.静态代码块 static { // 第一次加载解析类的代码时(初始化)执行 console.log('类代码初始化执行') } run() { console.log(this.#intro, Person.#maleTotalCount) } } const p = new Person("later", 18) console.log(p) console.log(p.name, p.age, p.height) // console.log(p.#intro) // Private field '#intro' must be declared in an enclosing class console.log(Person.totalCount) // 70亿 // console.log(Person.#maleTotalCount) // Private field '#intro' must be declared in an enclosing class p.run() // hello 20亿