卖坚果的怪叔叔 卖坚果的怪叔叔
  • 首页
  • 生活
  • 技术
  • 记录
  • 工具箱
  • 关于我
首页 › 技术 › ES6入门之Symbol

ES6入门之Symbol

坚果大叔
2019-07-08 10:15:35技术阅读 2,752

因为ES5的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了他人提供的对象,但又想为这个对象添加新的方法,新方法的名字就有可能与现有的方法产生冲突,所有就有了Symbol,它会保证每个属性名是独一无二的,可以从根本上防止属性名的冲突。

ES6引入了一种新的原始数据类型 Symbol,表示独一无二的值,它是Javascript语言的第七种数据类型。

Symbol值通过 Symbol函数生成,对象的属性名现在可以有两种类型,一种是原有的字符串,另一种就是新增的Symbol类型。 Symbol类型是独一无二的不会和其他属性名产生冲突

let s = Symbol()
typeof s
// 'Symbol'

注意: Symbol 函数前不能用 new命令,否则会报错。因为生成的Symbol是一个原始类型的值,不是对象。Symbol值不是对象,无法为其添加属性。它是一个类似字符串的数据类型

Symbol函数可以接受一个参数,表示对Symbol实例的描述,方便在控制台显示,在转为字符串的时候方便区分,如下:

let s1 = Symbol('foo');
let s2 = Symbol('far');

s1 // Symbol(foo)
s2 // Symbol(far)

s1.toString()   //  'Symbol(foo)'
s2.toString()   //  'Symbol(far)'

// 通过添加描述可以区分到底是哪个Symbol值输出了

如果 Symbol的参数是一个对象,那么会调用该对象的toString()方法将其转换成字符串,在生成Symbol值

const obj = {
    toString() {
        retrun 'abc'
    }
}
const sym = Symbol(obj)
sym // Symbol(abc)

// 注意: Symbol函数的参数只是表示对当前Symbol值的描述,
因此相同参数的Symbol函数的返回值不同

let s1 = Symbol()
let s2 = Symbol()

s1 === s2 // false

let s1 = Symbol('cc')
let s2 = Symbol('cc')

s1 === s2 // false

注意: Symbol 值不能与其他类型的值进行运算,会报错。但是,Symbol值可以显式转为字符串。另外,Symbol值可以转换为布尔值,但是不能转为数值。

创建 Symbol的时候可以添加一个描述。如果读取这个描述,则需要将Symbol显式转为字符串。但是这样很不方便,所以在ES2019中提供 实例属性 description 直接返回 Symbol的描述。

// 添加描述
const sym = Symbol('boo')

// 读取描述
String(sym) // 'Symbol(boo)'
sym.toString()  // 'Symbol(boo)'

// 新增方法
sym.description // 'boo'

因为 每一个 Symbol值都是不相等的,这意味着 Symbol 值 可以作为标识符,用于对象的属性名,就能保证不会出现同名的属性,防止某一个键被不小心改写 或 覆盖。如下:

let mySymbol = Symbol()

// 第一种写法
let a = {}
a[mySymbol] = 'hello'

// 第二种写法
let a = {
    [mySymbol]: 'hello'
}

// 第三种写法
let a = {}
Object.defineProperty(a, mySymbol, { value: 'hello' })

// 结果
a[mySymbol] // hello

注意: Symbol值作为对象属性名时,不能用点运算符,而且使用Symbol值定义属性时,Symbol值必须发放在方括号之中。另外,Symbol值作为属性名时,该属性还是公开属性,不是私有属性。

魔术字符串是指,在代码之中出现多次、与代码形成强耦合的某一个具体的字符串或数值。

function getArea(shape, options) {
  let area = 0;

  switch (shape) {
    case 'Triangle': // 魔术字符串
      area = .5 * options.width * options.height;
      break;
    /* ... more code ... */
  }

  return area;
}

getArea('Triangle', { width: 100, height: 100 }); // 魔术字符串

上述代码中,字符串Triangle就是一个魔术字符串,它多次出现。与代码形成“强耦合”,不利于修改维护,常用的方法就是把它写成一个变量。

const shapeType = {
  triangle: 'Triangle'
};

function getArea(shape, options) {
  let area = 0;
  switch (shape) {
    case shapeType.triangle:
      area = .5 * options.width * options.height;
      break;
  }
  return area;
}

getArea(shapeType.triangle, { width: 100, height: 100 });

可以发现 shapeType.triangle等于哪个值并不重要,只要确保不会跟其他的shapeType属性冲突就行,这样可以用 Symbol 来代替。

const shapeType = {
  triangle: Symbol()
};

Symbol作为属性名,该属性不会出现在 for..in | for...of 循环中,也不会被 Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。但是它还有个私有属性方法可以获取指定对象的所有Symbol属性名。Object.getOwnPropertySymbols,它返回的是一个数组,成员是该对象所有用作属性名的 Symbol值

const obj = {};
let a = Symbol('a');
let b = Symbol('b');

obj[a] = 'Hello';
obj[b] = 'World';

const objectSymbols = Object.getOwnPropertySymbols(obj);

objectSymbols
// [Symbol(a), Symbol(b)]

我们还可以 通过 新API Reflect.ownkeys方法 返回所有类型的键名,包括常规键名和 Symbol键名。

let obj = {
  [Symbol('my_key')]: 1,
  enum: 2,
  nonEnum: 3
};

Reflect.ownKeys(obj)

重点:由于以Symbol值作为名称的属性,不会被常规的方法遍历到,我们可以利用这个特性为对象定义一些非私有的,但又希望只用于内部的方法。

有时候我们希望重新使用同一个 Symbol值,Symbol.for方法可以做到这一点,它接受一个字符串作为参数,然后搜索有没有以该参数作为名称的Symbol值。如果又,就返回这个Symbol值,否则就新建并返回一个以该字符串为名称的Symbol值

let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');

s1 === s2 // true

区别: Symbol.for() 与 Symbol 这两种写法,都会生成新的Symbol,不同的是:

  • 前者会被登记在全局环境中供搜索,后者不会。
  • Symbol.for()不会每次调用就返回一个新的Symbol类型的值,而是会先检查给定的key是否已经存在,如果不存在才会新建一个值。
  • 调用 30此 Symbol.for('dog'),每次都只返回同一个Symbol,而调用Symbol('dog')则会返回30个不同的Symbol值。

Symbol.keyFor方法返回一个已登记的 Symbol 类型值的key 就是和 Symbol.for()对应使用。

let s1 = Symbol.for('foo')
Symbol.keyFor(s1)   // 'foo'

let s2 = Symbol('foo')
Symbol.keyFor(s2)   // undefined

Singleton 模式指的是调用一个类,任何时候返回的都是同一个实例。可以通过将实例放到顶层对象global实现。

8.1. Symbol.hasInstance

一个内部方法,当其他对象使用 instanceof 运算符,判断是否为该对象的实例时会调用这个方法。

8.2. Symbol.isConcatSpreadable

是一个布尔值,表示该对象用于 Array.prototype.caocat()时,是否可以展开

  • 数组的默认行为时可以展开。
  • 类数组的对象默认不展开。

8.3. Symbol.species

指向一个构造函数,创建衍生对象时,会使用该属性。它的作用在于,实例对象在运行过程中,需要再次调用自身的构造函数时,会调用该属性指定的构造函数。它的主要用途是,有些类库是在基类的基础上修改的。那么子类使用继承的方法时,希望返回的时基类的实例,而不是子类的实例。

8.4. Symbol.match

指向一个函数,当执行 str.match(myObject)时,如果该属性存在,则调用它,返回该方法的返回值。

8.5. Symbol.replace

对象的Symbol.replace属性,指向一个方法。当对象被 String.prototype.replace方法调用的时候,会返回该方法的值。

8.6. Symbol.search

对象的 Symbol.search属性,指向一个方法,当该对象被 String.prototype.search 方法调用时,会返回该方法的值

8.7. Symbol.split

对象调用Symbol.split属性,指向一个方法,当该对象被 String.prototype.split 方法调用时,会返回该方法的值。

8.8. Symbol.iterator

对象的 Symbol.iterator属性,指向该对象默认的遍历器方法

8.9 Symbol.iterator

对象的Symbol.toPrimitive属性,指向一个方法。该对象被转为原始类型的值时,会调用这个方法,返回该对象对应的原始类型值。Symbol.toPrimitive被调用时,会接受一个字符串参数,表示当前运算的模式,一共有三种模式。

  • Number:该场合需要转成数值
  • String:该场合需要转成字符串
  • Default:该场合可以转成数值,也可以转成字符串

8.10 Symbol.toStringTag

对象的Symbol.toStringTag属性,指向一个方法。在该对象上面调用Object.prototype.toString方法时,如果这个属性存在,它的返回值会出现在toString方法返回的字符串之中,表示对象的类型。也就是说,这个属性可以用来定制[object Object]或[object Array]中object后面的那个字符串。

8.11. Symbol.unscopables

对象的 Symbol.unscopables 属性,指向一个对象,该对象指定了使用 with 关键字时,哪些属性会被 with 环境排除。

Symbol
赞赏 赞(0)
本文系作者 @坚果大叔 原创发布在 卖坚果的怪叔叔。未经许可,禁止转载。
重学JavaScript之基本概念(下)=>运算符
上一篇
Python获取好友地区分布及好友性别分布
下一篇
在小程序中查看

这是个😊,挣点服务器费用😜

热门文章
Js时间小方法
小毛驴历险记2
使用uview-plus遇到的一些问题!
十月末
新年快乐🎉
WordPress博客评论微信通知功能!(更新版)
专题标签
agent (1) CSS (15) dom (1) Es6入门系列 (14) Git (3) html (1) iview (1) JavaScript (9) js (4) Lif (1) Node (4) pyecharts (1) Python (10) ref (1) scriptable (1) Skill (1) vsCode (1) vue (4) wordpress (2) 三月 (1) 上海 (1) 假期 (1) 其他分享 (3) 前端两三问 (15) 古镇 (1) 外滩 (1) 对象 (1) 小程序 (5) 年度总结 (6) 年终总结 (1) 微信机器人 (4) 打字机 (1) 技术 (1) 日常问题 (8) 日常问题记录 (1) 春天 (2) 服务器 (2) 海族馆 (1) 生活 (8) 网上国网 (1) 记录 (3) 通勤 (1) 重学JavaScript (11) 面试题 (10) 🌸 (1)
什么是Agent?
2026-08-15 23:49:12
395 0 2
什么是 Skill?
2026-08-12 21:32:42
322 1 0
失业在家,我给小朋友做了一个练字小程序!
2026-08-07 16:21:52
597 10 1
上线8年,15万用户的小程序,一共赚了多少钱?
2026-05-30 18:01:24
4,639 4 0
  • 0
博主

一位佛系的前端开发者,略通摄影,乐于尝试新事物,热衷于美食。

友链
故事胶片
公众号
坚果大叔 执行上下文 卖坚果的怪叔叔 Dacking
Copyright © 2017-2026 卖坚果的怪叔叔

开往-友链接力

萌ICP备20230818号

苏ICP备18048410号-3
  • 首页
  • 生活
  • 技术
  • 记录
  • 工具箱
  • 关于我
# CSS # # JavaScript # # vue # # 微信 # # 生活 #
坚果大叔
345
文章
171
评论
432
喜欢