文章目录
ECMAScript 基础知识
ECMAScript 是由 Ecma 国际在标准 ECMA-262 中定义的脚本语言规范。到 2015 年,一共发布了 1、2、3、4、5、5.1、6 共 7 个版本(其中 4 被废弃)参考链接
我们常把 5.1 之前的 ECMAScript 版本统称做 ES5,将 6 版本之后的版本统称做 ES6(因为从 2015 年起,ECMAScript 终于步入正轨,每年发布一次版本
版本 | 新特性 |
---|---|
ES6(2015) | 类(class)、模块化(ES Module)、箭头函数、函数参数默认值、模板字符串、解构赋值、延展操作符、对象属性简写、Promise、let和const |
ES7(2016) | Array.prototype.includes()、指数操作符 |
ES8(2017) | async/await、Object.values()、Object.entries()、String padding、函数参数列表结尾允许逗号、SharedArrayBuffer对象、Atomics对象 |
ES9(2018) | 异步迭代、Pomise.finally()、Rest/Spread属性、正则表达式命名捕获组、正则表达式反向断言、正则表达式dotAll模式 |
ES10(2019) | Array.flat()和Array.flatMap()、String.trimStart()和String.trimEnd()、String.prototype.matchAll、Symbol.prototype.description、Object.fromEntries、可选catch |
ES11(2020) | Nullish coalescing Operator(空值处理)、Optional chaining(可选链)、Promise.allSet、import按需导入、BigInt、globalThis |
ES12(2021) | replaceAll()、Promise.any()、WeakRefs、逻辑运算符和赋值表达式、数字分隔符 |
类
ECMAScript 6 提供了更接近传统语言的写法,新引入的class关键字具有正式定义类的能力。类(class)是ECMAScript中新的基础性语法糖结构,虽然ECMAScript 6类表面上看起来可以支持正式的面向对象编程,但实际上它背后使用的仍然是原型和构造函数的概念,让对象原型的写法更加清晰、更像面向对象编程的语法。
定义
定义类也有两种主要方式:类声明和类表达式。这两种方式都使用 class 关键字加大括号
// 类表达式
const person = class {}
// 类声明式
class className {
// 属性 properties
property1 = 1;
property2 = [];
peoperty3 = {};
property4 = function() {};
property5 = () => {};
// 构造器
constructor(...args) {
super();
// code here
};
// 方法 methods
method1() {
// code here
};
method2(...args) {
//code here
};
}
静态属性和静态方法
// 直接在类中,通过 static 关键字定义
class className {
static property = ...;
static methoed() {};
}
// 通过类直接添加属性和方法,即为静态的
class className {};
className.property = ...;
className.method = function() {};
私有属性和私有方法
class className {
// 定义,添加 #号
#property = ...;
#method() {};
// 只能在类中可见,调用也需要加 #号
getProperty() {
return this.#property;
}
setProperty(value) {
this.#property = value;
}
}
继承
class Child extends Parent {
// 重写父类方法
method1() {
// code here
}
}
模块
导入导出(静态)
-
export
定义:用于从模块中导出函数、对象或原始值,以便其他程序可以通过 import 语句使用它们// 写法一 export const name = 'Bob'; export function sayHello() { console.log('Hello'); } // 写法二 const number = '1' const add = (a, b)=>{ return a + b } export { number, add as addMethod // 重命名 }
-
export default
定义:用于导出一个模块的默认值。本质是给导出的模块多一个 default 属性,属性是一个对象,对象包含了要导出的内容,引入的时候语法为import Demo from './a'
,可以理解为import {default as Demo} from './a'
,算是一种语法糖注意:一个模块之间只能有一个默认输出
// a.js const number = '1' const add = (a, b)=>{ return a + b } export default { number, add } // b.js import Utils from './a' console.log(Utils) // { number: "1", add: ƒ }
与export区别:
- 两者均可以用于导出常量、函数、文件、模块等
- 在一个文件或模块中,export、import 可以有多个,export default 仅有一个
- 通过 export 方式导出,在导入时要加 {},export default 则不需要,并可以起任意名称
-
import
定义:用于导入其他模块提供的功能注意:
- 导入的路径不能是动态的
- 无法根据条件或者在运行时导入
import { number, add } from './a' // 按需导入 import {number as num, add as addMethod} from './a' // 起别名 import * as Utils from './a' // 全部导入 import Utils from './a' // 默认导入 import Utils, { number, add } from './a' // 按需+默认 import './a' // 执行 a.js里的内容
动态导入
是 JavaScript ES2019 中新增的语法特性,它可以通过将代码按需导入,从而实现更加高效的加载方式。动态导入允许用户在运行时动态地加载模块,这是 ES6 中静态导入所无法实现的。
// 路径可以是模板字面量来动态构造,比如`/src/utils/${moduleName}.js`
import('./a').then((modules) => {
console.log(modules)
// 1. 如果是用 export default 导出的,那么 modules 中包含 default 属性
console.log(modules.default)
// 2. 如果是用 export 导出的,则可以利用解构获取对应值和方法
const { number, add } = modules
}).catch(err => {
console.log(err)
})
promise
Promise是一个类,可以翻译为承诺、期约。参考链接
当通过 new 创建 Promise 实例时,需要传入一个回调函数,我们称之为 executor
- 这个回调函数会被立刻执行,并传入两个回调参数 resolve、reject
- 当调用 resolve 回调函数时,会执行 Promise 对象的 then 方法传入的回调
- 当调用 reject 回调函数时,会执行 Promise 对象的 catch 方法传入的回调
状态
Promise是一个状态机,分为 3 种状态:
- pending:待定状态,执行了 executor 后,处于该状态
- fulfilled:兑现状态,调用 resolve() 后,Promise 的状态更改为 fullfilled,且无法再次更改
- rejected:拒绝状态,调用 reject() 后,Promise 的状态更改为 rejected,且无法再次更改
resolve参数
- 如果传入的普通的值或对象,那么就会被传递到 then 的参数中
- 如果传入的是一个 Promise,那么当前的 Promise 的状态将会由传入的 Promise 来决定
- 如果传入的是一个对象,且该对象实现了 then 方法 (thenable),也会执行该 then 方法,并且由该 then 方法决定后续的状态
实例方法
- then()
- catch()
- finally()
类方法
- Promise.resolve()
相当于 new Promise((resolve) => resolve())
- Promise.reject()
- Promise.all()
当所有Promise执行完毕并且都是成功状态时,才会执行成功回调函数,否则会执行失败回调函数。
- Promise.allSettled()
所有 Promise 执行完毕,无论成功失败都会执行成功回调函数。
const promiseArr = [ new Promise((resolve, reject) => { resolve('success1') }), new Promise((resolve, reject) => { reject('error') }), new Promise((resolve, reject) => { resolve('success2') }), ] Promise.allSettled(promiseArr).then(res => { // res [ // { status: 'fulfilled', value: 'success1' }, // { status: 'rejected', reason: 'error' }, // { status: 'fulfilled', value: 'success2' } // ] console.log('res', res) })
- Promise.race()
返回第一个成功或失败的 promise 的结果。
- Promise.any()
等待第一个成功的 promise,如果队列中没有任何 promise 成功,则返回一个错误
async、await
是 ES2017(ES8) 提出的基于 Promise 的解决异步的最终方案
async
是一个加在函数前的修饰符,被 async 定义的函数会默认返回一个 Promise 对象 resolve 的值。因此对async 函数可以直接 then,返回值就是 then 方法传入的函数。
// 返回值为非 promise 对象
async function fun0(){
return 1;
}
fun0().then(val=>{
console.log(val) // 1
})
// 返回值为 promise 对象
async function fun1(){
return new Promise(function(resolve,reject){
resolve('Promise')
})
}
fun1().then(val => {
console.log(val); // Promise
})
await
也是一个修饰符,只能放在 async 定义的函数内。可以理解为等待。
await 修饰的如果是 Promise 对象:可以获取 Promise 中返回的内容(resolve 或 reject 的参数),且取到值后语句才会往下执行;如果不是 Promise 对象:把这个非 promise 的东西当做 await 表达式的结果
async function fun(){
let a = await 1;
let b = await new Promise((resolve,reject)=>{
setTimeout(function(){
resolve('setTimeout')
},3000)
})
let c = await function(){
return 'function'
}()
console.log(a,b,c)
}
fun(); // 3秒后输出: 1 "setTimeout" "function"