ES6中的Symbol

欢迎访问我的博客https://qqqww.com/,祝码农同胞们早日走上人生巅峰,迎娶白富美~~~

1 引入Symbol的好处

为解决属性名冲突问题而生

ES5 中方法和属性的命名

以前,我们给一个对象下的方法或者属性命名的时候,可能会与该对象原有的方法或者属性产生冲突,这样的场景想必大家也很熟悉,我们常用到的解决办法是将方法前加一段项目名称的简拼或者一些其他的方式,其根本原因就是给方发或者属性带上一个独一无二的标志,最大限度的防止命名上的冲突

ES6 中方法和属性的命名

ES6中引入了Symbol数据类型,其基本解决思路也是和ES5差不多的,只不过就是直接利用Symbol能够表示一个独一无二的值,这就从根本上防止方法或者属性名的冲突

2 Symbol基本概念

SymbolES6中引入得一种新型的数据类型,它是 JavaScript 语言的第七种数据类型,前六种是:undefinednull、布尔值Boolean、字符串String、数值Number、对象Object`

2.1 基本用法

下面一个简单的例子说明如何生成Symbol

let a = Symbol()
typeof a // 'symbol'

Symbol值通过Symbol()函数生成,且凡是属性名属于'symbol'类型就不会与其他属性名冲突,我们来看看下面一个例子

let a1 = Symbol()
let a2 = Symbol()
a1 === a2 // false

看起来仿佛一模一样的a1a2实际上是不相等的,这进一步说明了Symbol值是独一无二的

2.2 Symbol 中的参数

Symbol函数中可以传参,只用以描述Symbol实例,为了在控制台输出时利于区分

let a1 = Symbol('foo')
let a2 = Symbol('bar')

a1 // Symbol(foo)
a2 // Symbol(bar)

上述代码:

  1. 若不加参数,虽然二者都是独一无二的,二者是不一样的,这在上面的例子中也提到过,但是他们在控制台打印的结果却都是Symbol()
  2. 现在给他们分别加上参数,在控制台打印出来就能一眼辨别了
  3. 那么加上参数,若参数是一样的,说明描述也一样,那他们的Symbol值相等吗?看下面一个例子
let a1 = Symbol('foo')
let a2 = Symbol('foo')

a1 // Symbol(foo)
a2 // Symbol(foo)

a1 === a2 // false

可见,依然不相等,这又进一步的证明了,Symbol值的独一无二

2.3 Symbol 转换

请看下面的四个例子,对应这四点

  1. Symbol 值可以显式转为字符串
  2. Symbol 值也可以转为布尔值
  3. Symbol 值不能转为数值,且不能做数值运算
  4. Symbol 值不能与其他类型的值进行运算
let a1 = Symbol('foo')
String(a1) // 'Symbol(foo)'
a1.toString // 'Symbol(foo)'
let a1 = Symbol('foo')
Boolean(a1) // true
!a1 // false
let a1 = Symbol('foo')
Number(a1) // TypeError
a1 + 1 // TypeError
let a1 = Symbol('foo')
'hello' + a1 // TypeError: can't convert symbol to string

3 Symbol 值作为属性名

由于Symbol值的独一无二,将其作为对象的属性以防止属性名冲突问题再合适不过了

注意:关于下面例子中Object.definproperty

  1. 该方法会直接在一个对象上定义一个新对象,或者修改一个对象的现有属性,并返回这个对象
  2. 语法Object.defineProperty(obj, prop, descriptor)
  3. 参数
    1. obj:要在obj上定义属性,就写obj
    2. prop:要修改的属性
    3. descriptor:属性值
  4. 例如下面例子中的:Object.definproperty(obj3, a, { value: '我是symbol值a作为obj对象的属性' })表示在对象obj3上修改属性prop,其属性值修改为'我是symbol值a作为obj对象的属性'
let a = Symbol()
// 写法一
let obj1 = {}
obj1[a] = '我是symbol值a作为obj对象的属性'
// 写法二
let obj2 = {
    [a]: '我是symbol值a作为obj对象的属性'
}
// 第三种写法
let obj3 = {}
Object.definproperty(obj3, a, { value: '我是symbol值a作为obj对象的属性' })

obj1[a] // '我是symbol值a作为obj对象的属性'
obj2[a] // '我是symbol值a作为obj对象的属性'
obj3[a] // '我是symbol值a作为obj对象的属性'

注意:不能像以前对象那样用.运算

let a = Symbol()
let obj = {}
obj[a] = '我是symbol值a作为obj对象的属性'
obj[a] // '我是symbol值a作为obj对象的属性'
obj.a // undefined

注意:在对象的内部,使用 Symbol 值定义属性时,Symbol 值必须放在方括号之中

let a = Symbol()
let obj = {
    [a]: function(x) { ... }
}

也可以简写为

let a = Symbol()
let obj = {
    [a](x) { ... }
}
// 调用
obj[a](1)

4 Symbol 类型定义常量

定义一组常量,保证这组常量的值都是不相等的

const obj = {}
obj.alw = {
    DEBUG: Symbol('debug'),
    INFO: Symbol('info'),
    WARN: Symbol('warn') 
}

5 Symbol 消除魔术字符串

先解释几个名词:

什么叫魔术字符串:在代码中多次出现,且与代码形成强耦合的某一个具体的字符串或者数值,这种关联性太多的字符串就会导致变量含义不明确,所以应当尽量消除魔术字符串,改由含义清晰的变量代替

耦合性:常用来表示块之间的联系,耦合性越强,其代码块或者模块之间的联系就越强,设计代码块或者模块就是为了其功能的独立性,所以往往更希望低耦合

内聚性:常用来表示块内在的联系,内聚性越强,模块功能强度越强,即一个模块内各元素(语名之间、程序段之间)联系的就越紧密,所以一般就更希望高内聚

看了以上几个名词解释想必就能清晰地理解上面的魔术字符串了吧,简单粗暴的讲就是这样的变量出现多次,就和代码形成了强大的联系,不利于以后的修改和维护,下面的几个例子借用了阮一峰老师在《ES6标准入门第3版》中的例子

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 }); // 魔术字符串

常用的消除魔术字符串的方法,就是把它写成一个变量,这种方法也叫变量本地化,这样假如需要维护和修改就只需要修改最初定义的变量的值就行了

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()
};

6 属性名的遍历

ES6中提供有Object.getOwnPropertySymbols方法,可以获取指定对象的所有 Symbol 属性名

Object.getOwnPropertySymbols方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol

let a = Symbol('a')
let b = Symbol('b')
let obj = {}
obj[a] = 'hello'
obj[b] = 'world'
const objs = Object.getOwnPropertySymbols(obj)
objs // [Symbol(a), Symbol(b)]

7 Symbol.for()

若想使用同一个Symbol值,就用Symbol.for() 方法

let a1 = Symbol.for('a')
let a2 = Symbol.for('a')
a1 === a2 // true

let a1 = Symbol.for()
let a2 = Symbol.for()
a1 === a2 // true

let a1 = Symbol.for('a')
let a2 = Symbol.for('b')
a1 === a2 // false

看上述例子,请注意,当参数两个需要重用的值参数要不然都不写,要不然一定要一样,否则二者不会相等

8 Symbol.keyFor()

Symbol.keyFor方法返回一个已登记的 Symbol 类型值的key

// Symbol.for 有参数
let a1 = Symbol.for('a')
Symbol.keyFor(a1) // "a"

// Symbol.for 无参数
let a1 = Symbol.for()
Symbol.keyFor(a1) // undefined

// 无 Symbol.for 表明未登记
let a1 = Symbol()
Symbol.keyFor(a1) // undefined

从上述代码看出,往往返回的就是那个参数,但是当没有参数或者没有使用Symbol.for()方法的时候返回undefined

9 其他

剩下的一些内容,本来我自己也接触比较少,就没在这里写,详细请移步Symbol

10 参考文章

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • Symbol是Es6中的一个新特性,它是一个基本数据类型。 javascript从Es6起,基本数据类型变为6种 ...
    秦声阅读 714评论 1 9
  • 概述 ES5的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加...
    oWSQo阅读 508评论 1 3
  • 1.概述 ES5的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象...
    赵然228阅读 800评论 2 10
  • 关于循环的小伎俩 不管是while还是for,所发起的循环,在python编程中是经常被用到的。特别是for,一般...
    hiekay阅读 808评论 0 0
  • 爱是个会躲藏的精灵,你总觉得抓不住他,也看不见他。但其实,他一直在我的家中默默地和我捉迷藏。 ...
    巧克力豆1阅读 588评论 3 4