Symbol的應用場景
下面是幾個Symbol
在程序中的應用場景。
應用一:防止XSS
在React
的ReactElement
對象中,有一個$$typeof
屬性,它是一個Symbol
類型的變量:
var REACT_ELEMENT_TYPE =
(typeof Symbol === 'function' && Symbol.for && Symbol.for('react.element')) ||
0xeac7;
ReactElement.isValidElement
函數用來判斷一個React組件是否是有效的,下面是它的具體實現。
ReactElement.isValidElement = function (object) {
return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;
};
可見React
渲染時會把沒有$$typeof
標識,以及規則校驗不通過的組件過濾掉。
如果你的服務器有一個漏洞,允許用戶存儲任意JSON
對象, 而客戶端代碼需要一個字符串,這可能會成爲一個問題:
// JSON
let expectedTextButGotJSON = {
type: 'div',
props: {
dangerouslySetInnerHTML: {
__html: '/* put your exploit here */'
},
},
};
let message = { text: expectedTextButGotJSON };
<p>
{message.text}
</p>
而JSON
中不能存儲Symbol
類型的變量,這就是防止XSS
的一種手段。
應用二:私有屬性
藉助Symbol
類型的不可枚舉,我們可以在類中模擬私有屬性,控制變量讀寫:
const privateField = Symbol();
class myClass {
constructor(){
this[privateField] = 'ConardLi';
}
getField(){
return this[privateField];
}
setField(val){
this[privateField] = val;
}
}
應用三:防止屬性污染
在某些情況下,我們可能要爲對象添加一個屬性,此時就有可能造成屬性覆蓋,用Symbol
作爲對象屬性可以保證永遠不會出現同名屬性。
例如下面的場景,我們模擬實現一個call
方法:
Function.prototype.myCall = function (context) {
if (typeof this !== 'function') {
return undefined; // 用於防止 Function.prototype.myCall() 直接調用
}
context = context || window;
const fn = Symbol();
context[fn] = this;
const args = [...arguments].slice(1);
const result = context[fn](...args);
delete context[fn];
return result;
}
我們需要在某個對象上臨時調用一個方法,又不能造成屬性污染,Symbol
是一個很好的選擇。