JavaScript

モダン for (var x in obj) -> for (;;)

More than 5 years have passed since last update.


今までの 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() で引き継ぎさせています。