千文盘点 ES6(ECMAScript® 2015)在前端项目的使用,常用的比较详细了

116 阅读18分钟

ECMAScript® 2015 Language Specification (ES6)

ES6官方文档,吃定它让你通吃ES6阮一峰的入门笔记,当然也是一本很好学习es6基础的入门参考书籍了

在前端项目中,使用 ES6 语法能够提高代码的可读性和可维护性,同时也有助于减少错误,提升开发效率。随着现代前端框架(如 React、Vue、Angular)的流行,掌握 ES6 及其新特性已成为前端开发者的基本要求。

常用基础用法

1. 箭头函数 (Arrow Functions)

箭头函数提供了一种更简洁的函数表达方式,并且不绑定 this

const sum = (a, b) => a + b;
const numbers = [1, 2, 3].map(num => num * 2);

2. 模板字符串 (Template Literals)

模板字符串使得字符串拼接和多行字符串的处理更加简便,使用反引号(``)语法。

const name = "Alice";
const greeting = `Hello, ${name}!`;

3. 解构赋值 (Destructuring Assignment)

解构赋值让我们能够快速提取数组或对象中的值,提升代码可读性。

// 对象解构
const user = { name: "Bob", age: 25 };
const { name, age } = user;

// 数组解构
const numbers = [1, 2, 3];
const [first, second] = numbers;

4. 扩展运算符 (Spread Operator)

扩展运算符用于数组和对象的合并或复制,使得操作更加简洁。

const array1 = [1, 2, 3];
const array2 = [...array1, 4, 5]; // [1, 2, 3, 4, 5]

const obj1 = { a: 1 };
const obj2 = { ...obj1, b: 2 }; // { a: 1, b: 2 }

5. 默认参数 (Default Parameters)

函数参数可以设置默认值,避免未传入参数导致的错误。

const multiply = (x, y = 1) => x * y;

6. 模块化 (Modules)

ES6 引入了模块化,使得代码可以分割为多个文件,通过 export 和 import 进行管理。

// module.js
export const PI = 3.14;

// main.js
import { PI } from './module.js';

7. Promise

Promise 对象用于处理异步操作,提供了更好的错误处理和链式调用能力。

const fetchData = () => {
    return new Promise((resolve, reject) => {
        // 模拟异步请求
        setTimeout(() => resolve("数据加载成功"), 1000);
    });
};

fetchData().then(data => console.log(data));

8. 类 (Classes)

ES6 引入了类的概念,简化了对象的构造和继承的语法。

class Animal {
    constructor(name) {
        this.name = name;
    }

    speak() {
        console.log(`${this.name} makes a noise.`);
    }
}

const dog = new Animal('Dog');
dog.speak();

9. 异步函数 (async/await)

async/await 使得处理异步操作更加直观,代码看起来更像同步代码。

const getData = async () => {
    const response = await fetch('https://api.example.com/data');
    const data = await response.json();
    return data;
};

getData().then(data => console.log(data));

10. Set 和 Map

这两个数据结构可以更方便地处理唯一值和键值对。

const uniqueNumbers = new Set([1, 2, 2, 3]); // Set { 1, 2, 3 }
const map = new Map();
map.set('key1', 'value1');
console.log(map.get('key1')); // "value1"

11. WeakMap 和 weakSet

WeakSet 是一种类似于 Set 的集合类型,用于存储弱引用的对象。它具有以下特点:

  • 只能存储对象,基本类型(如字符串、数字、布尔值等)不能存储。
  • 存储的对象是弱引用,这意味着,如果没有其他对该对象的引用,垃圾回收器可以回收该对象,即使它仍在 WeakSet 中。
// 创建一个 WeakSet
const weakSet = new WeakSet();

const obj1 = { id: 1 };
const obj2 = { id: 2 };

// 添加对象到 WeakSet
weakSet.add(obj1);
weakSet.add(obj2);

// 检查对象是否在 WeakSet 中
console.log(weakSet.has(obj1)); // true
console.log(weakSet.has(obj2)); // true

// 删除对象
weakSet.delete(obj1);
console.log(weakSet.has(obj1)); // false

// WeakSet不支持迭代,因此不能使用 forEach,也不能转换为数组

WeakMap 是一种类似于 Map 的数据结构,用于存储键值对。它具有以下特点:

  • 键必须是对象,基本类型不能作为键。
  • 键是弱引用,这意味着如果没有其他对该键的引用,垃圾回收器可以回收该键及其关联的值。
// 创建一个 WeakMap
const weakMap = new WeakMap();

const obj1 = {};
const obj2 = {};

// 设置键值对
weakMap.set(obj1, 'Value associated with obj1');
weakMap.set(obj2, 'Value associated with obj2');

// 获取值
console.log(weakMap.get(obj1)); // Value associated with obj1
console.log(weakMap.get(obj2)); // Value associated with obj2

// 检查键是否存在
console.log(weakMap.has(obj1)); // true

// 删除键值对
weakMap.delete(obj1);
console.log(weakMap.has(obj1)); // false

// WeakMap不支持迭代,因此不能使用 forEach,也不能转换为数组
  • WeakSet 和 WeakMap 都允许存储对象,并且对这些对象的引用不是强引用。这意味着当没有其他引用指向这些对象时,它们可以被垃圾回收。
  • WeakSet 只能存储对象,而 WeakMap 则是以对象作为键并可以存储与之关联的任意值。
  • 由于 WeakSet 和 WeakMap 的特性,它们不支持迭代(比如没有 forEach 方法),也不能被转换为数组或其他可遍历的集合。

这些特性使 WeakSet 和 WeakMap 在需要频繁创建和销毁对象、并希望轻松管理内存时非常有用。

12. Symbol

Symbol 是一种新的原始数据类型,表示独一无二的值,常用于对象属性的唯一标识。

const uniqueSymbol = Symbol('description');

13. Iterators 和 Generators

迭代器提供了一种访问集合元素的统一接口,生成器函数(使用 function* 定义)可以控制函数的执行进程。

function* generatorFunc() {
    yield 1;
    yield 2;
}

const gen = generatorFunc();
console.log(gen.next().value); // 1

14. Proxy 和 Reflect

Proxy 允许你定义一个对象的代理,这样你可以拦截和自定义基本操作(如属性访问、赋值、调用等)。Proxy 接受两个参数:

  • target:要代理的原始对象。
  • handler:一个对象,定义了捕获器(interceptors),用于拦截代理对象的基本操作。

Reflect 是一个内置对象,提供了用于操作对象的方法,这些方法与 Proxy 的拦截方法相对应。Reflect 的方法通常用于在代理中调用,以确保对目标对象操作的一致性。

const target = {
    name: "Alice",
    age: 28
};

const handler = {
    get(target, property) {
        console.log(`Accessing property: ${property}`);
        // 使用 Reflect 获取
        return Reflect.get(target, property);
    },
    set(target, property, value) {
        console.log(`Updating property: ${property} to ${value}`);
        // 使用 Reflect 设置
        return Reflect.set(target, property, value);
    },
    deleteProperty(target, property) {
        console.log(`Deleting property: ${property}`);
        // 使用 Reflect 删除
        return Reflect.deleteProperty(target, property);
    }
};

const proxy = new Proxy(target, handler);

console.log(proxy.name); // Accessing property: name \n Alice
proxy.age = 30;          // Updating property: age to 30
console.log(proxy.age);  // Accessing property: age \n 30
delete proxy.name;      // Deleting property: name
console.log(proxy.name); // Accessing property: name \n undefined

15. let 和 const

let 和 const 是 ES6(ECMAScript 2015)中引入的用于声明变量的两种命令。它们相较于传统的 var 关键字有着更严格的作用域管理和更清晰的变量行为。

let
概述
  • let 用于声明变量,具有块级作用域,也就是说,它仅在定义它的代码块内有效。
  • let 声明的变量可以被重新赋值。
{
    let x = 10;
    console.log(x); // 10
}
console.log(x); // ReferenceError: x is not defined

let y = 5;
y = 15; // 合法的重新赋值
console.log(y); // 15
2. const
概述
  • const 用于声明常量,同样具有块级作用域。声明使用 const 的变量后,必须在声明时初始化。
  • const 声明的变量不能被重新赋值。需要注意的是,const 只保证变量的引用不可变,若引用的是对象,仍然可以修改对象的属性。
{
    const z = 20;
    console.log(z); // 20
}
console.log(z); // ReferenceError: z is not defined

const a = 30;
// a = 40; // TypeError: Assignment to constant variable.

const obj = { name: "Alice" };
obj.name = "Bob"; // 合法,修改对象属性
console.log(obj.name); // Bob
3. 总结对比
  • 作用域

    • let 和 const 都是块级作用域,而 var 是函数作用域。
  • 赋值

    • let 允许变量重新赋值。
    • const 不允许重新赋值,必须初始化。
  • 使用建议

    • 使用 const 声明常量,明确变量不应该被修改,能提高代码的可维护性。
    • 使用 let 声明会被修改的变量。
4. 注意事项
  • 使用 let 和 const 时会存在 "暂时性死区" 的现象。这意味着在变量声明之前访问变量会导致错误。
console.log(b); // ReferenceError: Cannot access 'b' before initialization
let b = 10;

总结来说,let 和 const 提供了更严格的变量管理,鼓励使用块级作用域,增强了代码的安全性和可维护性。在现代 JavaScript 开发中,推荐使用 let 和 const,避免使用 var

16. 迭代器和生成器

迭代器

迭代器是一个对象,它提供了一种机制,用于逐个访问一个集合(如数组、对象等)中的元素,而不需要暴露集合的内部结构。迭代器的核心在于它实现了一个方法——next(),每次调用此方法都会返回一个包含当前元素的对象。这个对象通常具有两个属性:

  • value:当前迭代的值。
  • done:一个布尔值,表示迭代是否完成。如果还有更多的元素可供迭代,则为 false;如果没有更多元素,则为 true
const myIterator = {
    current: 0,
    last: 5,
    
    next: function() {
        if (this.current < this.last) {
            return { value: this.current++, done: false };
        } else {
            return { value: undefined, done: true };
        }
    }
};

// 使用迭代器 从 `0` 循环到 `4`,使用 `next()` 方法返回当前值并递增
console.log(myIterator.next()); // { value: 0, done: false }
console.log(myIterator.next()); // { value: 1, done: false }
console.log(myIterator.next()); // { value: 2, done: false }
console.log(myIterator.next()); // { value: 3, done: false }
console.log(myIterator.next()); // { value: 4, done: false }
console.log(myIterator.next()); // { value: undefined, done: true }

生成器

生成器是一种特殊的函数,使用 function* 语法定义,可以在执行过程中暂停和恢复。这使得生成器函数能够生成一个迭代器,而不需要显式地实现 next() 方法。生成器函数中可以使用 yield 关键字来返回一个值,每当调用生成器的 next() 方法时,函数会从上次暂停的地方继续执行,直到遇到下一个 yield 或者函数结束。

function* myGenerator() {
    let current = 0;
    const last = 5;
    
    while (current < last) {
        yield current++;
    }
}

// 使用生成器 在其中使用 `yield` 关键字来生成值 每次调用 `next()` 方法时,会返回一个对象,包含当前值和 `done` 状态
const gen = myGenerator();

console.log(gen.next()); // { value: 0, done: false }
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: 4, done: false }
console.log(gen.next()); // { value: undefined, done: true }

对比

1. 箭头函数和普通函数的区别

  • 语法:箭头函数的语法更简洁,适合短小的函数。
  • this 绑定:箭头函数不绑定自己的 this,自动继承外层函数的 this
  • 构造函数:箭头函数不能被用作构造函数(不能使用 new 关键字创建实例)。
  • arguments:箭头函数没有自己的 arguments 对象(箭头函数不具有自己的 arguments 对象。如果需要访问参数,可以使用 rest 参数语法)。
  • 不能使用 super 和 new.target(在箭头函数内部,不能使用 super 和 new.target,这意味着箭头函数不能用于类的继承)。
  • 隐式返回:箭头函数可使用隐式返回(当函数体只有一行代码时,可以省略 return 和 {})。

2. exportexport defaultimport 和 import * as xxx 的区别

  • export:用于导出多个命名的变量、函数或类。
  • export default:用于导出一个默认值 (可以是变量、函数或类),每个模块只能有一个默认导出。
  • import:用于引入从模块中导出的命名或默认的值。
  • import * as xxx:将模块中所有的命名导出引入,并收集在指定的对象中,方便通过这个对象访问所有导出的内容。

3. let、const、var 的区别

  • 作用域var 是函数作用域,let 和 const 是块级作用域。
  • 重新赋值var 和 let 可以重新赋值,const 不允许重新赋值。
  • 提升var 允许在声明之前使用,但值为 undefinedlet 和 const 在被初始化之前不能访问。
  • 重复声明var 允许重复声明,let 和 const 不允许

4. proxy 与 defineproperty 的区别

功能与用途

  • Proxy

    • Proxy 是一种用于创建对象的代理,它可以拦截并自定义对目标对象基本操作(如属性访问、赋值、删除、函数调用等)的行为。
    • 支持对整个对象的操作,包括对嵌套对象的属性及方法的拦截。
    • 可以用来实现数据绑定、监听变化、访问控制等复杂逻辑。
  • Object.defineProperty

    • Object.defineProperty 用于直接在对象上定义新属性或修改现有属性并返回该对象。它可以控制属性的描述符,比如可写性、可枚举性和可配置性。
    • 适用于设置单个属性的特性,而不适用于对整个对象的拦截。

监听能力

  • Proxy

    • Proxy 可以拦截多种操作,例如获取(get)、设置(set)、删除(deleteProperty)、调用(apply)等,可以更广泛地管理对象的操作。
  • Object.defineProperty

    • 主要用来定义或修改单个属性,无法拦截属性的获取或设置操作,只能修改该属性的特性。

多个属性与嵌套对象

  • Proxy

    • 可以对整个对象及其所有嵌套属性进行操作和拦截,非常灵活。
  • Object.defineProperty

    • 对于属性的操作是单一的,不能批量定义或修改多个属性,也不能直接应用于嵌套对象。

性能

  • Proxy

    • 在某些操作中可能会带来额外的性能开销,因为每次操作都需要通过拦截器处理。
  • Object.defineProperty

    • 由于直接操作对象属性,对于单个属性的定义和修改性能较高。

兼容性

  • Object.defineProperty 具有更好的浏览器兼容性,适用于需要广泛支持的情况。
  • Proxy 由于不支持老旧浏览器(尤其是 IE),在需要兼容性时应谨慎使用,但可以用来进行更复杂的对象操作。对于现代浏览器的应用开发,一般推荐使用 Proxy,而在需要支持较旧环境时优先考虑 Object.defineProperty

5. WeakSet 和 WeakMap 和 Map 和 Set 的区别

特性SetWeakSetMapWeakMap
存储类型任何类型仅限对象任何类型仅限对象(作为键)
引用类型强引用弱引用强引用弱引用
是否支持迭代支持不支持支持不支持
是否可以用基本类型可以不可以可以不可以
键值对键值对键值对

使用场景

  • Set 和 WeakSet

    • Set 适用于需要存储唯一值的场景,如去重。WeakSet 适用于需要存储对对象的弱引用,并跟踪哪些对象仍在使用,用于实现一些内存管理的功能。
  • Map 和 WeakMap

    • Map 适用于需要用任何类型的键存储和访问数据的情况,支持可迭代操作。WeakMap 则适合在需要存储对象的元数据或缓存时使用,并希望避免因对象的引用而导致的内存泄漏。

6. 迭代器和生成器的区别

迭代器

  1. 定义:迭代器是一个对象,它实现了 next() 方法,每次调用这个方法时都返回一个对象,该对象包含两个属性:

    • value:当前迭代的值。
    • done:一个布尔值,表示迭代是否完成。
  2. 实现:为了创建一个迭代器,你需要手动实现一个对象,并定义 next() 方法。

  3. 用途:迭代器提供了一种统一的遍历方法,可以用于任何可迭代对象(如数组、字符串、Map、Set等)。

生成器

  1. 定义:生成器是一种特殊类型的函数,使用 function* 语法定义。它可以暂停和恢复执行,同时会自动生成迭代器对象。
  2. 实现:通过 yield 关键字,可以在生成器函数中暂停执行并返回一个值。下一次调用 next() 方法时,会从上一次暂停的地方恢复执行。
  3. 用途:生成器可以方便地生成序列、处理异步操作等,提供了比常规函数更灵活的控制流。

额外的一些常用的方法和特性

字符串相关

1. startsWith()

检查字符串是否以指定的字符序列开头。

const str = 'Hello, world!';
console.log(str.startsWith('Hello')); // true
console.log(str.startsWith('world')); // false

2. endsWith()

检查字符串是否以指定的字符序列结尾。

console.log(str.endsWith('world!')); // true
console.log(str.endsWith('Hello')); // false

3. includes()

判断字符串是否包含指定的字符序列。

console.log(str.includes('lo')); // true
console.log(str.includes('world')); // true
console.log(str.includes('JavaScript')); // false

4. repeat()

创建一个新字符串,表示将原字符串重复指定次数。

const repeatedStr = 'abc'.repeat(3);
console.log(repeatedStr); // 'abcabcabc'

5. padStart() 和 padEnd()

这两个方法用于在当前字符串的两端填充指定的字符,使最终字符串达到指定的长度。

  • padStart(targetLength, padString):在当前字符串的开头填充字符。
const str1 = '5';
console.log(str1.padStart(2, '0')); // '05'
  • padEnd(targetLength, padString):在当前字符串的结尾填充字符。
const str2 = '5';
console.log(str2.padEnd(2, '0')); // '50'

6. String.raw()

这是一个标签模板字面量的辅助函数,用于处理模板字符串中的转义字符。

const rawStr = String.raw`Hello\nWorld`;
console.log(rawStr); // 'Hello\nWorld'

对象相关

1. 对象字面量增强

  • 简写属性:在对象字面量中,如果属性名和变量名相同,可以省略属性名。
const x = 1;
const y = 2;
const obj = { x, y }; // 等同于 { x: x, y: y }
console.log(obj); // { x: 1, y: 2 }
  • 方法简写:定义对象的方法时,可以省略 function 关键字。
const obj = {
    greet() {
        console.log('Hello!');
    }
};

obj.greet(); // 'Hello!'
  • 计算属性名:可以使用表达式作为属性名。
const prop = 'name';
const obj = {
    [prop]: 'Alice'
};
console.log(obj.name); // 'Alice'

2. Object.is()

用于判断两个值是否严格相等,它比 === 更加严格。例如,NaN 与 NaN 被认为是相等的,而 +0 和 -0 被认为是不相等的。

console.log(Object.is(NaN, NaN)); // true
console.log(Object.is(+0, -0)); // false
console.log(Object.is('a', 'a')); // true

3. Object.assign()

用于将一个或多个源对象的可枚举属性复制到目标对象中,返回目标对象。

const target = { a: 1 };
const source = { b: 2 };

Object.assign(target, source);
console.log(target); // { a: 1, b: 2 }

4. Object.entries()

将一个对象的可枚举属性转换为一个二维数组,其中每个元素是一个 [key, value] 对。

const obj = { a: 1, b: 2 };
const entries = Object.entries(obj);
console.log(entries); // [['a', 1], ['b', 2]]

5. Object.values()

返回一个包含对象自身可枚举属性值的数组。

const obj = { a: 1, b: 2 };
const values = Object.values(obj);
console.log(values); // [1, 2]

6. Object.freeze()

使一个对象成为不可变的,不能更改其属性(即添加、删除或修改属性)。

const obj = { a: 1 };
Object.freeze(obj);
obj.a = 2; // 无效
console.log(obj.a); // 1

7. Object.seal()

将一个对象密封,不能添加或删除属性,但可以修改现有属性的值。

const obj = { a: 1 };
Object.seal(obj);
obj.a = 2; // 可以修改
delete obj.a; // 无效
console.log(obj.a); // 2

8. Object.getOwnPropertyDescriptors()

返回一个对象的所有属性描述符。

const obj = { a: 1 };
const descriptors = Object.getOwnPropertyDescriptors(obj);
console.log(descriptors); // { a: { value: 1, writable: true, enumerable: true, configurable: true } }

数值相关

1. Number.isFinite()

用于检查一个值是否是有限的数字。与全局的 isFinite() 方法不同,它不会在类型转换上进行处理。

console.log(Number.isFinite(10));           // true
console.log(Number.isFinite('10'));         // false
console.log(Number.isFinite(NaN));          // false
console.log(Number.isFinite(Infinity));     // false

2. Number.isInteger()

用于检查一个值是否是一个整数。

console.log(Number.isInteger(4));           // true
console.log(Number.isInteger(4.1));         // false
console.log(Number.isInteger('4'));         // false
console.log(Number.isInteger(NaN));         // false

3. Number.isSafeInteger()

用于检查一个值是否是一个安全的整数。安全整数是指大于或等于 -(2^53 - 1) 并且小于或等于 2^53 - 1 的整数。

console.log(Number.isSafeInteger(3));                     // true
console.log(Number.isSafeInteger(Math.pow(2, 53)));      // false
console.log(Number.isSafeInteger(Math.pow(2, 53) - 1));  // true

4. Number.MAX_SAFE_INTEGER 和 Number.MIN_SAFE_INTEGER

这两个属性表示 JavaScript 中安全整数的最大和最小值。

console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
console.log(Number.MIN_SAFE_INTEGER); // -9007199254740991

5. Math.trunc()

返回一个数值的整数部分,通过删除小数部分。

console.log(Math.trunc(4.9));  // 4
console.log(Math.trunc(-4.9)); // -4
console.log(Math.trunc(4));    // 4

6. Math.sign()

用于判断一个数的符号。返回值为 1 表示正数,-1 表示负数,0 表示零,NaN 表示不是一个数字。

console.log(Math.sign(5));   // 1
console.log(Math.sign(-5));  // -1
console.log(Math.sign(0));   // 0
console.log(Math.sign(-0));  // -0
console.log(Math.sign(NaN)); // NaN

7. Math.cbrt()

返回一个数的立方根。

console.log(Math.cbrt(27));  // 3
console.log(Math.cbrt(-27)); // -3

8. Math.hypot()

计算所有参数的平方和的平方根,可以用于计算欧几里得距离。

console.log(Math.hypot(3, 4));             // 5
console.log(Math.hypot(1, 2, 3));          // 3.7416573867739413
console.log(Math.hypot(3, 4, 'five'));     // 5

9. Math.imul()

用于计算两个 32 位整数的乘法,结果也是一个 32 位整数。

console.log(Math.imul(2, 4));  // 8
console.log(Math.imul(0xFFFFFFFF, 5)); // -5,因为结果超出了 32 位整数范围

数组相关

1. 数组的解构赋值

允许从数组中提取值到变量中,这样可以简化代码。

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

2. 数组的扩展运算符 ...

扩展运算符可以展开数组,常用于函数参数、数组连接等场景。

const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [...arr1, ...arr2];
console.log(arr3); // [1, 2, 3, 4, 5, 6]

3. Array.from()

该方法可以将类数组对象或可迭代对象转换为数组。

const str = 'hello';
const arr = Array.from(str);
console.log(arr); // ['h', 'e', 'l', 'l', 'o']

4. Array.of()

用于创建一个新数组,接受任意数量的参数并将它们作为数组元素。

const arr = Array.of(7, 8, 9);
console.log(arr); // [7, 8, 9]

5. copyWithin()

用于在数组内部复制指定位置的元素到另一个位置(会覆盖原有元素),而不改变数组长度。

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

6. find() 和 findIndex()

find() 方法用于查找数组中满足提供的测试函数的第一个元素,而 findIndex() 则返回满足条件的第一个元素的索引。

const arr = [5, 12, 8, 130, 44];
const found = arr.find(element => element > 10);
console.log(found); // 12

const index = arr.findIndex(element => element > 10);
console.log(index); // 1

7. fill()

该方法用于用一个静态值填充数组中的指定元素,改变原数组。

const arr = new Array(3).fill(0); // [0, 0, 0]
console.log(arr);

8. entries()

返回一个新的 Array Iterator 对象,该对象包含数组中每个索引的键值对。

const arr = ['a', 'b', 'c'];
const iterator = arr.entries();

for (const [index, element] of iterator) {
    console.log(index, element); 
}
// 输出:
// 0 'a'
// 1 'b'
// 2 'c'

9. includes()

判断数组是否包含某个元素,返回布尔值。

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

10. keys() 和 values()

  • keys() 方法返回一个新的 Array Iterator 对象,该对象包含数组中每个索引的键。
  • values() 方法返回一个新的 Array Iterator 对象,该对象包含数组中每个索引的值。
const arr = ['a', 'b', 'c'];

for (const key of arr.keys()) {
    console.log(key); // 0 1 2
}

for (const value of arr.values()) {
    console.log(value); // 'a' 'b' 'c'
}

运算符相关

  1. 解构赋值(Destructuring Assignment):允许从数组或对象中提取数据并直接分配给变量。

    const [a, b] = [1, 2];
    console.log(a); // 1
    console.log(b); // 2
    
    const {name, age} = {name: 'Alice', age: 30};
    console.log(name); // Alice
    
  2. 扩展运算符(Spread Operator)  (...):可以将数组或对象的内容展开

    const arr1 = [1, 2, 3];
    const arr2 = [...arr1, 4, 5];
    console.log(arr2); // [1, 2, 3, 4, 5]
    
    const obj1 = {x: 10, y: 20};
    const obj2 = {...obj1, z: 30};
    console.log(obj2); // {x: 10, y: 20, z: 30}
    
  3. 剩余参数(Rest Parameters)(...):在函数定义中收集传递给函数的多余参数到一个数组中

    function sum(...numbers) {
      return numbers.reduce((acc, curr) => acc + curr, 0);
    }
    console.log(sum(1, 2, 3, 4)); // 10
    
  4. 空值合并运算符(Nullish Coalescing Operator)  (??):虽然不是ES6的一部分,但在ES2020中引入,用于处理nullundefined

    const value = null ?? 'default';
    console.log(value); // 'default'
    
  5. 可选链式调用(Optional Chaining)  (?.):同样不是ES6的特性,但在ES2020中引入,允许安全地访问深层嵌套的对象属性

    const user = {name: 'Alice'};
    console.log(user.address?.street); // undefined