一、ECMASript 7 新特性
1. Array.prototype.includes
includes
方法用来检测数组中是否包含某个元素,返回布尔类型值。
2. 指数运算符
在 ES7 中引入指数运算符 **
,用来实现幂运算,功能与 Math.pow(a, b)
结果相同。
2 ** 3 // 8
Math.pow(2, 3) // 8
二、ECMAScript 8 新特性
1. async 和 await(重要)
async
和 await
两种语法结合可以让异步代码像同步代码一样。(即:看起来是同步的,实质上是异步的。)
先从字面意思理解,async
意为异步,可以用于声明一个函数前,该函数是异步的。await
意为等待,即等待一个异步方法完成。
1.1 async
async
声明function
的函数成为 async
函数,语法:
async function funcName() {
//statements
}
async
内部可以使用 await
,也可以不使用。 async
函数的返回值是一个 Promise
对象,因此执行这个函数时,可以使用 then
和 catch
方法。 根据 函数体内部 的返回值, async
函数返回值具体情况如下:
1、函数体内不返回任何值,则 async
函数返回值为一个成功(fulfilled)
的 Promise
对象,状态值为 undefined
。
let a = async function() {}
let res = a()
console.log(res)
// Promise{<fullfilled>: undefined}
2、返回结果不是一个 Promise
,则 async
函数返回值为一个成功(fulfilled)
的 Promise
对象,状态值为这个内部返回值。
let a = async function () {
return 'hello'
}
let res = a()
console.log(res)
// Promise{<fullfilled>: 'hello'}
3、内部抛出错误,则 async
函数返回值为一个失败的 Promise
对象。
let a = async function foo() {
throw new Error('出错了')
}
a().catch(reason => {
console.log(reason)
})
4、若函数内部返回值是一个 Promise
对象,则 async
函数返回值的状态取决于这个 Promise
对象。
let a = async function () {
return new Promise((resolve, reject) => {
resolve("成功")
})
}
a().then(value => {
console.log(value)
})
1.2 await
await
相当于一个运算符,右边接一个值。一般为一个 Promise
对象,也可以是一个非 Promise
类型。当右接一个非 Promise
类型,await
表达式返回的值就是这个值;当右接一个 Promise
对象,则 await
表达式会阻塞后面的代码,等待当前 Promise
对象 resolve
的值。
综合 async
和 await
而言。await
必须结合 async
使用,而 async
则不一定需要 await
。 async
会将其后的函数的返回值封装成一个 Promise
对象,而 await
会等待这个 Promise
完成,然后返回 resolve
的结果。当这个 Promise
失败或者抛出异常时,需要时使用 try-catch
捕获处理。
Promise
使用链式调用解决了传统方式回调地狱的问题,而 async-await 又进一步优化了代码的可读性。
const p = new Promise((resolve, reject)=>{
resolve('成功')
})
async function main() {
let res = await p
console.log(res)
}
main()
// '成功'
const p = new Promise((resolve, reject)=>{
reject('失败')
})
async function main() {
try {
let res = await p
console.log(res)
} catch(e) {
console.log(e)
}
}
main()
// '失败'
1.3 综合应用-读取文件
需求:先读取用户数据 user,然后读取订单数据 order,最后读取商品数据 goods。
对于这种异步操作很容易想到使用 Promise
,代码如下:
const fs = require('fs')
let p = new Promise((resolve, reject) => {
fs.readFile('./files/user.md', (err, data) => {
if (err) reject(err)
resolve(data)
})
})
p.then(value => {
return new Promise((resolve, rejecet) => {
fs.readFile('./files/order.md', (err, data) => {
if (err) rejecet(err)
resolve([value, data])
})
})
}, reason => {
console.log(reason)
}).then(value => {
return new Promise((resolve, reject) => {
fs.readFile('./files/goods.md', (err, data) => {
if (err) reject(err)
value.push(data)
resolve(value)
})
})
}, reason => {
console.log(reason)
}).then(value => {
console.log(value.join('\n'))
}, reason => {
console.log(reason)
})
但是,使用 Promise
链式调用虽然避免了回调地狱,但这种链式调用过多难免引起代码复杂,看起来不直观。可以使用 async
和 await
方法优化,代码如下:
const fs = require('fs')
function readUser() {
return new Promise((resolve, reject) => {
fs.readFile('./files/user.md', (err, data) => {
if (err) reject(err)
resolve(data)
})
})
}
function readOrder() {
return new Promise((resolve, reject) => {
fs.readFile('./files/order.md', (err, data) => {
if (err) reject(err)
resolve(data)
})
})
}
function readGoods() {
return new Promise((resolve, reject) => {
fs.readFile('./files/goods.md', (err, data) => {
if (err) reject(err)
resolve(data)
})
})
}
async function read() {
let user = await readUser()
let order = await readOrder()
let goods = await readGoods()
console.log([user, order, goods].join('\n'))
}
read()
这样,代码看起来很直观,就好像是同步代码一样,实际上是异步操作。
1.4 综合应用-封装ajax
function sendAjax(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open('get', url)
xhr.send()
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.response))
}
reject(xhr.status)
}
}
})
}
async function main() {
let res = await sendAjax('http://poetry.apiopen.top/sentences') //直接得到promise成功状态的值
console.log(res)
}
main()
2. Object.values 和 Object.entries
1、Object.values()
方法返回一个给定对象的所有可枚举属性值的数组,类似于 Object.keys()
,只是前者返回属性值,后者返回键值组合的数组。
let obj = {
a: 1,
b: {1:2},
c: [1,2,3]
}
console.log(Object.values(obj))
// [1, {1: 2}, [1,2,3]]
console.log(Object.keys(obj))
// ['a', 'b', 'c']
2、Object.entries()
方法返回一个给定对象自身可遍历属性 [key,value]
的数组(数组元素也是一个个的数组的数组)
const obj = {a: 1, b: 2, c: 3};
console.log(Object.entries(obj))
// [ [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ] ]
返回的是一个数组,这样就可以使用 for...of
遍历了。
const obj = { a: 1, b: 2, c: 3 };
for (let [k, v] of Object.entries(obj)) {
console.log(k, v)
}
三、ECMAScript 11 新特性
1、BigInt(新的数字类型)
BigInt
是一种特殊的数字类型,它提供了对任意长度整数的支持。
创建 bigint
的方式有两种:在一个整数字面量后面加 n
或者调用 BigIn
t 函数,该函数从字符串、数字等中生成 bigint
。
let n1 = 123n
let n2 = 456n
let n3 = BigInt(789)
console.log(typeof n1) // bigint
console.log(n1+n2) // 579n
console.log(n2+n3) // 1245n
比较运算符:
例如 < 和 >,使用它们来对 bigint
和 number
类型的数字进行比较没有问题:
alert( 2n > 1n ); // true
alert( 2n > 1 ); // true
但是请注意,由于 number 和 bigint 属于不同类型,它们可能在进行 ==
比较时相等,但在进行 ===
(严格相等)比较时不相等
alert( 1 == 1n ); // true
alert( 1 === 1n ); // false
2、globalThis
全局对象提供可在任何地方使用的变量和函数。默认情况下,这些全局变量内置于语言或环境中。
在浏览器中,它的名字是 window,对 Node.js 而言,它的名字是 global
,其它环境可能用的是别的名字。
ES11中 globalThis
被作为全局对象的标准名称加入到了 JavaScript
中,所有环境都应该支持该名称。所有主流浏览器都支持它。
使用场景: 假设我们的环境是浏览器,我们将使用 window。如果你的脚本可能会用来在其他环境中运行,则最好使用 globalThis
。