今までの for (var in )
JavaScript で オブジェクトをハッシュ、連想配列代わりに利用し、for 文で回す場合このように書いていました
var forEachHash = function (obj, callback) {
var name;
for (name in obj) {
if (obj.hasOwnProperty(name)) { // prototype を除く
callback(obj[name], name);
}
}
};
しかし、元々 for (var x in obj)
パターンのでは、name にプロトタイプからのプロパティ名まで取得してしまいます。
なので、Object.prototype.hasOwnProperty()
で条件付けする必要がありました。
Object.keys()
を使おう
ES5 で Object.keys()
が導入されたので、for (;;)
文で安全に目的のプロパティのみを参照してループできるようになります。
var forEachHash = function(obj, callback) {
var keys = Object.keys(obj),
index, length, key, value;
for(index = 0, length = keys.length; index < length; index++) {
key = keys[index];
value = obj[key];
callback(value, key);
}
};
Object.keys(obj)
は引数のオブジェクトから enumable なプロパティ名のみの配列を返します。
オブジェクトのクローンを作りたい時などは Object.getOwnPropertyNames()
目的がハッシュの各 key, value
をループで取得したい場合でなく、インスタンスのクローンを作りたい場合などは Object.keys()
でなく、 Object.getOwnPropertyNames()
を使います。
// 任意のオブジェクトを複製する
var clone = function (obj) {
var copied = Object.create(obj),
names = Object.getOwnPropertyNames(obj),
index, length, name, desc;
for (index = 0, length = names.length; index < length; index++){
name = names[index];
desc = Object.getOwnPropertyDescriptor(obj, name);
Object.defineProperty(copied, name, desc);
}
return copied;
};
上記の例では Object.create()
でまず prorotype のプロパティを引き継いだ新しいオブジェクトを作り、Object.getOwnPropertyNames()
でインスタンスメソッドやプロパティ名を取得します。
その後、 Object.getOwnPropertyDescriptor()
で元のプロパティの読み書き制限や列挙可能か、再定義可能かなどの指定をそのまま Object.defineProperty()
で引き継ぎさせています。