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


1545

オブジェクトのキー/プロパティの数を数える最も速い方法は何ですか?オブジェクトを繰り返すことなくこれを行うことは可能ですか?つまり、せずに

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

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



2
さまざまな方法のパフォーマンスベンチマーク:jsben.ch
#

回答:


2517

Node、Chrome、IE 9以降、Firefox 4以降、Safari 5 以降などのES5互換環境でこれを行うには:

Object.keys(obj).length

8
Node.jsだけでなく、ES5をサポートするすべての環境
Yi Jiang

59
ところで...いくつかのテストを実行しました...このメソッドはO(n)時間で実行されます。forループは、この方法ほど悪くありません。**悲しそうな顔** stackoverflow.com
questions/7956554/…

161
-1(可能な場合は-200)これは、オブジェクトを反復処理するだけでなく、すべてのキーを含むまったく新しい配列を作成するため、質問への回答に完全に失敗します。
GetFree

42
for(少なくともChrome 25では)よりもはるかに高速に見えます:jsperf.com/count-elements-in-object
fserb

34
@GetFreeなぜそんなに多くの賛成ですか?これは間違いなくコーディングの面で最速の方法です。追加のメソッドやライブラリは必要ありません。コード速度の点では、明らかにそれほど悪くもありません。完全な失敗ではありません。87イマイチは失敗します。
Andrew

150

次のコードを使用できます。

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;

2
チェックの目的は何(Object.prototype.hasOwnProperty.call(obj, k))ですか?
スタイル

14
@styfle forループを使用してオブジェクトのプロパティを反復処理すると、プロトタイプチェーンのプロパティも取得されます。そのため、チェックhasOwnPropertyが必要です。オブジェクト自体に設定されたプロパティのみを返します。
Renaat De Muynck、2012

13
@styfleシンプルにするために、次のように書くことができますobj.hasOwnProperty(k)(私は実際に元の投稿でこれを行いましたが、後で更新しました)。はのプロトタイプのhasOwnProperty一部であるため、すべてのオブジェクトで使用できますObjectが、まれにこのメソッドが削除またはオーバーライドされるため、予期しない結果が生じる可能性があります。それからそれを呼び出すことにより、Object.prototypeそれは少しより堅牢になります。使用する理由は、プロトタイプではなくcallメソッドを呼び出したいためですobj
Renaat De Muynck、2012

6
このバージョンを使用する方が良いでしょうか? developer.mozilla.org/en-US/docs/JavaScript/Reference/...
ザビエルDelamotte

1
@XavierDelamotteあなたは絶対に正しいです。私のバージョンは動作しますが、それは非常に基本的で、例としてメンターです。Mozillaのコードはより安全です。(
追記

137

使用している場合はUnderscore.jsを、あなたは使用することができます_.size(感謝@douweを):
_.size(obj)

別の方法として、_。keysを使用することもできます。
_.keys(obj).length

私はUnderscoreを強くお勧めします。これは、多くの基本的なことを行うためのタイトなライブラリです。それらは可能な限りECMA5に一致し、ネイティブの実装に従います。

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


9
underscore.jsを使用する場合は、代わりに_.sizeを使用する必要があります。良い点は、何らかの方法で配列からオブジェクトに、またはその逆に切り替えた場合、結果は同じままであることです。
douwe 2011年

2
そして、私の理解から、lodashは一般的にアンダースコアよりも優れています(ただし、同じことを行います)。
Merlyn Morgan-Graham、2015

1
@ MerlynMorgan-Graham私が正しく思い出せば、lodashはもともとアンダースコアのフォークです...
molson504x

6
_.keys(obj).length私にとって最も効果的に機能したのは、戻りオブジェクトが、プロパティのないプレーンな文字列になる場合があるためです。_.size(obj)一方で私は、文字列の長さをバック与え_.keys(obj).length戻り0
ジェイコブスタム

O(n)の複雑さ。LodashとUnderscoreはObject.keys内部的に使用されます。また、アンダースコアは、定義されていないfor..in場合、ループ内のすべてのキーを配列にコピーしますObject.keys
N.クドリャフツェフ

82

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

したがって、最も一般的に使用される選択肢は次のとおりです。

1. ECMAScriptのObject.keys()

Object.keys(obj).length;作品内部のキーを反復処理は、一時的な配列を計算し、その長さを返します。

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

2.ライブラリベースのソリューション

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

3. forループの最適化

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

それ以外の場合、コードをkローカルvar k++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;

これが特定の環境でより高速であるかどうかは、ベンチマークの問題です。とにかく非常に限られたパフォーマンスの向上が期待できます。


なぜvar k in myobjパフォーマンスが向上するのですか?私の知る限り、JavaScriptで新しいスコープを宣言するのは関数だけです。インループはこのルールの例外ですか?
Lars Gyrup Brink Nielsen 2014

1
これは速いですか?for (var k in myobj) hasOwn.call(myobj, k) && ++count;つまり、ifステートメントを単純な&&?に置き換えます。
Hamza Kubba 14

あなたができる最後のこと:Object.getOwnPropertyNames(obj).length; はるかに簡単です。
ウィルト

29

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

プロパティの初期数を一度計算するだけで、そこから先に進みます。実際のパフォーマンスの問題がない場合は、気にしないでください。そのコードを関数にラップして、それで終わりですgetNumberOfProperties(object)


4
@hitautodestruct彼はソリューションを提供しているからです。
2013

@crushこの回答は、直接的な解決策ではなく、やるべきことを示唆しているようです。
hitautodestruct 2013

5
@hitautodestructは答えを提案します:追加/削除メソッドでカプセル化されたカウントをインクリメント/デクリメントします。これとまったく同じような別の答えが以下にあります。唯一の違いは、Confusionがコードを提供しなかったことです。解答はコードソリューションのみを提供するように義務付けられていません。
2013

1
それは完璧ではないかもしれない...しかし、他の「答え」と比べて、これはいくつかの状況のために最善の解決策かもしれ
d.raev

1
これまでのところ、これはO(1)の一定時間のパフォーマンスの複雑さであることがわかっている唯一のソリューションであり、したがって、「反復なし」の質問の詳細に回答する唯一のソリューションであり、したがってtru Accepted Answerになります。O(n)線形時間のパフォーマンスの複雑さを提供するため、他のすべての回答ではなくてもほとんどの回答はそれを答えません。これは、.keys()関数のようなものを呼び出す1行のソリューションにも当てはまります。そのような関数呼び出しはO(n)だからです。
cellepo

17

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

ただし、ほとんどの場合、これらのタイプの操作にnonnumerableを含めたくない場合がありますが、違いを知っておくとよいでしょう;)


1
言及してくれてうれしいですObject.getOwnPropertyNames、あなたはここに一人
Wilt

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__関数が実行され、再計算されます。


13
注記Object.prototype.__count__のGecko 1.9.3で削除されている:whereswalden.com/2010/04/06/... -property・オブ・オブジェクト・-削除されています/
dshaw

17
Firefox 4がリリースされたため、この回答は廃止されました。Object.__count__無くなりました、そしてまた良いriddance。
Yi Jiang

1
答えが時代遅れだとは言いません。関数に値をカプセル化することは、興味深い戦略です。
devios1

プロトタイプオブジェクトを使用して拡張する必要があります
Aaria Carter-Weir

13

Avi Flaxの回答を反復するには、関数が関連付けられていないオブジェクトではObject.keys(obj).lengthが正しい

例:

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

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)


についてのコメントへの応答Array(obj).length:それは動作しません。http://jsfiddle.net/Jhy8M/
ジェイミーチョン

ええ、もう少し調べて、可能であればこの回答を削除するか、すべて一緒に編集することにします
Belldandu

これが関数と関係があるとは思わない。Chromeでは、この動作はまったく見られない。私は、これはデフォルトの動作を行うために持っていたかもしれない疑いがあるでしょう可算:)Object.defineProperty(false、私はまだどのように上の任意のドキュメントを見つけていませんでしたけれどもvar obj = { a: true, b: true }異なる場合がありvar obj = {}; obj.a = true; obj.b = true;W3の異なる解釈/意味がある場合、または単にをChromeで採用されました。
NOLO

10

上記のように: Object.keys(obj).length

しかし、ES6に実際のMapクラスができたので、オブジェクトのプロパティを使用する代わりにそれを使用することをお勧めします。

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

8

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

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

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

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

8

以下は、3つの方法のパフォーマンステストです。

https://jsperf.com/get-the-number-of-keys-in-an-object

Object.keys()。length

20,7351秒あたり操作

非常にシンプルで互換性があります。高速で実行されます、新しいキーの配列が作成されるためコストかかります。

return Object.keys(objectToRead).length;

キーをループする

1秒あたり15,734回の操作

let size=0;
for(let k in objectToRead) {
  size++
}
return size;

やや遅いが、メモリ使用量の近くではないため、モバイルまたは他の小型マシン向けに最適化したい場合はおそらく良い

オブジェクトの代わりにマップを使用する

1秒あたり953,839,338回の操作

return mapToRead.size;

基本的に、Mapは独自のサイズを追跡するため、数値フィールドを返すだけです。他のどの方法よりもはるかに高速です。オブジェクトを制御できる場合は、代わりにマップに変換してください。


6

送信元: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 = "leaked@example.com";
myObj.length; //output: 2

その方法を追加すると、for..inループでは表示されません。

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

出力:

name:John Doe
email:leaked@example.com

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


組み込みのプロトタイプを拡張する場合、またはプロパティ(つまり、モンキーパッチ)をポリフィルする場合は、正しく実行してください。前方互換性のために、プロパティが最初に存在するかどうかを確認し、次にプロパティを列挙不可にして、独自のキーが構築されたオブジェクトの汚染されていません。メソッドには実際の メソッドを使用します。私の推奨事項:次の例に従って組み込みメソッドのようにできるだけ近くで動作するメソッドを追加する方法を示します。
user4642212

5

この問題を解決する方法は、オブジェクトに格納されているアイテムの数の記録を保持する基本的なリストの独自の実装を構築することです。とてもシンプルです。このようなもの:

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];
   }
}

1
興味深い代替案。これにより、集計カウント関数のオーバーヘッドが排除されますが、要素を追加または削除するたびに関数が呼び出されるという犠牲を払って、残念ながらさらに悪化する可能性があります。このようなリストの実装は、単純な配列と比較して、データのカプセル化とカスタムメソッドに直接使用できますが、高速なアイテムカウントだけが必要な場合は使用しません。
Luc125 2013年

1
私はあなたの答えが好きですが、私はレミングでもあり、賛成投票をクリックしました。これは興味深いジレンマを示しています。私の回答がすでに賛成票を投じている私の状況など、命令の一部の行動を考慮に入れていませんが、「賛成票をクリック」するように指示されており、できません。命令はサイレントに失敗しますが、私はここのSOのコンテンツから収集します。サイレントに失敗することは、コードの実行が好きではないことです。頭を上げただけです。
L0j1k 2013

1
私はこの答え、いいデータ構造が本当に好きです。また、addの関数呼び出しでパフォーマンスに影響があった場合、オブジェクトを反復処理する必要があると、パフォーマンスが大幅に向上します。これにより、最速のループパッテンが可能になりますvar i = basiclist.count while(i--){...}
Lex

基本的なリストに少なくとも基本的なチェックを含めるべきではありませんか?add古いアイテムを置き換えるかどうか、またはremove存在しないインデックスで呼び出されるかどうかをチェックするように。また、リストがundefined有効なアイテム値である場合、リストに特定のインデックスがあるかどうかを確認することもできません。
Robert

2
リストは順序付けされ、反復可能でなければなりません。データはオブジェクトに格納されるため、要素の順序は保証されません。穴のあるリストの長さをどのようにして見つけますか?this.count?最高のインデックス値?同じインデックスに2つのアイテムを追加した場合、カウントはエラー状態になります。
Ultimate Gobblement 2014年

4

Object.keys(data).lengthキーデータを持つJSONオブジェクトの長さを見つけるために使用できます


3

Ext JS 4がプロジェクトに含まれている場合、次のことができます。

Ext.Object.getSize(myobj);

これの利点は、すべてのExt互換ブラウザー(IE6-IE8を含む)で動作することですが、他の推奨される解決策と同様に、実行時間はO(n)よりも優れているとは思いません。


2

以下を使用できます。

Object.keys(objectName).length; 

そして

Object.values(objectName).length;

1

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

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

0

上記のjQueryが機能しない場合は、

$(Object.Item).length

3
それObject.Itemは存在しないようです
Luc125

-1

これは可能ではないと思います(少なくとも、いくつかの内部を使用しない限り)。そして、これを最適化することで多くを得るとは思いません。


2
受け入れられた答えは、これが可能であり、得るものがないと断言する文脈がないことを示しています。
コンジット

-1

私はそれを次のようにすべてのオブジェクトで利用できるようにしています:

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.