深入理解ECMAScript 2015:版本特性全解析
作者:佚名 来源:高速下载 更新:2024-11-18 阅读:次
在手机上看
引言
JavaScript(JS)作为一门轻量级的面向对象编程语言,一直在不断发展和完善。ES6(ECMAScript 2015)是JS的一个重要里程碑,引入了大量新特性和语法改进,极大地提升了开发效率和代码可读性。
ES6版本概述
ES6,也称为ECMAScript 2015,是JS语言的一次重大更新。它不仅修复了旧版本的许多问题,还引入了许多新特性,使得JS更加现代化和强大。
主要特性
<h5>1. let和constlet
和const
是ES6引入的两个新的变量声明关键字,用于解决var
的变量提升问题。
let a = 10;
const b = 20;
2. 箭头函数
箭头函数提供了一种更简洁的函数声明方式。
const sum = (x, y) => x + y;
console.log(sum(1, 2)); // 3
3. 模板字符串
模板字符串可以简化字符串的拼接和处理。
const name = '张三';
const greeting = `你好,${name}!`;
console.log(greeting); // 你好,张三!
4. 解构赋值
解构赋值可以简化从数组或对象中提取数据的操作。
const [x, y] = [1, 2];
const {a, b} = {a: 3, b: 4};
console.log(x, y, a, b); // 1 2 3 4
5. Promise
Promise用于处理异步操作,使代码更加清晰和易于管理。
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功');
}, 1000);
}).then(result => console.log(result)); // 成功
6. 类(Class)
ES6引入了类的概念,使得面向对象编程更加直观。
class Person {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(`你好,我是${this.name}`);
}
}
const p = new Person('李四');
p.sayHello(); // 你好,我是李四
实际应用
理解ES6的特性不仅有助于提升代码质量,还能在实际项目中解决复杂问题。例如,使用Promise可以更好地处理异步请求,使用解构赋值可以简化数据处理逻辑。
ES6作为JS的一次重要更新,带来了许多实用的新特性和语法改进。掌握这些特性,不仅能提升编程技能,还能在实际开发中事半功倍。希望本文能帮助大家更好地理解和应用ES6。
ECMAScript2015+ 的新特性
let 和 const
新增的块级作用域声明方式。let 用于声明可变变量,const 用于声明常量。
解构赋值
允许从数组或对象中提取值并赋值给变量,简化代码书写。
字符串扩展
模板字符串
新增了模板字符串,使用反引号(``)定义字符串,支持多行字符串和插值表达式。
扩展方法
常用的一些方法如下:
-
String.prototype.repeat():返回一个新字符串,表示将原字符串重复n次。例如:"x".repeat(3) // "xxx" -
String.prototype.includes():返回布尔值,表示是否找到了参数字符串。例如:"Hello world".includes("world") // true -
String.prototype.startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。例如:"Hello world".startsWith("Hello") // true -
String.prototype.endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。例如:"Hello world".endsWith("world") // true
正则的扩展
RegExp 构造函数
当基于 RegExp 构造函数生成正则对象,第一个参数是正则表达式时,第二个参数可以指定修饰符,且修饰符会被第二个参数覆盖。
u 修饰符
u 修饰符用于处理 Unicode 字符,可以正确处理大于 \uFFFF 的 Unicode 字符。添加 u 修饰符后:
-
使用点字符(.)可以匹配 32 位的 UTF-16 字符 -
使用大括号包裹的 Unicode 字符可以被正确解析 -
量词可以正确匹配 32 位的 UTF-16 字符 -
预定义模式 \w、\W、\d、\D、\s、\S 可以正确匹配 32 位的 UTF-16 字符
y 修饰符
y 修饰符叫做"粘连"(sticky)修饰符,表示从剩余的第一个字符开始匹配。
y 修饰符的设计本意是,让头部匹配的标志^在全局匹配中都有效。
let s = 'aaa_aa_a';
let r1 = /a+/g; // 全局匹配
let r2 = /a+/y; // 粘连匹配
r1.exec(s); // ["aaa"]
r2.exec(s); // ["aaa"]
r1.exec(s); // ["aa"] // g修饰符会继续往后匹配
r2.exec(s); // null // y修饰符要求必须从剩余的第一个字符开始匹配,因为剩余的第一个字符是_,所以返回null
数值的扩展
二进制和八进制表示法
ES6 提供了二进制和八进制数值的新的写法:
-
二进制用前缀 0b
(或0B
)表示 -
八进制用前缀 0o
(或0O
)表示
// 二进制
0b111110111 === 503 // true
// 八进制
0o767 === 503 // true
Number.isFinite(), Number.isNaN()
新增了两个方法来检测数值:
-
Number.isFinite()
用来检查一个数值是否为有限的 -
Number.isNaN()
用来检查一个值是否为 NaN
Number.isFinite(15); // true
Number.isFinite(Infinity); // false
Number.isFinite(-Infinity); // false
Number.isFinite(NaN); // false
Number.isNaN(NaN); // true
Number.isNaN(15); // false
Number.isNaN('15'); // false
Number.parseInt(), Number.parseFloat()
ES6 将全局方法parseInt()
和parseFloat()
移植到 Number 对象上:
// 等同于
Number.parseInt === parseInt // true
Number.parseFloat === parseFloat // true
Number.isInteger()
用来判断一个数值是否为整数:
Number.isInteger(25) // true
Number.isInteger(25.0) // true
Number.isInteger(25.1) // false
Number.EPSILON
表示一个极小的常量,它的值是 JavaScript 能够表示的最小精度:
Number.EPSILON // 2.220446049250313e-16
// 用于浮点数运算的误差检查
0.1 + 0.2 === 0.3 // false
Math.abs((0.1 + 0.2) - 0.3) < Number.EPSILON // true
安全整数和 Number.isSafeInteger()
JavaScript 能够准确表示的整数范围在 -2^53 到 2^53 之间。ES6 引入了:
-
Number.MAX_SAFE_INTEGER
:最大安全整数 -
Number.MIN_SAFE_INTEGER
:最小安全整数 -
Number.isSafeInteger()
:判断一个整数是否在这个范围内
Number.MAX_SAFE_INTEGER // 9007199254740991
Number.MIN_SAFE_INTEGER // -9007199254740991
Number.isSafeInteger(9007199254740991) // true
Number.isSafeInteger(9007199254740992) // false
Math 对象的扩展
ES6 在 Math 对象上新增了多个方法:
-
Math.trunc()
去除小数部分 -
Math.sign()
判断一个数是正数、负数、还是零 -
Math.cbrt()
计算立方根 -
Math.hypot()
返回所有参数的平方和的平方根
Math.trunc(4.9) // 4
Math.sign(-5) // -1
Math.cbrt(27) // 3
Math.hypot(3, 4) // 5
指数运算符
引入了**
运算符,用来进行指数运算:
2 ** 3 // 8
2 ** 3 ** 2 // 512
let a = 2;
a **= 3; // 等同于 a = a ** 3
函数的扩展
箭头函数
ES6 引入了箭头函数,使用=>
定义函数。箭头函数有以下特点:
-
更简洁的语法:
// 普通函数
const fun1 = function(x) {
return x * 2;
}
// 箭头函数
const fun2 = x => x * 2;
-
不绑定自己的this:
const obj = {
data: [],
init() {
// 箭头函数中的this指向定义时的对象
document.addEventListener('click', () => {
this.data.push('clicked'); // this指向obj
});
}};
-
不能用作构造函数 -
不绑定arguments对象 -
不能用作Generator函数
函数参数的默认值
可以直接在参数定义时设置默认值:
function log(x, y = 'World') {
console.log(x, y);
}
log('Hello') // Hello World
log('Hello', 'China') // Hello China
// 解构赋值默认值
function fetch({url, method = 'GET'} = {}) {
console.log(method);
}
fetch({url: '/api'}) // GET
fetch() // GET
注意事项:
-
参数默认值不是传值的,而是每次都重新计算默认值表达式的值
let count = 1;
function foo(value = count) {
console.log(value);
}
foo(); // 1
count = 2;
foo(); // 2 // 每次调用时都会重新获取count的值
// 更复杂的例子
function bar(func = () => Date.now()) {
console.log(func());
}
bar(); // 1709xxxxx1
bar(); // 1709xxxxx2 // 每次调用都会得到新的时间戳
-
默认值参数应该是函数的尾参数
rest 参数
rest 参数(形式为...变量名)用于获取函数的多余参数:
// 代替 arguments
function add(...numbers) {
return numbers.reduce((sum, num) => sum + num, 0);
}
add(2, 3, 4) // 9
// 结合解构使用
function push(array, ...items) {
items.forEach(item => {
array.push(item);
});
}
let arr = [];
push(arr, 1, 2, 3); // arr现在是[1, 2, 3]
rest 参数的特点:
-
只能作为最后一个参数 -
函数的length属性不包括rest参数 -
替代了arguments对象,更加灵活 -
rest参数是一个真正的数组,可以直接使用数组方法
数组的扩展
扩展运算符
扩展运算符(...)将一个数组转为用逗号分隔的参数序列:
console.log(...[1, 2, 3]) // 1 2 3
// 常见用途
// 1. 复制数组
const arr1 = [1, 2, 3];
const arr2 = [...arr1];
// 2. 合并数组
const arr3 = [...arr1, ...arr2];
// 3. 与解构赋值结合
const [first, ...rest] = [1, 2, 3, 4, 5];
// first: 1
// rest: [2, 3, 4, 5]
Array.from()
将类数组对象和可遍历对象转换为真正的数组:
// 转换类数组对象
const arrayLike = {
0: 'a',
1: 'b',
2: 'c',
length: 3
};
Array.from(arrayLike) // ['a', 'b', 'c']
// 转换可遍历对象
Array.from('hello') // ['h', 'e', 'l', 'l', 'o']
// 接受第二个参数,类似于数组的map方法
Array.from([1, 2, 3], x => x * 2) // [2, 4, 6]
Array.of()
将一组值转换为数组,弥补数组构造函Array()的不足:
Array.of(3) // [3]
Array.of(1, 2, 3) // [1, 2, 3]
// 对比Array()构造函数
Array(3) // [empty × 3]
Array(1, 2, 3) // [1, 2, 3]
数组实例的 copyWithin()
在当前数组内部,指定位置的成员复制到其他位置:
// array.copyWithin(target, start = 0, end = this.length)
[1, 2, 3, 4, 5].copyWithin(0, 3) // [4, 5, 3, 4, 5]
数组实例的 find() 和 findIndex()
find()
用于找出第一个符合条件的数组成员,findIndex()
返回第一个符合条件的数组成员的位置:
const numbers = [1, 4, -5, 10];
numbers.find(n => n < 0) // -5
numbers.findIndex(n => n < 0) // 2
数组实例的 fill()
使用给定值,填充一个数组:
new Array(3).fill(7) // [7, 7, 7]
['a', 'b', 'c'].fill(7, 1, 2) // ['a', 7, 'c']
数组实例的 entries(),keys() 和 values()
用于遍历数组,它们都返回一个遍历器对象:
const arr = ['a', 'b', 'c'];
for (let index of arr.keys()) {
console.log(index); // 0, 1, 2
}
for (let elem of arr.values()) {
console.log(elem); // 'a', 'b', 'c'
}
for (let [index, elem] of arr.entries()) {
console.log(index, elem); // 0 'a', 1 'b', 2 'c'
}
对象的扩展
属性简写
当属性名与变量名相同时,可以简写:
const name = 'Tom';
const age = 18;
const person = { name, age }; // 等同于 { name: name, age: age }
方法简写
对象方法可以简写,省略function关键字:
const obj = {
sayHi() { // 等同于 sayHi: function()
console.log('Hi');
}
}
属性名表达式
支持用表达式作为属性名:
const prop = 'foo';
const obj = {
[prop]: 'bar',
[`a${prop}`]: 'hello'
};
Object.assign()
用于对象的合并,将源对象的所有可枚举属性复制到目标对象:
const target = { a: 1 };
const source = { b: 2 };
Object.assign(target, source); // { a: 1, b: 2 }
Object.is()
用于比较两个值是否严格相等:
Object.is(+0, -0) // false
Object.is(NaN, NaN) // true
Symbol
Symbol 是 ES6 引入的一种新的原始数据类型,表示独一无二的值。
基本用法
// 创建 Symbol
const s1 = Symbol();
const s2 = Symbol('描述文字');
// Symbol 值是唯一的
Symbol() !== Symbol() // true
Symbol('foo') !== Symbol('foo') // true
// 作为对象属性
const obj = {
[Symbol('foo')]: 'foo value',
[Symbol('bar')]: 'bar value'
};
Symbol.for() 和 Symbol.keyFor()
// Symbol.for() 会在全局注册表中搜索键为"foo"的 Symbol
const s1 = Symbol.for('foo');
const s2 = Symbol.for('foo');
s1 === s2 // true
// Symbol.keyFor() 返回一个已登记的 Symbol 类型值的 key
Symbol.keyFor(s1) // "foo"
内置的 Symbol 值
ES6 提供了一些内置的 Symbol 值,指向语言内部使用的方法:
// Symbol.iterator
// 对象进行 for...of 循环时,会调用这个方法
const arr = [1, 2, 3];
const iterator = arr[Symbol.iterator]();
iterator.next() // { value: 1, done: false }
// Symbol.hasInstance
// instanceof 运算符调用这个方法
class MyArray {
static [Symbol.hasInstance](instance) {
return Array.isArray(instance);
}
}
[] instanceof MyArray // true
// Symbol.toPrimitive
// 对象转换为原始类型值时调用
const obj = {
[Symbol.toPrimitive](hint) {
switch (hint) {
case 'number': return 123;
case 'string': return 'str';
case 'default': return 'default';
}
}
};
主要特点:
-
Symbol 值是唯一的,可用作对象属性名 -
Symbol 属性不会出现在常规的对象属性枚举中 -
可以用于定义一些非私有但又希望只用于内部的方法 -
提供了一些内置的 Symbol 值用于扩展对象的系统层面的功能
Set 和 Map 数据结构
Set
Set 是一个新的数据结构,类似于数组,但成员值都是唯一的:
// 基本用法
const s = new Set();
s.add(1).add(2).add(2); // Set(2) {1, 2}
// 接收数组初始化
const set = new Set([1, 2, 2, 3]); // Set(3) {1, 2, 3}
// 常用方法
set.has(1); // true
set.delete(2); // true
set.size; // 2
set.clear(); // 清空
// 数组去重
const arr = [...new Set([1, 2, 2, 3])]; // [1, 2, 3]
// 遍历方法
for (let item of set) {
console.log(item);
}
set.forEach((value, key) => console.log(value));
WeakSet
WeakSet 结构与 Set 类似,但有两个重要的区别:
-
成员只能是对象 -
对象都是弱引用,可被垃圾回收机制回收
const ws = new WeakSet();
const obj = {};
ws.add(obj);
ws.has(obj); // true
Map
Map 是一种键值对的集合,类似于对象,但键的范围不限于字符串:
// 基本用法
const m = new Map();
const obj = {p: 'Hello'};
m.set(obj, 'content');
m.get(obj); // 'content'
// 接收数组初始化
const map = new Map([
['name', '张三'],
['age', 18]
]);
// 常用方法
map.has('name'); // true
map.delete('name'); // true
map.size; // 1
map.clear(); // 清空
// 遍历方法
for (let [key, value] of map) {
console.log(key, value);
}
map.forEach((value, key) => console.log(key, value));
WeakMap
WeakMap 结构与 Map 类似,但有两个重要的区别:
-
只接受对象作为键名 -
键名所指向的对象,不计入垃圾回收机制
const wm = new WeakMap();
const key = {};
wm.set(key, 'value');
wm.get(key); // 'value'
主要特点:
-
Set 用于存储唯一值的集合 -
Map 提供了真正的"键值对"数据结构 -
WeakSet 和 WeakMap 都是弱引用,主要用于防止内存泄漏 -
这些数据结构都提供了丰富的操作方法和遍历接口
Proxy 和 Reflect
Proxy
Proxy 是一个强大的对象代理机制,它可以拦截并自定义对象的基本操作,比如属性查找、赋值、枚举、函数调用等。通过 Proxy,你可以在这些操作执行前后添加自定义行为。
// 基本用法
const target = {
name: '张三',
age: 18
};
const handler = {
// 拦截对象属性的读取
get(target, prop) {
console.log(`访问了${prop}属性`);
return target[prop];
},
// 拦截对象属性的设置
set(target, prop, value) {
console.log(`设置${prop}属性为${value}`);
target[prop] = value;
return true;
}
};
const proxy = new Proxy(target, handler);
// 使用代理对象
proxy.name; // 输出:"访问了name属性" 返回:"张三"
proxy.age = 20; // 输出:"设置age属性为20"
常用的 Proxy 处理方法
const handler = {
// 拦截属性的读取
get(target, prop) {},
// 拦截属性的设置
set(target, prop, value) {},
// 拦截函数的调用
apply(target, thisArg, argumentsList) {},
// 拦截 new 操作
construct(target, args) {},
// 拦截 Object.defineProperty
defineProperty(target, prop, descriptor) {},
// 拦截属性的删除
deleteProperty(target, prop) {},
// 拦截获取原型
getPrototypeOf(target) {},
// 拦截设置原型
setPrototypeOf(target, proto) {}
};
Reflect
Reflect 是一个内置的全局对象,它提供了一组统一的方法来操作对象。这些方法是对象操作的底层封装,与 Proxy 处理器的方法一一对应,使得代理对象的操作更加规范和可控。
// 基本用法
const obj = {
name: '张三'
};
// 读取属性
Reflect.get(obj, 'name'); // '张三'
// 设置属性
Reflect.set(obj, 'age', 18); // true
// 删除属性
Reflect.deleteProperty(obj, 'age'); // true
// 判断对象是否有某个属性
Reflect.has(obj, 'name');
Proxy 和 Reflect 结合使用
const target = {
name: '张三',
age: 18
};
const handler = {
get(target, prop, receiver) {
console.log(`获取${prop}属性`);
return Reflect.get(target, prop, receiver);
},
set(target, prop, value, receiver) {
console.log(`设置${prop}属性`);
return Reflect.set(target, prop, value, receiver);
}
};
const proxy = new Proxy(target, handler);
主要用途:
-
Proxy 用于创建对象的代理,实现对象操作的拦截和自定义 -
Reflect 提供了操作对象的统一 API -
常用于: -
数据验证 -
日志记录 -
数据绑定 -
访问控制
-
Promise 对象
Promise 是异步编程的一种解决方案,比传统的回调函数更加优雅。
基本用法
// 创建 Promise
const promise = new Promise((resolve, reject) => {
// 异步操作
setTimeout(() => {
if(/* 成功 */) {
resolve('成功结果');
} else {
reject('失败原因');
}
}, 1000);
});
// 使用 Promise
promise
.then(result => {
console.log(result);
})
.catch(error => {
console.log(error);
})
.finally(() => {
console.log('无论成功失败都会执行');
});
Promise 的状态
Promise 有三种状态:
-
pending(进行中) -
fulfilled(已成功) -
rejected(已失败)
状态一旦改变,就不会再变。
Promise 的常用方法
// Promise.all():所有 Promise 都成功才成功
Promise.all([promise1, promise2])
.then(([result1, result2]) => {
console.log(result1, result2);
});
// Promise.race():返回最快的那个 Promise 的结果
Promise.race([promise1, promise2])
.then(result => {
console.log(result);
});
// 【ES2020】Promise.allSettled():等待所有 Promise 完成
Promise.allSettled([promise1, promise2])
.then(results => {
results.forEach(result => {
if (result.status === 'fulfilled') {
console.log('成功:', result.value);
} else {
console.log('失败:', result.reason);
}
});
});
// 【ES2021】Promise.any():任意一个 Promise 成功就返回
Promise.any([promise1, promise2])
.then(result => {
console.log('第一个成功的结果:', result);
});
实际应用示例
// 封装 AJAX 请求
function fetchData(url) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.onload = () => {
if (xhr.status === 200) {
resolve(JSON.parse(xhr.response));
} else {
reject(new Error(`请求失败:${xhr.statusText}`));
}
};
xhr.onerror = () => reject(new Error('网络错误'));
xhr.send();
});
}
// 使用 async/await 更优雅地处理
async function getData() {
try {
const result = await fetchData('api/data');
console.log(result);
} catch (error) {
console.error(error);
}
}
主要特点:
-
链式调用,避免回调地狱 -
统一的错误处理机制 -
多个 Promise 的组合处理方法 -
与 async/await 完美配合
Iterator 和 for...of 循环
Iterator(迭代器)
Iterator 是一种遍历机制,它就像一个指针,指向数据结构的某个位置,并且通过 next() 方法指向下一个位置,直到遍历完所有数据。
// Iterator 的基本实现
function makeIterator(array) {
let nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ?
{value: array[nextIndex++], done: false} :
{value: undefined, done: true};
}
};
}
// 使用迭代器
const it = makeIterator(['a', 'b']);
console.log(it.next()); // { value: "a", done: false }
console.log(it.next()); // { value: "b", done: false }
console.log(it.next()); // { value: undefined, done: true }
原生具备 Iterator 接口的数据结构
// Array
const arr = ['a', 'b', 'c'];
const iter = arr[Symbol.iterator]();
iter.next(); // { value: 'a', done: false }
// String
const str = "hello";
for (let char of str) {
console.log(char); // h,e,l,l,o
}
// Map
const map = new Map([['name', '张三'], ['age', 18]]);
for (let [key, value] of map) {
console.log(key, value);
}
// Set
const set = new Set(['a', 'b', 'c']);
for (let value of set) {
console.log(value);
}
for...of 循环
for...of 循环可以自动遍历具有 Iterator 接口的数据结构:
// 遍历数组
const arr = ['red', 'green', 'blue'];
for (let value of arr) {
console.log(value);
}
// 与其他遍历方法的对比
const arr = ['a', 'b', 'c'];
// for...in 遍历索引
for (let index in arr) {
console.log(index); // "0", "1", "2"
}
// for...of 遍历值
for (let value of arr) {
console.log(value); // "a", "b", "c"
}
// forEach 无法中断
arr.forEach(value => {
console.log(value);
// 无法使用 break
});
自定义 Iterator 接口
class Collection {
constructor() {
this.items = ['a', 'b', 'c'];
}
[Symbol.iterator]() {
let index = 0;
const items = this.items;
return {
next() {
return index < items.length ?
{value: items[index++], done: false} :
{value: undefined, done: true};
}
};
}
}
const collection = new Collection();
for (let value of collection) {
console.log(value); // 'a', 'b', 'c'
}
Generator 函数
Generator 函数是一种特殊的函数,可以暂停执行和恢复执行。通过 yield 关键字,实现函数的分段执行。
基本用法
// 定义 Generator 函数
function* numberGenerator() {
yield 1;
yield 2;
return 3;
}
// 使用 Generator
const gen = numberGenerator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: true }
yield 表达式
function* calculateNumbers() {
const result1 = yield 1 + 1; // result1 是下一次 next 传入的值
console.log('第一次计算结果:', result1);
const result2 = yield 2 + 2;
console.log('第二次计算结果:', result2);
}
const calc = calculateNumbers();
console.log(calc.next()); // { value: 2, done: false }
console.log(calc.next(100)); // 打印 "第一次计算结果: 100"
// { value: 4, done: false }
console.log(calc.next(200)); // 打印 "第二次计算结果: 200"
// { value: undefined, done: true }
实际应用示例
// 1. 实现迭代器
function* createIterator(array) {
for(let item of array) {
yield item;
}
}
const iterator = createIterator(['a', 'b', 'c']);
console.log(iterator.next()); // { value: 'a', done: false }
// 2. 状态机
function* toggle() {
while(true) {
yield '开';
yield '关';
}}
const light = toggle();
console.log(light.next().value); // '开'
console.log(light.next().value); // '关'
console.log(light.next().value); // '开'
Generator 函数的特点
-
函数名前有 *
号 -
函数体内使用 yield
表达式 -
调用后返回遍历器对象 -
可以通过 next()
方法依次遍历 -
可以配合 Promise 实现异步控制流程
async 函数
async 函数是 Generator 函数的语法糖,使异步操作更简单直观。它返回一个 Promise 对象。
基本用法
// 基础示例
async function getData() {
try {
const response = await fetch('api/data');
const data = await response.json();
return data;
} catch (error) {
console.log('错误:', error);
}}
// 调用方式
getData().then(data => {
console.log(data);
});
async 函数的几种写法
// 函数声明
async function foo() {}
// 函数表达式
const foo = async function() {}
// 对象方法
const obj = {
async foo() {}
}
// 箭头函数
const foo = async () => {}
// Class 方法
class Storage {
async getData() {}
}
实际应用示例
// 1. 并行请求
async function getMultipleData() {
// Promise.all 并行执行多个请求
const [users, posts] = await Promise.all([
fetch('api/users').then(r => r.json()),
fetch('api/posts').then(r => r.json())
]);
return { users, posts };
}
// 2. 错误处理
async function fetchData() {
try {
const response = await fetch('api/data');
if (!response.ok) {
throw new Error('请求失败');
}
return await response.json();
} catch (error) {
console.error('出错了:', error);
// 可以返回默认值或重新抛出错误
return [];
}
}
// 3. 顺序请求
async function getOrderDetails() {
// 每个请求依赖前一个请求的结果
const user = await fetch('api/user').then(r => r.json());
const orders = await fetch(`api/orders/${user.id}`).then(r => r.json());
const details = await fetch(`api/details/${orders[0].id}`).then(r => r.json());
return details;
}
async 函数的特点
-
内置执行器,不需要手动执行 -
更好的语义,async 表示函数里有异步操作,await 表示紧跟在后面的表达式需要等待结果 -
返回值是 Promise,比 Generator 函数的返回值是 Iterator 对象方便 -
await 命令后面,可以是 Promise 对象或原始类型的值 -
错误处理方便,可以用 try-catch 捕获同步和异步的错误
Class
Class 是 ES6 引入的定义类的新方式,让对象原型的写法更加清晰、更像面向对象编程的语法。
基本用法
class Person {
// 构造方法
constructor(name, age) {
this.name = name;
this.age = age;
}
// 实例方法
sayHello() {
console.log(`你好,我是${this.name}`);
}
// getter
get info() {
return `${this.name}, ${this.age}岁`;
}
// setter
set age(value) {
this._age = value < 0 ? 0 : value;
}
// 静态方法
static create(name, age) {
return new Person(name, age);
}}
// 使用类
const person = new Person('张三', 20);
person.sayHello(); // 你好,我是张三
console.log(person.info); // 张三, 20岁
继承
class Student extends Person {
constructor(name, age, grade) {
// 调用父类构造函数
super(name, age);
this.grade = grade;
}
study() {
console.log(`${this.name}正在学习`);
}
// 重写父类方法
sayHello() {
super.sayHello();
console.log(`我是${this.grade}年级的学生`);
}
}
const student = new Student('小明', 15, '初三');
student.sayHello();
// 你好,我是小明
// 我是初三年级的学生
【ES2022】私有属性和方法
class Account {
// 私有属性(新提案)
#balance = 0;
// 私有方法(新提案)
#validate(amount) {
return amount > 0 && amount <= this.#balance;
}
deposit(amount) {
if (amount > 0) {
this.#balance += amount;
return true;
}
return false;
}
withdraw(amount) {
if (this.#validate(amount)) {
this.#balance -= amount;
return true;
}
return false;
}
get balance() {
return this.#balance;
}
}
const account = new Account();
account.deposit(100);
console.log(account.balance); // 100
console.log(account.#balance); // 语法错误
Class 的特点
-
类声明不会提升,必须先声明后使用 -
类内部默认启用严格模式 -
类的所有方法都是不可枚举的 -
必须使用 new 调用类构造函数 -
类的方法内部的 this 默认指向类的实例
Module
ES6 模块化规范,通过 import 和 export 实现模块的导入导出。
导出(export)
// math.js
// 单个导出
export const add = (x, y) => x + y;
export const subtract = (x, y) => x - y;
// 默认导出
export default class Calculator {
// ...
}
// 统一导出
const multiply = (x, y) => x * y;
const divide = (x, y) => x / y;
export { multiply, divide };
导入(import)
// main.js
// 导入单个或多个
import { add, subtract } from './math.js';
// 导入默认导出
import Calculator from './math.js';
// 导入全部并重命名
import * as MathUtils from './math.js';
// 重命名导入
import { add as addition } from './math.js';
// 同时导入默认和非默认
import Calculator, { add, subtract } from './math.js';
【ES2020】动态导入
// 按需加载模块
button.addEventListener('click', async () => {
const module = await import('./dialog.js');
module.showDialog();
});
【ES2020】在 HTML 中使用模块
<!-- 使用 type="module" -->
<script type="module">
import { add } from './math.js';
console.log(add(2, 3));
</script>
<!-- 导入外部模块脚本 -->
<script type="module" src="main.js"></script>
Module 的特点
-
自动采用严格模式 -
独立的模块作用域 -
单例模式:模块只会被加载一次 -
支持循环依赖 -
异步加载,不会阻塞主线程
- eset nod32激活码 nod32注册码大全可用 11-28
- steam出现您所在的国家/地区不允许看到此内容怎么办 11-28
- 《植物大战僵尸 2:奇妙时空之旅》游戏评测 玩家其实没有什么不可以 11-25
- 软件开发基本原则:构建高质量软件的基石 11-24
- 一文了解软件开发基本原则 11-24
- 平台对战派对游戏《King of the Hat》:帽子大作战! 11-24
- PHP8.4.1发布 PHP8.4的新特性有那些 11-22
- 苹果手机AppStore无法连接怎么办 11-18
- iPhone16ProMax电池续航评测 完胜其他对手 11-18

- 评论