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