1营曼、概述
ES5對象屬性名都是字符串容易造成屬性名的沖突黄锤。
eg:var a = { name: 'lucy'};
a.name = 'lili';
這樣就會重寫屬性
ES6引入了一種新的原始數(shù)據(jù)類型Symbol肠缨,表示獨(dú)一無二的值佩憾。
七種數(shù)據(jù)類型
JavaScript 在 1997 年被標(biāo)準(zhǔn)化時掩蛤,就有 6 種數(shù)據(jù)類型枉昏,直到 ES6 出現(xiàn)之前,程序中的變量一定是以下 6 種數(shù)據(jù)類型之一:
Undefined
Null
Boolean
Number (包括 NAN)
String
Object
注意揍鸟,Symbol函數(shù)前不能使用new命令兄裂,否則會報錯。這是因為生成的Symbol是一個原始類型的值,不是對象
Symbol函數(shù)可以接受一個字符串作為參數(shù)懦窘,表示對Symbol實(shí)例的描述前翎,主要是為了在控制臺顯示,或者轉(zhuǎn)為字符串時畅涂,比較容易區(qū)分港华。
var sym1 = Symbol();
var sym2 = Symbol("foo");
var sym3 = Symbol("foo");
console.log(sym1, sym2, sym3) //輸出Symbol() Symbol(foo) Symbol(foo)
// 沒有參數(shù)的情況
var s1 = Symbol();
var s2 = Symbol();
s1 === s2 // false
// 有參數(shù)的情況
var s1 = Symbol("foo");
var s2 = Symbol("foo");
s1 === s2 // false
Symbol值不能與其他類型的值進(jìn)行運(yùn)算
注:可以轉(zhuǎn)為字符串,布爾值午衰,不能轉(zhuǎn)為數(shù)值
2立宜、作為屬性名的Symbol
var mySymbol = Symbol();
// 第一種寫法
var a = {};
a[mySymbol] = 'Hello!';
// 第二種寫法
var a = {
[mySymbol]: 'Hello!'
};
// 第三種寫法
var a = {};
Object.defineProperty(a, mySymbol, { value: 'Hello!' });
// 以上寫法都得到同樣結(jié)果
a[mySymbol] // "Hello!"
我們可以用typeof判斷某一個變量類型為Symbol類型:
typeof Symbol() === 'symbol' //輸出:true
typeof Symbol('foo') === 'symbol' //輸出: true
typeof Symbol.iterator === 'symbol' //輸出 : true
如果我們不知道Symbol的實(shí)例名字是什么,我們怎么獲取到Symbol值的呢, Symbol無法被for in 臊岸, for of循環(huán)橙数,以及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的唯一區(qū)別是 Symbol.for創(chuàng)建的兩個實(shí)例可能相等灯帮, 根據(jù)Symbol的參數(shù)生成實(shí)例, 如果參數(shù)一樣逻住, 那么會返回同一個實(shí)例钟哥;
let foo = Symbol.for( "1111" );
let bar = Symbol.for("1111");
console.log( foo === bar ); //輸出: true
//只有通過Symbol.for創(chuàng)建的對象,才能用keyFor找到原來的參數(shù)瞎访;
console.log(Symbol.keyFor(foo)) //會輸出:1111
當(dāng)出現(xiàn) key1 === key2 時就會有 Symbol.for( key1 ) === Symbol.for( key2 ) 腻贰。這種對應(yīng)關(guān)系甚至是跨 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 值和字符串之間有一一對應(yīng)的關(guān)系扒秸,所以我們也可以檢索字符串鍵播演。使用 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 的方法之一是創(chuàng)建閉包:
let Square = (function() {
const _width = Symbol('width');
class Square {
constructor( width0 ) {
this[_width] = width0;
}
getWidth() {
return this[_width];
}
}
return Square;
} )();
這樣做的好處是,他人很難訪問到我們對象的私有 _width 值锣吼,而且也能很好地區(qū)分,哪些屬性是公有的蓝厌,哪些屬性是私有的玄叠。但這種方法的缺點(diǎn)也很明顯:
通過調(diào)用 Object.getOwnPropertySymbols ,我們可以使用 Symbol 鍵拓提。
如果要寫很多的代碼读恃,這會使得開發(fā)者的體驗不佳,訪問私有屬性不像 Java 或 TypeScript 那樣方便。
如果你要用 Symbol 來表示私有字段寺惫,那你需要表明哪些屬性不能被公開訪問疹吃,如若有人試圖違背這一規(guī)則,理應(yīng)承擔(dān)相應(yīng)的后果西雀。
內(nèi)置的Symbol值
有11個方法萨驶,具體可以查看http://es6.ruanyifeng.com/#docs/symbol