1. 块级作用域:let
和 const
let
:声明块级作用域的变量,替代var
。const
:声明常量(不可重新赋值)。let x = 10; if (true) { let x = 20; // 独立的块级作用域 const PI = 3.14; // 常量 } console.log(x); // 10
2. 箭头函数(Arrow Functions)
简化函数语法。
// 传统函数 function getSum(a, b) { return a + b; } // 箭头函数 const getSum1 = a => a + 3; const getSum2 = (a, b) => a + b; const getSum3 = (a, b, ...other) => console.log(a, b, other); const getResult = arr => { let sun = 0; arr.forEach(item => sum += item); return sun; };
自动绑定外部
this
(无自己的this
)。箭头函数没有自己的
this
绑定,它会继承外层作用域的this
值。箭头函数的this
在定义时确定,且不会因调用方式改变。// 普通函数(错误行为) const obj = { value: 42, getValue: function() { setTimeout(function() { console.log(this.value); // 输出 undefined(非严格模式)或报错(严格模式) }, 100); } }; // 箭头函数 const obj = { value: 42, getValue: function() { setTimeout(() => { console.log(this.value); // 42(箭头函数继承外层 this) }, 100); } };
3. 模板字符串(Template Literals)
使用反引号
`
包裹字符串,支持多行文本和变量插值(${expression}
)。const name = "Alice"; const message = ` Hello, ${name}! Today is ${new Date().toLocaleDateString()}. `;
4. 解构赋值(Destructuring Assignment)
从数组或对象中提取值并赋值给变量。
// 数组解构 const [a, b, ...rest] = [1, 2, 3, 4]; console.log(a); // 1 console.log(rest); // [3, 4] // 对象解构 const { name, age } = { name: "Bob", age: 25 }; console.log(name); // "Bob" // 函数参数解构 function getUser({ id, name }) { console.log(id, name); }
5. 默认参数(Default Parameters)
为函数参数设置默认值。
function greet(name = "Guest") { console.log(`Hello, ${name}!`); } greet(); // "Hello, Guest!"
6. 展开与剩余操作符(Spread & Rest)
展开操作符(
...
):展开数组或对象。const arr1 = [1, 2]; const arr2 = [...arr1, 3, 4]; // [1, 2, 3, 4] const obj1 = { a: 1, b: 2 }; const obj2 = { ...obj1, c: 3 }; // { a:1, b:2, c:3 }
剩余参数(
...
):收集剩余参数为数组。function sum(...numbers) { return numbers.reduce((acc, num) => acc + num, 0); } sum(1, 2, 3); // 6
7. 类(Class)
语法糖,基于原型的面向对象编程更清晰。
class Animal { #age; // 私有字段(ES2022特性) // 构造函数(实例化时调用) constructor(name, legs = 4, age = 1) { this.name = name; // 实例属性 this.legs = legs; // 支持默认参数 this.#age = age; // 私有属性 } // 实例方法(定义在原型上) speak() { console.log(`${this.name}发出声音。`); } // Getter get ageInfo() { return `${this.name}今年${this.#age}岁`; } // Setter set ageInfo(value) { if (value < 0) throw new Error('年龄不能为负'); this.#age = value; } // 静态方法(直接通过类调用,不继承给实例) static createBaby(name) { return new Animal(name, 4, 0); } } // 通过 extends 实现继承,子类构造函数中必须调用 super() class Dog extends Animal { constructor(name, breed = '中华田园犬') { super(name); // 调用父类构造函数 this.breed = breed; // 子类特有属性 } // 方法重写 speak() { super.speak(); // 调用父类方法 console.log(`${this.name}(${this.breed})汪汪汪!`); } // 子类特有方法 fetch(item) { console.log(`${this.name}叼回了${item}`); } } // 使用示例 const puppy = Animal.createBaby('小奶狗'); // 静态方法调用 console.log(puppy.ageInfo); // "小奶狗今年0岁" const dog = new Dog('旺财', '金毛'); // 实例化 dog.ageInfo = 2; // 通过setter修改年龄 dog.speak(); // "旺财发出声音。" + "旺财(金毛)汪汪汪!" dog.fetch('飞盘'); // "旺财叼回了飞盘" console.log(dog.ageInfo); // "旺财今年2岁" // 继承验证 console.log(dog instanceof Animal); // true console.log(dog instanceof Dog); // true
8. 模块化(Modules)
- 使用
export
和import
实现模块化,支持命名导出、默认导出和混合导出。 可通过
as
重命名,用*
导入整个模块的命名空间。// math.js // 命名导出:显式导出变量、函数或类。 export const add = (a, b) => a + b; export const PI = 3.14; // 默认导出:一个模块只能有一个默认导出。 export default function multiply(a, b) { return a * b; } // app.js import mult, { add as sum, PI } from './math.js'; // 默认导出需放在首位 import * as MathUtil from './math.js'; console.log(sum(2, 3)); // 5 console.log(mult(2, 3)); // 6 console.log(MathUtil.PI); // 3.14
9. Promise 和异步编程
在 ES6 之前,JavaScript 使用 回调函数(Callback) 处理异步操作(如网络请求、定时器等)。但多层嵌套回调会导致 回调地狱(Callback Hell),代码难以阅读和维护:
getData(function(a) { getMoreData(a, function(b) { getMoreData(b, function(c) { // 更多嵌套... }); }); });
Promise 的出现解决了这一问题,提供了更清晰的链式调用和错误处理。
Promise 的基本概念:
- Promise 是一个对象,表示一个异步操作的最终完成(或失败)及其结果值。
三种状态:
- Pending(进行中):初始状态。
- Fulfilled(已成功):操作成功完成。
- Rejected(已失败):操作失败。
- 状态不可逆:一旦状态从 Pending 变为 Fulfilled 或 Rejected,就不会再改变。
使用示例:处理异步操作,避免回调地狱。
基础用法 + 链式调用 + 错误处理
// 定义一个模拟异步获取数据的函数(返回 Promise) const fetchData = () => { return new Promise((resolve, reject) => { // 模拟异步操作(如网络请求) setTimeout(() => { const success = Math.random() > 0.3; // 70% 概率成功 if (success) { resolve("Data received!"); // 成功时调用 resolve } else { reject("Network Error!"); // 失败时调用 reject } }, 1000); }); }; // 定义一个处理数据的函数(返回处理后的 Promise) const processData = (rawData) => { return new Promise((resolve) => { setTimeout(() => { resolve(`${rawData} => Processed`); // 模拟数据处理 }, 500); }); }; // 执行异步操作链 fetchData() .then((rawData) => { console.log("1. 原始数据:", rawData); return processData(rawData); // 返回新 Promise 以继续链式调用 }) .then((processedData) => { console.log("2. 处理后的数据:", processedData); return "Final Result"; // 返回普通值会自动包装为 Promise }) .then((finalResult) => { console.log("3. 最终结果:", finalResult); }) .catch((error) => { // 捕获链中任意位置的错误 console.error("捕获到错误:", error); }) .finally(() => { // 无论成功失败都会执行 console.log("4. 请求流程结束"); });
并行处理多个 Promise
const fetchUser = () => { return new Promise((resolve) => { setTimeout(() => resolve({ id: 1, name: "Alice" }), 800); }); }; const fetchOrders = (userId) => { return new Promise((resolve) => { setTimeout(() => resolve([`Order1`, `Order2`]), 600); }); }; // 同时发起多个独立请求 Promise.all([fetchUser(), fetchOrders(1)]) .then(([user, orders]) => { console.log("\n并行请求结果:"); console.log("用户:", user); console.log("订单:", orders); });
使用 async/await 语法糖
async function fetchDataWithRetry(retryCount = 3) { for (let i = 0; i < retryCount; i++) { try { const data = await fetchData(); const processed = await processData(data); console.log(`\n第 ${i + 1} 次尝试成功:`, processed); return processed; // 成功时提前返回 } catch (error) { console.warn(`第 ${i + 1} 次尝试失败`); if (i === retryCount - 1) throw error; // 最后一次失败抛出错误 } } } // 执行带重试机制的请求 fetchDataWithRetry() .then(result => console.log("最终成功结果:", result)) .catch(error => console.error("全部重试失败:", error));
复杂错误处理场景
const validateData = (data) => { return new Promise((resolve, reject) => { if (data.includes("received")) { resolve("Validation passed"); } else { reject(new Error("Invalid data format")); } }); }; fetchData() .then(data => { console.log("\n原始数据:", data); return validateData(data); // 可能在此处抛出错误 }) .then(validationResult => { console.log("验证结果:", validationResult); }) .catch(error => { if (error.message === "Invalid data format") { console.error("数据格式错误:", error); return "Default Data"; // 提供默认值继续链式调用 } throw error; // 其他错误继续抛出 }) .then(finalData => { console.log("最终使用的数据:", finalData); });
分层错误处理
- 每个
.then
的第二个参数专门处理前一步的特定错误 - 通过
return 替代值
实现错误恢复 - 通过
throw new Error()
实现错误传播
// 策略1:步骤专属处理(适合可恢复错误) .then( data => { /* 正常逻辑 */ }, error => { console.log("当前步骤错误处理"); return recoveryValue; // 返回替代值继续流程 } ) // 策略2:中断流程(适合关键错误) .then( data => { /* 正常逻辑 */ }, error => { console.log("关键步骤失败,终止流程"); throw error; // 重新抛出,由后续 catch 处理 } ) // 策略3:错误转换(统一错误类型) .then( data => { /* 正常逻辑 */ }, error => { throw new CustomError(error.message); } )
层级 典型方法 作用域 最佳实践 生成层 throw new Error()
原子函数 抛具体类型错误,附加调试信息 中间处理层 .then()
二参 /.catch
单个Promise 局部恢复/转换/中断 全局兜底层 链尾 .catch()
整个链 最终日志/用户提示 进程兜底 unhandledrejection
进程级 防止静默崩溃,应急恢复 - 每个
10. Symbol 类型
- 唯一且不可变的值,用于对象属性的唯一标识。
- 通过
Symbol.for()
创建全局共享的 Symbol,使用description
获取描述。 - 直接
Symbol()
每次都会创建全新的 Symbol(sym1 ≠ sym2)。 相同 key 的
Symbol.for()
调用会返回同一个 Symbol 。const sym1 = Symbol("key"); const sym2 = Symbol("key"); const sym3 = Symbol.for("sharedKey"); const sym4 = Symbol.for("sharedKey"); console.log(sym1 === sym2); // false console.log(sym3 === sym4); // true console.log(sym1.description); // "key" // 内置 Symbol 应用 // Symbol.iterator:定义对象的默认迭代器。 // Symbol.toStringTag:定制对象的 toString() 行为。 const obj = { [sym1]: "value" }; console.log(obj[sym1]); // "value" const iterableObj = { [Symbol.iterator]: function* () { yield 1; yield 2; } }; console.log([...iterableObj]); // [1, 2]
11. 迭代器和生成器(Iterators & Generators)
迭代器:
- 对象需实现
Symbol.iterator
方法,返回一个包含next()
方法的对象。 next()
返回{ value: any, done: boolean }
。
const iterable = { [Symbol.iterator]() { let step = 0; return { next() { return { value: step++, done: step > 3 }; } }; } }; for (const val of iterable) console.log(val); // 0, 1, 2
- 对象需实现
生成器:
- 用
function*
声明,通过yield
暂停执行并返回值。 - 生成器函数返回迭代器对象。
function* idGenerator() { let id = 1; while (true) yield id++; // 无限ID序列 } const gen = idGenerator(); console.log(gen.next().value); // 1
- 用
应用场景:
- 惰性求值:按需生成数据(如分页加载)。
- 简化异步代码:与
async/await
结合使用。
12. Map 和 Set
Map
:键值对集合,键可以是任意类型。const map = new Map(); map.set("name", "Alice"); map.set(1, "One"); console.log(map.get("name")); // "Alice"
Set
:唯一值的集合,自动去重。const set = new Set([1, 2, 2, 3]); console.log([...set]); // [1, 2, 3]
13. Proxy 和 Reflect
Proxy
:创建对象的代理,拦截并自定义操作(如属性读取、设置)。const target = {}; const handler = { get: (obj, prop) => { console.log(`Accessing ${prop}`); return obj[prop] || "Not found"; } }; const proxy = new Proxy(target, handler); console.log(proxy.name); // "Accessing name" → "Not found"
Reflect
:提供操作对象的静态方法。Reflect.set(target, "age", 30); console.log(Reflect.get(target, "age")); // 30
14. 新的数据类型和结构
ArrayBuffer
和 TypedArray
- 用途:处理二进制数据(如文件、图像、网络协议等)。
ArrayBuffer
表示一段固定长度的原始二进制数据缓冲区,不能直接操作,需通过视图(TypedArray
或DataView
)。const buffer = new ArrayBuffer(16); // 创建一个16字节的缓冲区
TypedArray
提供不同类型的视图来操作ArrayBuffer
,如:Int8Array
(8位有符号整数)Uint8Array
(8位无符号整数,常用于处理像素数据)Float32Array
(32位浮点数,适用于WebGL)
const int32View = new Int32Array(buffer); // 用32位整数视图操作buffer int32View[0] = 42; // 写入数据
应用场景:
- 文件读写、网络数据传输(如WebSocket二进制通信)。
- WebGL图形处理、音视频编解码。
WeakMap
和 WeakSet
- 核心特性:键是弱引用(不阻止垃圾回收),避免内存泄漏。
WeakMap
- 键必须是对象,值可以是任意类型。
- 无法遍历、没有
size
属性。 - 用途:存储对象的私有数据或元数据。
const wm = new WeakMap(); const obj = {}; wm.set(obj, "私有数据"); obj = null; // 当obj被回收时,wm中的键值对自动清除
WeakSet
- 只能存储对象,无法遍历。
- 用途:跟踪对象是否存在(如避免重复操作)。
const ws = new WeakSet(); ws.add(obj); // 添加对象 console.log(ws.has(obj)); // true
15. 其他实用特性
字符串方法
includes()
判断字符串是否包含子串:"hello".includes("ell"); // true
startsWith()
/endsWith()
判断字符串是否以特定子串开头/结尾:const url = "https://example.com"; url.startsWith("https"); // true url.endsWith(".com"); // true
数值方法
Number.isNaN()
更精准的NaN
检测(全局isNaN("abc")
返回true
,而此方法返回false
)。Number.isNaN(NaN); // true Number.isNaN("NaN"); // false(全局isNaN("NaN")会返回true)
Number.isInteger()
判断是否为整数:Number.isInteger(3.0); // true Number.isInteger(3.1); // false
数组方法
Array.from()
将类数组对象(如arguments
、NodeList
)转为数组:Array.from(document.querySelectorAll("div")); // [div, div, ...]
function fn (){ Array.from(arguments).forEach(function (item) { console.log(item) // 1 2 3 }) } fn(1, 2, 3)
Array.of()
解决new Array(3)
的歧义问题,创建明确元素的数组:Array.of(3); // [3] new Array(3); // [空属性 ×3]
实例方法
find()
/findIndex()
:查找符合条件的元素或索引。[1, 2, 3].find(x => x > 1); // 2
includes()
:判断数组是否包含某值(替代indexOf
)。
对象方法
Object.assign()
合并对象(浅拷贝):const target = { a: 1 }; Object.assign(target, { b: 2 }, { c: 3 }); // { a:1, b:2, c:3 }
Object.entries()
返回对象的键值对数组(ES2017特性):const obj = { a: 1, b: 2 }; Object.entries(obj); // [["a", 1], ["b", 2]]
总结
ES6 的引入彻底改变了 JavaScript 的编程方式,核心改进包括:
- 更清晰的语法(箭头函数、类、模板字符串)。
- 更强的功能(模块化、Promise、解构赋值)。
- 更好的性能与安全性(块级作用域、
let
/const
)。
评论 (0)