ES6中基礎類型增長到了7種,比上一個版本多了一個Symbol
,貌似出現了很長時間,但卻因沒有使用場景,一直看成一個概念層來理解它,我想,用它的最好的方式,仍是要主動的去深刻了解它吧,因此我從基礎部分和總結的實用場景來分析這個特性。已經瞭解使用方法或者時間緊迫者能夠從實用場景一節開始閱讀javascript
首先,它給個人第一感受就是ES6作出了不少釋放語言特性方面的改變
,它能讓咱們更加了解語言內部機制,Symbol以對象的鍵值定義,好比java
let key = Symbol('test'); let obj = {}; obj[key] = 'alone'; obj[key]; // "alone"
Symbol正如其名,表示一個惟一的標示,以屬性的方式存在於對象當中,它接收一個參數,沒有實質的做用,只是爲了作一個描述。以上咱們經過直接量的方式來定義它,而且取值時,也須要使用key進行讀取,若是出現跨做用域的狀況,是否是就不能獲取了?git
function sent(key){ accept({[key]:"2018"}) } function accept(obj) { obj[???] //我怎麼拌? }
以上兩個做用域中,若是不把key傳遞過來,是沒法讀取的,一個屬性還好,可是若是多了,那麼靠參數傳遞key是不現實的. 在這種狀況下,咱們可使用 Symbol.for
來爲它再添加一個標示
,它接受一個參數String{key}。一般,它作爲一個偏功能性的標記來表示,在全劇中它是惟一的。es6
function sent(key){ return accept({[key]:"2018"},key) } function accept(obj,key) { console.log(Symbol.keyFor(key)) //CURRENT_YEAR return obj[Symbol.for(Symbol.keyFor(key))] //CURRENT_YEAR } sent(Symbol.for('CURRENT_YEAR'))
而且使用 Symbol.for
來生成,會在存入當前全局上下文中一個<List>
結構中,咱們稱它爲GlobalSymbolRegistry
, 顧名思義,它是全局的,因此使用key時咱們須要謹慎,尤爲是在大型項目中。github
須要還注意如下幾點:segmentfault
getOwnPropertySymbols
方法,具體請參看MDN but
Symbol.for('t') === Symbol.for('t')
目前的瀏覽器版本中把Symbol打印出來是字符串的格式,並無顯示具體的對象結構,咱們能夠直接打印 Symbol,來查看對應的prototype屬性以及內部方法,因此
Symbol().__proto__ === Symbol.prototype
在使用 Symbol 作key值時,它經歷瞭如下步驟數組
因此這樣寫也是能夠的,可是貌似沒有什麼意義瀏覽器
var n = 1; var key = Symbol('numer') n[key] = ‘Symbol Number’
n[key]的時候把n隱式轉換成封裝對象,併爲他添加Symbol,但並無辦法去經過封裝對象回訪這個Symbolasync
除了單純的用key之外,在Symbol類下還有一些有意思的方法,following :函數
爲指向對象添加 iterator 接口,好比使用數組解構
或者使用for of
,它接受一個generator函數
class IteratorExec { constructor(){ this.count = 1 } *[Symbol.iterator] = function* (){ yield this.count++; yield this.count++; yield this.count++; } } let obj = new IteratorExec() [...obj] //[1,2,3]
經過添加iterator
使用數據解構,還可使用for of
let values = []; for (let value of obj) { values.push(value) } values; //[1,2,3]
注:ES6中Map,Set,數組和添加了Iterator
接口的對象,擁有Iterator接口.
這不是ES6中的特性,貌似放到了ES7中,能夠提早意淫一下以下代碼:
for await (const line of readLines(filePath)) { console.log(line); }
在對對象類型進行轉換時,會進行一次 toPrimitive
,利用這個Symbol能夠改變目標對象的轉換規則,改變了之前的 "[object Object]"的固定形式
let obj = { [Symbol.toPrimitive](hint){ switch(hint){ case 'number': return 5; case 'string': return 'string'; case 'default': return 'default' } } } obj+11 // 'default11' obj*2 // 10
這裏須要注意+ Number操做是不屬於 'number' 的,其餘正常,這樣就能夠定義轉對象類型的轉換規則了。
在javascript一切皆爲對象,而在每一個對象中,都會有一個內部屬性[[Class]]表示其對象類型,這在Symbol.toStringTag
,中是能夠修改的,也就是說 '[object Object]' 後邊的字符串是可自定義的
let obj = { [Symbol.toStringTag]:'custom' } Object.prototype.toString(obj); // [object Object] obj.toString(); //[object custom]
一般咱們使用Object.prototype.toString讀取對象屬性,正是由於向後兼容,規範在對象自身的toString上實現了這種特性,而老式方法依舊使用。可是咱們可使用如下方式:
obj = { [Symbol.toStringTag]:'custom' get [Symbol.toStringTag](){ return 'custom' } } Object.prototype.toString.call(obj)
咱們把obj傳入執行toString,能夠達到這種效果,能夠預想es6中,Object.toString是受到上下文的影響的. 顯然,咱們上面的兩個例子都是獲取的Object.prototype.toString 二者有很大區別,只有它才能準確轉換
,若是你的toString不全等於它,那是沒法轉換的,好比
var n = new Number(); n[Symbol.toStringTag] = 123; n.toString(); // 「0」
太幼稚了,太無聊了?,Number私有的toString是直接把[[PrimitiveValue]]
轉換成了字符串,這裏你們要千萬留心,不要誤認爲全部的對象添加了Symbol.toStringTag
均可以改變,若是當前對象不是純對象,那麼你能夠爲此對象添加一個 getter
返回對應的類型,這樣外部在使用Object...call的時,會獲取自定的類型。因此,這須要外部配合使用,你添加getter,人家不call你也是沒辦法的。
另外Symbol暴露了幾種爲原生對象定義了一些類型,好比
Math.toString(); //[object Math]
其餘類型有 JSON, Promise, Map, TypedArray, DataView, ArrayBuffer, Genterator等等
const object1 = { property1: 42 }; object1[Symbol.unscopables] = { property1: true }; with (object1) { console.log(property1); }
這個功能我感受可用性爲0,基本不用,with就是據對禁止的.
對於 instance
運算符,爲此操做添加一個鉤子,第一參數是instance的左值,咱們能夠返回true|false來定義運算符的返回值
var obj1 = { [Symbol.hasInstance](instance){ return Array.isArray(Array) } } class Array1 { static [Symbol.hasInstance](instance) { return Array.isArray(instance); } } [] instance obj1 //true console.log([] instanceof Array1); //true
表示[].concat是否能夠展開,默認是true.
let arr = [1,2]; arr.concat([3,4],5) //[1,2,3,4,5] arr[Symbol.isConcatSpreadable] = false; arr.concat([3,4],5) //[[1,2],3,4,5] // 也能夠把[3,4]提出來處理 let arr2 = [3,4] arr2[Symbol.isConcatSpreadable] = false; arr.concat(arr2,5); //[[1,2],[3,4],5]
只有在數組中這個symbol屬性爲false,concat操做時,就不會去解構。那麼是否是意味着屬性設置爲ture,沒有意義了?對於數組來講是的,由於它默認就是true,但是對於類數組對象,它還有一個小功能:
// (續) arr.concat({length:2,0:3,1:4,[Symbol.isConcatSpreadable]:true}) //[1,2,3,4]
一些字符串的操做方法,一塊兒都說了,大概都一個意思,就是接受一個對象,而後實現一個鉤子處理的函數,並返回其處理結果,它們都是能夠接收正則的方法,在ES6以前,若是咱們須要對字符串有比較複雜的操做基本上都是在方法外部的,必
class MyMatch { [Symbol.match](string){return string.indexOf('world') } } 'hello world'.match(new MyMatch()); //6 class MyReplace{ [Symbol.replace](string) { return 'def' } } 'abcdef'.replace(new MyReplace(),'xxx'); //'abcxxx' class mySplit { [Symbol.split](val){ return val.split('-'); } } "123-123-123".split(new mySplit()); //['123','123','123'] class MySearch { constructor(value) { this.value = value; } [Symbol.search](string) { return string.indexOf(this.value); } } var fooSearch = 'foobar'.search(new MySearch('foo')); //0 var barSearch = 'foobar'.search(new MySearch('bar')); //3 var bazSearch = 'foobar'.search(new MySearch('baz')); //-1
sanycIterator
是將來的前景,目前還在草案階段 unique
性,好比咱們想要在一個對象中添加兩個同樣的key名,這種需求很不常見,var firstPerson = Symbol("peter"); var secondPerson = Symbol("peter"); var persons = {[firstPerson]:"first", [secondPerson]:"pan"};
Symbol
更多的是在使用和語言自己層面暴露更多的使用方式和特性(on Object type),是的,它只以key的方式存在Object當中,在一切皆爲對象中,它爲 Next ECMScript Standard 提供了更多的可能性擴展性,這也是ES6中作的最大改變方面之一,雖不經常使用但咱們仍是要總結學習一下,以便在極端狀況下應變自如,若是有什麼文章中沒有涉及到的點,歡迎補充! 注: 尤爲是使用場景方面