阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 常用内置Symbols介绍

常用内置Symbols介绍

作者:陈川 阅读数:18510人阅读 分类: JavaScript

ECMAScript 6 引入了Symbol原始类型,同时提供了一系列内置的Symbol值(称为“Well-known Symbols”),用于扩展对象的行为。这些内置Symbol作为对象属性的键,可以控制对象在特定操作下的表现方式,例如迭代、类型转换等。

Symbol.iterator

Symbol.iterator定义了对象的默认迭代器,用于for...of循环或展开运算符等场景。实现该方法的对象称为可迭代对象

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

console.log([...myIterable]); // [1, 2, 3]
for (const value of myIterable) {
  console.log(value); // 依次输出 1, 2, 3
}

内置类型如ArrayStringMapSet等均默认实现了Symbol.iterator。自定义类也可以通过实现该方法使其实例可迭代:

class Range {
  constructor(start, end) {
    this.start = start;
    this.end = end;
  }

  *[Symbol.iterator]() {
    for (let i = this.start; i <= this.end; i++) {
      yield i;
    }
  }
}

const range = new Range(1, 5);
console.log([...range]); // [1, 2, 3, 4, 5]

Symbol.toStringTag

Symbol.toStringTag用于定制对象调用Object.prototype.toString()时返回的字符串标签。默认情况下,普通对象返回[object Object],而通过该属性可以修改这一行为。

const myObj = {
  [Symbol.toStringTag]: 'MyCustomObject'
};

console.log(Object.prototype.toString.call(myObj)); // "[object MyCustomObject]"

内置类型利用此特性返回更有意义的标签:

console.log(Object.prototype.toString.call(new Map())); // "[object Map]"
console.log(Object.prototype.toString.call(new Set())); // "[object Set]"

Symbol.hasInstance

Symbol.hasInstance用于自定义instanceof操作符的行为。当执行obj instanceof Constructor时,实际上会调用Constructor[Symbol.hasInstance](obj)

class MyArray {
  static [Symbol.hasInstance](instance) {
    return Array.isArray(instance);
  }
}

console.log([] instanceof MyArray); // true
console.log({} instanceof MyArray); // false

Symbol.species

Symbol.species指定派生对象的构造函数。当需要创建派生对象时(如Array.prototype.map()返回新数组),会使用该属性指定的构造函数而非默认的。

class MyArray extends Array {
  static get [Symbol.species]() {
    return Array; // 覆盖默认返回的MyArray
  }
}

const myArr = new MyArray(1, 2, 3);
const mapped = myArr.map(x => x * 2);

console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array);   // true

Symbol.toPrimitive

Symbol.toPrimitive允许对象自定义类型转换行为。当对象需要被转换为原始值(如通过+操作符或String()函数)时,会调用该方法。

const temperature = {
  value: 25,
  unit: '°C',
  [Symbol.toPrimitive](hint) {
    switch (hint) {
      case 'string':
        return `${this.value}${this.unit}`;
      case 'number':
        return this.value;
      default:
        return this.value.toString();
    }
  }
};

console.log(String(temperature)); // "25°C"
console.log(+temperature);        // 25
console.log(temperature + 5);     // 30

Symbol.isConcatSpreadable

Symbol.isConcatSpreadable决定数组或类数组对象在Array.prototype.concat()时是否展开其元素。默认情况下数组会展开,而类数组不会。

const arr1 = [1, 2];
const arr2 = [3, 4];
arr2[Symbol.isConcatSpreadable] = false;

console.log(arr1.concat(arr2)); // [1, 2, [3, 4]]

const arrayLike = { 0: 'a', 1: 'b', length: 2 };
arrayLike[Symbol.isConcatSpreadable] = true;
console.log(['x'].concat(arrayLike)); // ['x', 'a', 'b']

Symbol.match

Symbol.match允许对象自定义String.prototype.match()的行为。正则表达式默认实现了此方法。

const customMatcher = {
  [Symbol.match](string) {
    return string.includes('hello') ? ['hello'] : null;
  }
};

console.log('world hello'.match(customMatcher)); // ["hello"]
console.log('world'.match(customMatcher));      // null

Symbol.replace

Symbol.replace定义String.prototype.replace()的行为。接收原始字符串和替换值作为参数。

const customReplacer = {
  [Symbol.replace](string, replacement) {
    return string.split(' ').join(replacement);
  }
};

console.log('a b c'.replace(customReplacer, '-')); // "a-b-c"

Symbol.search

Symbol.search定制String.prototype.search()方法。返回匹配的索引位置。

const customSearcher = {
  [Symbol.search](string) {
    return string.indexOf('ECMAScript');
  }
};

console.log('Learn ECMAScript 6'.search(customSearcher)); // 6

Symbol.split

Symbol.split控制String.prototype.split()的分割逻辑。

const customSplitter = {
  [Symbol.split](string) {
    return string.toUpperCase().split('');
  }
};

console.log('hello'.split(customSplitter)); // ["H", "E", "L", "L", "O"]

Symbol.unscopables

Symbol.unscopables用于排除某些属性被with语句绑定。在现代JavaScript中with已不推荐使用,但该特性仍存在。

const myObject = {
  foo: 1,
  bar: 2,
  [Symbol.unscopables]: {
    foo: true // 排除foo属性
  }
};

with (myObject) {
  console.log(bar); // 2
  console.log(foo); // ReferenceError: foo is not defined
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益,请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌