1. 为什么你需要这份ES6逆袭指南?
上周面试一个三年经验的前端,让他手写个Promise.all居然卡壳了。这让我想起五年前自己第一次接触ES6时的窘境——面对公司代码库里的箭头函数和class语法,硬着头皮查文档到凌晨两点。现在回头看,那些困扰新手的ES6特性,其实掌握核心20%就能解决80%的问题。
这份指南就是我想给当年自己的"作弊手册"。不同于教科书式的语法罗列,我会用真实项目中的代码对比,带你快速跨越从"能跑就行"到"优雅编码"的鸿沟。特别适合:
- 还在用var声明变量的jQuery时代遗民
- 能写React但说不清let/const区别的框架熟练工
- 面试被问"ES6用过哪些特性"就大脑空白的求职者
2. 七日蜕变路线图
2.1 Day1:变量声明革命
javascript复制// 老派写法
var count = 10
function updateCount() {
var count = 20 // 意外覆盖全局变量
console.log(count)
}
// 现代写法
let total = 100
const MAX_SIZE = 1024
function calculate() {
let total = 200 // 安全的块级作用域
console.log(total)
}
避坑提示:const声明的对象属性仍可修改,真正不可变需配合Object.freeze
2.2 Day2:函数式编程三件套
箭头函数+默认参数+剩余参数的组合拳:
javascript复制// 传统回调地狱
ajax.get('/data', function(res1) {
ajax.post('/save', res1, function(res2) {
// 更多嵌套...
})
})
// ES6优雅方案
const fetchData = async (url, timeout = 5000) => {
try {
const [res1, ...otherResults] = await Promise.all([
fetch(url),
fetch('/backup')
])
return processData(res1)
} catch (...errors) {
// 错误处理
}
}
2.3 Day3:解构的艺术
从对象到数组的精准提取:
javascript复制// 旧式取值
const firstName = user.firstName
const lastName = user.lastName
// 解构魔法
const { firstName, lastName: familyName } = user
const [firstItem, , thirdItem] = someArray
// 函数参数解构
function render({ title, content }) {
return `<article><h2>${title}</h2><p>${content}</p></article>`
}
2.4 Day4:模块化实战
对比CommonJS与ES Modules:
javascript复制// legacy.js
module.exports = {
methodA: function() {...},
methodB: function() {...}
}
// modern.js
export const methodA = () => {...}
export default function() {...}
// 使用侧对比
const legacy = require('./legacy')
import modern, { methodA } from './modern'
2.5 Day5:Class的真相
揭开JS"类"的面纱:
javascript复制class Component {
constructor(props) {
this.props = props
this.state = {}
}
// 等同于Component.prototype.setState
setState(newState) {
this.state = {...this.state, ...newState}
}
static version = '1.0'
}
// 本质仍是原型链
console.log(typeof Component) // function
2.6 Day6:异步进化论
从回调地狱到async/await的历程:
javascript复制// 回调金字塔
fs.readFile('a.txt', (err, dataA) => {
if (err) handleError(err)
fs.readFile('b.txt', (err, dataB) => {
// 更多嵌套...
})
})
// Promise链
readFilePromise('a.txt')
.then(combineData)
.catch(logError)
// 终极方案
async function processFiles() {
const [a, b] = await Promise.all([
readFile('a.txt'),
readFile('b.txt')
])
return a + b
}
2.7 Day7:元编程入门
用Proxy和Reflect实现数据绑定:
javascript复制const reactive = (target) => new Proxy(target, {
set(obj, key, value) {
Reflect.set(obj, key, value)
console.log(`属性${key}已更新`)
return true
}
})
const store = reactive({ count: 0 })
store.count++ // 控制台输出"属性count已更新"
3. 高频面试雷区解析
3.1 变量提升陷阱
javascript复制console.log(name) // undefined而非报错
var name = 'John'
console.log(age) // ReferenceError
let age = 30
3.2 this指向迷思
javascript复制const obj = {
name: 'Alice',
traditional: function() {
console.log(this.name) // Alice
},
arrow: () => {
console.log(this.name) // undefined(继承自外层作用域)
}
}
3.3 模块循环引用
javascript复制// a.js
import { b } from './b'
export const a = 'A'
// b.js
import { a } from './a'
export const b = 'B' // 运行时a为undefined
4. 现代代码风格检查清单
- 所有变量声明使用let/const
- 回调函数优先用箭头函数
- 超过3个参数改用对象解构
- 异步操作必须用try/catch包裹
- 类成员方法使用简写语法
- 导出接口使用命名导出优先
- 模板字符串替代字符串拼接
5. 升级你的工具链
5.1 Babel配置要点
json复制{
"presets": [
["@babel/preset-env", {
"targets": "> 0.25%, not dead",
"useBuiltIns": "usage",
"corejs": 3
}]
],
"plugins": ["@babel/plugin-transform-runtime"]
}
5.2 ESLint规则推荐
javascript复制module.exports = {
rules: {
'no-var': 'error',
'prefer-const': 'warn',
'arrow-parens': ['error', 'always'],
'template-curly-spacing': 'off'
}
}
6. 从理解到精通的练习题库
- 实现符合Promise A+规范的MyPromise
- 用Generator模拟async/await
- 深拷贝函数支持Symbol属性
- 实现自动柯里化工具函数
- 编写可取消的Promise包装器
7. 我的踩坑实录
去年在金融项目中使用Map对象存储交易记录时,遇到个诡异问题:JSON.stringify(mapInstance) 居然返回"{}"。后来改用Array.from转换才解决。这提醒我们:
- 新API要彻底了解序列化特性
- 生产环境慎用太新的语法
- 类型判断要用Object.prototype.toString.call
现在我的ES6代码审查清单里永远留着这条:Map/Set数据如需持久化,必须手动转换。
