1. 变量声明:从 var
到 let
/const
问题代码:var
存在变量提升,只有函数作用域,没有块级作用域,容易导致变量污染。
// 变量提升导致意外行为
console.log(num); // undefined 而非报错
var num = 10;
// 没有块级作用域
var name = '张三';
if (true) {
var name = '李四'; // 覆盖外部作用域的name
}
console.log(name); // 输出 '李四'
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i); // 输出5个5
}, 100);
}
ES6+ 解决方案:
const name = '张三'; // 不可重新赋值的常量
if (true) {
let name = '李四'; // 块级作用域
}
console.log(name); // '张三'
for (let i = 0; i < 5; i++) {
setTimeout(() => console.log(i), 100); // 0,1,2,3,4
}
最佳实践:
- 默认使用
const
- 需要重新赋值时使用
let
- 避免使用
var
2. 函数定义:从函数表达式到箭头函数
问题代码:冗长的语法,this
绑定问题。
var add = function(a, b) {
return a + b;
};
var obj = {
value: 1,
increment: function() {
var self = this;
setTimeout(function() {
self.value++;
}, 100);
}
};
ES6+ 解决方案:
const add = (a, b) => a + b;
const obj = {
value: 1,
increment() {
setTimeout(() => {
this.value++;
}, 100);
}
};
特性:
- 箭头函数继承外层
this
- 方法简写语法
- 隐式返回
3. 异步编程:从回调地狱到 Promise/async-await
问题代码:
getData(function(a) {
getMoreData(a, function(b) {
getEvenMoreData(b, function(c) {
getFinalData(c, function(result) {
console.log('Result:', result);
}, failCallback);
}, failCallback);
}, failCallback);
}, failCallback);
ES6+ 解决方案:
// Promise 链
getData()
.then(a => getMoreData(a))
.then(b => getEvenMoreData(b))
.then(c => getFinalData(c))
.then(result => console.log('Result:', result))
.catch(error => console.error(error));
// async、await
async function processData() {
try {
const a = await getData();
const b = await getMoreData(a);
const c = await getEvenMoreData(b);
const result = await getFinalData(c);
console.log('Result:', result);
} catch (error) {
console.error(error);
}
}
优势:
- 线性代码结构
- 统一错误处理
- 更好的可读性
4. 参数处理:从 arguments
到剩余参数
问题代码:
function sum() {
var args = Array.prototype.slice.call(arguments);
return args.reduce(function(total, num) {
return total + num;
}, 0);
}
ES6+ 解决方案:
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
特点:
- 真正的数组
- 更清晰的参数定义
- 可与普通参数混用
5. 面向对象:从构造函数到类语法
问题代码:
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log('Hello, ' + this.name);
};
ES6+ 解决方案:
class Person {
constructor(name) {
this.name = name;
}
sayHello() {
console.log(`Hello, ${this.name}`);
}
// 静态方法
static create(name) {
return new Person(name);
}
}
新增特性:
- 继承 (
extends
) - 静态方法
- 私有字段 (
#field
) - 静态块
6. 字符串处理:从拼接符到模板字符串
问题代码:
var name = '张三';
var age = 25;
var message = name + '今年' + age + '岁';
ES6+ 解决方案:
const message = `${name}今年${age}岁`;
高级用法:
// 多行字符串
const html = `
<div>
<h1>${title}</h1>
<p>${content}</p>
</div>
`;
// 标签模板
function highlight(strings, ...values) {
return strings.reduce((result, str, i) =>
`${result}${str}<span class="highlight">${values[i] || ''}</span>`, '');
}
const output = highlight`Hello ${name}, welcome to ${siteName}!`;
7. 对象和数组处理:从手动操作到展开运算符
问题代码:
var arr1 = [1, 2, 3];
var arr2 = [4, 5, 6];
var combined = arr1.concat(arr2);
var obj1 = { a: 1, b: 2 };
var obj2 = { b: 3, c: 4 };
var merged = Object.assign({}, obj1, obj2);
ES6+ 解决方案:
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2];
const obj1 = { a: 1, b: 2 };
const obj2 = { b: 3, c: 4 };
const merged = { ...obj1, ...obj2 };
实用技巧:
// 数组复制
const copy = [...original];
// 对象属性覆盖
const defaults = { color: 'red', size: 'medium' };
const config = { ...defaults, ...userConfig };
// 剩余参数解构
const { a, b, ...rest } = { a: 1, b: 2, c: 3, d: 4 };
8. 数组迭代:从 for 循环到高阶函数
问题代码:
var numbers = [1, 2, 3, 4];
var doubled = [];
for (var i = 0; i < numbers.length; i++) {
doubled.push(numbers[i] * 2);
}
ES6+ 解决方案:
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(num => num * 2);
常用高阶函数:
// 过滤
const evens = numbers.filter(n => n % 2 === 0);
// 累加
const sum = numbers.reduce((total, num) => total + num, 0);
// 查找
const firstEven = numbers.find(n => n % 2 === 0);
// 检查
const allPositive = numbers.every(n => n > 0);
const hasNegative = numbers.some(n => n < 0);
9. 模块系统:从 IIFE 到 ES Modules
问题代码:
// math.js
(function() {
function add(a, b) { return a + b; }
function subtract(a, b) { return a - b; }
window.math = { add: add, subtract: subtract };
})();
// app.js
math.add(1, 2);
ES6+ 解决方案:
// math.js
export function add(a, b) { return a + b; }
export function subtract(a, b) { return a - b; }
// app.js
import { add } from './math.js';
add(1, 2);
现代模块特性:
- 命名导出/默认导出
- 动态导入 (
import()
) - 顶层 await
- 模块元信息 (
import.meta
)
10. 其他重要 ES6+ 特性
解构赋值
// 对象解构
const { name, age } = person;
const { name: personName, age: personAge } = person;
// 数组解构
const [first, second] = numbers;
const [head, ...tail] = numbers;
可选链 (?.) 和空值合并 (??)
// 避免 Cannot read property 'x' of undefined/null
const street = user?.address?.street ?? 'Unknown';
// 函数调用可选链
someInterface.customMethod?.();
BigInt
const bigNumber = 9007199254740991n;
const biggerNumber = bigNumber + 1n;
全局对象标准化
// 浏览器环境
globalThis === window; // true
// Node.js 环境
globalThis === global; // true
11.类型系统缺陷
原始问题:
// 1. typeof null === 'object'
typeof null; // "object" (从JS诞生就存在的bug)
// 2. 隐式类型转换
[] + {}; // "[object Object]"
{} + []; // 0
// 3. == 的强制类型转换
'0' == false; // true
现代化实践:
// 1. 使用 Object.prototype.toString 检测类型
Object.prototype.toString.call(null); // "[object Null]"
// 2. 避免隐式转换,使用显式转换
Number([]) + Number({}); // NaN
// 3. 始终使用 ===
'0' === false; // false