前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Javascript Symbol 解惑 什么是Symbol创建Symbol如何使用Symbol

Javascript Symbol 解惑 什么是Symbol创建Symbol如何使用Symbol

作者头像
MudOnTire
发布2020-05-12 15:09:10
2.7K0
发布2020-05-12 15:09:10
举报
文章被收录于专栏:MudOnTire

Symbol是ES6中新引入的一种基本数据类型,在此之前Javascript中已有几种基本数据类型:

  • Numberg
  • String
  • Boolean
  • Null
  • Undefined
  • Object

不同于其他基本类型的通俗易懂,Symbol 是什么和有什么用一直有些让人困惑。

什么是Symbol

JavaScript标准中规定对象的key只能是 StringSymbol 类型,区别在于 String 类型的key可以重复而 Symbol 类型的key是唯一的。Symbol 的本质是表示一个唯一标识。每次创建一个Symbol,它所代表的值都不可能重复,该值的内部实现可以视为一段数字(类似:3423498431987719455..)。所以理论上 Symbol 的存在只有一个意义:用于必须使用唯一值的场景。

创建Symbol

创建 Number、String等基本类型的实例有两种方法:通过构造函数(或者叫工厂函数)和文字语法糖。比如:

代码语言:javascript
复制
// 构造函数
const num = Number(3);
const str = String('hi');

// 语法糖
const num = 3;
const str = 'hi';

显然使用语法糖更加简洁。但是 Symbol 只能通过构造函数 Symbol() 进行创建:

代码语言:javascript
复制
const sym = Symbol();

或者,我们可以传入一个字符串参数(descriptor)用于描述该Symbol:

代码语言:javascript
复制
const sym = Symbol('cat');

注意:传入的参数对 Symbol 值的产生并无影响,因为就算每次传入的参数都一样,生成的Symbol值也是不等的。该参数的作用仅用于描述被创建的Symbol,以便debug时可以识别出Symbol的含义。 所以,下列等式结果为 false

代码语言:javascript
复制
Symbol('cat') === Symbol('cat') // false

Symbol.for(key)

Symbol() 类似,Symbol.for(key) 也可以创建一个Symbol,不一样的是:创建的 Symbol 是全局的(在全局Symbol表中注册),而如果全局已经存在相同 key 的Symbol,则直接返回该Symbol。所以,下列等式结果为 true

代码语言:javascript
复制
Symbol.for('cat') === Symbol.for('cat') // true

如何使用Symbol

其实 Symbol 本身很简单,但是如何把它用好、且用的恰到好处却使人困惑,因为在平常工作中并没有多少非Symbol不用的场景。但是用对了Symbol会对你的代码质量有不少提升。来看下面几种案例:

1. 用作对象的key,防止命名冲突

使用Symbol作为Object的key,可以保证和其他key都不重复。因此,Symbol非常适合用于对对象的属性进行拓展。

比如,当使用 String 作为对象的key时,一旦出现重复的key则后面的属性会覆盖前面的:

代码语言:javascript
复制
const persons = {
  'bruce': 'wayne',
  'bruce': 'banner'
}

console.log(persons.bruce); // 'wayne'

使用Symbol作为Key可以避免这种情况:

代码语言:javascript
复制
const bruce1 = Symbol('bruce');
const bruce2 = Symbol('bruce');

const persons = {
  [bruce1]: 'wayne',
  [bruce2]: 'banner'
}

console.log(persons[bruce1]); // 'wayne'
console.log(persons[bruce2]); // 'banner'

JS很多内建的方法都是通过 Symbol 进行指定的,比如:Symobol.iterator 指定了一个iterable对象的迭代器方法;Symbol.replace 指定了对象字符串替换的方法,这类 Symbol 被称为 Well-know Symbols,代表了JS语言的内部行为。

2. 使用Symbol定义枚举

由于Javascript并不自带枚举类型,通常情况下我们会使用一个freezed的Object来模拟枚举类型,比如定义一个日期的枚举:

代码语言:javascript
复制
const DAYS = Object.freeze({
  monday: 1,
  tuesday: 2,
  wednesday: 3
});

此时有一个方法,接收 DAYS 的枚举值来返回当天要做的事:

代码语言:javascript
复制
function getTodo(day) {
  switch (day) {
    case DAYS.monday:
      return "看电影";
    case DAYS.tuesday:
      return "购物";
    case DAYS.wednesday:
      return "健身";
    default:
      return "日期错误";
  }
}

我们希望代码逻辑足够严谨,传入的参数严格按照 DAYS.monday 的形式,否则就返回日期错误,但是该枚举类型的实现却做不到。比如:getTodo(1) 依然能得到 “看电影” 这个结果。

但是使用Symbol却可以解决这一问题,DAYS 枚举类型可以重新定义为:

代码语言:javascript
复制
const DAYS = Object.freeze({
  monday: Symbol('monday'),
  tuesday: Symbol('tuesday'),
  wednesday: Symbol('wednesday')
});

此时 getTodo 方法必须接收 DAYS.monday 这样的枚举值作为参数,否则就返回 “日期错误”,因为世界上再没有任何一个值和 DAYS.monday 相等了。

这样定义枚举显然更严谨了。

3. 使用Symbol存储元数据

Key为Symbol类型的属性是不能被枚举的,这是 Symbol 除了唯一性外的第二大特性,因此使用for...inObject.keys()Object.hasOwnProperty()等方法不能识别Symbol属性,简而言之Symbol属性对用户是“隐藏”的(但并不是private的,因为有其他途径可以获取Symbol属性),例如:

因此Symbol作为“隐藏”属性可以用来存储对象的元数据。比如,有一个 TodoList

代码语言:javascript
复制
class TodoList {
  constructor() {
    // todo数量
    this.count = 0;
  }

  // 增加todo
  add(id, content) {
    this[id] = content;
    this.count++;
  }
}

const list = new TodoList();

我们使用 add() 方法向其中增加几个todo:

代码语言:javascript
复制
list.add('a', '看电影');
list.add('b', '购物');
list.add('c', '健身');

当我们想使用 for...in 查看里面所有的todo时,会把 count 属性也带出来:

为了隐藏count属性,更方便的对todo进行操作,我们可以使用Symbol来存储它,TodoList 类修改为:

代码语言:javascript
复制
const count = Symbol('count');
class TodoList {
  constructor() {
    this[count] = 0;
  }

  add(id, content) {
    this[id] = content;
    this[count]++;
  }
}

当我们再遍历 TodoList 的时候,count就隐藏了:

当我们想获取存储在Symbol中的原数据时,可以使用 Object.getOwnPropertySymbols() 方法:

以上是我能想到的 Symbol 的用途,如果大家有其他心得体会欢迎补充。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是Symbol
  • 创建Symbol
    • Symbol.for(key)
    • 如何使用Symbol
      • 1. 用作对象的key,防止命名冲突
        • 2. 使用Symbol定义枚举
          • 3. 使用Symbol存储元数据
          相关产品与服务
          对象存储
          对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档