Symbol類型是ES6中新加入的一種原始類型紧帕。
每個(gè)從Symbol()返回的symbol值都是唯一的。一個(gè)symbol值能作為對(duì)象屬性的標(biāo)識(shí)符悴侵;這是該數(shù)據(jù)類型僅有的目的箱叁。
下面來看看Symbol類型具有哪些特性。
Symbol的特性
1.獨(dú)一無二
直接使用Symbol()創(chuàng)建新的symbol變量积蔚,可選用一個(gè)字符串用于描述意鲸。當(dāng)參數(shù)為對(duì)象時(shí),將調(diào)用對(duì)象的toString()方法尽爆。
var sym1 = Symbol(); // Symbol()
var sym2 = Symbol('ConardLi'); // Symbol(ConardLi)
var sym3 = Symbol('ConardLi'); // Symbol(ConardLi)
var sym4 = Symbol({name:'ConardLi'}); // Symbol([object Object])
console.log(sym2 === sym3); // false
我們用兩個(gè)相同的字符串創(chuàng)建兩個(gè)Symbol變量怎顾,它們是不相等的,可見每個(gè)Symbol變量都是獨(dú)一無二的漱贱。
如果我們想創(chuàng)造兩個(gè)相等的Symbol變量槐雾,可以使用Symbol.for(key)。
使用給定的key搜索現(xiàn)有的symbol幅狮,如果找到則返回該symbol募强。否則將使用給定的key在全局symbol注冊(cè)表中創(chuàng)建一個(gè)新的symbol株灸。
var sym1 = Symbol.for('ConardLi');
var sym2 = Symbol.for('ConardLi');
console.log(sym1 === sym2); // true
原始類型
注意是使用Symbol()函數(shù)創(chuàng)建symbol變量,并非使用構(gòu)造函數(shù)擎值,使用new操作符會(huì)直接報(bào)錯(cuò)慌烧。
new Symbol(); // Uncaught TypeError: Symbol is not a constructor
我們可以使用typeof運(yùn)算符判斷一個(gè)Symbol類型:
typeof Symbol() === 'symbol'
typeof Symbol('ConardLi') === 'symbol'
不可枚舉
當(dāng)使用Symbol作為對(duì)象屬性時(shí),可以保證對(duì)象不會(huì)出現(xiàn)重名屬性鸠儿,調(diào)用for...in不能將其枚舉出來屹蚊,另外調(diào)用Object.getOwnPropertyNames、Object.keys()也不能獲取Symbol屬性捆交。
可以調(diào)用Object.getOwnPropertySymbols()用于專門獲取Symbol屬性淑翼。
var obj = {
name:'ConardLi',
[Symbol('name2')]:'code秘密花園'
}
Object.getOwnPropertyNames(obj); // ["name"]
Object.keys(obj); // ["name"]
for (var i in obj) {
console.log(i); // name
}
Object.getOwnPropertySymbols(obj) // [Symbol(name)]
Symbol的應(yīng)用場(chǎng)景
下面是幾個(gè)Symbol在程序中的應(yīng)用場(chǎng)景。
應(yīng)用一:防止XSS
在React的ReactElement對(duì)象中品追,有一個(gè)$$typeof屬性玄括,它是一個(gè)Symbol類型的變量:
var REACT_ELEMENT_TYPE =
(typeof Symbol === 'function' && Symbol.for && Symbol.for('react.element')) ||
0xeac7;
ReactElement.isValidElement函數(shù)用來判斷一個(gè)React組件是否是有效的,下面是它的具體實(shí)現(xiàn)肉瓦。
ReactElement.isValidElement = function (object) {
return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;
};
可見React渲染時(shí)會(huì)把沒有$$typeof標(biāo)識(shí)遭京,以及規(guī)則校驗(yàn)不通過的組件過濾掉。
如果你的服務(wù)器有一個(gè)漏洞泞莉,允許用戶存儲(chǔ)任意JSON對(duì)象哪雕, 而客戶端代碼需要一個(gè)字符串,這可能會(huì)成為一個(gè)問題:
// JSON
let expectedTextButGotJSON = {
type: 'div',
props: {
dangerouslySetInnerHTML: {
__html: '/* put your exploit here */'
},
},
};
let message = { text: expectedTextButGotJSON };
<p>
{message.text}
</p >
而JSON中不能存儲(chǔ)Symbol類型的變量鲫趁,這就是防止XSS的一種手段斯嚎。
應(yīng)用二:私有屬性
借助Symbol類型的不可枚舉,我們可以在類中模擬私有屬性挨厚,控制變量讀寫:
const privateField = Symbol();
class myClass {
constructor(){
this[privateField] = 'ConardLi';
}
getField(){
return this[privateField];
}
setField(val){
this[privateField] = val;
}
}
應(yīng)用三:防止屬性污染
在某些情況下堡僻,我們可能要為對(duì)象添加一個(gè)屬性,此時(shí)就有可能造成屬性覆蓋疫剃,用Symbol作為對(duì)象屬性可以保證永遠(yuǎn)不會(huì)出現(xiàn)同名屬性钉疫。
例如下面的場(chǎng)景,我們模擬實(shí)現(xiàn)一個(gè)call方法:
Function.prototype.myCall = function (context) {
if (typeof this !== 'function') {
return undefined; // 用于防止 Function.prototype.myCall() 直接調(diào)用
}
context = context || window;
const fn = Symbol();
context[fn] = this;
const args = [...arguments].slice(1);
const result = context[fn](...args);
delete context[fn];
return result;
}
我們需要在某個(gè)對(duì)象上臨時(shí)調(diào)用一個(gè)方法巢价,又不能造成屬性污染牲阁,Symbol是一個(gè)很好的選擇。