ES6系列Symbol数据类型

一. 概述

1. 基本含义

由于对象的属性名都是字符串,所以很容易出现属性名的冲突

在使用了某个别人的对象后,想给对象添加新的属性mixin模式,新属性的名字就可能和现有的属性发生冲突

Symbol数据类型的引入就是为了从根本上防止属性名冲突。

ES6中引入的Symbol数据类型表示独一无二的值,属于基本数据类型的一种

// 1. 使用Symbol函数生成

var a=Symbol("foo")

console.log(a);//Symbol(foo)

console.log(typeof a);//symbol

// 2. 使用new Symbol会报错(因为没有包装对象,没有构造器函数)

var b=new Symbol("b");//TypeError: Symbol is not a constructor

// 3. Symbol值即使参数一致,也不是同一个变量!

console.log(a===Symbol("foo"));//false

console.log(a==Symbol("foo"));//false

Symbol函数前不能使用new命令,否则会报错,这是因为Symbol值不是对象,只是类似字符串的数据类型,但是没有包装对象

Symbol值即使参数一致,也不是同一个变量!因为参数仅仅起到描述作用

2. 参数

如果Symbol可以有一个参数,表示该值的描述信息,也可以不添加该参数

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

// 1.没有参数

var a=Symbol()

// console.log(a);/Symbol()

// 2. 参数为字符串

var b=Symbol("b")

// console.log(b);//Symbol(b)

// 3. 参数为其他基本数据类型(先转换为字符串再转换为Symbol值,注意undefined会转为空)

var c=Symbol(1);//Symbol(1)

// var c=Symbol(false);//Symbol(false)

// var c=Symbol(undefined);//Symbol()

// var c=Symbol(null);//Symbol(null)

var c=Symbol(NaN);//Symbol(NaN)

console.log(c)

// 4. 参数为引用对象类型(即使无属性,也是Symbol([object Object]))

var d=Symbol({a:1})

console.log(d);//Symbol([object Object])

var e=Symbol({e:3,c:'ss'})

console.log(e);//Symbol([object Object])

var p=Symbol({})

console.log(p);//Symbol([object Object])

// 5.定义对象的toString方法

var obj={

toString(){

return '我是自定义对象的方法'

}

}

console.log(Symbol(obj));//Symbol(我是自定义对象的方法)

3. 转换

Symbol值不能和其他值进行运算,会报错!

Symbol值可以转换为字符串,通过toString()或者String()

Symbol值也可以转为布尔值,但是不可以转为数值

// 1.Symbol运算

// console.log(Symbol(1)+Symbol(2));//Cannot convert a Symbol value to a number

// console.log(Symbol(1)+1);//Cannot convert a Symbol value to a number

// console.log("i am"+Symbol("ww"));//Cannot convert a Symbol value to a string

// 2.Symbol值可以显式转为字符串

console.log(String(Symbol("2")));//Symbol(2)

console.log(Symbol("ss").toString());//Symbol(ss)

// 3.Symbol值可以转为布尔值

console.log(Boolean(Symbol(1)));//true

// 4.Symbol值不能转为数值

console.log(Number(Symbol(1)));//Cannot convert a Symbol value to a number

二. Symbol描述

虽然可以通过String(),toString()来获取Symbol值的描述,但是会带有Symbol()前缀

ES2019提供了description属性来直接返回描述console.log(Symbol("foo").description);//foo

三. Symbol作为属性名

Symbol常常用于作为属性名,防止属性被覆盖!

1.有以下三种用法

var a=Symbol("foo")

// 1.

// var obj={}

// obj[a]="ww";

// console.log(obj[a]);//ww

//2

/*  var obj={

[a]:"ww"

}

console.log(obj[a]);//ww */

//3.Object.defineProperty(),不设置enumerable的话,定义的属性默认是不可枚举的

var obj={}

Object.defineProperty(obj,a,{value:"ww"})

console.log(obj[a]);//ww

//{value: "ww", writable: false, enumerable: false, configurable: false}

console.log(Object.getOwnPropertyDescriptor(obj,a));

2.注意事项

如果属性a属于Symbol类型,那么不能使用obj.a 形式!因为会被识别为字符串

var a=Symbol()

var obj={}

// 1. 使用点运算符,后面的变量被视为字符串

obj.a="ss"

console.log(obj.a);//ss

// 2. 使用中括号形式

obj[a]="hello"

console.log(obj[a]);//hello,此时指向的是Symbol类型的变量

console.log(obj.a);//ss,此时指向的是a这个属性!

作为对象方法使用

// 1.相当于属性

var a=Symbol()

var obj={

[a]:function(){ return 1}

}

console.log(obj[a]());//1

//2.对象方法

let b={

[a](){

return 2

}

}

console.log(b[a]());//2

四. 消除魔术字符串

魔术字符串就是在代码中多次出现,和代码形成强耦合的字符串,应该尽量消除魔术字符串,改用变量代替

使用Symbol消除的一个例子

// 1. 存在魔术字符串时

function getData(str,options){

var res;

switch(str){

case "str":

res= options.a+options.b;

}

return res;

}

console.log(getData("str",{a:3,b:2}));// str这个字符串形成了强耦合

// 2. 使用Symbol解决

var a={

e:Symbol()

}

function tryData(str,options){

var res;

switch(str){

case a.e:

res= options.a+options.b;

}

return res;

}

console.log(tryData(a.e,{a:3,b:2}))

五.Symbol属性名的遍历

for...in;for...of循环;Object.keys(),Object.values(),Object.entries();Object.getOwnPropertyNames();JSON.stringfy()都不会出现Symbol属性名

Object.getOwnPropertySymbols()方法可以获取到对象的所有Symbol属性名,但是不能获取到除了Symbol之外的属性

另外Reflect.ownKeys()可以获取到所有类型的键名,包括Symbol,不可枚举

var obj={a:1,1:'e',3:'y',b:99}

obj[Symbol('q')]='symbol'

obj[Symbol('p')]='p'

//1.for in,for...of

for(var item in obj){

console.log(item);//1,3,a,b

}

// obj is not iterable 报错

// for(var item of obj){

//  console.log(item)

// }

//2.JSON.stringfy

console.log(JSON.stringify(obj));//{"1":"e","3":"y","a":1,"b":99}

//3. Object.getOwnPropertySymbols

console.log(Object.getOwnPropertySymbols(obj));//[Symbol(q), Symbol(p)]

//4. Reflect.ownkeys()

console.log(Reflect.ownKeys(obj));//["1", "3", "a", "b", Symbol(q), Symbol(p)]

六.Symbol.for()和Symbol.keyFor()

有时我们需要知道是否存在该名称的Symbol变量,或者进行修改,但是直接使用Symbol()会新增一个变量

1. Symbol.for()

使用Symbol.for()可以接受一个字符串作为参数,然后搜索是否存在使用过Symbol.for()的同名变量

// 1. Symbol,还有一个Symbol.for

var a=Symbol('a')

var aa=Symbol.for('a')

console.log(a===aa);//false

//2. 两个都是用了Symbol.for()

var b=Symbol.for('b')

var bb=Symbol.for('b')

console.log(b===bb);//true

//3. 空参数

var c=Symbol.for()

var cc=Symbol.for()

console.log(c===cc);//true

当不存在同名Symbol.for()定义的方法时,定义之后会注册到全局中

而使用Symbol()方法不会把变量注册到全局中!

2. Symbol.keyFor()

Symbol.keyFor()可以返回已在全局注册(Symbol.for())的Symbol类型的参数名

并且Symbol.for()即使在函数中,也是把变量注册到全局的

// 1. Symbol.keyFor()

var s1=Symbol.for('a')

var s2=Symbol('b')

console.log(Symbol.keyFor(s1));//a

console.log(Symbol.keyFor(s2));//undefined,没有在全局注册

// 2.在函数中使用Symbol.for()也是注册到全局中

function func(){

return Symbol.for('bar')

}

var x=func();// 注册bar到全局了

var y=Symbol.for('bar')

console.log(x===y);//true

七. Symbol的一些方法

1. Symbol.hasInstance()

foo instanceof MyClass相当于 MyClass[Symbol.hasInstance](foo)

class MyArray{

static [Symbol.hasInstance](instance){

return Array.isArray(instance)

}

}

console.log([1] instanceof MyArray);//true,static静态属性才能被类直接使用,去掉则false

2. Symbol.match()

对象的Symbol.match属性指向一个函数,当执行str.match(obj)的时候该属性存在则调用,返回方法的返回值

str.match(func),相当于 [symbol.macth](str)

// 使用方法一:使用类的实例

class MyClass{

[Symbol.match](str){

return '字符串'

}

}

console.log("hello blog".match(new MyClass()));//字符串

// 方法二;使用对象属性

var obj={

[Symbol.match](str){

return str;

}

}

console.log('hhha'.match(obj));//hhha

3. Symbol.iterator()

只要调用...拓展运算符,那么相当于执行了对象里面存在[Symbol.iterator]方法

var obj={

* [Symbol.iterator]() {

yield 1;

yield 2;

yield 3;

}

}

console.log([...obj]);//[1, 2, 3]

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200612A007F000?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

同媒体快讯

扫码关注云+社区

领取腾讯云代金券