LoginSignup
18
18

More than 5 years have passed since last update.

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

Last updated at Posted at 2012-06-25

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

18
18
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
18