ES6 核心特性详解(对比ES5)
一、变量声明:let 和 const
ES5 的问题
// 变量提升(hoisting)
console.log(a); // undefined
var a = 10;// 重复声明
var b = 20;
var b = 30; // 允许重复声明// 函数作用域
if (true) {var c = 40;
}
console.log(c); // 40 - 变量泄漏到外部作用域
ES6 解决方案
// 块级作用域
let d = 10;
// let d = 20; // 报错:Identifier 'd' has already been declaredif (true) {let e = 30;const PI = 3.14;// PI = 3.15; // 报错:Assignment to constant variable
}
// console.log(e); // 报错:e is not defined// 暂时性死区(TDZ)
// console.log(f); // 报错:Cannot access 'f' before initialization
let f = 50;
二、箭头函数(Arrow Functions)
ES5 函数
var numbers = [1, 2, 3];
var doubled = numbers.map(function(n) {return n * 2;
});var obj = {value: 42,getValue: function() {var self = this; // 需要保存this引用setTimeout(function() {console.log(self.value); // 42}, 100);}
};
ES6 箭头函数
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2); // 单行隐式返回const obj = {value: 42,getValue() {setTimeout(() => {console.log(this.value); // 42 - 自动绑定外部this}, 100);}
};// 多行函数体
const sum = (a, b) => {const result = a + b;return result;
};
三、模板字符串(Template Literals)
ES5 字符串拼接
var name = '张三';
var age = 28;
var message = '姓名: ' + name + '\n' +'年龄: ' + age + '\n' +'明年他就' + (age + 1) + '岁了';var html = '<div class="card">' +'<h2>' + name + '</h2>' +'<p>年龄: ' + age + '</p>' +'</div>';
ES6 模板字符串
const name = '张三';
const age = 28;
const message = `姓名: ${name}
年龄: ${age}
明年他就${age + 1}岁了`;const html = `<div class="card"><h2>${name}</h2><p>年龄: ${age}</p></div>
`;// 标签模板(高级用法)
function highlight(strings, ...values) {return strings.reduce((result, str, i) => `${result}${str}<mark>${values[i] || ''}</mark>`, '');
}
const marked = highlight`姓名: ${name},年龄: ${age}`;
四、解构赋值(Destructuring)
ES5 赋值方式
var person = {firstName: '李',lastName: '四',age: 35,address: { city: '北京' }
};var firstName = person.firstName;
var lastName = person.lastName;
var city = person.address.city;var colors = ['红', '绿', '蓝'];
var firstColor = colors[0];
var thirdColor = colors[2];
ES6 解构赋值
const person = {firstName: '李',lastName: '四',age: 35,address: { city: '北京' }
};// 对象解构
const { firstName="aaa", lastName, address: { city } } = person;// 重命名
const { firstName: fName } = person;// 默认值
const { middleName = '无' } = person;// 数组解构
const colors = ['红', '绿', '蓝'];
const [firstColor, , thirdColor] = colors;// 交换变量
let x = 1, y = 2;
[x, y] = [y, x]; // x=2, y=1// 函数参数解构
function printUser({ firstName, lastName }) {console.log(`${firstName} ${lastName}`);
}
printUser(person)
五、默认参数和Rest参数
ES5 处理方式
function greet(name) {name = name || '访客'; // 默认值处理console.log('你好, ' + name);
}
greet()
function sum() {var args = Array.prototype.slice.call(arguments);return args.reduce(function(acc, val) {return acc + val;}, 0);
}
sum(1,2,3,4)
ES6 解决方案
// 默认参数
function greet(name = '访客') {console.log(`你好, ${name}`);
}// Rest参数
const sum = (...args) => {return args.reduce((acc, val) => acc + val, 0);
};// 解构结合默认值
function createPerson({ name = '匿名', age = 0 } = {name = '匿名', age = 0}) {console.log(`姓名: ${name}, 年龄: ${age}`);
}
createPerson({a:1})
// Spread操作符(与Rest相反)
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2]; // [1,2,3,4,5,6]
六、类(Class)
ES5 面向对象
// 构造函数
function Person(name, age) {this.name = name;this.age = age;
}
let p1 = new Person("aa",12)
let p2 = new Person()
// 原型方法
Person.prototype.greet = function() {console.log('你好, 我是 ' + this.name);
};
p1.greet()
// 继承
function Student(name, age, grade) {Person.call(this, name, age); // 调用父类构造函数this.grade = grade;
}// 设置原型链
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;// 子类方法
Student.prototype.study = function() {console.log(this.name + '正在学习');
};
ES6 类语法
class Person {// 构造函数constructor(name, age) {this.name = name;this.age = age;}// 实例方法greet() {console.log(`你好, 我是 ${this.name}`);}// 静态方法static info() {console.log('这是一个Person类');}
}class Student extends Person {constructor(name, age, grade) {super(name, age); // 调用父类构造函数this.grade = grade;}// 重写方法greet() {super.greet(); // 调用父类方法console.log(`我是${this.grade}年级学生`);}study() {console.log(`${this.name}正在学习`);}// Getter/Setterget studentInfo() {return `${this.name}-${this.grade}年级`;}set studentInfo(value) {[this.name, this.grade] = value.split('-');}
}
七、模块化(Modules)
ES5 模块化(CommonJS)
// math.js
module.exports = {add: function(a, b) { return a + b; },PI: 3.14
};// app.js
var math = require('./math.js');
console.log(math.add(2, 3));
ES6 模块化
// math.js
export function add(a, b) {return a + b;
}export const PI = 3.14;// 默认导出
export default function multiply(a, b) {return a * b;
}// app.js
import { add, PI } from './math.js';
import multiply from './math.js'; // 导入默认导出console.log(add(2, 3)); // 5
console.log(multiply(2, 3)); // 6// 重命名导入
import { PI as piValue } from './math.js';// 全部导入
import * as math from './math.js';
console.log(math.PI);
八、Promise 和异步处理
ES5 回调地狱(Callback Hell)
function fetchData(callback) {setTimeout(function() {callback(null, '数据');}, 1000);
}fetchData(function(err, data) {if (err) {console.error(err);} else {console.log('第一步:', data);fetchData(function(err, data2) {if (err) {console.error(err);} else {console.log('第二步:', data2);// 更多嵌套...}});}
});
ES6 Promise
function fetchData() {return new Promise((resolve, reject) => {setTimeout(() => {Math.random() > 0.5 ? resolve('数据') : reject(new Error('请求失败'));}, 1000);});
}fetchData().then(data => {console.log('第一步:', data);return fetchData();}).then(data => {console.log('第二步:', data);}).catch(err => {console.error('错误:', err.message);});// Promise.all - 并行处理
Promise.all([fetchData(), fetchData()]).then(results => {console.log('所有结果:', results);});// Promise.race - 竞速
Promise.race([fetchData(), fetchData()]).then(firstResult => {console.log('第一个结果:', firstResult);});
ES7 async/await
async function processData() {try {const data1 = await fetchData();console.log('第一步:', data1);const data2 = await fetchData();console.log('第二步:', data2);const [result1, result2] = await Promise.all([fetchData(), fetchData()]);console.log('并行结果:', result1, result2);} catch (err) {console.error('错误:', err.message);}
}processData();
九、其他重要特性
1. 对象字面量增强
// ES5
var name = '张三';
var age = 30;
var person = {name: name,age: age,sayHello: function() {console.log('你好');}
};// ES6
const name = '张三';
const age = 30;
const person = {name, // 属性简写age, // 属性简写sayHello() { // 方法简写console.log('你好');},// 计算属性名[prefix + 'Info']: '用户信息'
};
2. 迭代器和生成器
// 迭代器
const iterable = {[Symbol.iterator]() {let step = 0;return {next() {step++;if (step <= 5) {return { value: step, done: false };}return { done: true };}};}
};for (const value of iterable) {console.log(value); // 1,2,3,4,5
}// 生成器
function* idGenerator() {let id = 1;while (true) {yield id++;}
}const gen = idGenerator();
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2
3. 新增数据结构
// Set - 唯一值集合
const set = new Set();
set.add(1);
set.add(2);
set.add(1); // 重复值被忽略
console.log(set.size); // 2// Map - 键值对集合
const map = new Map();
map.set('name', '张三');
map.set('age', 30);
console.log(map.get('name')); // 张三// WeakSet 和 WeakMap - 弱引用集合
十、ES6+ 兼容性和转换
1. Babel 转译
# 安装Babel
npm install @babel/core @babel/cli @babel/preset-env --save-dev# .babelrc 配置
{"presets": ["@babel/preset-env"]
}# 转译文件
npx babel src -d dist
2. Polyfill 服务
<!-- 使用polyfill.io动态提供polyfill -->
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6,es7"></script>
3. 浏览器支持情况
- 现代浏览器(Chrome、Firefox、Edge)基本支持ES6
- IE11需要转译
- 使用 Can I use 检查特性支持