web-dev-qa-db-ja.com

JavaScriptでオブジェクトのキー/プロパティの数を効率的に数える方法は?

オブジェクトのキー/プロパティの数を数えるための最速の方法は何ですか?オブジェクトを反復せずにこれを実行することは可能ですか?すなわちせずに

var count = 0;
for (k in myobj) if (myobj.hasOwnProperty(k)) count++;

(Firefoxは魔法の__count__プロパティを提供していましたが、これはバージョン4の前後のどこかで削除されました。)

1346
mjs

[Node](http://nodejs.org), Chrome, IE 9+, FF 4+, or Safari 5+:などの任意のES5-compatible environmentでこれを行うには

Object.keys(obj).length
2171
Avi Flax

このコードを使うことができます:

if (!Object.keys) {
    Object.keys = function (obj) {
        var keys = [],
            k;
        for (k in obj) {
            if (Object.prototype.hasOwnProperty.call(obj, k)) {
                keys.Push(k);
            }
        }
        return keys;
    };
}

それからあなたは同様に古いブラウザでこれを使うことができます:

var len = Object.keys(obj).length;
146

Underscore.js を使用している場合は、 _.size を使用できます(Thanks @douwe)。
_.size(obj)

あるいは、 _.keys を使用することもできます。
_.keys(obj).length 

Underscoreは、基本的なことをたくさん行うためのきついライブラリです。可能な限りECMA5と一致し、ネイティブの実装に従います。

それ以外の場合は、@ Aviの回答を支持します。私はそれを編集して、ECMA5以外のブラウザに追加できるkeys()メソッドを含むMDCドキュメントへのリンクを追加しました。

132
studgeek

標準のObject実装( ES5.1 Objectの内部プロパティとメソッド )は、キー/プロパティの数を追跡するためにObjectを必要としないため、明示的または暗黙的にObjectのサイズを決定する標準的な方法はありません。そのキーを反復処理します。

だからここで最も一般的に使用される選択肢があります:

1. ECMAScriptのObject.keys()

Object.keys(obj).length;internalキーを繰り返し処理して一時配列を計算し、その長さを返します。

  • 長所 - 読みやすくてきれいな構文。ネイティブサポートが利用できない場合は、シム以外にライブラリやカスタムコードは必要ありません。
  • 短所 - 配列の作成によるメモリのオーバーヘッド。

2.図書館ベースのソリューション

このトピックの他の場所にある多くのライブラリベースの例は、それらのライブラリの文脈では便利な慣用句です。ただし、パフォーマンスの観点から見ると、これらのすべてのライブラリメソッドは実際にはfor-loopまたはES5のObject.keys(ネイティブまたはシム)をカプセル化しているため、完全なライブラリなしコードに比べて何も得られません。

3. forループの最適化

関数呼び出しのオーバーヘッドがあるため、このようなforループの 最も遅い部分 は一般に.hasOwnProperty()呼び出しです。そのため、JSONオブジェクトのエントリ数だけが必要な場合は、コードがObject.prototypeを拡張もしないこともわかっていれば、.hasOwnProperty()呼び出しをスキップします。

そうでなければ、kをlocal(var k)にし、postfixの代わりにprefix-increment演算子(++count)を使うことであなたのコードはわずかに最適化されるかもしれません。

var count = 0;
for (var k in myobj) if (myobj.hasOwnProperty(k)) ++count;

別のアイデアはhasOwnPropertyメソッドのキャッシュに依存しています。

var hasOwn = Object.prototype.hasOwnProperty;
var count = 0;
for (var k in myobj) if (hasOwn.call(myobj, k)) ++count;

特定の環境でこれが速いかどうかは、ベンチマークの問題です。とにかく、非常に限られた性能向上が期待できます。

69
Luc125

実際にパフォーマンスの問題が発生している場合は、適切な名前付き(size?)プロパティを増減する関数を使用して、オブジェクトにプロパティを追加または削除する呼び出しをラップすることをお勧めします。

最初のプロパティ数を1回計算してそこから先に進むだけで済みます。実際にパフォーマンスの問題がなければ、気にしないでください。そのコードの一部を関数getNumberOfProperties(object)で囲み、それを実行するだけです。

23
Confusion

Avi Flaxが述べたように https://stackoverflow.com/a/4889658/1047014

Object.keys(obj).length

あなたのオブジェクトのすべての列挙可能なプロパティのためのトリックをするでしょうが、あなたが代わりにObject.getOwnPropertyNamesを使うことができる列挙不可能なプロパティも含めるために。違いは次のとおりです。

var myObject = new Object();

Object.defineProperty(myObject, "nonEnumerableProp", {
  enumerable: false
});
Object.defineProperty(myObject, "enumerableProp", {
  enumerable: true
});

console.log(Object.getOwnPropertyNames(myObject).length); //outputs 2
console.log(Object.keys(myObject).length); //outputs 1

console.log(myObject.hasOwnProperty("nonEnumerableProp")); //outputs true
console.log(myObject.hasOwnProperty("enumerableProp")); //outputs true

console.log("nonEnumerableProp" in myObject); //outputs true
console.log("enumerableProp" in myObject); //outputs true

述べたように ここ これはObject.keysと同じブラウザサポートを持っています

ただし、ほとんどの場合、これらのタイプの操作には列挙できないものを含めたくないかもしれませんが、違いを知っておくことは常に良いことです。)

15

私はこれを行う方法を知りませんが、繰り返しを最小限に抑えるために、あなたは__count__の存在をチェックすることを試みることができます、そしてそれが存在しないなら(すなわちFirefoxではない)後で使用するために定義してください。

if (myobj.__count__ === undefined) {
  myobj.__count__ = ...
}

このようにして__count__をサポートするブラウザはそれを使用するでしょう、そして、繰り返しは使用しないものに対してのみ実行されるでしょう。カウントが変わってこれを実行できない場合は、常にそれを関数にすることができます。

if (myobj.__count__ === undefined) {
  myobj.__count__ = function() { return ... }
  myobj.__count__.toString = function() { return this(); }
}

こうすれば、いつmyobj .__count__を参照しても、関数が起動して再計算されます。

15
Luke Bennett

Avi Flaxで反復するにはObject.keys(obj).lengthはそれに結び付けられた関数を持たないオブジェクトに対しては正しいです。

例:

obj = {"lol": "what", owo: "pfft"};
Object.keys(obj).length; // should be 2

versus

arr = [];
obj = {"lol": "what", owo: "pfft"};
obj.omg = function(){
    _.each(obj, function(a){
        arr.Push(a);
    });
};
Object.keys(obj).length; // should be 3 because it looks like this 
/* obj === {"lol": "what", owo: "pfft", omg: function(){_.each(obj, function(a){arr.Push(a);});}} */

これを回避する手順

  1. キーの数を数えたいオブジェクトに関数を入れないでください。

  2. 別のオブジェクトを使用するか、または関数専用の新しいオブジェクトを作成します(Object.keys(obj).lengthを使用してファイル内にいくつの関数があるかを数えたい場合)

私の例ではnodejsの_またはアンダースコアモジュールを使っていました 

ドキュメントはここにあります http://underscorejs.org/ およびgithubのソースおよび他のさまざまな情報

そして最後にlodashの実装 https://lodash.com/docs#size

_.size(obj)

12
Belldandu

プロジェクトにUnderscore.jsが含まれている場合は、次のことができます。

_({a:'', b:''}).size() // => 2

または機能的なスタイル:

_.size({a:'', b:''}) // => 2
8
hakunin

差出人: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty

Object.defineProperty(obj、prop、descriptor)

すべてのオブジェクトにそれを追加することができます。

Object.defineProperty(Object.prototype, "length", {
    enumerable: false,
    get: function() {
        return Object.keys(this).length;
    }
});

あるいは単一のオブジェクト:

var myObj = {};
Object.defineProperty(myObj, "length", {
    enumerable: false,
    get: function() {
        return Object.keys(this).length;
    }
});

例:

var myObj = {};
myObj.name  = "John Doe";
myObj.email = "[email protected]";
myObj.length; //output: 2

そのように追加されて、それはfor..inループに表示されません:

for(var i in myObj) {
     console.log(i + ":" + myObj[i]);
}

出力:

name:John Doe
email:[email protected]

注:IE9以下のブラウザでは機能しません。

6
lepe

この問題をどのように解決したかというと、オブジェクトに格納されている項目の数を記録した基本リストを自分で実装することです。とても簡単です。このようなもの:

function BasicList()
{
   var items = {};
   this.count = 0;

   this.add = function(index, item)
   {
      items[index] = item;
      this.count++;
   }

   this.remove = function (index)
   {
      delete items[index];
      this.count--;
   }

   this.get = function(index)
   {
      if (undefined === index)
        return items;
      else
        return items[index];
   }
}
5
Click Upvote

上で答えたように:Object.keys(obj).length

しかし、ES6には実際の Map クラスが追加されたので、オブジェクトのプロパティを使用する代わりに、 を使用して を提案します。

const map = new Map();
map.set("key", "value");
map.size; // THE fastest way
4
Flavien Volken

プロジェクトにExt JS 4が含まれている人のために、あなたはできる:

Ext.Object.getSize(myobj);

これの利点は全てのExt互換ブラウザ(IE6-IE8を含む)で動作することですが、他の提案された解決策と同様に、実行時間はO(n)以上ではないと思います。

3
Mark Rhodes

Object.keys(data).lengthを使ってキーデータを持つJSONオブジェクトの長さを見つけることができます

2
Codemaker

上記のjQueryが機能しない場合は、試してみてください

$(Object.Item).length
1
codejoecode

OPは、オブジェクトがnodeListであるかどうかを指定しませんでした。その場合は、lengthメソッドを直接使用できます。例:

buttons = document.querySelectorAll('[id=button)) {
console.log('Found ' + buttons.length + ' on the screen'); 
1
Robert Sinclair

私はこれが可能であるとは思わない(少なくともいくつかの内部を使わずに)。そして、これを最適化することによってあなたが多くを得るとは思わない。

0
amix

このようにすべてのオブジェクトで利用できるようにします。

Object.defineProperty(Object.prototype, "length", {
get() {
    if (!Object.keys) {
        Object.keys = function (obj) {
            var keys = [],k;
            for (k in obj) {
                if (Object.prototype.hasOwnProperty.call(obj, k)) {
                    keys.Push(k);
                }
            }
            return keys;
        };
    }
    return Object.keys(this).length;
},});

console.log({"Name":"Joe","Age":26}.length) //returns 2
0
Taquatech