# 【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的基本步骤如下:

  1. 创建一个Promise对象,传入一个executor函数,executor函数接受两个参数:resolve和reject。
  2. 在executor函数中执行异步操作,并根据异步操作的结果调用resolve或reject函数。
  3. 使用.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"

# 学习参考网站

https://zh.javascript.info/js (opens new window)