快速浏览 ES2015、ES2016、ES2017、ES2018 及以后的 JavaScript 新特性
常用
块范围
Let
{2,4}1 2 3 4 5 6
| function fn () { let x = 0 if (true) { let x = 1 } }
|
Const
let
是新的 var
。 常量(const
) 就像 let
一样工作,但不能重新分配。
请参阅:Let 和 const
反引号字符串
插值
1
| const message = `Hello ${name}`
|
多行字符串
1 2 3 4
| const str = ` hello world `
|
模板和多行字符串。
请参阅:模板字符串
二进制和八进制文字
1 2
| let bin = 0b1010010 let oct = 0o755
|
请参阅:二进制和八进制文字
指数运算符
新方法
新的字符串方法
1 2 3 4 5 6 7
| "hello".repeat(3) "hello".includes("ll") "hello".startsWith("he") "hello".padStart(8) "hello".padEnd(8) "hello".padEnd(8, '!') "\u1E9B\u0323".normalize("NFC")
|
新的数字方法
1 2 3
| Number.EPSILON Number.isInteger(Infinity) Number.isNaN("NaN")
|
新的 Math 方法
1 2 3
| Math.acosh(3) Math.hypot(3, 4) Math.imul(Math.pow(2, 32) - 1, Math.pow(2, 32) - 2)
|
新的 Array 方法
1 2 3 4
| Array.from(document.querySelectorAll("*"))
Array.of(1, 2, 3)
|
请参阅: 新方法
类
1
| class Circle extends Shape {
|
构造函数
{1}1 2 3
| constructor (radius) { this.radius = radius }
|
方法
{1}1 2 3
| getArea () { return Math.PI * 2 * this.radius }
|
调用超类方法
{2}1 2 3
| expand (n) { return super.expand(n) * Math.PI }
|
静态方法
{1}1 2 3 4
| static createFromDiameter(diameter) { return new Circle(diameter / 2) } }
|
原型的语法糖。
请参阅: 类
私有类
javascript 默认字段是公共的(public
),如果需要注明私有,可以使用(#
)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Dog { #name; constructor(name) { this.#name = name; } printName() { console.log(`你的名字是${this.#name}`) } }
const dog = new Dog("putty")
dog.printName()
|
静态私有类
1 2 3 4 5 6 7 8
| class ClassWithPrivate { static #privateStaticField; static #privateStaticFieldWithInitializer = 42;
static #privateStaticMethod() { } }
|
Promises
做出承诺
{1}1 2 3 4
| new Promise((resolve, reject) => { if (ok) { resolve(result) } else { reject(error) } })
|
用于异步编程。
请参阅:Promises
使用 Promises
{2,3}1 2 3
| promise .then((result) => { ··· }) .catch((error) => { ··· })
|
在 finally 中使用 Promise
{4}1 2 3 4 5 6
| promise .then((result) => { ··· }) .catch((error) => { ··· }) .finally(() => { })
|
当承诺被履行或被拒绝时,处理程序被调用
Promise 函数
1 2 3 4
| Promise.all(···) Promise.race(···) Promise.reject(···) Promise.resolve(···)
|
Async-await
{2,3}1 2 3 4 5
| async function run () { const user = await getUser() const tweets = await getTweets(user) return [user, tweets] }
|
async
函数是使用函数的另一种方式。
请参阅:异步函数
解构 Destructuring
解构赋值
Arrays
{1}1
| const [first, last] = ['Nikola', 'Tesla']
|
Objects
{1}1 2 3 4
| let {title, author} = { title: 'The Silkworm', author: 'R. Galbraith' }
|
支持匹配数组和对象。
请参阅:解构
默认值
1 2
| const scores = [22, 33] const [math = 50, sci = 50, arts = 50] = scores
|
可以在解构数组或对象时分配默认值
函数参数
{1}1 2 3
| function greet({ name, greeting }) { console.log(`${greeting}, ${name}!`) }
|
1
| greet({ name: 'Larry', greeting: 'Ahoy' })
|
对象和数组的解构也可以在函数参数中完成
默认值
{1}1 2 3
| function greet({ name = 'Rauno' } = {}) { console.log(`Hi ${name}!`); }
|
1 2
| greet() greet({ name: 'Larry' })
|
重新分配键
{1}1 2 3
| function printCoordinates({ left: x, top: y }) { console.log(`x: ${x}, y: ${y}`) }
|
1
| printCoordinates({ left: 25, top: 90 })
|
此示例将 x
分配给 left
键的值
循环
{1}1 2 3
| for (let {title, artist} of songs) { ··· }
|
赋值表达式也在循环中工作
对象解构
{1}1
| const { id, ...detail } = song;
|
使用 rest(...)
运算符单独提取一些键和对象中的剩余键
扩展运算符 Spread
对象扩展
与对象扩展
{2}1 2 3 4
| const options = { ...defaults, visible: true }
|
没有对象扩展
1 2 3
| const options = Object.assign( {}, defaults, { visible: true })
|
对象扩展运算符允许您从其他对象构建新对象。
请参阅:对象传播
数组扩展
具有数组扩展
{2,3}1 2 3 4 5
| const users = [ ...admins, ...editors, 'rstacruz' ]
|
没有数组扩展
1 2 3
| const users = admins .concat(editors) .concat([ 'rstacruz' ])
|
扩展运算符允许您以相同的方式构建新数组。
请参阅:扩展运算符
函数 Functions
函数参数
默认参数
{1}1 2 3
| function greet (name = 'Jerry') { return `Hello ${name}` }
|
Rest 参数
{1}1 2 3 4
| function fn(x, ...y) { return x * y.length }
|
扩展
Default(默认), rest, spread(扩展)。
请参阅:函数参数
箭头函数
箭头函数
{1}1 2 3
| setTimeout(() => { ··· })
|
带参数
{1}1 2 3
| readFile('text.txt', (err, data) => { ... })
|
隐式返回
{1,4,5,6}1 2 3 4 5 6 7
| arr.map(n => n*2)
arr.map(n => ({ result: n*2 }))
|
类似函数,但保留了 this
。
请参阅:箭头函数
参数设置默认值
1 2 3 4 5 6 7
| function log(x, y = 'World') { console.log(x, y); }
log('Hello') log('Hello', 'China') log('Hello', '')
|
与解构赋值默认值结合使用
1 2 3 4 5
| function foo({x, y = 5} = {}) { console.log(x, y); }
foo()
|
name 属性
1 2
| function foo() {} foo.name
|
length 属性
1 2
| function foo(a, b){} foo.length
|
Objects
速记语法
1
| module.exports = { hello, bye }
|
同下:
1 2 3
| module.exports = { hello: hello, bye: bye }
|
请参阅:对象字面量增强
方法
{2}1 2 3 4 5 6
| const App = { start () { console.log('running') } }
|
请参阅:对象文字增强
Getters and setters
{2,5}1 2 3 4 5 6 7 8
| const App = { get closed () { return this.status === 'closed' }, set closed (value) { this.status = value ? 'closed' : 'open' } }
|
请参阅:对象字面量增强
计算属性名称
{3}1 2 3 4 5
| let event = 'click' let handlers = { [`on${event}`]: true }
|
请参阅:对象字面量增强
提取值
{3,5}1 2 3 4 5
| const fatherJS = { age: 57, name: "张三" } Object.values(fatherJS)
Object.entries(fatherJS)
|
Modules 模块
Imports 导入
1 2
| import Express from 'express'
|
1 2
| import { indent } from 'helpers'
|
1 2
| import * as Helpers from 'helpers'
|
1 2
| import { indentSpaces as indent } from 'helpers'
|
import
是新的 require()
。
请参阅:Module imports
Exports 导出
1 2
| export default function () { ··· }
|
1 2
| export function mymethod () { ··· }
|
1 2
| export const pi = 3.14159
|
1 2 3 4
| const firstName = 'Michael'; const lastName = 'Jackson'; const year = 1958; export { firstName, lastName, year };
|
1
| export * from "lib/math";
|
export
是新的module.exports
。
请参阅:Module exports
as
关键字重命名
{2,8,12-14}1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import { lastName as surname } from './profile.js';
function v1() { ... } function v2() { ... }
export { v1 as default };
export { v1 as streamV1, v2 as streamV2, v2 as streamLatestVersion };
|
动态加载模块
1 2 3 4 5 6 7 8 9
| button.addEventListener('click', event => { import('./dialogBox.js') .then(dialogBox => { dialogBox.open(); }) .catch(error => { }) });
|
ES2020提案 引入 import()
函数
import() 允许模块路径动态生成
1 2 3 4 5 6 7 8 9
| const main = document.querySelector('main')
import(`./modules/${someVariable}.js`) .then(module => { module.loadPageInto(main); }) .catch(err => { main.textContent = err.message; });
|
ES2020 为 import
命令添加了一个元属性 import.meta
,返回当前模块的元信息
1
| new URL('data.txt', import.meta.url)
|
Node.js 环境中,import.meta.url
返回的总是本地路径,即 file:URL
协议的字符串,比如 file:///home/user/foo.js
导入断言(Import Assertions)
静态导入
1 2
| import json from "./package.json" assert {type: "json"}
|
动态导入
1 2
| const json = await import("./package.json", { assert: { type: "json" } })
|
Generators
Generator 函数
1 2 3 4
| function* idMaker () { let id = 0 while (true) { yield id++ } }
|
1 2 3 4
| let gen = idMaker() gen.next().value gen.next().value gen.next().value
|
情况很复杂。
请参阅:Generators
For..of + 迭代器(iterator)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| let fibonacci = { [Symbol.iterator]() { let pre = 0, cur = 1; return { next() { [pre, cur] = [cur, pre + cur]; return { done: false, value: cur } } } } }
for (var n of fibonacci) { if (n > 1000) break; console.log(n); }
|
用于迭代生成器和数组。
请参阅:For..of iteration
与 Iterator 接口的关系
1 2 3 4 5 6 7 8
| var gen = {}; gen[Symbol.iterator] = function* () { yield 1; yield 2; yield 3; };
[...gen]
|
Generator
函数赋值给 Symbol.iterator
属性,从而使得 gen
对象具有了 Iterator
接口,可以被 ...
运算符遍历了
Symbol.iterator 属性
1 2 3 4
| function* gen() { } var g = gen();
g[Symbol.iterator]() === g
|
gen
是一个 Generator
函数,调用它会生成一个遍历器对象g
。它的 Symbol.iterator
属性,也是一个遍历器对象生成函数,执行后返回它自己
另见