JavaScript进阶篇:你真的了解symbol吗?

161 阅读4分钟

你真的了解symbol嘛?

在我刚学JavaScript的时候,Symbol这种数据类型确实没有特别在意过,项目中很少使用。直到再次了解JavaScript之时,这次才刻意的注意到了Symbol。下面我们就来详细的了解一下symbol。

symbol是什么?

Symbol是 JavaScript 中的一种数据类型,它是独一无二且不可改变的值。它们可以用作对象属性的键,因为它们总是独一无二的。每个 Symbol 都有一个描述,但是它不是用于识别该 Symbol 的,而只是为了调试目的。

使用语法:Symbol([description]),其中 description 是可选的字符串,描述 Symbol 的目的。

const symbol1 = Symbol();
const symbol2 = Symbol('symbol2');
console.log(typeof symbol1);  // "symbol"
console.log(symbol1.toString());  // "Symbol()"
console.log(symbol2.toString());  // "Symbol(symbol2)"

symbol的基础用法

1.创建一个 符号

const symbol = Symbol('symbol');

2.使用 Symbol 值作为对象键:

const obj = { [symbol]: 'value' };
console.log(obj[symbol]);  // "value"

3.使用 'typeof

console.log(typeof symbol);  // "symbol"

4.使用 'Object.get'获取对象的所有 Symbol 键:

const symbol1 = Symbol('symbol1');
const symbol2 = Symbol('symbol2');
const obj = { [symbol1]: 'value1', [symbol2]: 'value2' };
console.log(Object.getOwnPropertySymbols(obj));  // [Symbol(symbol1), Symbol(symbol2)]

5.使用 'Symbol.for'

const symbol1 = Symbol.for('symbol');
const symbol2 = Symbol.for('symbol');
console.log(symbol1 === symbol2);  // true

6.使用Symbol.keyFor获取全局 Symbol 的标识符: `

const symbol = Symbol.for('symbol');
console.log(Symbol.keyFor(symbol));  // "symbol"

以上是 Symbol 类型的基本用法,其中:

  • 创建 Symbol 值时,可以通过传入字符串参数来为 Symbol 添加描述信息;
  • 使用 Symbol 值作为对象键时,可以保证该键的唯一性,防止与其他键冲突;
  • 'Object.getOwnPropertySymb方法可以用来获取对象的所有 Symbol 键;
  • 使用Symbol.for创建的全局 Symbol 值可以在多处使用,并且总是相等;
  • Symbol.keyFor方法可以用来获取全局

symbol的常用内置符号

Symbol.iterator

Symbol.iterator 是一个内置的 Symbol 值,用于定义对象的默认遍历器(default iterator)。

当使用 for...of 循环遍历一个对象时,如果该对象定义了 Symbol.iterator 属性,则该属性的值会被用作该对象的默认遍历器。

举个例子:

let myArray = [1, 2, 3];
let it = myArray[Symbol.iterator]();

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

上面代码中,我们使用 Symbol.iterator 访问了数组的默认遍历器,并通过遍历器逐一遍历了数组的元素。

Symbol.toStringTag

Symbol.toStringTag 是一个内置的 Symbol 值,用于定义对象的字符串表现形式。

通过设置对象的 Symbol.toStringTag 属性,开发人员可以控制该对象在使用 Object.prototype.toString.call 方法时的字符串输出。

例如:

class MyClass {
  get [Symbol.toStringTag]() {
    return 'MyClass';
  }
}

let myObj = new MyClass();
console.log(Object.prototype.toString.call(myObj)); 
// '[object MyClass]'

上面代码中,我们定义了一个类 MyClass,并通过设置 Symbol.toStringTag 属性,使得该类的实例在调用 Object.prototype.toString 方法时,输出的字符串为 [object MyClass]

Symbol.hasInstance

Symbol.hasInstance 是一个内置的 Symbol 值,用于定义一个类的实例判定方法。

通过设置类的 Symbol.hasInstance 属性,开发人员可以自定义类的实例判定逻辑,并控制 instanceof 运算符的行为。

例如:

class MyClass {
  static [Symbol.hasInstance](instance) {
    return instance.num === 42;
  }
}

let myObj = { num: 42 };
console.log(myObj instanceof MyClass); // true

上面代码中,我们定义了一个类 MyClass,并通过设置 Symbol.hasInstance 属性,控制了该类的实例判定逻辑。当一个对象的 num 属性为 42 时,它就是 MyClass 的实例,因此 myObj instanceof MyClass 的结果为 true

Symbol.species

Symbol.species 是一个内置的 Symbol 值,用于指定一个对象的构造函数,在该对象作为某个方法的返回值时,用于构造新的对象。

通过设置类的 Symbol.species 属性,开发人员可以控制该类的衍生类,以适应多种使用场景。

例如:

class MyArray extends Array {
  static get [Symbol.species]() {
    return Array;
  }
}

let myArr = new MyArray(1, 2, 3);
let mappedArr = myArr.map(x => x * x);
console.log(mappedArr instanceof MyArray); // false
console.log(mappedArr instanceof Array);   // true

上面代码中,我们定义了一个类 MyArray,继承自内置类 Array。并通过设置 Symbol.species 属性,使得该类的衍生类为 Array。当调用 myArr.map 方法后,返回的 mappedArr 对象为内置类 Array 的实例,而非 MyArray 的实例。

Symbol.isConcatSpreadable

Symbol.isConcatSpreadable 是一个内置的 Symbol 值,用于指定一个对象在 Array.prototype.concat 方法中是否可以展开。

当一个对象的 Symbol.isConcatSpreadable 属性为 true 时,该对象在 Array.prototype.concat 方法中会被展开,否则该对象会作为一个整体被添加到新数组的末尾。

例如:

let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let arr3 = [7, 8, 9];
arr2[Symbol.isConcatSpreadable] = false;

let newArr = arr1.concat(arr2, arr3);
console.log(newArr); // [1, 2, 3, [4, 5, 6], 7, 8, 9]

上面代码中,我们定义了三个数组 arr1arr2arr3,并将 arr2Symbol.isConcatSpreadable 属性设置为 false。调用 Array.prototype.concat 方法后,arr2 不会被展开,而作为一个整体被添加到新数组的末尾。

Symbol.unscopables

Symbol.unscopables 是一个内置的 Symbol 值,它是一个对象属性,指定了该对象的哪些属性不能被 with 语句查找到。

例如:

let obj = {a: 1, b: 2};
obj[Symbol.unscopables] = {a: false, b: true};

with (obj) {
  console.log(a); // 1
  console.log(b); // ReferenceError: b is not defined
}

上面代码中,我们定义了一个对象 obj,并将它的 Symbol.unscopables 属性设置为 {a: false, b: true}。在 with 语句中,a 属性可以被查找到,但 b 属性不能被查找到,将会导致错误。

另外,其他更多Symbol属性和特性可以查阅相关文档和书籍。

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情