Symbol

1、概述
ES5对象属性名都是字符串容易造成属性名的冲突。

eg:var a = { name: 'lucy'};
a.name = 'lili';

这样就会重写属性

ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。
七种数据类型
JavaScript 在 1997 年被标准化时,就有 6 种数据类型,直到 ES6 出现之前,程序中的变量一定是以下 6 种数据类型之一:
Undefined
Null
Boolean
Number (包括 NAN)
String
Object

注意,Symbol函数前不能使用new命令,否则会报错。这是因为生成的Symbol是一个原始类型的值,不是对象
Symbol函数可以接受一个字符串作为参数,表示对Symbol实例的描述,主要是为了在控制台显示,或者转为字符串时,比较容易区分。

var sym1 = Symbol();
var sym2 = Symbol("foo");
var sym3 = Symbol("foo");
console.log(sym1, sym2, sym3) //输出Symbol() Symbol(foo) Symbol(foo)

// 没有参数的情况
var s1 = Symbol();
var s2 = Symbol();
s1 === s2 // false

// 有参数的情况
var s1 = Symbol("foo");
var s2 = Symbol("foo");
s1 === s2 // false

Symbol值不能与其他类型的值进行运算
注:可以转为字符串,布尔值,不能转为数值

2、作为属性名的Symbol

var mySymbol = Symbol();

// 第一种写法
var a = {};
a[mySymbol] = 'Hello!';

// 第二种写法
var a = {
  [mySymbol]: 'Hello!'
};

// 第三种写法
var a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });

// 以上写法都得到同样结果
a[mySymbol] // "Hello!"

我们可以用typeof判断某一个变量类型为Symbol类型:

typeof Symbol() === 'symbol' //输出:true
typeof Symbol('foo') === 'symbol' //输出: true
typeof Symbol.iterator === 'symbol' //输出 : true

如果我们不知道Symbol的实例名字是什么,我们怎么获取到Symbol值的呢, Symbol无法被for in , for of循环,以及Object.keys, Object.values 等都无法遍历到Symbol的属性; Object下给我们提供了一个

getOwnPropertySymbols;

let sym0 = Symbol("o_o?");
let obj = {
    [sym0] : "heheda"
}
for( let prop of Object.getOwnPropertySymbols(obj) ) {
    //prop就是Symbol的名字
    console.log( obj[prop] ); //输出:heheda
};
或者用ES6提供的反射 : Reflect.ownKeys
let sym0 = Symbol("o_o?");
let obj = {
    [sym0] : "heheda"
}
console.log( Reflect.ownKeys(obj) ); //输出:[ Symbol(o_o?) ]

Symbol.for和Symbol的唯一区别是 Symbol.for创建的两个实例可能相等, 根据Symbol的参数生成实例, 如果参数一样, 那么会返回同一个实例;

let foo = Symbol.for( "1111" );
let bar = Symbol.for("1111");
console.log( foo === bar );  //输出: true
//只有通过Symbol.for创建的对象,才能用keyFor找到原来的参数;
console.log(Symbol.keyFor(foo)) //会输出:1111

当出现 key1 === key2 时就会有 Symbol.for( key1 ) === Symbol.for( key2 ) 。这种对应关系甚至是跨 service worker 和 iframe 的。

let privateProperty1 = Symbol.for( 'firstName' );
let privateProperty2 = Symbol.for( 'firstName' );
 
myObject[ privateProperty1 ] = 'Dave';
myObject[ privateProperty2 ] = 'Zsolt';
 
console.log( myObject[ privateProperty1 ] );
// Zsolt

因为 Symbol 注册表中的 Symbol 值和字符串之间有一一对应的关系,所以我们也可以检索字符串键。使用 Symbol.keyFor 方法。

Symbol.keyFor( privateProperty1 );
> "firstName"
 
Symbol.keyFor( Symbol() );
> undefined

Symbol 作为半私有属性键

即使 Symbol 不能使属性私有,它们也能用作带有私有属性的符号。你可以使用 Symbol 来分隔公有和私有属性的枚举 ,Symbol 能使它更清楚。

const _width = Symbol('width');
class Square {
    constructor( width0 ) {
        this[_width] = width0;
    }
    getWidth() {
        return this[_width];
    }
}

只要你能隐藏 _width 就行了,隐藏 _width 的方法之一是创建闭包:

let Square = (function() {
 
    const _width = Symbol('width');
 
    class Square {
        constructor( width0 ) {
            this[_width] = width0;
        }
        getWidth() {
            return this[_width];
        }
    }
 
    return Square;  
 
} )();

这样做的好处是,他人很难访问到我们对象的私有 _width 值,而且也能很好地区分,哪些属性是公有的,哪些属性是私有的。但这种方法的缺点也很明显:

通过调用 Object.getOwnPropertySymbols ,我们可以使用 Symbol 键。
如果要写很多的代码,这会使得开发者的体验不佳,访问私有属性不像 Java 或 TypeScript 那样方便。
如果你要用 Symbol 来表示私有字段,那你需要表明哪些属性不能被公开访问,如若有人试图违背这一规则,理应承担相应的后果。

内置的Symbol值
有11个方法,具体可以查看http://es6.ruanyifeng.com/#docs/symbol

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 1.概述 ES5的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象...
    赵然228阅读 818评论 2 10
  • 1. 概述 ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数...
    ForeverYoung20阅读 775评论 1 0
  • 前端技术日新月异,不断有新技术出现,我们就需要不断地学习新知识,虽然ES6已经提出很久了,但是最近我才有时间静下心...
    艰苦奋斗的侯小憨阅读 4,198评论 3 5
  • 每天写亲子日记,真的是一种习惯了,不管多晚多累,这件事已成为我生活的一部分了,今天不说孩子就说说自己的生活吧!今天...
    云轩妈妈阅读 118评论 0 0
  • 「招聘是最重要的事情」--《Google 是如何运作的》 我们希望依靠良好的招聘机制,并配合优秀的团队氛围,以吸引...
    Samuel_龚生阅读 261评论 0 0