Symbol 是 ES6 中新增的一种数据类型,其主要作用是用来表示一个独一无二的标识符,常用于对象属性的名称、迭代器方法等场景。ES10 中增加了一些新的 API,本文将详细介绍 Symbol 的用法和新特性。
Symbol 的基本用法
Symbol 类型的值是一种基本数据类型,使用 Symbol 函数创建。下面是几个基本的使用示例:
const sym1 = Symbol(); const sym2 = Symbol("foo"); console.log(sym1); // Symbol() console.log(sym2); // Symbol(foo) typeof sym1 // "symbol" typeof sym2 // "symbol"
Symbol 函数可以接受一个字符串作为参数,表示该 Symbol 的描述信息。为了方便调试和查看,可以将描述信息打印出来:
const sym = Symbol("description"); console.log(String(sym)); // "Symbol(description)" console.log(sym.toString()); // "Symbol(description)"
Symbol 作为属性名
在对象中使用 Symbol 作为属性名时,该属性会被视为一个私有属性,不会出现在 for...in、Object.keys()、JSON.stringify() 等操作中。这样可以更好地保护对象的属性,避免被意外修改或访问。
const obj = {}; const sym = Symbol(); obj[sym] = "secret value"; console.log(obj[sym]); // "secret value" console.log(JSON.stringify(obj)); // "{}" console.log(Object.keys(obj)); // []
在某些场景下,我们也可以使用 Symbol 作为一些特殊属性的名称,比如迭代器方法。下面是一个示例:
// javascriptcn.com 代码示例 class RangeIterator { constructor(start, end) { this.start = start; this.end = end; } [Symbol.iterator]() { let current = this.start; return { next: () => { if (current <= this.end) { return { value: current++, done: false }; } else { return { done: true }; } } }; } } const range = new RangeIterator(1, 5); for (const number of range) { console.log(number); } // 1 // 2 // 3 // 4 // 5
在 RangeIterator 类中,将 Symbol.iterator 方法定义为迭代器方法,使得该类的实例可以使用 for...of 循环进行遍历。
新增的 Symbol 属性
ES10 中新增了一些新的 Symbol 静态属性,这些属性的主要作用是提供一些已有方法的默认实现,也可以用于查找与 Symbol 相关的信息。下面是这些属性的具体介绍:
Symbol.asyncIterator
Symbol.asyncIterator 是一个 Symbol 值,代表一个对象的默认异步迭代器方法。通过该属性,对象可以实现异步迭代功能。
// javascriptcn.com 代码示例 const obj = { *[Symbol.iterator]() { yield 1; yield 2; yield 3; }, async *[Symbol.asyncIterator]() { for (const value of this) { await new Promise(resolve => setTimeout(resolve, 1000)); yield value; } } }; (async () => { for await (const number of obj) { console.log(number); } })(); // 等待 1 秒,输出 1 // 等待 1 秒,输出 2 // 等待 1 秒,输出 3
在 obj 对象中,通过定义 Symbol.iterator 来实现同步迭代,定义 Symbol.asyncIterator 来实现异步迭代。
Symbol.hasInstance
Symbol.hasInstance 也是一个 Symbol 值,用于派生类的继承,可以用来自定义 instanceof 运算符的行为。
class MyArray extends Array { static [Symbol.hasInstance](instance) { return Array.isArray(instance); } } const arr = []; console.log(arr instanceof MyArray); // true
在 MyArray 类中,使用 static 关键字定义了一个 Symbol.hasInstance 函数,该函数表示如果 instance 是数组的话,那么 arr 实例也是 MyArray 类的实例。
Symbol.matchAll
Symbol.matchAll 也是一个 Symbol 值,用于扩展字符串的 matchAll() 方法,返回一个正则表达式在字符串中所有匹配结果的迭代器。
const str = "Hello, world!"; const regexp = /[\s,]+/g; const matches = str.matchAll(regexp); for (const match of matches) { console.log(match); } // [" ", index: 5, input: "Hello, world!", length: 1]
Symbol.replace
Symbol.replace 是一个 Symbol 值,用于扩展字符串的 replace() 方法,用于实现自定义的替换逻辑。
// javascriptcn.com 代码示例 String.prototype[Symbol.replace] = function(searchValue, replaceValue) { let result = ""; let startIndex = 0; let matchIndex = this.indexOf(searchValue, startIndex); while (matchIndex !== -1) { result += this.slice(startIndex, matchIndex) + replaceValue; startIndex = matchIndex + searchValue.length; matchIndex = this.indexOf(searchValue, startIndex); } result += this.slice(startIndex); return result; }; const str = "Hello, world!"; console.log(str.replace(",", "|")); // "Hello| world!"
在该示例中,通过将 [Symbol.replace] 属性赋值为一个自定义的函数,重写了字符串的替换逻辑。
Symbol.search
Symbol.search 是一个 Symbol 值,用于扩展字符串的 search() 方法,用于实现自定义的匹配逻辑。
String.prototype[Symbol.search] = function(searchValue) { const index = this.indexOf(searchValue); return index === -1 ? -1 : 2 * index; }; const str = "Hello, world!"; console.log(str.search(",")); // 12
总结
本文介绍了 Symbol 的基本用法和新增的特性,包括使用 Symbol 作为属性名、Symbol 迭代器方法、Symbol 静态属性等内容。Symbol 的特性使得我们可以更好地保护对象的私有属性,同时也可以扩展已有方法的实现,更好地适应代码的需求。希望本文对读者有所帮助,对学习 ES10 及前端开发有所指导。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/653d02a67d4982a6eb6ece4e