前端阅读 325月28日 03:36
ES5 和 ES6 有什么区别?
ES6(ES2015)是 JavaScript 历史上最大的一次版本更新,面试中这道题考查的是你对 JS 语言演进的理解深度。回答的关键不是罗列特性,而是讲清楚每个变化解决了什么问题。变量声明:从 var 到 let/constES5 只有 var,存在两大问题:// 问题1:变量提升console.log(a); // undefined(不会报错,但容易出 bug)var a = 1;// 问题2:无块级作用域for (var i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0); // 3, 3, 3}ES6 用 let/const 解决了这两个问题:// let 有块级作用域 + 暂时性死区console.log(b); // ReferenceError(声明前访问直接报错)let b = 1;for (let i = 0; i < 3; i++) { setTimeout(() => console.log(i), 0); // 0, 1, 2}// const 不可重新赋值(但对象属性仍可修改)const obj = { a: 1 };obj.a = 2; // OKobj = { a: 2 }; // TypeError面试要点:const 保证的是绑定不可变,不是值不可变。想冻结对象用 Object.freeze()。函数:箭头函数与 this 绑定ES5 中 this 指向取决于调用方式,经常需要 var self = this 或 .bind(this):// ES5var obj = { name: 'ES5', say: function() { var self = this; setTimeout(function() { console.log(self.name); // 必须用 self/cache }, 0); }};// ES6 — 箭头函数继承外层 thisconst obj2 = { name: 'ES6', say() { setTimeout(() => { console.log(this.name); // 直接用 this }, 0); }};注意:箭头函数没有自己的 arguments、super、new.target,不能用作构造函数。字符串:模板字符串// ES5var greeting = 'Hello, ' + name + '! You are ' + age + ' years old.';// ES6const greeting = `Hello, ${name}! You are ${age} years old.`;模板字符串支持多行、变量插值、标签模板,彻底告别字符串拼接。解构赋值与展开运算符// 对象解构const { name, age } = user;// 数组解构const [first, ...rest] = [1, 2, 3, 4]; // first=1, rest=[2,3,4]// 展开运算符 — 浅拷贝与合并const copy = [...arr];const merged = { ...defaults, ...config };解构让数据提取更简洁,展开运算符替代了 Object.assign 和 concat 的大多数场景。类与继承:class 语法// ES5 — 构造函数 + 原型链function Animal(name) { this.name = name;}Animal.prototype.speak = function() { return this.name + ' makes a sound';};// ES6 — class 语法class Animal { constructor(name) { this.name = name; } speak() { return `${this.name} makes a sound`; }}class Dog extends Animal { speak() { return `${this.name} barks`; }}class 本质是原型继承的语法糖,但有行为差异:内部默认严格模式、方法不可枚举、必须用 new 调用。模块系统:import/export// ES5 — CommonJS(Node.js)const module = require('./module');module.exports = { foo };// ES6 — ES Modulesimport { foo } from './module';export const bar = 1;export default function() {}ES Modules 是静态的,支持 Tree Shaking;CommonJS 是动态的,运行时加载。现代项目(Vite/Webpack)均以 ESM 为优先。异步编程:Promise 与 async/await// ES5 — 回调地狱getData(function(a) { getMore(a, function(b) { getEvenMore(b, function(c) { console.log(c); }); });});// ES6 — Promise 链式调用getData() .then(a => getMore(a)) .then(b => getEvenMore(b)) .then(c => console.log(c));// ES8 — async/await(同步写法)const a = await getData();const b = await getMore(a);const c = await getEvenMore(b);Promise 解决了回调地狱,async/await 让异步代码看起来像同步,是面试高频追问点。新数据结构与 API| 特性 | 用途 ||------|------|| Map | 键值对集合,键可以是任意类型(Object 的键只能是字符串/Symbol) || Set | 去重数组:[...new Set(arr)] || WeakMap/WeakSet | 键是弱引用,适合缓存和关联私有数据,不阻止 GC || Symbol | 创建唯一标识符,用于私有属性和内置协议 || Proxy/Reflect | 拦截对象操作(Vue 3 响应式核心) || Generator/Iterator | 可暂停函数,for...of 遍历统一接口 |追问ES6 之后还有什么重要的新特性?| 版本 | 关键特性 ||------|----------|| ES7 | Array.prototype.includes、指数运算符 ** || ES8 | async/await、Object.values/entries || ES9 | Promise.finally、异步迭代 for await...of || ES10 | flat/flatMap、Object.fromEntries || ES11 | ??(空值合并)、?.(可选链)、Promise.allSettled || ES12 | replaceAll、逻辑赋值 ||= &&= ??= || ES13 | at()、Object.hasOwn、Top-level await |let/const 和 var 最大的实际区别?块级作用域 — 解决 for 循环闭包问题暂时性死区 — 声明前访问报 ReferenceError,var 是 undefined不可重复声明 — 同一作用域内 let/const 不能重复声明同名变量const 不可重新赋值 — 但对象/数组内容仍可修改class 只是语法糖吗?基本是。class 编译后就是原型链模式(构造函数 + prototype + Object.create)。但有几个行为差异:class 内部默认严格模式class 方法不可枚举(for...in 遍历不到)只能用 new 调用(有 new.target 检查,直接调用报错)extends 内部用 Object.create 设置原型链,比 ES5 手动写更规范面试回答策略面试官问这道题,不是让你背特性列表。推荐的回答结构:一句话概括:ES6 让 JS 从脚本语言变成工程化语言按类别讲 3-4 个重点,每个说清楚"ES5 什么问题 → ES6 怎么解决"追问时深入:挑一个你最熟悉的特性展开(如 class 的原型链原理、Promise 的微任务机制)