1. 块级作用域: 使用{}定义块级作用域,使变量在块内有效。
特点和优势:
变量隔离:在块级作用域内声明的变量不会污染全局作用域,避免了变量命名冲突和意外的全局变量修改。
提高可读性和可维护性:可以更清晰地组织代码,将相关的变量和操作放在一起,提高代码的可读性和可维护性。
避免变量提升:在 ES5 中,变量声明会被提升到函数作用域的顶部,而在块级作用域中,变量只有在声明后才能访问,避免了一些因变量提升导致的问题。
更好的内存管理:由于变量的作用域更小,在不需要时可以更及时地被垃圾回收器回收,提高了内存管理的效率。
示例
{
let x = 10; // 在块级作用域内声明变量 x
console.log(x); // 可以在块内访问变量 x
}
console.log(x); // 在块外访问变量 x 会导致ReferenceError
2. 箭头函数:简洁的函数表达式,使用=> 定义,没有this。
特点和优势:
简洁的语法:箭头函数的语法比传统的函数表达式更简洁,减少了代码的冗余。
没有 this 绑定:箭头函数中的 this 指向的是函数定义时的上下文,而不是函数调用时的上下文。这使得箭头函数在某些情况下更容易理解和使用。
不支持 new 操作符:箭头函数不能作为构造函数使用,因为它没有 prototype 属性。
没有自己的 arguments 对象:箭头函数中没有自己的 arguments 对象,如果需要访问函数的参数,可以使用 rest 参数 或展开运算符。
隐式返回:如果箭头函数只有一个表达式作为 body,那么这个表达式的值就是函数的返回值,不需要使用 return 语句。
示例
let myFunction = () => { // 定义一个箭头函数
console.log('Hello, World!');
};
myFunction(); // 调用箭头函数
3. 类和类的继承:支持面向对象编程的类语法。
特点和概念
类的定义:使用 class 关键字来定义类,类中可以包含属性和方法。
构造函数:类中默认有一个构造函数,可以在构造函数中初始化类的属性。
方法:类中可以定义方法,方法可以访问类的属性和调用其他方法。
继承:使用 extends 关键字来实现类的继承,子类可以继承父类的属性和方法,并可以重写父类的方法。
** super 关键字**:在子类的构造函数或方法中,可以使用 super 关键字来调用父类的构造函数或方法。
静态属性和方法:类可以定义静态属性和方法,静态属性和方法可以通过类名直接访问,而不需要创建类的实例。
示例:
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(Hello, I'm ${this.name} and I'm ${this.age} years old.);
}
}
class Employee extends Person {
constructor(name, age, salary) {
super(name, age); // 调用父类的构造函数
this.salary = salary;
}
calculateSalary() {
console.log(My salary is ${this.salary} per month.);
}
}
let person = new Person('John Doe', 30);
person.sayHello();
let employee = new Employee('Jane Doe', 40, 5000);
employee.sayHello();
employee.calculateSalary();
4. 增强的对象属性:如属性简写、计算属性、方法属性等。
特点:
属性简写:可以在对象的定义中直接省略属性名后面的 : 和值,例如 let obj = { name },相当于 let obj = { name: '' }。
计算属性:使用 get 和 set 方法来定义计算属性,计算属性的值可以根据其他属性的值动态计算得到。
方法属性:对象的属性值可以是一个函数,这样就可以将方法作为对象的属性来使用。
示例:
let person = {
name: "John Doe",
age: 30,
sayHello: function () {
console.log(Hello, I'm ${this.name} and I'm ${this.age} years old.);
},
};
person.sayHello();
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
// 定义计算属性 fullName
get fullName() {
return this.name + " " + this.age;
}
// 定义 set 方法来处理 fullName 的设置
set fullName(newFullName) {
// 解析 newFullName 并设置 name 和 age 属性
const nameAndAge = newFullName.split(" ");
this.name = nameAndAge[0];
this.age = parseInt(nameAndAge[1]);
}
}
let person = new Person("John Doe", 30);
console.log(person.fullName);
person.fullName = "JaneDoe 40";
console.log(person.name);
console.log(person.age);
5. 模版字符串: 使用``定义包含变量和表达式的字符串。
特点
变量插值:可以在模版字符串中使用花括号 {} 来插入变量或表达式,例如 let name = 'John Doe'; let greeting = Hello, ${name}!;。
多行字符串:模版字符串可以包含多行文本,不需要使用换行符或字符串拼接,例如 let multiLineText = This is a
multiline string.;。
模板标签:模版字符串可以使用模板标签来进行逻辑处理,例如 let condition = true; let result = condition? Yes:No;。
示例
let name = 'John Doe';
let age = 30;
let greeting = Hello, ${name}! You are ${age} years old.;
console.log(greeting);
6. 解构赋值:方便地从对象或数组中提取并赋值给变量。
特点
对象解构赋值:可以使用花括号 {} 来解构对象,将对象中的属性赋值给变量,例如 let { name, age } = { name: 'John Doe', age: 30 };。
数组解构赋值:可以使用方括号 [ ] 来解构数组,将数组中的元素赋值给变量,例如 let [one, two, three] = [1, 2, 3];。
默认值:可以为解构赋值指定默认值,如果对象或数组中没有对应的属性或元素,则使用默认值,例如 let { name = 'Unknown', age = 0 } = {};。
嵌套解构:可以进行嵌套解构,将对象或数组中的嵌套对象或数组进行解构赋值,例如 let { person: { name, age } } = { person: { name: 'John Doe', age: 30 } };。
不完全解构:可以只解构对象或数组中的部分属性或元素,例如 let { name } = { name: 'John Doe', age: 30 };。
示例
let person = { name: 'John Doe', age: 30, city: 'New York' };
let { name, age } = person;
console.log(name);
console.log(age);
7. 迭代器和生成器:用于遍历和生成数据。
迭代器是一种可以遍历数据结构的工具。它提供了一种统一的接口,使得我们可以使用相同的方式来遍历不同的数据结构,例如数组、对象、Set、Map 等。迭代器有以下特点:
可迭代对象:一些数据结构(如数组、Set、Map 等)本身就是可迭代对象,可以直接使用迭代器进行遍历。
next 方法:通过调用迭代器的 next 方法,可以获取下一个元素。
三种状态:迭代器有三种状态:ready(准备好下一个元素)、value(当前元素)和 done(遍历结束)。
生成器是一种特殊的函数,它可以在函数执行的过程中暂停和恢复执行。生成器有以下特点:
yield 关键字:使用 yield 关键字可以在函数中暂停执行,并返回一个值。
可迭代对象:生成器函数本身就是一个可迭代对象,可以使用迭代器进行遍历。
异步操作:生成器可以用于处理异步操作,例如异步请求。
示例
// 迭代器示例
let array = [1, 2, 3, 4, 5];
let iterator = arraySymbol.iterator;
while (true) {
let result = iterator.next();
if (result.done) {
break;
}
console.log(result.value);
}
// 生成器示例
function* generateNumbers() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
}
let generator = generateNumbers();
for (let value of generator) {
console.log(value);
}
8. 模块系统:引入了模块的概念,提高了代码的组织和复用性。
特点:
导入导出:模块可以使用 import 关键字导入其他模块的代码,使用 export 关键字导出自己的代码。
模块作用域:模块内部的代码具有独立的作用域,不会影响其他模块的代码。
模块打包:可以使用模块打包工具(如 Webpack、Rollup 等)将多个模块打包成一个文件,以便在浏览器中加载。
示例
// 模块 A
export function multiply(a, b) {
return a * b;
}
// 模块 B
import { multiply } from './moduleA';
console.log(multiply(2, 3));
9. Set和Map数据结构:用于处理集合和关联数据。
Set 数据结构是一种不允许重复元素的数据结构。它可以用于存储唯一的元素,并提供了一些有用的方法,例如添加元素、删除元素、检查元素是否存在等。Set 数据结构的特点包括:
不允许重复元素:Set 中的元素必须是唯一的。
无序性:Set 中的元素没有顺序。
快速查找:Set 可以快速查找元素是否存在。
let set = new Set();
set.add(1);
set.add(2);
set.add(2); // 重复元素不会被添加到 Set 中
console.log(set.size); // 输出 2,因为 Set 中只有 2 个元素
set.delete(1);
console.log(set.has(1)); // 输出 false,因为 1 已经被删除了
Map 数据结构是一种键值对的数据结构,它可以用于存储关联的数据。Map 提供了一些有用的方法,例如添加键值对、获取键对应的值、删除键值对等。Map 数据结构的特点包括:
键值对:Map 中的每个元素都是一个键值对。
无序性:Map 中的键值对没有顺序。
快速查找:Map 可以快速根据键查找对应的值。
示例
let map = new Map();
map.set('name', 'John Doe');
map.set('age', 30);
map.set('city', 'New York');
console.log(map.get('name')); // 输出 'John Doe'
console.log(map.size); // 输出 3,因为 Map 中有 3 个键值对
map.delete('age');
console.log(map.has('age')); // 输出 false,因为 'age' 已经被删除了
10. Promise:处理异步操作的一种方式。
特点
异步操作的封装:Promise 用于封装异步操作的结果,使得异步操作可以像同步操作一样进行处理。
状态:Promise 有三种状态:pending(进行中)、fulfilled(成功)和 rejected(失败)。
回调函数:可以为 Promise 添加回调函数,以便在异步操作完成后执行相应的操作。
链式调用:Promise 支持链式调用,可以方便地组合多个异步操作。
示例
function fetchData(url) {
return new Promise((resolve, reject) => {
fetch(url)
.then(response => response.json())
.then(data => resolve(data))
.catch(error => reject(error));
});
}
fetchData('xxx')
.then(data => console.log(data))
.catch(error => console.error(error));
11. 异步/等待(async /await):更方便的编写异步代码。
async/await 的特点包括:
异步代码同步化:使用 async/await 可以将异步代码转换为同步代码的形式,提高代码的可读性和可维护性。
返回Promise:async 函数总是返回一个 Promise 对象。
暂停执行:当遇到 await 关键字时,异步操作会暂停执行,等待 Promise 的结果。
错误处理:如果异步操作失败,可以在 catch 语句中捕获错误。
示例
async function fetchData() {
try {
let response = await fetch('example.com/data');
let data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}
fetchData();
12. 扩展运算符:用于展开数组和对象。
特点
展开数组:可以将一个数组展开为多个参数,例如 [1, 2, 3,...arr]。
展开对象:可以将一个对象展开为多个参数,例如 {a: 1, b: 2,...obj}。
合并数组:可以使用扩展运算符合并多个数组,例如 [...arr1,...arr2]。
替换对象的属性:可以使用扩展运算符替换对象的属性,例如 {...obj, newProp: newValue}。
示例
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let mergedArr = [...arr1,...arr2];
console.log(mergedArr);
let obj1 = {a: 1, b: 2};
let obj2 = {c: 3, d: 4};
let mergedObj = {...obj1,...obj2};
console.log(mergedObj);