首先,為什麼說叫所謂呢? 因為在2007年之前Js給予我們typeof解析數據類型的一共有六種(一直有爭議,但是我們暫時就按typeof來算) 'function' 'Number' 'Object' 'boolean' 'String' 'undefined' 但當我們去 typeof Symbo ...
因為在2007年之前Js給予我們typeof解析數據類型的一共有六種(一直有爭議,但是我們暫時就按typeof來算)
'function'
'Number'
'Object'
'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中。讓我們繼續慢慢探索好了。