JavaScript原始數(shù)據(jù)類型Symbol的用法詳解
Symbol介紹與創(chuàng)建
ES6引入了一種新的原始數(shù)據(jù)類型Symbol,表示獨一無二的值,它是JavaScript語言的第七種數(shù)據(jù)類型,是一種類似于字符串的數(shù)據(jù)類型。
Symbol特點:
Symbol的值是唯一的,用來解決命名沖突問題。
Symbol值不能與其他數(shù)據(jù)進行運算。
Symbol定義的對象屬性不能使用 for...in 循環(huán)遍歷,但是可以使用 Reflect.ownKeys 來獲取對象的所有鍵名。
Symbol值通過Symbol()函數(shù)生成,也就是說,對象的屬性名可以有兩種類型,一種就是原來就有的字符串,另一種就是新增的Symbol類型。
創(chuàng)建Symbol有倆種方式,Symbol和Symbol.for(),這兩種方式的區(qū)別前者不能登記在全局環(huán)境中供搜索,后者卻可以,所有Symbol.for()不會每次調(diào)用就返回一個新的Symbol類型值,而是先檢查給定的key值是否存在,不存在才會新建一個值。
<script> // 創(chuàng)建Symbol let s = Symbol() console.log(s,typeof s);//Symbol() 'symbol' //Symbol()函數(shù)可以接受一個字符串作為參數(shù),表示對 Symbol 實例的描述 //Symbol()函數(shù)的參數(shù)只是表示對當(dāng)前 Symbol 值的描述,因此相同參數(shù)的Symbol函數(shù)的返回值是不相等的。 let s1 = Symbol('張三') let s2 = Symbol('張三') console.log(s1 === s2);//false // 創(chuàng)建Symbol的另一種方法:Symbol.for() 該方法創(chuàng)建的字符串參數(shù)相等,Symbol也相等 let s3 = Symbol.for('張三') let s4 = Symbol.for('張三') // Symbol.keyFor()方法返回一個已登記的 Symbol 類型值的key。 console.log(Symbol.keyFor(s3));//張三 console.log(s3 === s4);//true </script>
Symbol 值不能與其他類型的值進行運算,否則會報錯,但是Symbol值可以顯示轉(zhuǎn)換為字符串,而且Symbol也可以轉(zhuǎn)為布爾值。
<script> let s = Symbol('My Symbol') // let result = s + 100 // console.log(result);//Cannot convert a Symbol value to a number // 轉(zhuǎn)字符串 console.log(String(s));//Symbol(My Symbol) // 轉(zhuǎn)布爾值 console.log(Boolean(s));//true </script>
當(dāng)然如果你想直接返回 Symbol 的字符串參數(shù)的值的話,可以借用 Symbol 的實例屬性:description,直接返回 Symbol 值的描述。
<script> let s = Symbol('My Symbol') console.log(s.description);//My Symbol </script>
針對數(shù)據(jù)類型的類別可以總結(jié)以下方式:(面試官問你JS有哪幾種數(shù)據(jù)類型好用到)
USONB (you are so niubility)
u:undefined
s:string、Symbol
o:object
n:null、number
b:boolean
設(shè)置Symbol屬性的注意點
為了保證不會出現(xiàn)同名的屬性,防止對象的某一個鍵不小心被改寫或覆蓋。使用作為屬性名的Symbol 進行操作。設(shè)置Symbol的方式如下:
注意:我們在進行設(shè)置Symbol值作為對象屬性名時,是不能用點運算符,因為點運算符后面總是字符串,所以不會讀取作為Symbol標識名所指代的那個值,導(dǎo)致Symbol的屬性名實際上是一個字符串,而不是一個Symbol值,所以在對象內(nèi)部使用Symbol值定義屬性時,Symbol值必須放在方括號里面。
<script> let s = Symbol('My Symbol') // 第一種 let a = {} a[s] = 'hello world' // 第二種 let b = { [s]:'hello people' } // 第三種 let c = {} Object.defineProperty(c,s,{value:'hello animal'}) // 以上結(jié)果都能達到相同的效果,舉例 console.log(c); </script>
Symbol屬性名的遍歷
如果想遍歷Symbol的屬性名,正常的方法是辦不到的,需要使用特定的方法,有一個方法可以獲取指定對象的所有鍵名并返回一個數(shù)組,方法為:Object.getOwnPropertySymbols()方法。
<script> let obj = {} let a = Symbol('a') let b = Symbol('b') obj[a] = 'hello' obj[b] = 'world' const objectSymbols = Object.getOwnPropertySymbols(obj) console.log(objectSymbols);//[Symbol(a), Symbol(b)] </script>
上面的方法能夠返回Symbol的鍵名,還有一個方法能夠返回Symbol鍵名,但不只有Symbol鍵名而是所有的鍵名都被返回出來。該方法為:Reflect.ownKeys(obj)。
<script> let obj = { name:'張三', age:18, [Symbol('mySymbol')]:1, gender:'男' } console.log(Reflect.ownKeys(obj));//['name', 'age', 'gender', Symbol(mySymbol)] </script>
Symbol內(nèi)置值
除了定義自己使用的 Symbol 值以外,ES6還提供了 11 個內(nèi)置的 Symbol 值,指向語言內(nèi)部使用的方法。方法如下:
Symbol.hasInstance
當(dāng)其他對象使用 instanceof 運算符,判斷是否為該對象的實例時,會調(diào)用這個方法。
<script> class Person { static [Symbol.hasInstance](param){ console.log(param); console.log('我被用來檢測類型了'); //return true } } let o = {} console.log(o instanceof Person); </script>
當(dāng)出現(xiàn) instanceof 時,symbol 的 hasInstance 屬性就會被觸發(fā),并且可以把要判斷的實例對象傳進來。也就是說將 instanceof 前面的值傳遞到 param 形參這個方法,由它來決定返回的true還是false。說白了就是可以自己控制類型檢測。
Symbol.isConcatSpreadable
對象的 Symbol.isConcatSpreadable 屬性等于的是一個布爾值,表示該對象用于數(shù)組上面時Array.prototype.concat()語句,判斷數(shù)組是否可以展開。false為不展開。
<script> const arr = [1,2,3] const arr1 = [4,5,6] console.log(arr.concat(arr1)); // 將arr1設(shè)置為不展開,作為一個整體與arr進行合并 arr1[Symbol.isConcatSpreadable] = false console.log(arr.concat(arr1)); </script>
類似數(shù)組的對象正好相反,默認不展開,它的 Symbol.isConcatSpreadable 屬性設(shè)為 true,才能展開。
<script> let obj = { 0:'a', 1:'b', 2:'c', length:3 } console.log([1,2].concat(obj,'d')); // 將該屬性設(shè)置為true,進行展開 obj[Symbol.isConcatSpreadable] = true console.log([1,2].concat(obj,'d')); </script>
Symbol.unscopables
該對象指定了使用 with 關(guān)鍵字時,哪些屬性會被 with 環(huán)境排除。
<script> // 將排除的鍵名以數(shù)組方式打印出來 console.log(Object.keys(Array.prototype[Symbol.unscopables])); </script>
// 沒有 unscopables 時 class MyClass { foo() { return 1; } } var foo = function () { return 2; }; with (MyClass.prototype) { foo(); // 1 } // 有 unscopables 時 // 通過指定Symbol.unscopables屬性,使得with語法塊不會在當(dāng)前作用域?qū)ふ襢oo屬性,即foo將指向外層作用域的變量 class MyClass { foo() { return 1; } get [Symbol.unscopables]() { return { foo: true }; } } var foo = function () { return 2; }; with (MyClass.prototype) { foo(); // 2 }
Symbol.match
JavaScript中的Symbol.match屬性是well-known符號,用于標識正則表達式與字符串的匹配,當(dāng)執(zhí)行 str.match(myObject) 時,如果該屬性存在,會調(diào)用它,返回該方法的返回值。
<script> const reg = /hello world/ reg[Symbol.match] = false console.log('/hello/'.startsWith(reg));//false console.log('/hello world/'.startsWith(reg));//true </script>
Symbol.replace
當(dāng)該對象被 str.replace(myObject) 方法調(diào)用時,會返回該方法的返回值。
<script> const x = {}; // Symbol.replace方法會收到兩個參數(shù),第一個參數(shù)是replace方法正在作用的對象,第二個參數(shù)是替換后的值。 x[Symbol.replace] = (...s) => console.log(s); // ["Hello", "World"] 'Hello'.replace(x, 'World') </script>
Symbol.search
指定了一個搜索方法,這個方法接受用戶輸入的正則表達式,返回該正則表達式在字符串中匹配到的下標,這個方法由以下的方法來調(diào)用 String.prototype.search()。該屬性指向一個方法,當(dāng)該對象被 str.search(myObject)方法調(diào)用時,會返回該方法的返回值。
<script> class caseInsensitiveSearch { constructor(value) { this.value = value.toLowerCase(); } [Symbol.search](string) { return string.toLowerCase().indexOf(this.value); } } console.log('foobar'.search(new caseInsensitiveSearch('BaR'))); // expected output: 3 </script>
Symbol.split
Symbol.split 這個屬性方法 指向的是一個正則表達式的索引處分割字符串的方法,這個方法通過 String.prototype.split() 調(diào)用;該屬性指向一個方法,當(dāng)該對象被 str.split(myObject)方法調(diào)用時,會返回該方法的返回值。
<script> var exp = { pat:'in', [Symbol.split](str) { return str.split(this.pat); } } // "dayinlove".split(exp)調(diào)用[Symbol.split](str)處理,并把實參"dayinlove"傳給形參str console.log("dayinlove".split(exp));//["day", "love"] </script>
Symbol.iterator
對象進行 for...of 循環(huán)時,會調(diào)用 Symbol.iterator 方法,返回該對象的默認遍歷器。
<script> const myIterable = {}; myIterable[Symbol.iterator] = function* () { //function*這種聲明方式會定義一個生成器函數(shù),它返回一個對象。 yield 1; yield 2; yield 3; }; console.log([...myIterable]);// [1, 2, 3] </script>
Symbol.toPrimitive
作為對象的函數(shù)值屬性存在的,當(dāng)一個對象轉(zhuǎn)換為對應(yīng)的原始值時,會調(diào)用此函數(shù)。該函數(shù)被調(diào)用時,會傳遞一個字符粗參數(shù) hint ,表示要轉(zhuǎn)換到的原始值的預(yù)期類型。hint參數(shù)的取值是:number、string 和 default 中的任意一個。
// 一個沒有提供 Symbol.toPrimitive 屬性的對象,參與運算時的輸出結(jié)果 var obj1 = {}; console.log(+obj1); // NaN console.log(`${obj1}`); // "[object Object]" console.log(obj1 + ""); // "[object Object]" // 接下面聲明一個對象,手動賦予了 Symbol.toPrimitive 屬性,再來查看輸出結(jié)果 var obj2 = { [Symbol.toPrimitive](hint) { if (hint == "number") { return 10; } if (hint == "string") { return "hello"; } return true; } }; console.log(+obj2); // 10 -- hint 參數(shù)值是 "number" console.log(`${obj2}`); // "hello" -- hint 參數(shù)值是 "string" console.log(obj2 + ""); // "true" -- hint 參數(shù)值是 "default"
Symbol.toStringTag
通常作為對象的屬性鍵使用,對應(yīng)的屬性值應(yīng)該為字符串類型,這個字符串用來表示該對象的自定義類型標簽。
<script> class Person { get [Symbol.toStringTag](){ return 'xxx' } } let per = new Person() console.log(Object.prototype.toString.call(per));//[object xxx] </script>
Symbol.species
指定構(gòu)造函數(shù)用于創(chuàng)建派生對象的函數(shù)值屬性,即創(chuàng)建衍生對象時,會使用該屬性。作用:實例對象在運行過程中,會調(diào)用該屬性指定的構(gòu)造函數(shù),用來返回基類的實例而不是子類的實例。
<script> class Array1 extends Array { static get [Symbol.species]() { return Array; } } const a = new Array1(1, 2, 3); const mapped = a.map(x => x * x); // 定義了Symbol.species屬性后,導(dǎo)致 a.map(x => x * x) 生成的衍生對象不在是Array1的實例而是Array console.log(mapped instanceof Array1);//false console.log(mapped instanceof Array);//true </script>
到此這篇關(guān)于JavaScript原始數(shù)據(jù)類型Symbol的用法詳解的文章就介紹到這了,更多相關(guān)JS Symbol內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JavaScript插入排序算法原理與實現(xiàn)方法示例
這篇文章主要介紹了JavaScript插入排序算法原理與實現(xiàn)方法,簡單分析了插入排序的概念、原理并結(jié)合實例形式分析了JavaScript插入排序算法的具體實現(xiàn)技巧與注意事項,需要的朋友可以參考下2018-08-08JavaScript setTimeout使用閉包功能實現(xiàn)定時打印數(shù)值
這篇文章主要介紹了JavaScript setTimeout使用閉包功能實現(xiàn)定時打印數(shù)值 的相關(guān)資料,需要的朋友可以參考下2015-12-12innerHTML,outerHTML,innerTEXT三者之間的區(qū)別
innerHTML,outerHTML,innerTEXT三者之間的區(qū)別...2007-01-01