標籤:javascript 伺服器編程 對象屬性枚舉 原型汙染
前面文章中討論了JS開發中對象屬性枚舉的ES3和ES5方案並給出了一組常用工具函數,其實,企業開發中真正應用時還存在不少問題。本文想基於前文進一步探討一下有關原型汙染的問題。由於JS的先天不足,有關原型汙染背後隱藏著一個大的“故事”,以後我們的文章中還要涉及其中一些情節。
問題
前面在討論使用in運算子檢測對象中是否存在屬性的方案,但是通過所舉的樣本也發現一個問題,例如:
console.log(‘"ID" in contacts: ‘,"ID" in contacts);
其輸出結果也是true。這說明in運算子在屬性檢測時不僅搜尋當前對象的自有屬性,還會沿著對象的原型鏈搜尋。
根據前面對於屬性繼承的分析可得知,JS中的對象總是以繼承的方式工作,即使是一個空的對象字面量也會繼承Object.prototype的大量屬性。因此,對於下面的測試結果正在我們的意料之中:
var pol={};
console.log("Hi" in pol); //false
console.log("toString" in pol); //true
console.log("valueOf" in pol); //true
console.log("constructor" in pol); //true
console.log("__defineGetter__" in pol); //true
console.log("__defineSetter__" in pol); //true
console.log("__lookupGetter__" in pol); //true
console.log("__lookupSetter__" in pol); //true
console.log("hasOwnProperty" in pol); //true
console.log("isPrototypeOf" in pol); //true
console.log("propertyIsEnumerable" in pol); //true
console.log("toLocaleString" in pol); //true
而在ES5中使用Object.prototype中的hasOwnProperty方法正好可以避免上面的問題,因為它只檢索對象的自有屬性,包括不可枚舉的屬性(ES3中沒有定義這樣的概念)。
更進一步
如果對象本身有一個自有屬性hasOwnProperty,情況又該如何呢?參考如下代碼:
var o={};
o.hasOwnProperty="*********";
console.log(o.hasOwnProperty("Alice");
運行測試時,出現如所示的執行階段錯誤:
650) this.width=650;" title="無標題.jpg" src="http://s3.51cto.com/wyfs02/M00/6D/28/wKiom1VdeFzzyFEeAAFdskcrBaM427.jpg" alt="wKiom1VdeFzzyFEeAAFdskcrBaM427.jpg" />
對於這種情況,專家的建議是“最安全的方法是不做任何假設”。於是,我們可以提前在任何安全的位置提取出hasOwnProperty方法,同時利用立即執行的匿名函數的詞法範圍特點,實現如下解決方案:
(function testOwnProperty(){
//var hasOwn=Object.prototype.hasOwnProperty;也可以使用如下更簡潔方式
var hasOwn={}.hasOwnProperty;
var dict={};
dict.Alice=12;
console.log("------------");
console.log(hasOwn.call(dict,"hasOwnProperty"));
console.log(hasOwn.call(dict,"Alice"));
dict.hasOwnProperty=100;
console.log("-------------");
console.log(hasOwn.call(dict,"hasOwnProperty"));
console.log(hasOwn.call(dict,"Alice"));
console.log("---------------");
})();
於是,不管對象的hasOwnProperty方法是否被覆蓋,上述方案都能夠正常工作。值得注意的是,許多知名JS庫就是利用了上述技術。
本文出自 “青峰” 部落格,請務必保留此出處http://zhuxianzhong.blog.51cto.com/157061/1653484
JavaScript伺服器編程(對象屬性枚舉中應當避免原型汙染問題)