Symbol 函数
Symbol :每次返回的都是一個新的值;
1.Symbol是ES6引進的一種新的原始數據類型,表示一種獨一無二的值;2.Symbol值通過Symbol函數來生成,這就是說,現在的屬性值有兩種類型:
2.1 一種是原有的字符串的值;
2.2 一種是新增的Symbol函數的值;
2.3 凡是屬性名屬于Symbol類型,就是獨一無二的值,可以保證不會和其他屬性名產生沖突;
example:?
let s = Symbol() ;
typeof s ;
在這里的Symbol就是一個獨一無二的值 ;
注意:?
Symbol函數不能使用new, 因為他不是一個對象,而是一個類似于字符串的值;所以,它不能添加屬性;
4.Symbol可以接收一個字符串作為參數,表示對Symbol函數的描述;
這樣是為了方便的在控制臺里面顯示,或者是轉換稱為字符串時方便輸出;
example 1 :
var s1 = Symbol( 'foo1' ) ;
var s1 = Symbol( 'foo2' ) ;
s1 // Symbol( 'foo1' ) ;
s2 // Symbol( 'foo2' ) ;
s1.toString() // "Symbol( 'foo2' )" ;
s2.toString() // "Symbol( 'foo2' )" ;
注意:?
上面Symbol()函數生成的值,如果沒有添加字符串進行區分,輸出的時候就不能區分那個數值是那個數值;
example 2 :
at1: 如果Symbol的值是一個對象,就會自動調用對象的toString方法,將其轉換成字符串,
?然后才生成一個Symbol值;
const obj = {
toString () {
return 'abc' ;
}
}
const sym = Symbol( obj ) ;
sym // Symbol( obj ) ;
at2: Symbol即使里面傳入的參數是一致的,每個Symbol返回的都是一個不一樣的值;
沒有參數的情況:
var s1 = Symbol() ;
var s2 = Symbol() ;
s1 === s2 ; // false ;
有參數的情況:
var s1 = Symbol( 'foo' ) ;
var s2 = Symbol( 'foo' ) ;
s1 === s2 ; // false ;
5.Symbol值不能與其他類型值進行運算,會報錯;
example:?
var sym = Symbol( 'my symbol' ) ;
'you symbol id ' + sym ;
但是,Symbol值可以顯示轉換策劃那個字符串 ;
var sym = Symbol( 'my symbol' ) ;
String( sym ) ; // 'Symbol( my symbol )' ;
sym.toString() ; // 'Symbol( my symbol )' ;
6.Symbol也可以轉為bool值,但是不能轉為數值;
example:?
var sym = Symbol() ;
Boolean( sym ) ; // true
!sym ;// false
if ( sym ) {
// 程序是可以執行的。。。
}
Number( sym ) ; // type error
sym + 2 ; // type error
? 7.Symbol值作為對象的屬性名,可以防止我們在編寫代碼的時候對象的某個鍵值被修改 ;
? var sym = Symbol() ;
? var a = {} ;
?
? a[ symbol ] = 'hello' ;
?
? var a = {
? [ symbol ]: 'hello' ,
? }
? Object.defineProperty( a , mySymbol , { value : 'hello!' } ) ;
? 上面的代碼通過方括號結構和defineProperty, 將對象屬性名定義為一個Symbol值 ;
? Symbol作為對象的屬性名時,不能作為點運算符 ;
? 因為點運算后面的總是字符串,不能取到作為Symbol所標識的值 ;
? example:?
? var mySymbol = Symbol() ;
? a.mySymbol ; // 'hello' ;
? a[mySymbol] ; // undefined
? a[ 'mySymbol' ] ; // 'hello'
? 同理,在對象內部的時候,使用Symbol值作為一個屬性的時候,也需要將其放置在一個方括號里面 ;
? const COLOR_GREEN = Symbol() ;
? const COLOR_RED = Symbol() ;
? function checkColor ( color ) {
? switch ( color ) {
? case COLOR_GREEN :
? return COLOR_RED ;
? case COLOR_RED :
? return COLOR_RED ;
? default throw new Error ( ' undefined color ' ) ;
? }
? }
? 需要注意的是Symbol值作為屬性的時候,該屬性還是公有屬性,而不是私有屬性 ;
? 8. Symbol值可以消除代碼的強耦合,使代碼的結構看起來更加的清晰 ;
? 下面就是一段強耦合的代碼:
? function getArea ( shapeType , options ) {
? switch ( shapeType ) {
? case 'Triangle' :
? area = .5 * options.width * options.height ;
? break ;
? ...more code ;
? }
? return area ;
? }
? getArea( 'Triangle' , { width: 10 , height: 10 } ) ;
?
? 常用的消除字符串的方法,就是把它寫成一個變量;
? var shapeType = {
? triangle : 'triangle' ,
? }
? function getArea ( area , options ) {
? var area = 0 ;
? switch ( shape ) {
? case shape === 'triangle' :
? area = options.width * options.height * .5 ;
? break ;
? }
? return area ;
? }
? getArea( shapeType.shape , { width: 10 , height: 10 } ) ;
? 9.Symbol作為一個屬性值,不會出現在 for...in , for...of 循環中 ,也不會被Object.keys() ,?
? Object.getOwnPropertyNames() , JSON.Stringfy()返回 ;
? 但是,它也不是私有屬性,有一個getOwnPropertySymbols()方法,可以獲取指定對象的所有Symbol屬性名 ;
? getOwnPropertySymbols() 方法返回一個數組, 成員是當前對象的所有用作屬性名的Symbol值 ;
? var obj = {} ;
? var a = Symbol( 'a' ) ;
? var b = Symbol( 'b' ) ;
? obj[a] = 'hello' ;
? obj[b] = 'world' ;
? var objectSymbols = Object.getOwnPropertySymbols( obj ) ;
? objectSymbols ; // Symbol( 'a' ) , Symbol( 'b' ) ;
? example:?
? getOwnPropertyNames() , for...in , getOwnPropertySymbols() 之間的對比 ;
? var obj = {} ;
? var foo = Symbol( 'foo' ) ;
? Object.defineProperty( obj , foo , { value : 'foobar' } ) ;
? for ( var i in obj ) { console.log( i ) ; } ;
? Object.getOwnPropertyNames( obj ) ; // []
? Object.getOwnPropertySymbols( obj ) ; //[Symbol('foo')]
? 10.Reflect.ownKeys() , 新的API , 方法可以返回所有類型的鍵名,包括常規的鍵名和Symbol鍵名 ;
? let obj = {
? [Symbol('myKey')] : 1 ,
? enum: 2 ,
? nonEnum: 3 ,
? } ;
? 11.Symbol.for()?
? 它接收一個字符串作為參數,然后搜索有沒有該參數作為名稱的Symbol值,如果有就返回這個值,
? 如果沒有就重新新建并返回一個Symbol值;
? example:?
? var s1 = Symbol.for( 'foo' ) ;
? var s2 = Symbol.for( 'foo' ) ;
? s1 === s2 ; // true ;
? 上面的代碼中,雖然都是Symbol值,但都是通過Symbol.for生成的值,所以它們是相等的;
?
? 12.Symbol() , Symbol.for()之間的區別 ;
? 前者會登記在全局中搜索,后者則不會,不會每次新建一個Symbol值,而是去輪詢是否存在,如果存在
? 則返回已存在的值,不存在才會新建一個新的值 ;
? example:?
? Symbol.for( 'bar' ) === Symbol( 'bar' ) ; // true
? Symbol( 'bar' ) === Symbol( 'bar' ) ; // false
? 13.Symbol.keyFor() ; 每次調用都會返回一個已經存在的Symbol值, 若是不存在則會返回undefined ;
? example:?
? var s1 = Symbol.for( 'foo' ) ;
? Symbol.keyFor( s1 ) ; // foo ;
? var s2 = Symbol( 'foo' ) ;
? Symbol.keyFor( s2 ) ; // undefined ;
? 14.Symbol.for() 生成的Symbol值是在全局環境中的, 可以在不同的iframe或者server worker中
? 取得同一個值 ;
? var iframe = Document.createElement( 'iframe' ) ;?
? iframe.src = String( window.location ) ;
? document.body.appendChild( iframe ) ;
? iframe.contentWindow.Symbol.for( 'foo' ) === Symbol.for( 'foo' ) ;
? 上面的代碼中生成的Symbol值,可以在主頁面得到 ;
? 15.模塊的SingleTon模式 ;
? 該模式調用的是一個類,但是任何時候返回的都是一個實例 ;
? 對于node來說,模塊可以看成是一個類 ,要保證每次執行這個模塊文件,生成同一個實例 ,?
? 只要把這個類放置在頂級對象global中 ;
? example:?
? // mod.js
? function foo () { this.foo = 'hello' ; }
? if ( !global._foo ) { return new foo() ; }
? module.exports = global._foo ;
? var mod = require( 'mod.js' ) ;
? console.log( foo._foo ) ;
? 但是這里的global._foo每次返回的都是一個實例,但是是可以修改的,為了保證這個這個變量不會失真,
? 引進Symbol可以達到這樣的目標 ;
?example:?
? const FOO_KEY = Symbol.for( 'foo' ) ;
? function A () { this.foo = 'hello' ; }
? if ( !global[ FOO_KEY ] ) { return new A() ; }
? module.exports = global[ FOO_KEY ] ;
? 上面的代碼中,可以保證鍵值不會被無意間被覆蓋,但還是可以被改寫 ;
? var a = require( './mod.js' ) ;
? global[ Symbol.for( 'foo' ) ] = 123 ;
? 如果鍵名使用的是Symbol方法生成 ,那么外部將無法引用這個值, 當然也就無法改寫 ;?
.Symbol.for() 和 Symbol() 每次都會生成新的值;
區別在于 .for 不會主動去創建一個新的Symbol值,每次都會返回同樣的值,輪詢是否存在,若不存在則會創建新的值;Symbol每次都會返回新的值;
總結
- 上一篇: 【unity3D弹跳的小球游戏制作】
- 下一篇: iOS进阶 - GCD总结