五、ES7~ES13的特性

2022/8/6 ES6ES7ES8ES9ES10ES11ES12ES13

# 1、ES7新增特性解析

# 1.1.ES7 - Array.prototype.includes()

  • 在ES7之前,如果我们想判断一个数组中是否包含某个元素,需要通过 indexOf 获取结果,并且判断是否为 -1。
    • 返回的值为:-1则该数组不包含该元素;
    • 返回的是大于等于0的索引值,则说明该数组包含该元素,拿到的返回值是该元素在数组中的索引值
  • 在ES7中,我们可以通过includes来判断一个数组中是否包含一个指定的元素,根据情况,如果包含则返回 true,否则返回false。
    • includes语法:arr.prototype.includes(valueToFind[,formIndex])
      • valueToFind参数一:要搜索的元素
      • formIndex参数二:要从数组中哪个索引值开始往后面搜索
const arr = ['nba','cba','ncaa']
const str = 'cba'
const str1 = 'bba'
console.log(arr.indexOf(str))//1  数组包含该元素,且该元素在数组中的索引为1的位置
console.log(arr.indexOf(str1))//-1 数组不包含该元素
console.log(arr.includes(str))//true 数组包含该元素
console.log(arr.includes(str1))//false 数组不包含该元素
console.log(arr.includes(str,2))//false 从数组中索引值为2的位置开始向后搜索,没有找到该元素,所以返回false
1
2
3
4
5
6
7
8

# 1.2.ES7 – 指数exponentiation运算符

  • 在ES7之前,计算数字的乘方需要通过 Math.pow 方法来完成。
  • 在ES7中,增加了 ** 运算符,可以对数字来计算乘方。
const result1 = Math.pow(2,10)
const result2 = 2 ** 10
console.log(result1,result2)//1024 1024
1
2
3

# 2、ES8新增特性解析

# 2.1.ES8 - Object.values()

  • 之前我们可以通过 Object.keys(obj) 获取一个对象所有的key
  • 在ES8中提供了 Object.values(obj) 来获取所有的value值:
const obj = {
  name:'kobe',
  age:39
}
const str = "lyk"
// ES8之前想一次获取对象所有属性对应的value值

console.log(Object.keys(obj))//[ 'name', 'age' ]
console.log(Object.keys(str))//[ '0', '1', '2' ]
const values = []
for(const key of Object.keys(obj)) {
  values.push(obj[key])
}
console.log(values)//[ 'kobe', 39 ]

// ES8直接用Object.values(obj)来获取
console.log(Object.values(obj))//[ 'kobe', 39 ]
console.log(Object.values(str))//[ 'l', 'y', 'k' ]


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

# 2.2.ES8 - Object.entries()

  • 通过 Object.entries(obj) 可以获取到一个数组,数组中会存放可枚举属性的键值对数组。
    • 可以针对对象、数组、字符串进行操作;
    • entries中文意思是:条目
const obj = {
  name:'kobe',
  age:39
}
const str = "lyk"
const arr = ['nba','cba']

// 1.如果是一个对象
console.log(Object.entries(obj))//[ [ 'name', 'kobe' ], [ 'age', 39 ] ]
for(const entry of Object.entries(obj)) {
  const [key,value] = entry
  console.log(key,value) //name kobe  //age 39
}
// for(const [key,value] of Object.entries(obj)) {
//   console.log(key,value)
// }

// 2.如果是一个数组
console.log(Object.entries(arr))//[ [ '0', 'nba' ], [ '1', 'cba' ] ]

// 3.如果是一个字符串
console.log(Object.entries(str))//[ [ '0', 'l' ], [ '1', 'y' ], [ '2', 'k' ] ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 2.3.ES8 - String Padding 字符串填充(String的实例方法:padStart 和 padEnd)

  • 某些字符串我们需要对其进行前后的填充,来实现某种格式化效果,ES8中增加了 padStart 和 padEnd 方法,分别是对字符串的首尾进行填充的。(前面写秒杀活动倒计时功能 有用到过padStart方法)

  • String.prototype. padStart(targetLength [, padString]) 从当前字符串的左侧开始填充。

    • 参数1:targetLength :当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身。

    • 参数2:padString(可选):填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断。此参数的默认值为 " "

    • padStart语法查看 (opens new window)

  • String.prototype. padEnd(targetLength [, padString]) 从当前字符串的末尾(右侧)开始填充;

const str = "Hello World"
const strStart = str.padStart(16,'a96')
console.log(strStart)// a96a9Hello World      
console.log(str)//Hello World

const str1 = "Hello World"
const str1End = str.padEnd(15,'z52')
console.log(str1End)// Hello Worldz52z
console.log(str1)//Hello World
1
2
3
4
5
6
7
8
9
  • 我们简单具一个应用场景:比如需要对身份证、银行卡的前面位数进行隐藏
const identityStr = '362426198908963664'
const identityStrLength = identityStr.length
const lastFourStr = identityStr.slice(-4)
const identityStrHidden = lastFourStr.padStart(identityStrLength,'*')
console.log(identityStrLength)//18
console.log(lastFourStr)//3664
console.log(identityStrHidden)//**************3664
1
2
3
4
5
6
7

# 2.4.ES8 - Trailing Commas(尾随逗号)

  • 在ES8中,我们允许在函数定义和调用时多加一个逗号:()
function foo(a,b,) {
  console.log(a,b)
}
foo(a,b,)
1
2
3
4

# 2.5.ES8 - Object.getOwnPropertyDescriptors () 获取对象的属性描述符信息

  • Object.getOwnPropertyDescriptors :获取对象所有属性的 数据/存取 属性描述符
const obj = {
  name:'kobe'
}
// 1.获取obj所有属性的(数据/存取)属性描述符
console.log(Object.getOwnPropertyDescriptors(obj))
/*{
  name: {
    value: 'kobe',
    writable: true,
    enumerable: true,
    configurable: true
  }
}
*/
// 2.获取obj的name属性的(数据/存取)属性描述符
console.log(Object.getOwnPropertyDescriptor(obj,'name'))
//{ value: 'kobe', writable: true, enumerable: true, configurable: true }


// 3.获取存取属性描述符及案例
let age = 18
Object.defineProperty(obj,'age',{
  enumerable:true,
  configurable:true,
  set(value) {
    console.log('我修改了属性值')
    age = value
  },
  get(){
    console.log('我正在获取属性值')
    return age
  }
})
console.log(Object.getOwnPropertyDescriptor(obj,'age'))//{get: [Function: get],set: [Function: set],enumerable: true,configurable: true}
obj.age = 39
console.log(obj.age)//39
console.log(obj)//{ name: 'kobe', age: [Getter/Setter] }
console.log(Object.keys(obj))//[ 'name', 'age' ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# 2.6.ES8 - async、await(学完 Promise 再学习)

  • Async Function:async、await
    • 后续学完 Promise 再学习

# 3、ES9新增特性解析

# 3.1.ES9 - Async iterators(迭代器后续学习)

# 3.2.ES9 - Object spread operators:对象展开运算符

  • 该特性前面有学习过: 展开运算符...
//在构建对象字面量时,可使用展开运算符;会将对象表达式按key-value的方式进行展开
const obj = {
  name:'kobe',
  age:39
}

const obj1 = {
  address:'洛杉矶',
  ...obj
}

console.log(obj1)//{ address: '洛杉矶', name: 'kobe', age: 39 }
1
2
3
4
5
6
7
8
9
10
11
12

# 3.3.ES9 - Promise.prototype.finally()(学Promise时再学习)

  • Promise的实例方法:finally

# 4、ES10新增特性解析

# 4.1.ES10 - Array.prototype.flat() 和 Array.prototype.flatMap()

  • flat() 方法会按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组返回。Array.prototype.flat(depth)
const arrs = [10, 20, 30, [40, 50, [60, 70, 80, [90, 100]]], [110, 120, [130, 140, 150]]]//这个数组的深度为:3

const arrs1 = arrs.flat(1)
console.log(arrs1) //[10, 20, 30, 40, 50, [ 60, 70, 80, [ 90, 100 ] ],110, 120, [ 130, 140, 150 ]]
const arrs2 = arrs.flat(2)
console.log(arrs2)//[10, 20, 30, 40, 50, 60, 70, 80, [ 90, 100 ], 110, 120, 130, 140, 150] 
const arrs3 = arrs.flat(3)
console.log(arrs3)//[10,  20,  30,  40,  50,  60, 70,  80,  90, 100, 110, 120, 130, 140, 150]
const arrs4 = arrs.flat(4)//设置值超过数组深度 则返回最大深度时得到的返回值结果
console.log(arrs4)//[10,  20,  30,  40,  50,  60, 70,  80,  90, 100, 110, 120, 130, 140, 150]
1
2
3
4
5
6
7
8
9
10
  • flatMap() 方法首先使用映射函数映射每个元素,然后将结果压缩成一个新数组。Array.prototype.flatMap()
const message = ["Hello World", "你好呀 李银河", "my name is kobe"]

// 1.flatMap方法的使用
const newMessage = message.flatMap(item => {
  return item.split(" ")
})

console.log(newMessage)//['Hello', 'World', '你好呀', '李银河', 'my', 'name', 'is', 'kobe']

// 2.上面的flatMap方法 相当于 如下操作:先map  再flat
const messageArr1 = message.map(item => {
  return item.split(" ")
})
console.log(messageArr1)//[[ 'Hello', 'World' ], [ '你好呀', '李银河' ], [ 'my', 'name', 'is', 'kobe' ]]
const newMessage1 = messageArr1.flat(1)
console.log(newMessage1)//['Hello', 'World', '你好呀', '李银河', 'my', 'name', 'is', 'kobe']
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 4.2.ES10 - Object.fromEntries()

  • 在前面,我们可以通过 Object.entries() 将一个对象转换成 entries(条目)
  • 那么如果我们有一个entries了,如何将其转换成对象呢?
const info = {
  name:'kobe',
  age:28
}

const entries = Object.entries(info)
console.log(entries)//[ [ 'name', 'kobe' ], [ 'age', 28 ] ]

const obj = Object.fromEntries(entries)
console.log(obj)//{ name: 'kobe', age: 28 }
1
2
3
4
5
6
7
8
9
10
  • 那么这个方法有什么应用场景呢?
const paramsString = 'name=kobe&age=39&height=1.98'
const searchParams = new URLSearchParams(paramsString)
console.log(searchParams)//URLSearchParams { 'name' => 'kobe', 'age' => '39', 'height' => '1.98' }
for(const param of searchParams) {
  console.log(param)//[ 'name', 'kobe' ]  //[ 'age', '39' ]  //[ 'height', '1.98' ]
}
const searchObj = Object.fromEntries(searchParams)
console.log(searchObj)//{ name: 'kobe', age: '39', height: '1.98' }
1
2
3
4
5
6
7
8

# 4.3.ES10 - 去除字符串前面或后面的空格:String的实例方法:trimStart和trimEnd

  • 去除一个字符串首尾的空格,我们可以通过String.prototype.trim()方法;
  • 如果单独去除前面或者后面呢?
    • ES10中给我们提供了String.prototype.trimStart()String.prototype.trimEnd()
const message = "  Hello   "
console.log(message.trim())//"Hello"
console.log(message.trimStart())//"Hello   "
console.log(message.trimEnd())//"  Hello"
1
2
3
4

# 4.4.ES10 - Symbol description(Symbol类型的描述)

  • 【该特性前面学Symbol类型时有学过】

  • 我们可以在创建Symbol值的时候传入一个描述:description :const s1 = Symbol(description)

    • 当然也可以通过创建的Symbol值的description方法,来获取创建时传入的描述信息
const s1 = Symbol('bba')//传入一个描述:'bba'
console.log(s1.description)//bba
1
2

# 4.5.ES10 - Optional catch binding(可选的捕获绑定:try catch -> 后续学习)

# 5、ES11新增特性解析

# 5.1.ES11 - BigInt数据类型

  • 在早期的JavaScript中,我们不能正确的表示过大的数字:
    • 大于MAX_SAFE_INTEGER的数值,表示的可能是不正确的。
    • ES11之前:Number.MAX_SAFE_INTEGER 可获取能正确表示的最大数值;超过了这个数值,表示的数值可能就会出现错误
const maxInt = Number.MAX_SAFE_INTEGER
console.log(maxInt)  //9007199254740991

//大于MAX_SAFE_INTEGER值的一些数值,无法正确表示
console.log(maxInt + 1)  //9007199254740992
console.log(maxInt + 2)  //9007199254740992   -> 超过了出现了错误
console.log(maxInt + 1010)  //9007199254742000   -> 超过了出现了错误
1
2
3
4
5
6
7
  • 那么ES11中,引入了新的数据类型BigInt,用于表示大的整数:
    • BigInt的表示方法是在数值的后面加上n
const bigInt = 9007199254740991n

console.log(bigInt + 1n)  //9007199254740992n
console.log(bigInt + 2n)  //9007199254740993n
console.log(bigInt + 1010n)  //9007199254742001n  
console.log(typeof(bigInt + 1010n))  //bigint
1
2
3
4
5
6

# 5.2.ES11 - Nullish Coalescing Operator(空值合并操作符??)

  • ES11,Nullish Coalescing Operator增加了空值合并操作符??
const foo = "" //这里可以试试这些值转为Boolean值为false的值:“”,0,false,undefined,null,NaN

const result1 = foo || '默认值'
const result2 = foo ?? '默认值' //该语句 ---> 相当于下面这种写法:const result3 = foo === null || foo === undefined ? '默认值' : foo
const result3 = foo === null || foo === undefined ? '默认值' : foo
console.log(result1)
console.log(result2)
console.log(result3)
1
2
3
4
5
6
7
8

# 5.3.ES11 - Optional Chaining(可选链?.)

  • 可选链也是ES11中新增一个特性,主要作用是让我们的代码在进行null和undefined判断时更加清晰和简洁:
const obj = {
  name:'kobe',
  friend:{
    name:'james',
    running() {
      console.log(this.name,'running')
    }
  },
  eating() {
    console.log(this.name,'eating')
  }
}
// obj.friend.eating()//之前这种写法会报错

//可选链写法:可选链写法不会报错
const result = obj?.friend?.eating?.()
console.log(result)//undefined
//第一个?.:判断obj中是否有friend属性;如果有则拿到 obj.friend  没有则返回undefined
// 第二个?.:判断obj.friend是否有eating方法:如果有则拿到obj.friend.eating  没有则返回undefined
// 第三个?.:这里第三个是为了防止出现(obj.friend没有eating方法的情况,这样obj?.friend?.eating会返回undefined;如果没有第三个?.;则会发生undefined()抛出错误问题)



obj?.friend?.running?.()//james running
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  • 可选链是为了避免我们在进行多人合作业务开发时,用到别人封装的函数或者对象,当获取不存在的属性或调用不存在的方法时 出现的抛出错误情况(报错情况)

# 5.4.ES11 - GlobalThis(统一规范的全局对象)

  • 在之前我们希望获取JavaScript环境的全局对象,不同的环境获取的方式是不一样的
    • 比如在浏览器中可以通过this、window来获取;
    • 比如在Node中我们需要通过global来获取;
//浏览器中拿到全局对象
console.log(this)
console.log(window)

//Node中拿到全局对象
console.log(global)
1
2
3
4
5
6
  • 在ES11中对获取全局对象进行了统一的规范:globalThis
    • 不管是在浏览器中,还是Node中,我们都可以通过globalThis拿到全局对象
console.log(globalThis)
1

# 5.5.ES11 - for..in标准化

  • 在ES11之前,虽然很多浏览器支持for...in来遍历对象类型,但是并没有被ECMA标准化。
    • 在ES11中,对其进行了标准化,for...in是用于遍历对象的key的:
const obj = {
  name:'kobe',
  age:39
}

for(const key in obj) {
  console.log(key) //name //age
}
1
2
3
4
5
6
7
8

# 5.6.ES11 - Dynamic Import(动态导入):后面ES Module模块化中学习。

# 5.7.ES11 - Promise.allSettled:后面Promise中学习。

  • Promise的类方法:Promise.allSettled()

# 5.8.ES11 - import meta(导入元):后面ES Module模块化中学习。

# 6、ES12新增特性解析

# 6.1.ES12 - FinalizationRegistry类(监控对象垃圾回收 进行相应回调)

<script>
  let obj = { name: 'kobe' } //强引用
  
  const finalization = new FinalizationRegistry((value) => {
    console.log(value,'被垃圾回收器回收了')
  })
  finalization.register(obj, 'obj')
  obj = null //强引用消失 -> 则obj对象引用(引用的内存地址找到对应的存储空间)的 堆内存的存储空间 会被垃圾回收器回收(标记清除算法->可达性)
  
  //过一会浏览器会打印:obj 被垃圾回收器回收了
</script>
1
2
3
4
5
6
7
8
9
10
11

# 6.2.ES12 - WeakRefs

  • 如果我们默认将一个对象赋值给另外一个引用,那么这个引用是一个强引用
    • 如果我们希望是一个弱引用的话,可以使用WeakRef;
<script>
  let obj = { name: 'kobe' } //强引用
  let info = new WeakRef(obj) //弱引用

  const finalization = new FinalizationRegistry((value) => {
    console.log(value,'被垃圾回收器回收了')
  })
  finalization.register(obj, 'obj')
  obj = null //强引用消失 -> 因为info对obj对象对应的存储空间的引用是弱引用;所以该存储空间,在obj为null后,垃圾回收器会将该存储空间进行回收

  //过一会浏览器会打印:obj 被垃圾回收器回收了
</script>
1
2
3
4
5
6
7
8
9
10
11
12

# 6.3.ES12 - logical assignment operators(逻辑赋值运算符:||=,&&=,??=)

  • 之前我们学过赋值运算符:=,-=,+=,*=,/=,%=等;和逻辑运算符:!,||,&&,??等
  • 那么接下来我们来学习赋值逻辑运算符:||=,&&=,??=
//1.逻辑或赋值运算符:||=
let message1 = ""
// message1 = message1 || "默认值"  //之前写法
message1 ||= "默认值"
console.log(message1)//默认值


//2.逻辑与赋值运算符:&&=
let obj = {
  name:'kobe'
}
//obj = null
//obj = obj && obj.name  //之前写法
obj &&= obj.name  
console.log(obj)//kobe


//3.逻辑空赋值运算符:??=
let foo = null
//foo = foo ?? "默认值" //之前写法
foo ??= "默认值"
console.log(foo)//默认值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 6.4.ES12 - Numeric Separator(数字分隔符_)

//之前表示大数字
const num = 136565656656656
//用数字分隔符表示大数字 ---> 方便阅读
const num1 = 136_565_656_656_656
1
2
3
4

# 6.5.ES12 - String.prototype.replaceAll()(字符串替换-全部)

  • 前面我们学习过一个字符串替换的实例方法:String.prototype.replaceAll()
  • ES12新增了字符串替换全部的实例方法:String.prototype.replaceAll()
  • 下面我们通过案例来体会他们的不同之处吧
const str = 'My good friend is kobe My good friend is kobe'

var str1 = str.replace('kobe','james')//替换字符串中 第一项符合规则的 字符串
console.log(str1)//My good friend is james My good friend is kobe

var str2 = str.replaceAll('kobe','james')//-> 替换字符串中 全部符合规则的 字符串
console.log(str2)//My good friend is james My good friend is james
1
2
3
4
5
6
7

# 7、ES13新增特性解析

# 7.1.ES13 - method.at()

  • 前面我们有使用过字符串、数组的at方法,它们是作为ES13中的新特性加入的:
// 1.数组
const names = ['nba','cba','ncaa']
console.log(names.at(0))//nba
console.log(names.at(-1))//ncaa

// 2.字符串
const str = "Hello World"
console.log(str.at(4))//o
console.log(str.at(-3))//r
1
2
3
4
5
6
7
8
9

# 7.2.ES13 - Object.hasOwn(obj, propKey) - 判断对象上是否有某个属性

  • Object中新增了一个静态方法(类方法): hasOwn(obj, propKey)

  • 那么和之前学习的Object.prototype.hasOwnProperty有什么区别呢?

    • 注意: Object.hasOwn() 旨在替代 Object.prototype.hasOwnProperty() (opens new window).

    • 区别一:防止 Object实例对象和所有Object子类的实例对象 中 内部有重写hasOwnProperty

    • 区别二:对于 Object实例对象和所有Object子类的实例对象的 隐式原型指向null的情况, hasOwnProperty无法进行判断 (因为这样的话该实例对象的原型链中不存在Object.prototype,所以拿不到Object.prototype.hasOwnProperty()方法,即无法进行判断)

    • 知识点提醒:Object是所有类的父类

// 1.区别一:防止对象内部有重写hasOwnProperty
const obj = {
  name:'obj',
  hasOwnProperty(value) {
    console.log(this.name,'对象内部有重写hasOwnProperty,就调用不到Object.prototype.hasOwnProperty方法了')
  }
}
obj.hasOwnProperty('name')//obj 对象内部有重写hasOwnProperty,就调用不到Object.prototype.hasOwnProperty方法了
const flag = Object.hasOwn(obj,'name')
console.log(flag)//true  -> obj对象上有name属性


// 2.区别二:对于隐式原型指向null的对象, hasOwnProperty无法进行判断
const info = {
  name:'info'
}
console.log(info.hasOwnProperty('name'))//true
Object.setPrototypeOf(info,null)//info.__proto__ = null
// console.log(info.hasOwnProperty('name'))//报错:info.hasOwnProperty is not a function

const flag1 = Object.hasOwn(info,'name')
console.log(flag1)//true  -> info对象上有name属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 7.3.ES13 - New members of classes (class类中新增的字段)

  • 在ES13中,新增了定义class类中成员字段(field)的其他方式:
    • Instance public fields :实例公共字段
    • Static public fields:静态公共字段
    • Instance private fields:实例私有字段
    • static private fields:静态私有字段
    • staticblock:静态块
// 1.创建父类
class Person {
  //类外部可以访问
  address = '中国' //实例公共字段
  static totalCount = '70亿' //静态公共字段

  //只能类内部访问
  #sex = 'male' //实例私有字段
  static #maleCount = '10亿'  //静态私有字段

  constructor(name, age) {
    this.name = name,
    this.age = age
  }

  static {// 1.1.静态块 -> 类中的代码进行解析初始化时,解析到了静态块,静态块会就会立即执行,且只执行这一次 (只要类中有静态块,静态块就会立即执行:)
    console.log('static block execution')
  }

  printInfo() {
    console.log(this.address,Person.totalCount, this.#sex, Person.#maleCount)
  }
}

const p = new Person('kobe',39)
console.log(p)//Person { address: '中国', name: 'kobe', age: 39 }
p.printInfo()//中国 70亿 male 10亿

// 2.创建子类
class Student extends Person {
  constructor(name,age) {
    super(name,age)
  }
}
const stu = new Student('james',37)
console.log(stu)//Student { address: '中国', name: 'james', age: 37 }
stu.printInfo()//中国 70亿 male 10亿

console.log(Student.totalCount,Person.totalCount)//70亿 70亿
console.log(p.address,stu.address)//中国 中国

    
// 3.类中定义的私有字段,只能在类的内部进行访问,外部访问会抛出错误
// console.log(Student.#maleCount)//报错: Private field '#maleCount' must be declared in an enclosing class
// console.log(Person.#maleCount)//报错: Private field '#maleCount' must be declared in an enclosing class
// console.log(p.#sex)//报错:Private field '#sex' must be declared in an enclosing class
// console.log(stu.#sex)//报错:Private field '#sex' must be declared in an enclosing class
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
最后更新时间: 2022/08/06, 13:10:00
彩虹
周杰伦