はてなブックマークで『ObjectをJSONへ変換するJavaScript Library』に対して次の様な突っ込みが入っていた。
json化するのにhasOwnPropertyじゃなくてfunctionかそうでないかくらいで十分な気がする
確かに説明不足な感は否めないので、補足。Functionオブジェクトはswitchの『default:』に振り分けられ、『case Object:』内は実行されない。では、『hasOwnProperty』は何のためにあるのか。著名なLibraryである『Prototype.js』等で、javascriptのnativeのObjectを拡張している。有用な機能を拡張しているため、便利ではあるが、手放しには喜べない。例えば、次の様な処理を考える。
//[for in]処理
var obj={"a":"apple","b":"box","c":"cat"};
var res="";
for(var key in obj){
res+=key+":"+obj[key]+"¥n";
}
alert(res);
/*
以下のように表示される。
a:apple
b:box
c:cat
*/
var obj={"a":"apple","b":"box","c":"cat"};
var res="";
for(var key in obj){
res+=key+":"+obj[key]+"¥n";
}
alert(res);
/*
以下のように表示される。
a:apple
b:box
c:cat
*/
通常では上記方法で問題はないが、Objectを拡張している場合は問題となる。
//Objectの拡張
Object.prototype.f1=function(){return "function1";}
Object.f2=function(){return "function2";}
Object.prototype.v1="value1";
Object.v2="value2";
//[for in]処理
var obj={"a":"apple","b":"box","c":"cat"};
var res="";
for(var key in obj){
res+=key+":"+obj[key]+"¥n";
}
alert(res);
/*
以下のように表示される。
a:apple
b:box
c:cat
f1:function(){
return "function1";
}
v1:value1
*/
Object.prototype.f1=function(){return "function1";}
Object.f2=function(){return "function2";}
Object.prototype.v1="value1";
Object.v2="value2";
//[for in]処理
var obj={"a":"apple","b":"box","c":"cat"};
var res="";
for(var key in obj){
res+=key+":"+obj[key]+"¥n";
}
alert(res);
/*
以下のように表示される。
a:apple
b:box
c:cat
f1:function(){
return "function1";
}
v1:value1
*/
つまり、prototypeに拡張したクラスメソッドやクラスフィールドまで拾ってきてしまうのである(正確にはJavaScriptはクラスとは言わない)。『for in』処理はさほどマイナーな処理ではないため、既存システムのカスタマイズ時に『Prototype.js』を安易に導入すると、既存処理と衝突する可能性がある。これを一部では『Object汚染』と表現する。これを回避するために『hasOwnProperty』を使用しているのである。
//Objectの拡張
Object.prototype.f1=function(){return "function1";}
Object.f2=function(){return "function2";}
Object.prototype.v1="value1";
Object.v2="value2";
//[for in]処理
var obj={"a":"apple","b":"box","c":"cat"};
var res="";
for(var key in obj){
//Object汚染回避
if(obj.hasOwnProperty(key)){
res+=key+":"+obj[key]+"¥n";
}
}
alert(res);
/*
以下のように表示される。
a:apple
b:box
c:cat
*/
Object.prototype.f1=function(){return "function1";}
Object.f2=function(){return "function2";}
Object.prototype.v1="value1";
Object.v2="value2";
//[for in]処理
var obj={"a":"apple","b":"box","c":"cat"};
var res="";
for(var key in obj){
//Object汚染回避
if(obj.hasOwnProperty(key)){
res+=key+":"+obj[key]+"¥n";
}
}
alert(res);
/*
以下のように表示される。
a:apple
b:box
c:cat
*/
前述のLibraryのhasOwnPropertyは、この問題を回避するためのものであり、Functionの判定処理ではない。