接续上文:
深入 JavaScript 函数式编程:从基础到实战(含面试题解析)
https://blog.csdn.net/m0_73589512/article/details/157845649
个人空间:
叁佰万
https://blog.csdn.net/m0_73589512
如若本篇文章对您有所帮助,请留下你的小艾心哟,收藏加关注,系列更新的文章不迷路哟!!
目录
叁佰万https://blog.csdn.net/m0_73589512
[从 ES6 到 ESNext:JavaScript 现代语法全解析(含编译工具与实战)](#从 ES6 到 ESNext:JavaScript 现代语法全解析(含编译工具与实战))
[一、ES6 核心语法:从基础到实战](#一、ES6 核心语法:从基础到实战)
[1.1 const/let:块级作用域与变量声明](#1.1 const/let:块级作用域与变量声明)
[1.2 解构赋值:简化数据提取](#1.2 解构赋值:简化数据提取)
[1. 对象解构](#1. 对象解构)
[2. 数组解构](#2. 数组解构)
[3. 实用场景:变量交换](#3. 实用场景:变量交换)
[1.3 箭头函数:简洁语法与上下文绑定](#1.3 箭头函数:简洁语法与上下文绑定)
[1. 语法简化](#1. 语法简化)
[2. 上下文绑定(核心区别)](#2. 上下文绑定(核心区别))
[3. 禁止使用场景](#3. 禁止使用场景)
[1.4 class:面向对象语法糖](#1.4 class:面向对象语法糖)
[1. 基本用法](#1. 基本用法)
[2. 访问器属性(getter/setter)](#2. 访问器属性(getter/setter))
[3. 继承与适配器模式](#3. 继承与适配器模式)
[二、ESNext 特性:JS 的持续进化](#二、ESNext 特性:JS 的持续进化)
[2.1 可选链操作符(?.)](#2.1 可选链操作符(?.))
[2.2 空值合并操作符(??)](#2.2 空值合并操作符(??))
[2.3 逻辑赋值运算符(??=、&&=、||=)](#2.3 逻辑赋值运算符(??=、&&=、||=))
[2.4 顶层 await](#2.4 顶层 await)
[三、编译工具:Babel 的核心作用](#三、编译工具:Babel 的核心作用)
[3.1 Babel 工作原理](#3.1 Babel 工作原理)
[3.2 基础使用(实战)](#3.2 基础使用(实战))
[3.3 Polyfill:补全 API](#3.3 Polyfill:补全 API)
从 ES6 到 ESNext:JavaScript 现代语法全解析(含编译工具与实战)
ECMAScript(简称 ES)是 JavaScript 的标准化规范,就像 "普通话" 统一了不同浏览器("方言")的 JS 实现。ES6(ES2015)的发布彻底改变了 JS 的编程体验,而后续的 ESNext(ES2016+)则持续迭代优化。本文将聚焦 ES6 核心语法、ESNext 新特性、编译工具(Babel),结合实战案例和面试考点,帮你彻底掌握现代 JS 语法。
一、ES6 核心语法:从基础到实战
1.1 const/let:块级作用域与变量声明
ES5 只有var声明变量,存在 "变量提升""全局污染""无块级作用域" 三大问题。ES6 新增let和const,彻底解决这些痛点。
核心特性对比
| 声明方式 | 块级作用域 | 变量提升 | 重复声明 | 重新赋值 | 初始化要求 |
|---|---|---|---|---|---|
| var | ❌ 无 | ✅ 有 | ✅ 允许 | ✅ 允许 | ❌ 可选 |
| let | ✅ 有 | ❌ 无 | ❌ 禁止 | ✅ 允许 | ❌ 可选 |
| const | ✅ 有 | ❌ 无 | ❌ 禁止 | ❌ 禁止 | ✅ 必须 |
关键细节
-
const 的 "常量" 本质:
-
基本类型(字符串、数字、布尔):值不可变;
-
引用类型(对象、数组):地址不可变,但属性 / 元素可修改(需冻结属性用
Object.freeze())。
const obj = { name: 'Alice' }; obj.name = 'Bob'; // ✅ 允许(地址未变) obj = {}; // ❌ 禁止(修改地址) -
-
暂时性死区(TDZ):
let/const声明的变量在声明前不可访问,避免了var的变量提升问题:// ES5(变量提升,输出undefined) console.log(arg1); var arg1 = 'test'; // ES6(暂时性死区,报错) console.log(arg2); let arg2 = 'test'; -
ES5 模拟 const(面试考点):
通过
Object.defineProperty设置writable: false,但仅能阻止重新赋值,无法触发严格模式报错:// ES5模拟const Object.defineProperty(window, 'arg3', { value: 'yy', writable: false // 禁止重新赋值 }); arg3 = 'student'; // 不报错,但赋值无效 console.log(arg3); // "yy" // ES6 const(严格模式下报错) const arg4 = 'yy'; arg4 = 'student'; // Uncaught TypeError: Assignment to constant variable
面试题:如何冻结对象所有属性(包括嵌套属性)?
Object.freeze()仅冻结当前层级属性,嵌套对象需递归冻结:
function deepFreeze(obj) {
// 冻结当前对象
Object.freeze(obj);
// 递归冻结嵌套对象
Object.keys(obj).forEach(key => {
const value = obj[key];
if (typeof value === 'object' && value !== null) {
deepFreeze(value);
}
});
return obj;
}
// 测试
const obj = {
teacher: 'yy',
hkc: { score: 5 }
};
deepFreeze(obj);
obj.teacher = 'xx'; // 无效
obj.hkc.score = 4.9; // 无效(嵌套属性已冻结)
1.2 解构赋值:简化数据提取
解构赋值是 ES6 的 "语法糖",用于快速从对象、数组中提取数据,大幅提升代码可读性和开发效率。
1. 对象解构
const hkc = { teacher: 'yy', course: 'ES6' };
// ES5提取方式
const teacher = hkc.teacher;
const course = hkc.course;
// ES6解构方式
const { teacher, course } = hkc;
// 进阶用法:别名、默认值
const { teacher: t, course: c = 'JS' } = hkc;
console.log(t); // "yy"(别名)
console.log(c); // "ES6"(默认值未生效)
2. 数组解构
const arr = ['yy', 'hkc', 'ES6'];
// ES5提取方式
const a = arr[0];
const b = arr[1];
const c = arr[2];
// ES6解构方式
const [a, b, c] = arr;
// 进阶用法:跳过元素、剩余参数
const [, , third, ...rest] = arr;
console.log(third); // "ES6"
console.log(rest); // [](若arr长度为3)
3. 实用场景:变量交换
无需临时变量,一行代码完成交换:
let x = 1, y = 2;
[x, y] = [y, x];
console.log(x, y); // 2, 1
1.3 箭头函数:简洁语法与上下文绑定
箭头函数(() => {})是 ES6 最常用的语法之一,核心优势是 "简洁 " 和 "固定上下文"。
1. 语法简化
// ES5函数
const add = function(a, b) {
return a + b;
};
// ES6箭头函数(简化写法)
const add = (a, b) => a + b; // 单表达式可省略{}和return
const greet = name => `Hello, ${name}`; // 单个参数可省略()
const sayHi = () => console.log('Hi'); // 无参数需写()
2. 上下文绑定(核心区别)
箭头函数没有独立的this ,其this继承自外层作用域(定义时的上下文),而非调用时的上下文:
const obj = {
teacher: 'yy',
// 普通函数:this指向obj
getTeacher: function() {
console.log(this.teacher); // "yy"
},
// 箭头函数:this继承外层上下文(此处为window/global)
getCourse: () => {
console.log(this.course); // undefined(this不指向obj)
}
};
obj.getTeacher();
obj.getCourse();
3. 禁止使用场景
-
DOM 事件回调:
this需指向元素本身,箭头函数会导致
this指向全局;const btn = document.querySelector('#btn'); // 错误:this指向window,无法操作元素 btn.addEventListener('click', () => { this.style.color = '#fff'; }); // 正确:普通函数,this指向btn btn.addEventListener('click', function() { this.style.color = '#fff'; }); -
类方法:箭头函数无法作为类的实例方法(
this不指向实例)。
1.4 class:面向对象语法糖
ES6 的class是原型继承的语法糖,让 JS 的面向对象编程 更接近传统语言(如 Java),但底层仍基于构造函数和原型。
1. 基本用法
// ES5构造函数
function Course(teacher, course) {
this.teacher = teacher;
this.course = course;
}
Course.prototype.getCourse = function() {
return `老师:${this.teacher},课程:${this.course}`;
};
// ES6 class
class Course {
// 构造函数(初始化实例属性)
constructor(teacher, course) {
this.teacher = teacher;
this.course = course;
}
// 实例方法(挂载到原型)
getCourse() {
return `老师:${this.teacher},课程:${this.course}`;
}
// 静态方法(挂载到类,无需实例化)
static getInfo() {
return '这是ES6课程';
}
}
// 实例化
const es6Course = new Course('yy', 'ES6');
console.log(es6Course.getCourse()); // "老师:yy,课程:ES6"
console.log(Course.getInfo()); // "这是ES6课程"
2. 访问器属性(getter/setter)
用于控制属性的读取 和赋值,适合做数据校验、格式转换:
class Course {
constructor(teacher, course) {
this._teacher = teacher; // 下划线表示私有属性(约定)
this.course = course;
}
// getter:读取属性时触发
get teacher() {
return `前缀_${this._teacher}`;
}
// setter:赋值属性时触发
set teacher(val) {
if (typeof val !== 'string') {
throw new Error('老师姓名必须是字符串');
}
this._teacher = val;
}
}
const course = new Course('yy', 'ES6');
console.log(course.teacher); // "前缀_yy"(触发getter)
course.teacher = 'xx'; // 触发setter
course.teacher = 123; // 报错(触发校验)
3. 继承与适配器模式
class通过extends实现继承,结合访问器属性可实现适配器模式(适配不同数据格式):
// 基础类
class Core {
constructor(name) {
this.name = name;
this.outName = '';
}
}
// 适配器类(适配Core类的数据格式)
class Utils extends Core {
constructor(core) {
super(core.name);
this._main = core;
this._name = {
firstName: 'zhaowa_',
lastName: '_course'
};
}
// 适配名称格式
get name() {
return this._name.firstName + this._main.name + this._name.lastName;
}
set name(val) {
this._name.outName = val;
}
get customerName() {
return this._name.firstName + this._name.outName + this._name.lastName;
}
}
// 使用
const core = new Core('ES6');
const utils = new Utils(core);
console.log(utils.name); // "zhaowa_ES6_course"
utils.name = 'TS';
console.log(utils.customerName); // "zhaowa_TS_course"
二、ESNext 特性:JS 的持续进化
ESNext 指 ES2016 及以后的提案特性,部分已成为标准,部分仍在草案阶段,以下是最常用的实用特性:
2.1 可选链操作符(?.)
解决嵌套对象属性访问时的 "Cannot read property 'x' of undefined" 错误:
A?.B → 先判 A 是否为null/undefined,是则返回undefined并终止;否则正常执行 A.B。
核心使用原则
-
哪里可能空,哪里加
?.:只给嵌套中可能为null/undefined的层级加,非空层级直接访问; -
赋值不用,读取 / 调用用 :
?.仅用于属性读取、数组索引、方法调用,不能用于赋值左侧; -
默认值用
??搭配 :替代||,避免假值被误判,让默认值更精准; -
仅判断
null/undefined:记住0/''/false/NaN不会触发终止,这是避坑关键。
const user = { profile: { name: 'Alice' } };
// ES6及以前(需层层判断)
const userName = user && user.profile && user.profile.name;
// ESNext(可选链)
const userName = user?.profile?.name; // 不存在则返回undefined
2.2 空值合并操作符(??)
解决||的 "0、''、false 被误判为假值" 问题,仅当左侧为null/undefined时才返回右侧:
// ES6及以前(问题:0会被误判)
const count = 0 || 10; // 10(错误,实际需要保留0)
// ESNext(空值合并)
const count = 0 ?? 10; // 0(正确)
const name = '' ?? 'Unknown'; // ""(正确)
const age = undefined ?? 18; // 18(正确)
2.3 逻辑赋值运算符(??=、&&=、||=)
结合逻辑运算和赋值,简化代码:
// 空值合并赋值:仅当左侧为null/undefined时赋值
let num = 0;
num ??= 10; // 0(未赋值)
let name = undefined;
name ??= 'Alice'; // "Alice"(已赋值)
// 与赋值:左侧为真时赋值
let flag = true;
flag &&= false; // false
// 或赋值:左侧为假时赋值
let msg = '';
msg ||= 'Hello'; // "Hello"
2.4 顶层 await
允许在模块顶层使用await,无需包裹在async函数中,简化异步模块加载:
// 模块顶层(ESNext)
const data = await fetch('https://api.example.com/data');
const json = await data.json();
export default json;
三、编译工具:Babel 的核心作用
现代 JS 语法(ES6+、ESNext)在老旧浏览器(如 IE)中不兼容,Babel 的核心作用是 "转译"------ 将高级语法转为 ES5 语法,确保跨浏览器兼容。
3.1 Babel 工作原理
-
解析(Parse) :将 JS 代码解析为抽象语法树 (AST);
-
转换(Transform):将 AST 中的高级语法节点转为 ES5 节点;
-
生成(Generate):将转换后的 AST 转为 ES5 代码。
3.2 基础使用(实战)
-
安装依赖:
npm install @babel/core @babel/cli @babel/preset-env --save-dev -
配置文件(.babelrc):
{ "presets": [ ["@babel/preset-env", { "targets": "> 0.25%, not dead", // 兼容目标浏览器 "useBuiltIns": "usage", // 自动引入需要的polyfill "corejs": 3 // 指定core-js版本(补全API) }] ] } -
转译命令:
npx babel src --out-dir dist # 将src目录的JS转译到dist目录
3.3 Polyfill:补全 API
Babel 仅转译语法(如箭头函数、class),但不补全 ES6 + 的新 API(如Array.prototype.includes、Promise)。core-js是常用的 polyfill 库,通过useBuiltIns: "usage"自动按需引入。
四、常见语法误区与修正
文档中部分内容存在误差,以下是修正和补充:
-
const 引用类型的修改:
文档中 "obj.course='es' 有问题的" 表述错误 ------const 声明的引用类型,属性可修改(地址未变),仅禁止重新赋值对象本身。
-
Object.assign 的作用:
Object.assign(obj, obj1)是将 obj1 的属性合并到 obj(浅拷贝),而非 "两个对象的合并" 生成新对象。若需生成新对象,应写为Object.assign({}, obj, obj1)。 -
class 的类型:
typeof Course返回function是正确的,因为 class 本质是构造函数的语法糖,并非新的类型。
五、总结
ES6 + 的语法升级让 JavaScript 更简洁、更健壮、更具工程化能力:
-
基础语法(const/let、解构、箭头函数)解决了传统 JS 的痛点;
-
面向对象(class)让代码结构更清晰;
-
ESNext 特性持续优化开发体验;
-
Babel 等工具确保跨浏览器兼容。
掌握这些语法不仅能提升开发效率,更是前端面试的高频考点。建议在项目中主动使用现代语法,结合 Babel、Webpack 等构建工具,打造高效、兼容的前端工程。