JavaScript 之 ES6 新特性

模块化

在ES6中,模块化成为了JavaScript的标准特性。ES6模块化提供了一种更加优雅和可维护的方式来组织和管理JavaScript代码,可以有效地避免全局变量的污染和命名冲突的问题。以下是ES6模块化的一些主要特性:

  1. 导出(export): 可以通过export关键字将一个变量、函数或类导出为一个模块,以便在其他模块中使用。

例如,以下代码将一个函数square导出为一个模块:

// module.js
export function square(x) {
    
    
  return x * x;
}
  1. 导入(import): 可以通过import关键字从其他模块中导入一个变量、函数或类,并在当前模块中使用。

例如,以下代码从module.js模块中导入square函数并使用它:

// app.js
import {
    
     square } from './module.js';

console.log(square(5)); // 25
  1. 默认导出: 可以通过export default语法将一个变量、函数或类默认导出为一个模块。

例如,以下代码将一个函数add默认导出为一个模块:

// module.js
export default function add(x, y) {
    
    
  return x + y;
}
  1. 默认导入: 可以通过import语法从其他模块中默认导入一个变量、函数或类,并在当前模块中使用。

例如,以下代码从module.js模块中默认导入add函数并使用它:

// app.js
import add from './module.js';

console.log(add(2, 3)); // 5

总之,ES6模块化提供了一种更加灵活和可维护的方式来组织和管理JavaScript代码,可以有效地避免全局变量的污染和命名冲突的问题。

Class类

ES6引入了class关键字,提供了一种更加简洁和面向对象的方式来定义和使用对象。class可以看做是JavaScript中的一种特殊函数,它可以定义一个类并创建类的实例。以下是ES6 class的一些主要特性:

  1. 类定义: 使用class关键字定义一个类。

例如,以下代码定义了一个名为Person的类:

class Person {
    
    
  constructor(name, age) {
    
    
    this.name = name;
    this.age = age;
  }

  sayHello() {
    
    
    console.log(`Hello, my name is ${
      
      this.name}, I'm ${
      
      this.age} years old.`);
  }
}
  1. 构造函数: 使用constructor方法定义一个类的构造函数。

例如,以下代码定义了一个Person类的构造函数:

class Person {
    
    
  constructor(name, age) {
    
    
    this.name = name;
    this.age = age;
  }
}
  1. 类方法: 使用类方法定义一个类的方法。

例如,以下代码定义了一个Person类的sayHello方法:

class Person {
    
    
  constructor(name, age) {
    
    
    this.name = name;
    this.age = age;
  }

  sayHello() {
    
    
    console.log(`Hello, my name is ${
      
      this.name}, I'm ${
      
      this.age} years old.`);
  }
}
  1. 类继承: 使用extends关键字实现类的继承。

例如,以下代码定义了一个Student类,它继承自Person类:

class Person {
    
    
  constructor(name, age) {
    
    
    this.name = name;
    this.age = age;
  }

  sayHello() {
    
    
    console.log(`Hello, my name is ${
      
      this.name}, I'm ${
      
      this.age} years old.`);
  }
}

class Student extends Person {
    
    
  constructor(name, age, grade) {
    
    
    super(name, age);
    this.grade = grade;
  }

  study() {
    
    
    console.log(`${
      
      this.name} is studying in grade ${
      
      this.grade}.`);
  }
}
  1. super关键字: 使用super关键字调用父类的构造函数和方法。

例如,以下代码使用super关键字调用Person类的构造函数:

class Student extends Person {
    
    
  constructor(name, age, grade) {
    
    
    super(name, age);
    this.grade = grade;
  }
}

总之,ES6 class提供了一种更加简洁和面向对象的方式来定义和使用对象,可以大大简化JavaScript代码的编写和维护。同时,ES6 class还支持继承、多态等面向对象编程的重要特性,使得JavaScript代码更加灵活和可扩展。

Symbol

ES6 引入了一种新的基本数据类型 Symbol,它是一种不可变的原始值,可以用作对象属性的唯一标识符。每个 Symbol 值都是唯一的,它们不会重复。Symbol 是一种类似于字符串的数据类型,但是它的值是唯一的,不可变的,且不会被自动转换为其他类型。

可以使用 Symbol() 函数创建一个新的 Symbol 值,它可以接受一个可选的描述字符串作为参数,用于描述这个 Symbol 的用途,但是这个描述字符串不会对 Symbol 的唯一性产生影响。

下面是 Symbol 的一些特性:

  1. Symbol 值可以作为对象的属性名,因为每个 Symbol 值都是唯一的,所以不会产生命名冲突的问题。在对象字面量中,可以使用方括号语法来定义 Symbol 属性。
const mySymbol = Symbol();
const obj = {
    
    
  [mySymbol]: 'value'
};

console.log(obj[mySymbol]); // 输出 'value'
  1. Symbol 值不会被自动转换成字符串,因此不能用作对象属性名的一部分,否则会抛出 TypeError 错误。
const mySymbol = Symbol();
const obj = {
    
    };

// 正确做法:将 Symbol 作为属性名
obj[mySymbol] = 'value';

// 错误做法:将 Symbol 转换成字符串作为属性名
obj[mySymbol.toString()] = 'value'; // 抛出 TypeError 错误
  1. 内置的 Symbol 值具有特殊的含义,例如 Symbol.iteratorSymbol.hasInstance 等,用于指定对象的默认迭代器、自定义 instanceof 行为等。
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 }
  1. Symbol 值可以被用作常量,以避免命名冲突的问题。比如,可以使用一个 Symbol 值作为事件名称,以确保不会和其他事件名称产生冲突。
const EVENT_A = Symbol('event_a');
const EVENT_B = Symbol('event_b');

// 发送事件 A
eventEmitter.emit(EVENT_A);

// 监听事件 B
eventEmitter.on(EVENT_B, () => {
    
    
  // do something
});

综上所述,Symbol 是一种可以用作对象属性名的唯一标识符,可以用于定义常量、指定默认迭代器等。它的出现使得 JavaScript 中对象属性名的命名更加灵活和丰

箭头函数

ES6引入了箭头函数(Arrow Functions)作为一种新的函数定义语法。箭头函数相比于传统的函数定义方式具有一些特殊的语法和行为。

特点如下:

  1. 简洁的语法:箭头函数使用箭头(=>)来定义,省略了function关键字和函数体中的大括号。如果函数体只有一条语句,则可以省略return关键字并隐式返回该表达式的结果。

    // 传统函数定义
    function add(a, b) {
          
          
      return a + b;
    }
    
    // 箭头函数定义
    const add = (a, b) => a + b;
    
  2. 箭头函数没有自己的thisargumentssupernew.target。它们继承外层作用域的对应值。这意味着在箭头函数内部,this指向的是定义函数时的上下文对象,而不是调用时的对象。

    const person = {
          
          
      name: 'John',
      sayHello: function () {
          
          
        setTimeout(() => {
          
          
          console.log(`Hello, ${
            
            this.name}!`);
        }, 1000);
      }
    };
    
    person.sayHello(); // 输出 "Hello, John!"
    
  3. 箭头函数不能作为构造函数使用,不能使用new关键字实例化对象。箭头函数没有prototype属性,因此无法使用new关键字创建对象实例。

    const Person = (name) => {
          
          
      this.name = name; // 错误:箭头函数不能用作构造函数
    };
    
    const john = new Person('John'); // 错误:无法使用new关键字实例化对象
    
  4. 如果箭头函数只有一个参数,可以省略参数的括号;如果没有参数或有多个参数,则需要使用括号。

    // 一个参数
    const greet = name => console.log(`Hello, ${
            
            name}!`);
    
    // 没有参数
    const sayHello = () => console.log('Hello!');
    
    // 多个参数
    const add = (a, b) => a + b;
    

箭头函数在许多场景中简化了函数的定义,尤其在处理回调函数、处理上下文绑定和简化函数嵌套等方面非常有用。然而,需要注意箭头函数和传统函数之间的差异,特别是在处理this上下文时的行为。

解构赋值

ES6的解构赋值是一种方便地从数组或对象中提取值并赋给变量的语法。它能够让我们以简洁的方式编写代码,并从复杂的数据结构中快速提取需要的值。

解构赋值可以应用于数组和对象,下面分别详解这两种情况:

  1. 数组解构赋值:

    数组解构赋值允许我们按照特定的模式从数组中提取值,并将它们赋给变量。模式匹配是基于数组的位置。

    const [a, b, ...rest] = [1, 2, 3, 4, 5];
    console.log(a); // 1
    console.log(b); // 2
    console.log(rest); // [3, 4, 5]
    

    在上面的例子中,我们使用数组解构赋值将数组 [1, 2, 3, 4, 5] 中的值分别赋给变量 abrestab 分别接收数组的第一个和第二个元素,而 rest 接收剩余的元素组成的新数组。

  2. 对象解构赋值:

    对象解构赋值允许我们从对象中提取属性值并赋给变量,通过属性名进行匹配。

    const person = {
          
          
      name: 'Alice',
      age: 25,
      address: {
          
          
        city: 'New York',
        country: 'USA'
      }
    };
    
    const {
          
           name, age, address: {
          
           city, country } } = person;
    console.log(name); // 'Alice'
    console.log(age); // 25
    console.log(city); // 'New York'
    console.log(country); // 'USA'
    

    在上面的例子中,我们使用对象解构赋值从 person 对象中提取属性 nameageaddress.cityaddress.country,并将它们赋给对应的变量。

    注意,通过冒号 : 可以为解构赋值的属性指定别名。在上面的例子中,我们将 person.address 的值赋给变量 address,并进一步从 address 中解构出 citycountry

解构赋值还支持默认值、嵌套结构、忽略某些元素等更多功能,可以根据具体的需求进行灵活运用。它在处理复杂的数据结构时可以提高代码的可读性和编写效率。

rest参数

ES6引入了rest参数(剩余参数)的概念,它允许我们将不定数量的参数表示为一个数组。在函数声明中,rest参数用三个点(…)后跟一个参数名来表示。这样做可以方便地处理传递给函数的多余参数。

下面是rest参数的一些特点和用法的详细解释:

  1. 语法:

    function functionName(...rest) {
          
          
      // 函数体
    }
    

    在函数声明中,使用...rest的形式来定义rest参数。rest是一个数组,包含了函数调用时传入的所有额外参数。

  2. 处理多余参数:
    当函数调用时传递了多个参数,而函数声明中只有少数参数定义时,多余的参数将会被捕获到rest参数中。

    function sum(...rest) {
          
          
      let total = 0;
      for (let num of rest) {
          
          
        total += num;
      }
      return total;
    }
    
    console.log(sum(1, 2, 3, 4, 5)); // 15
    

    在上面的例子中,sum函数的参数列表中只有一个rest参数rest,但是我们可以传递任意数量的参数给sum函数,并通过在函数体中遍历rest数组来计算总和。

  3. rest参数与其他参数结合使用:
    在函数声明中,rest参数可以与其他参数共存,但是rest参数必须是最后一个参数。

    function foo(a, b, ...rest) {
          
          
      console.log(a); // 1
      console.log(b); // 2
      console.log(rest); // [3, 4, 5]
    }
    
    foo(1, 2, 3, 4, 5);
    

    在上面的例子中,ab是普通的参数,而rest是rest参数,它接收了传递给函数的额外参数。

  4. rest参数的应用:

    • 收集剩余参数:当我们不确定函数调用时会传入多少参数时,可以使用rest参数来收集剩余的参数,以便在函数体中进行处理。
    • 替代arguments对象:ES6中的rest参数更直观和易于使用,相比之下,arguments对象是一个类数组对象,而rest参数是一个真正的数组,可以使用数组的各种方法。
    • 函数参数的灵活性:通过使用rest参数,我们可以声明接收任意数量参数的函数,而不需要事先指定固定数量的参数。

总结:ES6的rest参数为我们提供了一种处理不定数量参数的方式,将其收集为一个数组,并在函数体中进行操作。它使函数声明更加灵活,使得处理多余参数变得更加方便和可读。

Set/Map

ES6引入了SetMap这两个新的数据结构,它们提供了更方便和高效的方式来处理数据集合和键值对。

  1. Set:

    • Set是一种无序且不重复的数据集合。
    • 它的成员值唯一,不会重复。
    • 可以存储任意类型的值,包括原始值和引用值。
    • Set中的元素没有索引,无法通过索引进行访问。
    • 主要的应用场景是用于去重和判断某个元素是否存在。
    const set = new Set();
    set.add(1);
    set.add(2);
    set.add(3);
    set.add(2); // 添加重复元素,但不会生效
    
    console.log(set.size); // 3
    console.log(set.has(2)); // true
    
    set.delete(3);
    console.log(set.size); // 2
    
    set.clear();
    console.log(set.size); // 0
    
  2. Map:

    • Map是一种键值对的集合,类似于对象。
    • 它的键和值可以是任意类型的数据,包括原始值和引用值。
    • Map中的键值对是有序的。
    • 可以使用键来获取对应的值。
    const map = new Map();
    const key1 = 'key1';
    const key2 = {
          
           name: 'John' };
    
    map.set(key1, 'value1');
    map.set(key2, 'value2');
    
    console.log(map.size); // 2
    console.log(map.get(key1)); // 'value1'
    
    map.delete(key2);
    console.log(map.size); // 1
    
    console.log(map.has(key2)); // false
    
    map.clear();
    console.log(map.size); // 0
    

    Map还提供了迭代器(Iterator)方法,如keys()values()entries(),可以用于遍历Map的键、值和键值对。

    const map = new Map();
    map.set('a', 1);
    map.set('b', 2);
    map.set('c', 3);
    
    for (let key of map.keys()) {
          
          
      console.log(key); // 'a', 'b', 'c'
    }
    
    for (let value of map.values()) {
          
          
      console.log(value); // 1, 2, 3
    }
    
    for (let [key, value] of map.entries()) {
          
          
      console.log(key, value); // 'a' 1, 'b' 2, 'c' 3
    }
    

    Map还可以接受一个数组作为参数来初始化。

    const array = [['a', 1], ['b', 2], ['c', 3]];
    const map = new Map(array);
    
    console.log(map.get('a')); // 1
    

Set和Map提供了高效的数据处理方法,适用于需要管理集合和键值对的场景。它们的设计和使用方式使得操作更直观和高效,并且具有更好的性能和扩展性。## let/const

模板字符串

ES6引入了模板字符串(Template Strings),它提供了一种更便捷和灵活的方式来处理字符串。

模板字符串是用反引号(`)包围的字符串,它支持以下特性:

  1. 字符串插值(String Interpolation):
    使用${}语法在模板字符串中插入变量或表达式。

    const name = 'John';
    const age = 30;
    
    const message = `My name is ${
            
            name} and I'm ${
            
            age} years old.`;
    console.log(message); // "My name is John and I'm 30 years old."
    

    ${}内部可以是任意的JavaScript表达式,可以包含变量、函数调用、运算符等。

  2. 多行字符串:
    模板字符串可以跨越多行,不需要使用转义字符或拼接操作符。

    const multiline = `
      This is
      a multiline
      string.
    `;
    
    console.log(multiline);
    /*
      "This is
      a multiline
      string."
    */
    

    多行字符串保留了模板字符串中的缩进和换行符,使代码更具可读性。

  3. 嵌套模板字符串:
    可以在模板字符串中嵌套其他模板字符串,以构建更复杂的字符串。

    const name = 'John';
    const message = `Welcome to our website, ${
            
            name}!
    
    Today's special offer:
    Buy 1 get 1 free!
    Offer valid until ${
            
            new Date().toLocaleDateString()}.`;
    
    console.log(message);
    /*
      "Welcome to our website, John!
    
      Today's special offer:
      Buy 1 get 1 free!
      Offer valid until 5/11/2023."
    */
    

    在上述示例中,${name}嵌套在外部模板字符串中,${new Date().toLocaleDateString()}嵌套在内部模板字符串中。

  4. 原始字符串(Raw Strings):
    在模板字符串前添加前缀String.raw可以创建一个原始字符串,该字符串不会对反斜杠进行转义处理。

    const path = String.raw`C:\Users\John\Documents\file.txt`;
    console.log(path); // "C:\Users\John\Documents\file.txt"
    

    在上述示例中,反斜杠在原始字符串中保持不变,而不会被转义为特殊字符。

模板字符串提供了更直观和便捷的方式来处理字符串,尤其在需要插入变量或构建复杂文本的情况下。它的使用可以提高代码的可读性和可维护性,并且减少了字符串拼接和转义的繁琐操作。

扩展运算符

ES6中的扩展运算符(Spread Operator)是一个三个连续的点(…)用于展开可迭代对象(如数组、字符串或类数组对象)。

扩展运算符有以下主要用途和特性:

  1. 数组展开:
    扩展运算符可以将一个数组展开为多个独立的元素。

    const arr = [1, 2, 3];
    console.log(...arr); // 1 2 3
    

    这样可以方便地将一个数组的元素传递给函数或合并多个数组。

  2. 字符串展开:
    扩展运算符可以将一个字符串展开为单个字符。

    const str = 'hello';
    console.log(...str); // "h" "e" "l" "l" "o"
    

    这对于需要对字符串进行逐字符处理的操作非常有用。

  3. 对象展开:
    扩展运算符可以将一个对象展开为多个键值对。

    const obj = {
          
           x: 1, y: 2 };
    console.log({
          
           ...obj }); // { x: 1, y: 2 }
    

    这可以用于复制对象、合并对象或创建新的对象。

  4. 函数调用时的参数传递:
    扩展运算符可以将一个数组或类数组对象的元素作为函数的参数传递。

    function sum(x, y, z) {
          
          
      return x + y + z;
    }
    
    const numbers = [1, 2, 3];
    console.log(sum(...numbers)); // 6
    

    这样可以避免使用apply()或手动解构参数的麻烦。

  5. 数组和对象的浅拷贝:
    扩展运算符可以用于创建数组和对象的浅拷贝。

    const arr = [1, 2, 3];
    const arrCopy = [...arr];
    
    const obj = {
          
           x: 1, y: 2 };
    const objCopy = {
          
           ...obj };
    

    这样可以创建原始数组和对象的副本,而不是引用相同的数据。

扩展运算符提供了一种简洁和灵活的方式来处理数组、字符串和对象,使代码更具可读性和可维护性。它在函数调用、数组合并、对象复制等场景下非常有用,并且可以大大简化相关操作的代码。

迭代器/生成器

ES6引入了迭代器(Iterator)和生成器(Generator)两个概念,用于处理可迭代对象和生成可迭代对象的函数。

  1. 迭代器(Iterator):
    迭代器是一种对象,它提供了一种顺序访问数据集合的方式。它具有一个next()方法,每次调用都会返回一个包含valuedone属性的对象。

    • value:表示迭代器当前返回的值。
    • done:表示迭代器是否已经遍历完所有元素,如果为true则表示迭代器已经结束,否则为false

    迭代器可以手动实现,也可以使用ES6提供的可迭代对象(如数组、字符串、Set、Map等)的内置迭代器。

    const arr = [1, 2, 3];
    const iterator = arr[Symbol.iterator]();
    
    console.log(iterator.next()); // { value: 1, done: false }
    console.log(iterator.next()); // { value: 2, done: false }
    console.log(iterator.next()); // { value: 3, done: false }
    console.log(iterator.next()); // { value: undefined, done: true }
    
  2. 可迭代对象(Iterable):
    可迭代对象是具有迭代器的对象,它可以被迭代(遍历)的数据集合。可迭代对象必须具有一个名为Symbol.iterator的方法,返回一个迭代器对象。

    内置的可迭代对象包括数组、字符串、Set、Map等。

    const arr = [1, 2, 3];
    const str = 'hello';
    const set = new Set([1, 2, 3]);
    const map = new Map([['a', 1], ['b', 2], ['c', 3]]);
    
    console.log(arr[Symbol.iterator]); // [Function: values]
    console.log(str[Symbol.iterator]); // [Function: [Symbol.iterator]]
    console.log(set[Symbol.iterator]); // [Function: values]
    console.log(map[Symbol.iterator]); // [Function: entries]
    
  3. 生成器(Generator):
    生成器是一种特殊的函数,它使用function*关键字定义,并且在函数体内使用yield语句来暂停函数的执行,并返回一个迭代器对象。

    生成器函数可以通过迭代器的方式来逐步产生值,每次调用生成器函数的next()方法,都会执行到下一个yield语句,并返回一个包含valuedone属性的对象。

    function* generator() {
          
          
      yield 1;
      yield 2;
      yield 3;
    }
    
    const iterator = generator();
    
    console.log(iterator.next()); // { value: 1, done: false }
    console.log(iterator.next()); // { value: 2, done: false }
    console.log(iterator.next()); // { value: 3, done: false }
    console.log(iterator.next()); // { value: undefined, done: true }
    

猜你喜欢

转载自blog.csdn.net/qq_48439911/article/details/130583745