首先,為什么說叫所謂呢?
因為在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中,讓我們繼續慢慢探索好了,
總結
如果你覺得這篇文章不錯,請別忘記點個贊跟關注哦~??
更多學習內容請閱讀我的知乎專欄: 打造全網web高級前端工程師資料庫(總目錄)看完學的更加快,知識更牢固,你值得擁有(持續更新)~
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/45574.html
標籤:JavaScript
