javascript中symbol使用场景及使用方法

Symbol 是 JavaScript ES6 引入的一种新数据类型,表示独一无二的值。它是 JavaScript 的基本类型之一(除了 StringNumberBooleanNullUndefinedObject 之外)。Symbol 值是唯一的,即使两个 Symbol 具有相同的描述,它们的值也是不同的。Symbol 的主要用处是创建对象的唯一属性名,以避免属性名冲突,特别是在大型项目或库中非常有用。

1. Symbol 的基本使用

const sym1 = Symbol('description');
const sym2 = Symbol('description');

console.log(sym1 === sym2); // false

即使 sym1sym2 都有相同的描述('description'),它们依然是不同的值。

2. Symbol 作为对象的属性键

在 JavaScript 对象中,通常属性名是字符串。但有时可能会有两个不同的模块使用相同的属性名,导致冲突。Symbol 可以用作对象的唯一属性键,避免这种冲突。

const sym = Symbol('myKey');
const obj = {
  [sym]: 'value associated with symbol'
};

console.log(obj[sym]); // "value associated with symbol"
console.log(obj['myKey']); // undefined
  • 这里的 sym 是唯一的,即使有其他对象也用类似的描述 'myKey',它们也不会冲突。

3. 隐藏属性

因为 Symbol 属性不会出现在常规的对象属性遍历操作中(如 for...inObject.keys()),它可以用来定义一些“隐藏”的或“内部”的属性,防止外部不小心修改。

const sym = Symbol('hiddenProperty');
const obj = {
  [sym]: 'secret',
  normalProp: 'visible'
};

console.log(Object.keys(obj)); // ["normalProp"]
console.log(Object.getOwnPropertyNames(obj)); // ["normalProp"]
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(hiddenProperty)]

虽然 Symbol 属性不会被 Object.keysObject.getOwnPropertyNames 枚举到,但可以通过 Object.getOwnPropertySymbols() 获取它们。

4. 全局 Symbol

有时你可能希望在不同模块或文件中共享同一个 Symbol,这时可以使用 Symbol.for() 方法。它在全局 Symbol 注册表中查找并返回一个符号,如果该符号不存在则会创建它。

const sym1 = Symbol.for('sharedSymbol');
const sym2 = Symbol.for('sharedSymbol');

console.log(sym1 === sym2); // true
  • Symbol.for() 不同于 Symbol(),前者会检查全局 Symbol 注册表,而后者每次都会创建一个新的 Symbol。

此外,可以使用 Symbol.keyFor() 来获取全局 Symbol 的键:

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

5. 常见场景

5.1 避免对象属性名称冲突

在一些大型项目中,不同的模块或第三方库可能会向同一个对象添加属性,如果属性名冲突,可能会覆盖或破坏彼此的逻辑。通过 Symbol,我们可以确保每个属性都是唯一的。

const library1 = {
  [Symbol('id')]: 123
};

const library2 = {
  [Symbol('id')]: 456
};

console.log(library1[Symbol('id')]); // undefined (无法通过其他 Symbol 访问)
5.2 模拟私有属性

虽然 JavaScript 没有真正的私有属性,但可以使用 Symbol 来实现类似于“私有”的属性,因为它们不会出现在常规的属性枚举中。

const createPerson = () => {
  const age = Symbol('age');
  return {
    setAge(value) {
      this[age] = value;
    },
    getAge() {
      return this[age];
    }
  };
};

const person = createPerson();
person.setAge(30);
console.log(person.getAge()); // 30
  • 通过 Symbol,可以模拟出一个不易被外部访问或修改的“私有”属性。
5.3 迭代器 (Iterators)

Symbol.iterator 是内置的 Symbol,它允许对象自定义迭代行为。可以通过为对象定义 Symbol.iterator,使其可以被 for...of 循环迭代。

const myIterable = {
  [Symbol.iterator]: function* () {
    yield 1;
    yield 2;
    yield 3;
  }
};

for (let value of myIterable) {
  console.log(value); // 1, 2, 3
}
  • Symbol.iterator 是 ES6 引入的,用于使对象成为可迭代的。
5.4 元编程

Symbol 还可以用作元编程的一部分,通过覆盖语言内部行为。以下是一些内置的 Symbol,用于修改对象的默认行为:

  • Symbol.iterator:用于定义对象的默认迭代器。
  • Symbol.toStringTag:用于自定义 Object.prototype.toString 返回的内容。
  • Symbol.hasInstance:自定义 instanceof 操作符的行为。
class MyClass {
  static [Symbol.hasInstance](instance) {
    return typeof instance === 'string';
  }
}

console.log('hello' instanceof MyClass); // true
  • 在上面的例子中,MyClass 自定义了 instanceof 的行为,使其返回 true 只要对象是一个字符串。

6. 总结

  • Symbol 是一种创建独一无二值的数据类型,通常用于避免属性名冲突。
  • Symbol 常用于对象的属性键,尤其是在库或框架中,用来定义不会被意外覆盖的“隐藏”属性。
  • Symbol.forSymbol.keyFor 允许在全局共享 Symbol
  • 通过 Symbol,可以模拟私有属性,并通过内置的 Symbol 修改对象的内置行为,如 Symbol.iteratorSymbol.toStringTag 等。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端李易安

打赏1元鼓励作者

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值