知识篇 -- JS ES6+新特性:现代JS
Ray Shine
2024/1/20 JavaScript进阶知识ES6ES2015
本文为博主原创文章,遵循
CC 4.0 BY-SA
版权协议,转载请附上原文出处链接和本声明。
如有侵权,请联系
本博主
删除。
ECMAScript 2015 (ES6) 是JavaScript语言的一个里程碑式版本,引入了大量新特性,极大地提升了JavaScript的开发效率和代码质量。随后的ES版本(ES2016, ES2017, ...)也持续带来了许多有用的改进。掌握这些现代JavaScript特性,是成为一名优秀前端开发者的必备条件。
# 一、变量声明:let 和 const 块级作用域
ES6引入了 let 和 const,解决了 var 存在的许多问题,提供了更严格、更可控的变量声明方式。
let:声明块级作用域的变量,没有变量提升,不允许重复声明。const:声明块级作用域的常量,没有变量提升,不允许重复声明,且声明时必须初始化,一旦赋值后不能再重新赋值(对于引用类型,其指向的内存地址不可变,但对象内部属性可变)。
示例:
// var 的问题
var a = 1;
if (true) {
var a = 2; // 覆盖了外部的 a
console.log(a); // 2
}
console.log(a); // 2
// let 和 const 解决
let b = 1;
if (true) {
let b = 2; // 块级作用域,与外部的 b 是不同变量
console.log(b); // 2
}
console.log(b); // 1
const C = 10;
// C = 20; // TypeError
const obj = { name: "test" };
obj.name = "new test"; // 允许修改对象属性
// obj = {}; // TypeError
# 二、箭头函数 (Arrow Functions) 简洁语法
提供了一种更简洁的函数书写方式,并且解决了 this 的指向问题。
- 语法简洁:
// 传统函数 function add(a, b) { return a + b; } // 箭头函数 const add = (a, b) => a + b; // 单个参数可省略括号 const square = x => x * x; // 无参数需保留空括号 const greet = () => "Hello!"; this的词法作用域:箭头函数没有自己的this绑定,它会捕获其外层(词法)作用域的this值。这使得在回调函数中使用this变得更加直观。const person = { name: "Alice", sayHi: function() { setTimeout(function() { // console.log(`Hello, ${this.name}`); // 这里的this指向全局对象或undefined }, 1000); }, sayHiArrow: function() { setTimeout(() => { console.log(`Hello, ${this.name}`); // 这里的this指向person对象 }, 1000); } }; person.sayHiArrow(); // 1秒后输出:Hello, Alice
# 三、模板字符串 (Template Literals) 字符串增强
使用反引号 ` 定义,允许嵌入表达式和多行文本,告别了繁琐的字符串拼接。
- 字符串插值:使用
${expression}语法嵌入变量或表达式。 - 多行字符串:直接在反引号中换行即可。
- 示例:
const name = "Bob"; const age = 25; const message = `My name is ${name} and I am ${age} years old.`; console.log(message); // My name is Bob and I am 25 years old. const html = ` <div> <h1>Welcome</h1> <p>${message}</p> </div> `; console.log(html);
# 四、解构赋值 (Destructuring Assignment) 数据提取
允许从数组或对象中提取值,对变量进行赋值,语法简洁且可读性强。
- 数组解构:
const numbers = [10, 20, 30]; const [first, second, third] = numbers; console.log(first); // 10 const [a, , c] = [1, 2, 3]; // 跳过第二个元素 const [x, y, ...rest] = [1, 2, 3, 4, 5]; // 剩余元素 - 对象解构:
const person = { name: "Charlie", age: 40 }; const { name, age } = person; console.log(name); // Charlie const { name: userName, age: userAge } = person; // 重命名变量 const { city = "New York" } = person; // 设置默认值
# 五、Promise:异步编程的解决方案 异步处理
Promise是处理异步操作的一种模式,解决了回调地狱(Callback Hell)问题,使异步代码更易于管理和阅读。
- 状态:
pending(进行中),fulfilled(已成功),rejected(已失败)。 - 方法:
then(),catch(),finally(),Promise.all(),Promise.race(),Promise.any(),Promise.allSettled()。 - 示例:
function fetchData() { return new Promise((resolve, reject) => { setTimeout(() => { const success = true; if (success) { resolve("Data fetched successfully!"); } else { reject("Failed to fetch data."); } }, 2000); }); } fetchData() .then(data => console.log(data)) // Data fetched successfully! .catch(error => console.error(error)) .finally(() => console.log("Fetch attempt finished."));
# 六、Async/Await:更优雅的异步编程 更简洁
async 和 await 是基于Promise的语法糖,使得异步代码看起来和写起来更像同步代码,进一步提高了可读性。
async函数:async关键字用于声明一个异步函数。异步函数总是返回一个Promise。await表达式:await关键字只能在async函数内部使用,它会暂停async函数的执行,直到其等待的Promise解决(fulfilled)或拒绝(rejected)。- 示例:
async function loadData() { try { console.log("Start loading..."); const data = await fetchData(); // 等待Promise解决 console.log(data); console.log("Data processing complete."); } catch (error) { console.error("Error:", error); } } loadData(); // 输出: // Start loading... // (2秒后) Data fetched successfully! // Data processing complete.
# 七、Class:面向对象编程的语法糖 OOP
ES6引入了 class 关键字,提供了更清晰、更简洁的方式来创建构造函数和实现继承,但其底层仍然是基于原型链的。
- 定义类:
class Animal { constructor(name) { this.name = name; } speak() { console.log(`${this.name} makes a sound.`); } } - 继承:使用
extends关键字实现继承,super()调用父类构造函数。class Dog extends Animal { constructor(name, breed) { super(name); this.breed = breed; } speak() { console.log(`${this.name} barks.`); } static info() { // 静态方法 console.log("Dogs are loyal."); } } const myDog = new Dog("Buddy", "Golden Retriever"); myDog.speak(); // Buddy barks. Dog.info(); // Dogs are loyal.
# 八、模块化 (Modules):组织代码的新方式 代码组织
ES6引入了原生的模块系统,通过 import 和 export 关键字,使得JavaScript代码可以更好地组织和复用。
export:用于导出模块中的变量、函数、类。// math.js export const PI = 3.14159; export function add(a, b) { return a + b; } export default class Calculator { /* ... */ } // 默认导出import:用于导入其他模块导出的内容。// main.js import { PI, add } from './math.js'; import MyCalc from './math.js'; // 导入默认导出 console.log(PI); // 3.14159 console.log(add(1, 2)); // 3 const calc = new MyCalc();- 特点:模块是独立的作用域,默认处于严格模式,可以按需加载。
# 九、Set 和 Map:新的数据结构 新数据结构
ES6引入了两种新的集合类型,提供了更高效的数据存储和操作方式。
- Set:存储唯一值的集合,不允许重复。
const mySet = new Set([1, 2, 2, 3, 4, 4]); console.log(mySet); // Set {1, 2, 3, 4} mySet.add(5); mySet.delete(1); mySet.has(2); // true - Map:存储键值对的集合,键可以是任意类型(包括对象),解决了传统对象只能用字符串作为键的限制。
const myMap = new Map(); myMap.set("name", "David"); myMap.set(1, "number one"); const objKey = { id: 1 }; myMap.set(objKey, "object value"); console.log(myMap.get("name")); // David console.log(myMap.has(objKey)); // true
# 十、Proxy 和 Reflect:元编程的利器 元编程
- Proxy:用于创建一个对象的代理,从而实现对对象基本操作的拦截和自定义。
- Reflect:一个内置对象,提供了一组静态方法,用于拦截JavaScript操作。
这些ES6+的新特性极大地提升了JavaScript的表达能力和开发体验,使得JavaScript能够更好地应对复杂的应用场景。