Symbol类型存在的目的是什么?如何正确运用?

2026-05-18 01:045阅读0评论SEO教程
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计2737个文字,预计阅读时间需要11分钟。

Symbol类型存在的目的是什么?如何正确运用?

什么是Symbol?为什么会有这样的东西?

下面本篇章节为大家介绍JavaScript中的一种特殊类型——Symbol,聊聊使用方法,希望对大家有所帮助!

Symbol(符号)是一种特殊的数据类型,用于创建独一无二的标识符。Symbol可以用来定义对象属性的唯一键名,从而避免属性名冲突。

为什么会有Symbol这样的东西?

在JavaScript中,对象的属性名通常是字符串或数字。然而,在实际开发中,我们可能会遇到属性名冲突的问题,例如,不同的库可能会使用相同的属性名。为了解决这个问题,ES6引入了Symbol类型。

Symbol类型的特点:

1. 唯一性:Symbol值是唯一的,任何两个Symbol值都不相等。

2.私有性:Symbol值作为对象属性名时,具有私有性,不会被外部访问。

3.不可以转换为原始类型。

使用Symbol:

1. 创建Symbol:使用`Symbol()`函数创建Symbol值。

javascript

let sym=Symbol();

2. 使用Symbol作为对象属性名:将Symbol值作为对象属性名时,需要使用方括号语法。

javascriptlet obj={};obj[sym]='Hello, world!';

3. 获取Symbol值:可以使用`Object.keys()`、`Object.getOwnPropertySymbols()`等方法获取对象中Symbol属性名。

javascriptconsole.log(Object.keys(obj)); // []console.log(Object.getOwnPropertySymbols(obj)); // [Symbol()]

4. Symbol方法:Symbol类型提供了`toString()`、`valueOf()`等方法。

javascriptconsole.log(sym.toString()); // Symbol()console.log(sym.valueOf()); // Symbol()

希望以上内容对大家有所帮助!

什么是 Symbol?为什么会有这么个东西?下面本篇文章给大家介绍一下JavaScript中的Symbol类型,聊聊使用方法,希望对大家有所帮助!

什么是 Symbol?为什么会有这么个东西?

Symbol(符号)是 ES6 新增的数据类型。Symbol 是原始值(基础数据类型),且 Symbol 实例是唯一、不可变的。它的产生是因为要用来唯一的标记,进而用作非字符串形式的对象属性,是确保对象属性使用唯一标识符,不会发生属性冲突的危险。

用法1. 基本用法

符号需要使用 Symbol()函数初始化。因为符号本身是原始类型,所以 typeof 操作符对符号返回 symbol。

let sym = Symbol(); console.log(typeof sym); // symbol

Symbol()函数可以接收一个字符串参数用来描述,后,后续可以通过这个字符串来调试代码。但值得注意的是,多个 Symbol()函数即使接受的参数是一样的,他们的值也是不相等的。

let genericSymbol = Symbol(); let otherGenericSymbol = Symbol(); let fooSymbol = Symbol("foo"); let otherFooSymbol = Symbol("foo"); console.log(genericSymbol == otherGenericSymbol); // false console.log(fooSymbol == otherFooSymbol); // false2. 使用全局符号注册表

如果在代码中有多个地方需要使用同一个 Symbol 实例的时候,可以传入一个字符串,然后使用 Symbol.for()方法来创建一个可以复用的 Symbol,类似于单例模式,在第一次使用 Symbol.for()的时候,它会根据传入的参数会全局的去寻找是否使用 Symbol.for()创建过同样的实例,如果有,则复用,如果没有,则新建

Symbol类型存在的目的是什么?如何正确运用?

let fooGlobalSymbol = Symbol.for("foo"); // 创建新符号 let otherFooGlobalSymbol = Symbol.for("foo"); // 重用已有符号 console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true

Symbol.for()创建的实例和 Symbol()创建的实例区别: Symbol()创建的实例永远都是唯一的,不会因为你传入的参数相同而跟其他的实例相等,但是 Symbol.for()创建的实例如果参数相同的话他们是会相等的,因为他们会公用同一个 Symbol 实例

let fooSymbol = Symbol("foo"); let otherFooSymbol = Symbol("foo"); console.log(fooSymbol == otherFooSymbol); // false let fooGlobalSymbol = Symbol.for("foo"); // 创建新符号 let otherFooGlobalSymbol = Symbol.for("foo"); // 重用已有符号 console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true3. 使用符号作为属性

对象中的属性一般都是字符串的形式,但其实也是可以使用 Symbol 实例来作为属性的,这样的好处就是你新增的属性不会覆盖掉以前的任何属性

let s1 = Symbol("foo"), s2 = Symbol("bar"), s3 = Symbol("baz"), s4 = Symbol("qux"); let o = { [s1]: "foo val", }; // 这样也可以:o[s1] = 'foo val'; console.log(o); // {Symbol(foo): foo val} Object.defineProperty(o, s2, { value: "bar val" }); console.log(o); // {Symbol(foo): foo val, Symbol(bar): bar val} Object.defineProperties(o, { [s3]: { value: "baz val" }, [s4]: { value: "qux val" }, }); console.log(o); // {Symbol(foo): foo val, Symbol(bar): bar val, // Symbol(baz): baz val, Symbol(qux): qux val}

注意: 创建 Symbol 实例作为对象属性的时候,如果改 symbol 一开始没有声明一个变量进行接收的话,后续就必须遍历对象的所有符号属性才能找到相应的属性键:

let o = { [Symbol("foo")]: "foo val", [Symbol("bar")]: "bar val", }; console.log(o); // {Symbol(foo): "foo val", Symbol(bar): "bar val"} let barSymbol = Object.getOwnPropertySymbols(o).find(symbol => symbol.toString().match(/bar/)); console.log(barSymbol); // Symbol(bar)4. 常用内置符号

ES6 也引入了一批常用内置符号(well-known symbol),用于暴露语言内部行为,开发者可以直接访问、重写或模拟这些行为。如果对这些默认的属性进行了修改的话,是可以改变一些操作最后执行的结果的。比如 for-of 循环会在相关对象上使用 Symbol.iterator 属性,那么就可以通过在自定义对象上重新定义 Symbol.iterator 的值,来改变 for-of 在迭代该对象时的行为。

5. Symbol.asyncIterator

其实就是一个返回 Promise 的 Generator,一般配合 for await of 使用

6. Symbol.hasInstance

根据 ECMAScript 规范,这个符号作为一个属性表示“一个方法,该方法返回对象默认的 AsyncIterator。 由 for-await-of 语句使用”。换句话说,这个符号表示实现异步迭代器 API 的函数。

这个属性定义在 Function 的原型上。都知道 instanceof 操作符可以用来确定一个对象实例是否属于某个构造函数。其原理就是 instanceof 操作符会使用 Symbol.hasInstance 函数来确定关系

function Foo() {} let f = new Foo(); console.log(f instanceof Foo); // true class Bar {} let b = new Bar(); console.log(b instanceof Bar); // true

如果你重新定义一个函数的 Symbol.hasInstance 属性,你就可以让 instanceof 方法返回一些意料之外的东西

class Bar {} class Baz extends Bar { static [Symbol.hasInstance]() { return false; } } let b = new Baz(); console.log(Bar[Symbol.hasInstance](b)); // true console.log(b instanceof Bar); // true console.log(Baz[Symbol.hasInstance](b)); // false console.log(b instanceof Baz); // falseSymbol.isConcatSpreadabl

这个属性定义在 Array 的原型上

根据 ECMAScript 规范,这个符号作为一个属性表示“一个布尔值,如果是 true,则意味着对象应该用 Array.prototype.concat()打平其数组元素”。ES6 中的 Array.prototype.concat()方法会 根据接收到的对象类型选择如何将一个类数组(伪数组)对象拼接成数组实例。所以修改 Symbol.isConcatSpreadable 的值可以修改这个行为。

Symbol.isConcatSpreadable 对应的效果

false: 将一整个对象添加进数组true: 将一整个对打平添加进数组

let initial = ["foo"]; let array = ["bar"]; console.log(array[Symbol.isConcatSpreadable]); // undefined console.log(initial.concat(array)); // ['foo', 'bar'] array[Symbol.isConcatSpreadable] = false; console.log(initial.concat(array)); // ['foo', Array(1)] let arrayLikeObject = { length: 1, 0: "baz" }; console.log(arrayLikeObject[Symbol.isConcatSpreadable]); // undefined console.log(initial.concat(arrayLikeObject)); // ['foo', {...}] arrayLikeObject[Symbol.isConcatSpreadable] = true; console.log(initial.concat(arrayLikeObject)); // ['foo', 'baz'] let otherObject = new Set().add("qux"); console.log(otherObject[Symbol.isConcatSpreadable]); // undefined console.log(initial.concat(otherObject)); // ['foo', Set(1)] otherObject[Symbol.isConcatSpreadable] = true; console.log(initial.concat(otherObject)); // ['foo']8. Symbol.iterator

根据 ECMAScript 规范,这个符号作为一个属性表示“一个方法,该方法返回对象默认的迭代器。由 for-of 语句使用”

该属性会返回一个 Generator 函数,for of 就会依次的去调用 next()方法,这就是为什么 for of 可以使用在某些对象身上。

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 // 49. Symbol.match

根据 ECMAScript 规范,这个符号作为一个属性表示“一个正则表达式方法,该方法用正则表达式去匹配字符串。由 String.prototype.match()方法使用”。

String.prototype.match()方法会使用以 Symbol.match 为键的函数来对正则表达式求值。所以更改一个正则表达式的 Symbol.match 属性,可以让 String.prototype.match()得到你想要的值

console.log(RegExp.prototype[Symbol.match]); // ƒ [Symbol.match]() { [native code] } console.log("foobar".match(/bar/)); // ["bar", index: 3, input: "foobar", groups: undefined] class FooMatcher { static [Symbol.match](target) { return target.includes("foo"); } } console.log("foobar".match(FooMatcher)); // true console.log("barbaz".match(FooMatcher)); // false class StringMatcher { constructor(str) { this.str = str; } [Symbol.match](target) { return target.includes(this.str); } } console.log("foobar".match(new StringMatcher("foo"))); // true console.log("barbaz".match(new StringMatcher("qux"))); // false11. Symbol.search

这个符号作为一个属性表示“一个正则表达式方法,该方法返回字符串中 匹配正则表达式的索引。由 String.prototype.search()方法使用”

12. Symbol.species

这个符号作为一个属性表示“一个函数值,该函数作为创建派生对象的构 造函数”。

13. Symbol.split

这个符号作为一个属性表示“一个正则表达式方法,该方法在匹配正则表 达式的索引位置拆分字符串。由 String.prototype.split()方法使用”。

14. Symbol.toPrimitive

这个符号作为一个属性表示“一个方法,该方法将对象转换为相应的原始 值。由 ToPrimitive 抽象操作使用”

15. Symbol.toStringTag

这个符号作为一个属性表示“一个字符串,该字符串用于创建对象的默认 字符串描述。由内置方法 Object.prototype.toString()使用”

16. Symbol.unscopables

这个符号作为一个属性表示“一个对象,该对象所有的以及继承的属性, 都会从关联对象的 with 环境绑定中排除

更多编程相关知识,请访问:编程视频!!

本文共计2737个文字,预计阅读时间需要11分钟。

Symbol类型存在的目的是什么?如何正确运用?

什么是Symbol?为什么会有这样的东西?

下面本篇章节为大家介绍JavaScript中的一种特殊类型——Symbol,聊聊使用方法,希望对大家有所帮助!

Symbol(符号)是一种特殊的数据类型,用于创建独一无二的标识符。Symbol可以用来定义对象属性的唯一键名,从而避免属性名冲突。

为什么会有Symbol这样的东西?

在JavaScript中,对象的属性名通常是字符串或数字。然而,在实际开发中,我们可能会遇到属性名冲突的问题,例如,不同的库可能会使用相同的属性名。为了解决这个问题,ES6引入了Symbol类型。

Symbol类型的特点:

1. 唯一性:Symbol值是唯一的,任何两个Symbol值都不相等。

2.私有性:Symbol值作为对象属性名时,具有私有性,不会被外部访问。

3.不可以转换为原始类型。

使用Symbol:

1. 创建Symbol:使用`Symbol()`函数创建Symbol值。

javascript

let sym=Symbol();

2. 使用Symbol作为对象属性名:将Symbol值作为对象属性名时,需要使用方括号语法。

javascriptlet obj={};obj[sym]='Hello, world!';

3. 获取Symbol值:可以使用`Object.keys()`、`Object.getOwnPropertySymbols()`等方法获取对象中Symbol属性名。

javascriptconsole.log(Object.keys(obj)); // []console.log(Object.getOwnPropertySymbols(obj)); // [Symbol()]

4. Symbol方法:Symbol类型提供了`toString()`、`valueOf()`等方法。

javascriptconsole.log(sym.toString()); // Symbol()console.log(sym.valueOf()); // Symbol()

希望以上内容对大家有所帮助!

什么是 Symbol?为什么会有这么个东西?下面本篇文章给大家介绍一下JavaScript中的Symbol类型,聊聊使用方法,希望对大家有所帮助!

什么是 Symbol?为什么会有这么个东西?

Symbol(符号)是 ES6 新增的数据类型。Symbol 是原始值(基础数据类型),且 Symbol 实例是唯一、不可变的。它的产生是因为要用来唯一的标记,进而用作非字符串形式的对象属性,是确保对象属性使用唯一标识符,不会发生属性冲突的危险。

用法1. 基本用法

符号需要使用 Symbol()函数初始化。因为符号本身是原始类型,所以 typeof 操作符对符号返回 symbol。

let sym = Symbol(); console.log(typeof sym); // symbol

Symbol()函数可以接收一个字符串参数用来描述,后,后续可以通过这个字符串来调试代码。但值得注意的是,多个 Symbol()函数即使接受的参数是一样的,他们的值也是不相等的。

let genericSymbol = Symbol(); let otherGenericSymbol = Symbol(); let fooSymbol = Symbol("foo"); let otherFooSymbol = Symbol("foo"); console.log(genericSymbol == otherGenericSymbol); // false console.log(fooSymbol == otherFooSymbol); // false2. 使用全局符号注册表

如果在代码中有多个地方需要使用同一个 Symbol 实例的时候,可以传入一个字符串,然后使用 Symbol.for()方法来创建一个可以复用的 Symbol,类似于单例模式,在第一次使用 Symbol.for()的时候,它会根据传入的参数会全局的去寻找是否使用 Symbol.for()创建过同样的实例,如果有,则复用,如果没有,则新建

Symbol类型存在的目的是什么?如何正确运用?

let fooGlobalSymbol = Symbol.for("foo"); // 创建新符号 let otherFooGlobalSymbol = Symbol.for("foo"); // 重用已有符号 console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true

Symbol.for()创建的实例和 Symbol()创建的实例区别: Symbol()创建的实例永远都是唯一的,不会因为你传入的参数相同而跟其他的实例相等,但是 Symbol.for()创建的实例如果参数相同的话他们是会相等的,因为他们会公用同一个 Symbol 实例

let fooSymbol = Symbol("foo"); let otherFooSymbol = Symbol("foo"); console.log(fooSymbol == otherFooSymbol); // false let fooGlobalSymbol = Symbol.for("foo"); // 创建新符号 let otherFooGlobalSymbol = Symbol.for("foo"); // 重用已有符号 console.log(fooGlobalSymbol === otherFooGlobalSymbol); // true3. 使用符号作为属性

对象中的属性一般都是字符串的形式,但其实也是可以使用 Symbol 实例来作为属性的,这样的好处就是你新增的属性不会覆盖掉以前的任何属性

let s1 = Symbol("foo"), s2 = Symbol("bar"), s3 = Symbol("baz"), s4 = Symbol("qux"); let o = { [s1]: "foo val", }; // 这样也可以:o[s1] = 'foo val'; console.log(o); // {Symbol(foo): foo val} Object.defineProperty(o, s2, { value: "bar val" }); console.log(o); // {Symbol(foo): foo val, Symbol(bar): bar val} Object.defineProperties(o, { [s3]: { value: "baz val" }, [s4]: { value: "qux val" }, }); console.log(o); // {Symbol(foo): foo val, Symbol(bar): bar val, // Symbol(baz): baz val, Symbol(qux): qux val}

注意: 创建 Symbol 实例作为对象属性的时候,如果改 symbol 一开始没有声明一个变量进行接收的话,后续就必须遍历对象的所有符号属性才能找到相应的属性键:

let o = { [Symbol("foo")]: "foo val", [Symbol("bar")]: "bar val", }; console.log(o); // {Symbol(foo): "foo val", Symbol(bar): "bar val"} let barSymbol = Object.getOwnPropertySymbols(o).find(symbol => symbol.toString().match(/bar/)); console.log(barSymbol); // Symbol(bar)4. 常用内置符号

ES6 也引入了一批常用内置符号(well-known symbol),用于暴露语言内部行为,开发者可以直接访问、重写或模拟这些行为。如果对这些默认的属性进行了修改的话,是可以改变一些操作最后执行的结果的。比如 for-of 循环会在相关对象上使用 Symbol.iterator 属性,那么就可以通过在自定义对象上重新定义 Symbol.iterator 的值,来改变 for-of 在迭代该对象时的行为。

5. Symbol.asyncIterator

其实就是一个返回 Promise 的 Generator,一般配合 for await of 使用

6. Symbol.hasInstance

根据 ECMAScript 规范,这个符号作为一个属性表示“一个方法,该方法返回对象默认的 AsyncIterator。 由 for-await-of 语句使用”。换句话说,这个符号表示实现异步迭代器 API 的函数。

这个属性定义在 Function 的原型上。都知道 instanceof 操作符可以用来确定一个对象实例是否属于某个构造函数。其原理就是 instanceof 操作符会使用 Symbol.hasInstance 函数来确定关系

function Foo() {} let f = new Foo(); console.log(f instanceof Foo); // true class Bar {} let b = new Bar(); console.log(b instanceof Bar); // true

如果你重新定义一个函数的 Symbol.hasInstance 属性,你就可以让 instanceof 方法返回一些意料之外的东西

class Bar {} class Baz extends Bar { static [Symbol.hasInstance]() { return false; } } let b = new Baz(); console.log(Bar[Symbol.hasInstance](b)); // true console.log(b instanceof Bar); // true console.log(Baz[Symbol.hasInstance](b)); // false console.log(b instanceof Baz); // falseSymbol.isConcatSpreadabl

这个属性定义在 Array 的原型上

根据 ECMAScript 规范,这个符号作为一个属性表示“一个布尔值,如果是 true,则意味着对象应该用 Array.prototype.concat()打平其数组元素”。ES6 中的 Array.prototype.concat()方法会 根据接收到的对象类型选择如何将一个类数组(伪数组)对象拼接成数组实例。所以修改 Symbol.isConcatSpreadable 的值可以修改这个行为。

Symbol.isConcatSpreadable 对应的效果

false: 将一整个对象添加进数组true: 将一整个对打平添加进数组

let initial = ["foo"]; let array = ["bar"]; console.log(array[Symbol.isConcatSpreadable]); // undefined console.log(initial.concat(array)); // ['foo', 'bar'] array[Symbol.isConcatSpreadable] = false; console.log(initial.concat(array)); // ['foo', Array(1)] let arrayLikeObject = { length: 1, 0: "baz" }; console.log(arrayLikeObject[Symbol.isConcatSpreadable]); // undefined console.log(initial.concat(arrayLikeObject)); // ['foo', {...}] arrayLikeObject[Symbol.isConcatSpreadable] = true; console.log(initial.concat(arrayLikeObject)); // ['foo', 'baz'] let otherObject = new Set().add("qux"); console.log(otherObject[Symbol.isConcatSpreadable]); // undefined console.log(initial.concat(otherObject)); // ['foo', Set(1)] otherObject[Symbol.isConcatSpreadable] = true; console.log(initial.concat(otherObject)); // ['foo']8. Symbol.iterator

根据 ECMAScript 规范,这个符号作为一个属性表示“一个方法,该方法返回对象默认的迭代器。由 for-of 语句使用”

该属性会返回一个 Generator 函数,for of 就会依次的去调用 next()方法,这就是为什么 for of 可以使用在某些对象身上。

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 // 49. Symbol.match

根据 ECMAScript 规范,这个符号作为一个属性表示“一个正则表达式方法,该方法用正则表达式去匹配字符串。由 String.prototype.match()方法使用”。

String.prototype.match()方法会使用以 Symbol.match 为键的函数来对正则表达式求值。所以更改一个正则表达式的 Symbol.match 属性,可以让 String.prototype.match()得到你想要的值

console.log(RegExp.prototype[Symbol.match]); // ƒ [Symbol.match]() { [native code] } console.log("foobar".match(/bar/)); // ["bar", index: 3, input: "foobar", groups: undefined] class FooMatcher { static [Symbol.match](target) { return target.includes("foo"); } } console.log("foobar".match(FooMatcher)); // true console.log("barbaz".match(FooMatcher)); // false class StringMatcher { constructor(str) { this.str = str; } [Symbol.match](target) { return target.includes(this.str); } } console.log("foobar".match(new StringMatcher("foo"))); // true console.log("barbaz".match(new StringMatcher("qux"))); // false11. Symbol.search

这个符号作为一个属性表示“一个正则表达式方法,该方法返回字符串中 匹配正则表达式的索引。由 String.prototype.search()方法使用”

12. Symbol.species

这个符号作为一个属性表示“一个函数值,该函数作为创建派生对象的构 造函数”。

13. Symbol.split

这个符号作为一个属性表示“一个正则表达式方法,该方法在匹配正则表 达式的索引位置拆分字符串。由 String.prototype.split()方法使用”。

14. Symbol.toPrimitive

这个符号作为一个属性表示“一个方法,该方法将对象转换为相应的原始 值。由 ToPrimitive 抽象操作使用”

15. Symbol.toStringTag

这个符号作为一个属性表示“一个字符串,该字符串用于创建对象的默认 字符串描述。由内置方法 Object.prototype.toString()使用”

16. Symbol.unscopables

这个符号作为一个属性表示“一个对象,该对象所有的以及继承的属性, 都会从关联对象的 with 环境绑定中排除

更多编程相关知识,请访问:编程视频!!