每周分享:类型新成员 Symbol

前面我们介绍了迭代器的本质在于 Symbol.iterator 这个属性

let obj = {}
obj[Symbol.iterator] =  () => { ... }

一般来说对象的 key 都是一个字符串,而这里的 Symbol.iterator 也是一个字符串吗?很明显不是的,这是一个 symbol 类型的值,它和 string,number,boolean,null,undefined 一起组成了 JavaScript 的 6 种基本数据类型。

自定义 symbol

我们可以通过下面的语法定义自己的 symbol

Symbol([描述])

注意,不能使用 new Symbol()。这里的描述主要用于调试的时候方便查看,比如

var sym1 = Symbol('hello')
var sym2 = Symbol('hello')

由于 symbol 具有唯一性,所以上面两个即便描述一样,但是却不相等

sym1 === sym2
// false

除了这种方式,还可以用 Symbol.for(key) 语法,使用一个唯一 key 搜索现有的 symbol,找到了就返回,没有找到就创建一个新的

var sym3 = Symbol.for('key')
var sym4 = Symbol.for('key')

sym3 === sym4
// true

其实这种方式主要是用来查找已经存在的 symbol,不建议用来创建新的 symbol。创建好的 symbol 就可以用在一个对象的键中了

var man = {}
var key = Symbol('age')

man[key] = 25

console.log(man[key])
// 25

注意,由于 symbol 的特殊性,在用作 key 的时候只能是括号语法(obj[symbol]),而不能是点语法(obj.symbol)。

内置 symbol

除了 Symbol.iterator,还有一些其它的内置 symbol,比如 Symbol.search 用在字符串搜索 String.prototype.search() 方法中

var str = 'hello'

'hello'.search('o')
// 4

let mySearch = {}
mySearch[Symbol.search] = () => {
  return '弄啥呢'
}


'hello'.search(mySearch)
// '弄啥呢'

可见 search() 方法确实使用了 Symbol.search 。

枚举

var man = {
  name: 'tom'
}
var key = Symbol('age')

man[key] = 25

Object.keys(man)
// ["name"]

因为 symbol 类型的属性是不可枚举的,自然也不能被 for...in 遍历到,包括 getOwnPropertyNames 也是拿不到的

Object.getOwnPropertyNames(man)
// ["name"]

此外 JSON.stringify() 也拿它没办法

JSON.stringify(man)
// "{"name":"tom"}"

所以要拿到 symbol 类型的键,只能通过一个特殊的方法 getOwnPropertySymbols

Object.getOwnPropertySymbols(man)
// [Symbol(age)]

因此我们可以拿到一个数组的迭代器 symbol 属性(在其原型上)

Object.getOwnPropertySymbols([].__proto__)
// (2)[Symbol(Symbol.iterator), Symbol(Symbol.unscopables)]

其实还可以用 Reflect.ownKeys(),用于返回一个对象自身的所有属性,它等价于 Object.getOwnPropertyNames()Object.getOwnPropertySymbols() 之和

Reflect.ownKeys(man)
// [Symbol(age)]

可见,symbol 类型的 key 在很多对象操作方法中都是拿不到的,更像是一个隐身的键,在有类似需求的时候是不错的选择。

最新评论

  1. Wow, what a video it is! Actually fastidious feature video, the lesson given in this video is actually informative. Graig Baras

发表评论

邮箱地址不会被公开。 必填项已用*标注