ES7、ES8、ES9、ES10、ES11、ES12、ES13、ES14(ES进阶之路二)

简介

JavaScript是世界上发展最快的编程语言之一,不仅可以用于编写运行在浏览器的客户端程序,随着Node.js的发展,JavaScript也被广泛应用于编写服务端程序。而随着JavaScript这门语言的不断发展和完善,在2015年正式发布的ECMAScript6已经成为了JavaScript这门语言的下一代标准,使得JavaScript用来编写复杂的大型应用程序更加的得心应手。近几年几乎所有使用JavaScript这门语言开发的项目,都在使用ES的新特性来开发。

随着ES2015的发布,标准委员会决定在每年都会发布一个ES的新版本。但很多开发者并没有真正的理解ES2015+每个版本都具有哪些新特性,以及这些新特性与ES5语法的差别,更不清楚这些新特性在实际项目中的应用场景是怎么样的。

由于篇幅原因笔者将ES6~ES12分成了ES进阶之路一ES进阶之路二两篇文章,如果对ES6还不是很清楚了可以先看ES6(ES进阶之路一)

我相信只要你们认真看完了笔者的ES系列文章,你一定会成为ES大神。

接下来我们来看看ES7-ES12吧。篇幅有点长,建议收藏后再看,后期也可以当做字典查阅。

IMG_0387.jpeg

ECMAScript2016(ES7)

Array扩展

Array.prototype.includes()

ES7 之前想判断数组中是否包含一个元素,基本可以这样写:

console.log(array1.find(function(item) {
   
   
    return item === 2
}))

或者

console.log(array1.findIndex(function(item) {
   
   
    return item === 2
}))

或者

console.log(array1.indexOf(2) > -1)

或者

console.log(array1.filter(function(item) {
   
   
    return item === 2
}).length > 0)

ES7引入的Array.prototype.includes() 方法用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回 true,否则返回false

const arr = ['es6', 'es7', 'es8']
console.log(arr.includes('es6')) // true
console.log(arr.includes('es9')) // false

includes方法接收俩个参数,要搜索的值和搜索的开始索引。第二个参数可选。从该索引处开始查找 searchElement。如果为负值,则从末尾第几个开始查找。

const arr = ['es6', 'es7', 'es8']
console.log(arr.includes('es7', 1)) // true
console.log(arr.includes('es7', 2)) // false
console.log(arr.includes('es7', -1)) // false
console.log(arr.includes('es7', -2)) // true

indexOf()比较

  1. indexOf返回的不是boolean值,而是下标或-1。
['a', 'b', 'c'].includes('a') //true
['a', 'b', 'c'].indexOf('a') > -1 //true

console.log(arr.indexOf('es7')) // 1
console.log(arr.indexOf('es7') > -1) // true
  1. includes方法只能判断简单类型的数据,对于复杂类型的数据,比如对象类型的数组,二维数组,这些是无法判断的.
const arr = [1, [2, 3], 4]
arr.includes([2, 3]) //false
arr.indexOf([2, 3]) //-1
  1. 两者都是采用===的操作符来作比较的,不同之处在于:对于NaN的处理结果不同。我们知道jsNaN === NaN 的结果是false, indexOf()也是这样处理的,但是includes()不是这样的。
const demo = [1, NaN, 2, 3]
demo.indexOf(NaN) //-1
demo.includes(NaN) //true

总结

如果只想知道某个值是否在数组中存在,而并不关心它的索引位置,建议使用includes()。如果想获取一个值在数组中的位置,那么只能使用indexOf方法。

幂运算符**

如果不使用任何函数,如何实现一个数的求幂运算?

function pow(x, y) {
   
   
    let res = 1
    for (let i = 0; i < y; i++) {
   
   
        res *= x
    }
    return res
}

pow(2, 10) // 1024

除了自己封装函数来实现,也可是使用 Math.pow() 来完成。

Math.pow() 函数返回基数(base)的指数(exponent)次幂。

console.log(Math.pow(2, 10)) // 1024

ES7 可以这样写了:

console.log(2 ** 10) // 1024

注意,幂运算符的两个*号之间不能出现空格,否则语法会报错。

ECMAScript2017(ES8)

Async/Await

ES2017(ES8)中引入了 async 函数,使得异步操作变得更加方便。Async/Await 的出现,被很多人认为是js异步操作的最终且最优雅的解决方案。我们可以简单理解Async/Await = Generator + Promise

语法

async 用于声明一个 function 是异步的,await 用于等待一个异步方法执行完成,只有当异步完成后才会继续往后执行。await不是必须的并且await 只能出现在 async 函数中。

async function() {
   
   
  const result = await getData()
  console.log(result)
}

一个函数如果加上 async ,那么该函数就会返回一个 Promise

async function async1() {
   
   
  return "1"
}
console.log(async1()) // -> Promise {<resolved>: "1"}

这种用书写同步代码的方式处理异步是不是很舒服呢。

错误处理

Async/Await没有Promise那么多的api,错误需要自己使用try catch处理。

async function() {
   
   
  try{
   
   
    const result = await getData()
    console.log(result)
  } catch(e) {
   
   
    console.log(e)
  }
}
Async/Await和Promise对比
  1. Async/Await相较于Promise的链式调用完全用书写同步代码的方式处理异步使代码分厂优雅易懂。

  2. Async/Await这种用书写同步代码的方式使得await 会阻塞后面代码正常运行,也许之后的异步代码并不依赖于前者,但仍然需要等待前者完成,导致代码失去了并发性。

下面笔者使用Async/AwaitPromise作为对比举个例子说明。

function getData() {
   
   
  return Promise.resolve("模拟获取后端数据");
}

async function fun1() {
   
   
  console.log("主程序开始执行");
  const result = await getData();
  console.log(result);
  console.log("让异步代码自己去执行,不阻塞我们主程序");
}

fun1(); // 主程序开始执行、模拟获取后端数据、让异步代码自己去执行,不阻塞我们主程序

async function fun2() {
   
   
  console.log("主程序开始执行");
  getData().then((result) => {
   
   
    console.log(result);
  });
  console.log("让异步代码自己去执行,不阻塞我们主程序");
}

fun2(); // 主程序开始执行、让异步代码自己去执行,不阻塞我们主程序、模拟获取后端数据

从上面的例子我们可以看出使用Async/Await的弊端,就是不管后面依不依赖异步结果,Async/Await都一定会阻塞后面代码的执行。

Async/Await和Generator对比
  1. Async/Await内置执行器。 Generator 函数的执行必须靠执行器(如co 函数库),而 Async/Await 函数自带执行器。也就是说,Async/Await 函数的执行,与普通函数一模一样

  2. Async/Await更好的语义。 asyncawait,比起星号和 yield,语义更清楚了。async 表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果。

Object 扩展

之前的语法如何获取对象的每一个属性值

const obj = {
   
   
    name: 'randy',
    age: 24
}
console.log(Object.keys(obj)) // ['name', 'age']
const res = Object.keys(obj).map(key => obj[key])
console.log(res)// ["randy", 24]

ES8中对象扩展补充了两个静态方法,用于遍历对象:Object.values(),Object.entries()

Object.values()

Object.values() 返回一个数组,其元素是在对象上找到的可枚举属性值。属性的顺序与通过手动循环对象的属性值所给出的顺序相同(for...in,但是for...in还会遍历原型上的属性值)。

const obj = {
   
   
    name: 'randy',
    age: 24
}
console.log(Object.values(obj)) // ["randy", 24]
Object.entries()

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

const obj = {
   
   
    name: 'randy',
    age: 24
}

for (let [key, value] of obj) {
   
   
    console.log(key, value) // Uncaught TypeError: obj is not iterable
}

我们知道 Object 是不可直接遍历的,上述代码足以说明直接遍历触发了错误。如果使用 Object.entries() 则可以完成遍历任务。

const obj = {
   
   
    name: 'randy',
    age: 24
}

for (let [k, v] of Object.entries(obj)) {
   
   
    console.log(k, v)
    // name randy
    // age 24
}
Object.getOwnPropertyDescriptors()

Object.getOwnPropertyDescriptors用来获取对象所有属性的描述符。

想理解 Object.getOwnPropertyDescriptors 这个方法之前,首先要弄懂什么是描述符descriptor

const data = {
   
   
    Portland: '78/50',
    Dublin: '88/52',
    Lima: '58/40'
}

还是上述那个对象,这里有 keyvalue,上边的代码把所有的 key、value 遍历出来,如果我们不想让 Lima 这个属性和值被枚举怎么办?

Object.defineProperty(data, 'Lima', {
   
   
    enumerable: false
})

Object.entries(data).map(([city, temp]) => {
   
   
    console.log( `City: ${
     
     city.padEnd(16)} Weather: ${
     
     temp}` )
    // City: Portland         Weather: 78/50
    // City: Dublin           Weather: 88/52
})

很成功,Lima 没有被遍历出来,那么 defineProperty 的第三个参数就是描述符descriptor。这个描述符包括几个属性:

  • value [属性的值]
  • writable [属性的值是否可被改变]
  • enumerable [属性的值是否可被枚举]
  • configurable [描述符本身是否可被修改,属性是否可被删除]

ES6中笔者就已经讲过了,关于Object更多API可以看看笔者前面写的JS Object API详解

console.log(Object.getOwnPropertyDescriptor(data, 'Lima'))
// {value: "58/40", writable: true, enumerable: false, configurable: true}

这个是获取对象指定属性的描述符,如果想获取对象的所有属性的描述符:

console.log(Object.getOwnPropertyDescriptors(data))

String 扩展

ES8String 新增了两个实例函数 String.prototype.padStartString.prototype.padEnd,允许将空字符串或其他字符串添加到原始字符串的开头或结尾。

String.prototype.padStart()

把指定字符串填充到字符串头部,返回新字符串。

str.padStart(targetLength [, padString])

参数 含义 必选
targetLength 目标字符要保持的长度值 Y
padString 如果目标字符的长度不够需要的补白字符,默认为空 N
const str = 'randy'
console.log(str.padStart(8, 'x')) // xxxrandy
console.log(str.padEnd(8, 'y')) // randyyyy
console.log(str.padStart(8)) //    randy

场景1:日期格式化,希望把当前日期格式化城:yyyy-mm-dd的格式:

const now = new Date()
const year =</
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值