前端
由於在2007年以前Js給予咱們typeof解析數據類型的一共有六種(一直有爭議,可是咱們暫時就按typeof來算)es6
'function'web
'Number'json
'Object'api
'boolean'數組
'String'安全
'undefined'前端工程師
但當咱們去 typeof Symbol () 的時候,會驚奇的發現,返回了一個學習
‘symbol’測試
首先確定要有疑問,這貨是啥?
固然第一種想法其實就是確定很強大。由於前六種已經強大的一種地步了,這貨確定也必定很是強大。
首先咱們先帶着咱們的好奇心一步一步來看看這個鬼東西。
首先先驗證一下它是否是對象。
經過我先說一下我對對象研究的他有三種機制:
只要是對象就能夠引用。
只要是對象均可以賦予私有屬性。
對象都不相等。
那麼
var a = Symbol(); a.b = 10;// 賦予私有屬性 a.b // undefined
看來這貨不是個對象,既然不是對象咱們來看看它的一些別的特性。
首先在 api 上 Symbol 提供了兩個方法第一個是 for 另一個是 keyFor 。
var s1 = Symbol.for('abc'); var s2 = Symbol.for('abc'); Symbol() === Symbol() //false s1 === s2 //true Symbol.keyFor(s1)// 'abc'
固然這兩個看起來比較容易 彷佛就是一個賦予一個值而後就會把原來的值吐出來,固然真是原來的值麼?帶着這樣的疑問我又繼續作了一些實驗。
var s1 = Symbol.for([1,2,3]); Symbol.keyFor(s1); // "1,2,3" 字符串的 1,2,3 var s1 = Symbol.for(function (){}); Symbol.keyFor(s1); "function (){}" 字符串的fn;
你會發現這貨你存的東西只會以字符串的東西吐出來。
固然這個東西官方說因爲每個 Symbol 值都是不相等的,這意味着 Symbol 值能夠做爲標識符,用於對象的屬性名,就能保證不會出現同名的屬性。這對於一個對象由多個模塊構成的狀況很是有用,能防止某一個鍵被不當心改寫或覆蓋。
也就是說能夠做爲存在 json 中讓 key 永遠不相等。OK ,那麼就徹底能夠這樣:
var a = {}; a[Symbol()]= 'Hello!'; a[Symbol()]= 'Hello!'; a[Symbol()]= 'Hello!'; console.log(a); Object Symbol(): "Hello!" Symbol(): "Hello!" Symbol(): "Hello!" __proto__: Object
你會發現出現了連續的三個 a的屬性 都是hello 而且沒有覆蓋 。也就是說這麼寫的話能夠有效的防止其json重名問題,不過拿起來就很是費勁了。
for(var i in a){ console.log(i +',' +a[i]) //沒有任何的東西 }
固然這就比較能夠可疑了,json 用 symbol 存上東西了,可是又用 for in 拿不到。也就說若是直接這麼賦值 json 認,可是 for in 循環不認,並且我們也拿不到。
可是換一種方式就沒問題了。用變量存的話,雖然雖然 for in 拿不到,可是我們能夠拿到值。
var a = Symbol('aaa'); b = {}; b[a] = 10 ; console.log(b[a])//10
輕鬆拿到值。其實不難看出來 Symbol 對 for in 不是很友好,可是 對 json 很友好。
這時若是使用別的方法拿值呢?顧名思義,Object.getOwnPropertyNames() 是拿對象私有屬性的的方法,咱們來試試。
let b = {}; b[Symbol()]=10; b[Symbol()]=15; Object. getOwnPropertyNames(b) //
能夠理解爲:其實 Symbol 不做爲 b 的私有屬性存在。拿能不能拿到呢?其實也能拿到。他提供了一個 getOwnPropertySymbols 方法可讓我找到存在內存裏的 Symbol 。
例如:
let a = {}; a[Symbol()]=10; a[Symbol()]=15; Object.getOwnPropertySymbols(a) //[Symbol(),Symbol()] //這裏面以數組的形式返回了 我們使用的兩個Symbol(); Object.getOwnPropertySymbols(a)[0]//Symbol() 第一個Symbol() a[Object.getOwnPropertySymbols(a)[0]]//10 拿到存在的這個值。
其實知道是數組後 咱們就能夠循環 obj.getOwnPropertySymbols(a) 這個東西 而後輸出值了。其實說回來只是換了一種方法拿值,存值。而這種方法更安全更隱蔽而已。
而Symbol還有一些比較特殊的特性。js中的~(按位非) 是一個比較強勢的轉換number的東西。
例如:
~NaN //-1 ~function (){}//-1 ~undefined //-1 var a = function (){}; ~a() //-1 ~new a() //-1
基本任何東西都能轉成number,而:
~Symbol //-1 ~Symbol() //報錯
彷佛說明了 其跟function 有着本質的區別,另外呢,Symbol值不能與其餘類型的值進行運算,會報錯。
var sym = Symbol('My symbol'); "your symbol is " + sym // TypeError: can't convert symbol to string es5以前的報錯 `your symbol is ${sym}` // TypeError: can't convert symbol to string es6字符串照樣的報錯
另外,Symbol值也能夠轉爲布爾值,可是不能轉爲數值。這些都是Symbol的一些小特性。
var sym = Symbol(); Boolean(sym) // true !sym // false Number(sym) // TypeError sym + 2 // TypeError
其實來講Symbol做爲一個新的數據類型 最強的而不是幹以上的這些事而是一些配合原型方法的一些開關,能夠強化方法的使用。
好比說 Symbol.isConcatSpreadable 這個方法,我們都知道 正常的數組concat方法是鏈接字符串。
let arr = ['c', 'd']; ['a', 'b'].concat(arr2,'e') //['a','b','c','d','e'];
而咱們一旦把開關打開後會發現一些意想不到的結果。
let arr2 = ['c', 'd']; arr2[Symbol.isConcatSpreadable] = false; ['a', 'b'].concat(arr2, 'e') //['a','b',['c','d'],'e']
會發現以數組的形式插入到裏面了。固然他還包括了一些別的方法,例如,他能夠測試 ES6 新增的內置對象方法 Symbol.toStringTag 。
JSON[Symbol.toStringTag]:'JSON' Math[Symbol.toStringTag]:'Math' Module對象M[Symbol.toStringTag]:'Module' ArrayBuffer.prototype[Symbol.toStringTag]:'ArrayBuffer' DataView.prototype[Symbol.toStringTag]:'DataView' Map.prototype[Symbol.toStringTag]:'Map' Promise.prototype[Symbol.toStringTag]:'Promise' Set.prototype[Symbol.toStringTag]:'Set' %TypedArray%.prototype[Symbol.toStringTag]:'Uint8Array'等 WeakMap.prototype[Symbol.toStringTag]:'WeakMap' WeakSet.prototype[Symbol.toStringTag]:'WeakSet' %MapIteratorPrototype%[Symbol.toStringTag]:'Map Iterator' %SetIteratorPrototype%[Symbol.toStringTag]:'Set Iterator' %StringIteratorPrototype%[Symbol.toStringTag]:'String Iterator' Symbol.prototype[Symbol.toStringTag]:'Symbol' Generator.prototype[Symbol.toStringTag]:'Generator' GeneratorFunction.prototype[Symbol.toStringTag]:'GeneratorFunction'
不過,用 ES5 以前的方法依然也能夠檢驗出來內置對象,因此 Symbol 就是更規範化而已,就用 map 舉例。
Object.prototype.toString.call(new Map())//'[object Map]'
別的內置對象也是同理。Symbol.unscopables 也是Symbol一個比較有意思的東西。能夠找到對象內哪些屬性被with排除。
Object.keys(Array.prototype[Symbol.unscopables])//['copyWithin', 'entries', 'fill', 'find', 'findIndex', 'keys']
以數組的形式返回 也就是說 這些屬性會被with排除。其實這些只是Smybol的冰山一角,更多的是Symbol是服務於ES6中。讓咱們繼續慢慢探索好了。
更多學習內容請閱讀個人知乎專欄: 打造全網web高級前端工程師資料庫(總目錄)看完學的更加快,知識更牢固。你值得擁有(持續更新)~