# 【ES6语言特性】
# let&const
let 和 const 是块级作用域的变量声明方式,用于替代原来的 var。
# let
- 在循环中定义计数器变量。
- 当需要在后续代码中重新赋值的变量。
- 当需要重新定义一个同名变量的情况下。
# const
- 在定义常量的情况下,例如数学常数、API密钥等。
- 在声明不会改变的变量的情况下,例如函数、对象和数组。
- 当需要避免意外重新赋值的情况下。
# 箭头函数
使用箭头语法可以创建更简洁的函数,并且可以隐式地将this绑定到定义函数的上下文中。
一个简单的箭头函数,接受两个参数并返回它们的和:
const add = (a, b) => a + b;
console.log(add(2, 3)); // 输出 5
如果函数只有一个参数,可以省略括号:
const double = num => num * 2;
console.log(double(5)); // 输出 10
如果函数体不只是一条语句,可以使用花括号括起来,并且需要使用return关键字来返回值:
const multiply = (a, b) => {
const result = a * b;
return result;
};
console.log(multiply(2, 3)); // 输出 6
在箭头函数中使用解构赋值:
const person = { name: 'Alice', age: 30 };
const greet = ({ name, age }) => {
console.log(`Hello, my name is ${name} and I am ${age} years old.`);
};
greet(person); // 输出 "Hello, my name is Alice and I am 30 years old."
在数组方法中使用箭头函数:
const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = numbers.map(num => num * 2);
console.log(doubledNumbers); // 输出 [2, 4, 6, 8, 10]
# 类
引入了类和类继承,使JavaScript更像传统的面向对象编程语言。 类是一种模板或蓝图,用于创建对象的属性和方法。类可以看作是一种特殊的函数,定义时使用class关键字。
# 创建类
示例:
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`Hello, my name is ${this.name}.`);
}
}
const john = new Person('John', 30);
john.sayHello();
# 使用继承
示例:
class Student extends Person {
constructor(name, age, grade) {
super(name, age);
this.grade = grade;
}
sayHello() {
console.log(`Hello, my name is ${this.name} and I am in grade ${this.grade}.`);
}
}
const mary = new Student('Mary', 15, 10);
mary.sayHello();
# 模板字符串
使用反引号(``)可以创建多行字符串,并且可以在字符串中嵌入变量。 上面的 Student 类使用了模版字符串
# 解构赋值
可以将数组和对象中的值解构为单独的变量,并将其赋值给另一个变量。
# 数组解构赋值
用法:
const arr = [1, 2, 3];
const [a, b, c] = arr;
console.log(a); // 1
console.log(b); // 2
console.log(c); // 3
如果我们只需要提取数组中的一部分元素,可以使用逗号来跳过我们不需要的元素:
const arr = [1, 2, 3];
const [a, , c] = arr;
console.log(a); // 1
console.log(c); // 3
# 对象解构赋值
对象解构赋值与数组解构赋值类似,但是使用的是对象的属性名而不是数组的索引。以下是对象解构赋值的示例:
const person = { name: 'John', age: 30 };
const { name, age } = person;
console.log(name); // 'John'
console.log(age); // 30
我们也可以使用别名来为解构赋值的变量命名:
const person = { name: 'John', age: 30 };
const { name: fullName, age } = person;
console.log(fullName); // 'John'
console.log(age); // 30
# 默认参数
在函数参数中可以指定默认值,如果调用函数时未传递该参数,则使用默认值。
例如:
function greet(name = 'Guest') {
console.log(`Hello, ${name}!`);
}
greet(); // 输出:Hello, Guest!
greet('John'); // 输出:Hello, John!
# 展开运算符
使用三个点(...)可以将数组或对象“展开”,使其元素可以作为参数传递给函数或合并到其他数组或对象中。
# 展开数组
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5, 6];
console.log(arr2); // 输出:[1, 2, 3, 4, 5, 6]
# 展开对象
const obj1 = { foo: 'bar', baz: 42 };
const obj2 = { ...obj1, qux: 99 };
console.log(obj2); // 输出:{ foo: 'bar', baz: 42, qux: 99 }
# 作为函数参数
function sum(a, b, c) {
return a + b + c;
}
const arr = [1, 2, 3];
const result = sum(...arr);
console.log(result); // 输出:6
# Promise
它用于处理异步操作并提供更好的可读性和可维护性。 Promise表示一个异步操作的最终状态,可以是成功(resolved),也可以是失败(rejected)。
三种状态:
- pending(等待中)
- resolved(已完成)
- rejected(已失败)
Promise对象一旦处于resolved或rejected状态,就不能再改变状态。当Promise对象的状态改变时,会触发相应的回调函数。
使用Promise的基本步骤如下:
- 创建一个Promise对象,传入一个executor函数,executor函数接受两个参数:resolve和reject。
- 在executor函数中执行异步操作,并根据异步操作的结果调用resolve或reject函数。
- 使用.then()方法添加成功回调函数,使用.catch()方法添加失败回调函数。
示例:
function getData() {
return new Promise((resolve, reject) => {
// 执行异步操作
setTimeout(() => {
const data = [1, 2, 3];
if (data.length > 0) {
resolve(data); // 成功时调用resolve函数,并传递数据
} else {
reject(new Error('No data')); // 失败时调用reject函数,并传递错误对象
}
}, 1000);
});
}
getData()
.then((data) => {
console.log(data); // 成功时输出数据
})
.catch((error) => {
console.log(error.message); // 失败时输出错误信息
});
在上面的示例中,我们定义了一个函数getData(),它返回一个Promise对象,执行异步操作,并根据操作结果调用resolve或reject函数。我们使用.then()方法添加成功回调函数,使用.catch()方法添加失败回调函数。
当getData()函数被调用时,它会返回一个Promise对象,我们可以使用.then()方法和.catch()方法来处理异步操作的结果。如果异步操作成功,.then()方法将被调用,并传递数据;如果异步操作失败,.catch()方法将被调用,并传递错误对象。
需要注意的是,Promise对象的.then()方法和.catch()方法都返回一个新的Promise对象,因此它们可以链式调用。如果.then()方法中返回了一个新的Promise对象,后续的.then()方法将等待该Promise对象的状态改变。
# Generator函数
Generator函数是一种可以暂停和恢复执行的函数,可以用于编写更复杂的异步代码。 Generator函数使用函数关键字function定义,但是在函数名和参数列表之间使用一个星号(*)来表示它是一个Generator函数。
下面是一个简单的Generator函数的例子:
function* myGenerator() {
yield 1;
yield 2;
yield 3;
}
const gen = myGenerator();
console.log(gen.next().value); // 输出:1
console.log(gen.next().value); // 输出:2
console.log(gen.next().value); // 输出:3
console.log(gen.next().done); // 输出:true
除了暂停和恢复执行状态外,Generator函数还可以使用yield语句接受外部传入的值,并返回一个结果值。例如:
function* fibonacci() {
let a = 0;
let b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const gen = fibonacci();
console.log(gen.next().value); // 输出:0
console.log(gen.next().value); // 输出:1
console.log(gen.next().value); // 输出:1
console.log(gen.next().value); // 输出:2
console.log(gen.next().value); // 输出:3
# 模块
引入了模块化,在文件之间共享代码变得更加容易。
以下是一个简单的模块示例:
// file1.js
export function square(x) {
return x * x;
}
// file2.js
import { square } from './file1.js';
console.log(square(2)); // 输出:4
# Symbol数据类型
唯一且不可变的值,可以用作对象属性的标识符。
Symbol可以作为对象属性名来使用,这样可以避免命名冲突。 使用Symbol作为属性名时,需要使用方括号语法来访问该属性,因为点号语法不支持Symbol属性名。
示例:
const sym = Symbol();
const obj = {
[sym]: 'value'
};
console.log(obj[sym]); // 输出 "value"
Symbol还可以接受一个可选的字符串参数作为标识符的描述,该描述不影响Symbol的唯一性,只是用于调试和表示该Symbol的信息。
示例:
const sym = Symbol('my symbol');
console.log(sym); // 输出 "Symbol(my symbol)"
除了创建一个新的Symbol值之外,ES6还引入了一些内置的Symbol常量,这些常量用于表示一些语言内部的操作和行为,例如Symbol.iterator用于表示一个对象是否可迭代。
示例:
const arr = [1, 2, 3];
const iter = arr[Symbol.iterator]();
console.log(iter.next()); // 输出 { value: 1, done: false }
console.log(iter.next()); // 输出 { value: 2, done: false }
console.log(iter.next()); // 输出 { value: 3, done: false }
console.log(iter.next()); // 输出 { value: undefined, done: true }
上面的代码中,我们使用数组的Symbol.iterator属性获取一个迭代器对象,并使用next()方法逐个访问数组的元素。
# Map和Set集合
# Map
Map是一种键值对的集合,其中每个键都是唯一的,可以使用任何JavaScript值作为键或值。 Map的优点是可以使用各种类型的键,而对象的键只能是字符串或符号。 另外,Map提供了许多有用的方法,例如size属性用于获取Map中键值对的数量,set()方法用于添加键值对,get()方法用于获取指定键的值,delete()方法用于删除指定键的键值对等。
示例:
const map = new Map();
map.set('key1', 'value1');
map.set('key2', 'value2');
console.log(map.get('key1')); // 输出 "value1"
console.log(map.size); // 输出 2
map.delete('key2');
console.log(map.has('key2')); // 输出 false
# Set
Set是一种值的集合,其中每个值都是唯一的,可以使用任何JavaScript值作为值。 Set的优点是它提供了一种快速的方式来检查值是否在集合中。 Set也提供了许多有用的方法,例如size属性用于获取Set中的值的数量,add()方法用于添加值,has()方法用于检查值是否在集合中,delete()方法用于删除值等。
示例:
const set = new Set();
set.add('value1');
set.add('value2');
console.log(set.has('value1')); // 输出 true
console.log(set.size); // 输出 2
set.delete('value2');
console.log(set.has('value2')); // 输出 false
Map和Set可以一起使用,例如使用Set来存储Map中的键,这样就可以快速地检查某个键是否在Map中。另外,Map和Set还可以相互嵌套使用,例如使用Map来存储一组Set,每个Set中存储一组相关的值。
# Rest参数
它允许函数接受任意数量的参数,并将它们作为一个数组传递给函数。 Rest参数使用三个点(...)符号表示,放置在函数参数的最后面,表示接受任意数量的参数。
Rest参数可以在函数定义时使用,也可以在函数调用时使用。在函数定义时,Rest参数将其余的参数收集到一个数组中;在函数调用时,Rest参数将数组中的元素分解为独立的参数。
示例:
function sum(...numbers) {
return numbers.reduce((acc, cur) => acc + cur, 0);
}
console.log(sum(1, 2, 3)); // 输出 6
console.log(sum(1, 2, 3, 4, 5)); // 输出 15
在上面的示例中,Rest参数被用于收集函数的所有参数,并将它们作为一个数组传递给函数。在函数体中,我们使用reduce()方法计算数组中所有元素的总和。
Rest参数也可以与其他参数一起使用,例如:
function concat(separator, ...strings) {
return strings.join(separator);
}
console.log(concat('-', 'a', 'b', 'c')); // 输出 "a-b-c"
console.log(concat('_', 'x', 'y', 'z')); // 输出 "x_y_z"