JS的所謂的第七種數據類型Symbol

首先,爲何說叫所謂呢?前端

 

由於在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高級前端工程師資料庫(總目錄)看完學的更加快,知識更牢固。你值得擁有(持續更新)~

相關文章
相關標籤/搜索