ES6的Symbol详解 

Symbol 是什么?

Symbol 是一个基本类型,用于生成唯一的标识符。每次调用 Symbol() 函数,都会创建一个新的、唯一的 Symbol 值,即使传递相同的描述(description),它们也不会相等。

let symbol1 = Symbol('example');
let symbol2 = Symbol('example');
console.log(symbol1 === symbol2); // false,每个 Symbol 都是唯一的

如何创建 Symbol

可以使用 Symbol() 函数创建 Symbol,它可以带一个可选的描述(通常用于调试目的,不影响唯一性)。

let sym1 = Symbol();
let sym2 = Symbol('description');
console.log(sym1); // Symbol()
console.log(sym2); // Symbol(description)

Symbol 作为对象属性的键

Symbol 常用于对象属性的键,因为它是唯一的,避免了属性名冲突问题。普通的字符串属性名可能会被重写,但 Symbol 保证唯一性。

let uniqueKey = Symbol('unique');
let myObject = {
  [uniqueKey]: 'value'
};

console.log(myObject[uniqueKey]); // 'value'
console.log(myObject.uniqueKey);  // undefined,因为 Symbol 不是字符串

Symbol 的特性

  • 唯一性:每一个 Symbol 都是唯一的,即使描述相同也不相等。
  • 不可改变:Symbol 是不可变的,不像对象可以更改内容。
  • 非枚举属性:使用 Symbol 作为属性名时,该属性默认是不可枚举的,不会被 for...inObject.keys() 枚举。可以使用Object.getOwnPropertySymbols获取
let hiddenKey = Symbol('hidden');
let person = {
  name: 'John',
  age: 30,
  [hiddenKey]: 'Secret'
};

// 使用 for...in 枚举属性时不会显示 Symbol
for (let key in person) {
  console.log(key); // 'name', 'age'
}

console.log(Object.keys(person)); // ['name', 'age']
console.log(Object.getOwnPropertySymbols(person)); // [Symbol(hidden)]

Symbol 的内置方法和属性

Symbol.for()Symbol.keyFor()

Symbol.for() 方法可以在全局注册表中创建和重用 Symbol,以便不同的模块中可以共享同一个 Symbol。而 Symbol.keyFor() 可以通过全局 Symbol 查找其键。只针对Symbol.for() 方法创建的Symbol才能找到其键。

let globalSym1 = Symbol.for('shared');
let globalSym2 = Symbol.for('shared');
console.log(globalSym1 === globalSym2); // true,引用的是同一个 Symbol

console.log(Symbol.keyFor(globalSym1)); // 'shared'
console.log(Symbol.keyFor(Symbol('not shared'))); // undefined

Symbol 内置的静态属性

Symbol 提供了一些内置的静态属性,称为内置 Symbol,通常用于 JavaScript 内部的操作,它们的用途如下:

  1. Symbol.iterator:用于定义对象的迭代器,可以使用 for...of 进行遍历。
  2. Symbol.hasInstance:自定义 instanceof 操作符的行为。
  3. Symbol.toStringTag:定义 Object.prototype.toString.call 方法返回的值。
  4. Symbol.isConcatSpreadable:用于控制 Array.prototype.concat 方法是否可以展开对象。
  5. Symbol.species:定义派生对象使用的构造函数。
  6. Symbol.toPrimitive:定义对象转换为基本类型时的默认行为。
// Symbol.iterator 例子
let iterableObj = {
  data: [1, 2, 3],
  [Symbol.iterator]() {
    let index = 0;
    let data = this.data;
    return {
      next() {
        return {
          value: data[index++],
          done: index > data.length
        };
      }
    };
  }
};

for (let value of iterableObj) {
  console.log(value); // 1, 2, 3
}

// Symbol.toStringTag 例子
class CustomClass {
  get [Symbol.toStringTag]() {
    return 'CustomClass';
  }
}

let instance = new CustomClass();
console.log(Object.prototype.toString.call(instance)); // [object CustomClass]

Symbol.iterator 返回的对象可以通过next()方法陆续返回值。也可以隐式地通过生成器函数返回:

class Emitter {
  constructor(max) {
    this.max = max;
    this.idx = 0;
  }
  *[Symbol.iterator]() {
    while(this.idx < this.max) {
      yield this.idx++;
    }
  }
}
function count() {
  let emitter = new Emitter(5);
  for (const x of emitter) {
    console.log(x);
  }
}
count();
// 0
// 1
// 2
// 3
// 4

Symbol.replace

  • 这个符号作为一个属性表示“一个正则表达式方法,该方法替换一个字符串中匹配的子串。由String.prototype.replace()方法使用”
  • String.prototype.replace() 会调用 Symbol.replace 为键的方法来正则求值
  • 正则表达式原型上也有 Symbol.replace
这个符号作为一个属性表示“一个正则表达式方法,该方法替换一个字符串中匹配的子串。由String.prototype.replace()方法使用”
String.prototype.replace() 会调用 Symbol.replace 为键的方法来正则求值
正则表达式原型上也有 Symbol.replace

这个方法传入非正则表达式值会导致该值被转换为RegExp 对象,可以重新定义Symbol.replace 函数取代默认对正则表达式求值的行为。

Symbol.replace 函数接收两个参数,即调用replace()方法的字符串实例和替换字符串

class FooReplacer {
  static [Symbol.replace](target, replacement) {
    return target.split('foo').join(replacement);
  }
}
console.log('barfoobaz'.replace(FooReplacer, 'qux')); // "barquxbaz"
class StringReplacer {
  constructor(str) {
    this.str = str;
  }
  [Symbol.replace](target, replacement) {
    return target.split(this.str).join(replacement);
  }
}
console.log('barfoobaz'.replace(new StringReplacer('foo'), 'qux')); // "barquxbaz"
© 版权声明
THE END
喜欢就支持一下吧
点赞13 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容