JavaScript でオブジェクトのキー/プロパティの数を効率的にカウントするにはどうすればよいですか?
-
02-07-2019 - |
質問
オブジェクトのキー/プロパティの数を数える最も速い方法は何ですか?オブジェクトを反復処理せずにこれを行うことは可能ですか?つまりやらずに
var count = 0;
for (k in myobj) if (myobj.hasOwnProperty(k)) count++;
(Firefox は魔法を提供しました __count__
プロパティですが、これはバージョン 4 あたりで削除されました。)
解決
これをどの環境でも行うには ES5対応環境, 、 のような ノード, 、Chrome、IE 9 以降、Firefox 4 以降、または Safari 5 以降:
Object.keys(obj).length
- ブラウザの互換性
- Object.keys ドキュメント (ES5 以外のブラウザに追加できるメソッドを含む)
他のヒント
次のコードを使用できます。
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;
使用している場合 アンダースコア.js 使用できます _。サイズ (@douwe に感謝):
_.size(obj)
あるいは、次のように使用することもできます _.keys 人によってはこちらの方がわかりやすいかもしれません。
_.keys(obj).length
Underscore を強くお勧めします。これは、多くの基本的なことを行うための厳密なライブラリです。可能な場合は常に ECMA5 に一致し、ネイティブ実装に従います。
それ以外の場合、私は@Aviの答えを支持します。これを編集して、ECMA5 以外のブラウザに追加できる key() メソッドを含む MDC ドキュメントへのリンクを追加しました。
標準のオブジェクト実装 (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;
特定の環境でこれが速いかどうかは、ベンチマークの問題です。いずれにせよ、期待できるパフォーマンスの向上は非常に限られています。
実際にパフォーマンスの問題が発生している場合は、オブジェクトにプロパティを追加/削除する呼び出しを、適切な名前 (サイズ?) プロパティを増減する関数でラップすることをお勧めします。
プロパティの初期数を一度計算するだけで済み、そこから先に進むことができます。実際のパフォーマンスに問題がない場合は、気にする必要はありません。そのコード部分を関数でラップするだけです getNumberOfProperties(object)
そしてそれで終わりです。
これを行う方法はわかりませんが、反復を最小限に抑えるために、 __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__
関数が起動して再計算されます。
アヴィ・フラックスが述べたように 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
ただし、ほとんどの場合、この種の操作には非数値を含めたくないかもしれませんが、違いを知っておくことは常に良いことです ;)
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);});}} */
これを回避する手順は次のとおりです。
キーの数を数えたいオブジェクトに関数を入れないでください。
別のオブジェクトを使用するか、関数専用の新しいオブジェクトを作成します (ファイル内に関数の数を数えたい場合は、
Object.keys(obj).length
)
また、はい、私の例ではnodejsの_またはアンダースコアモジュールを使用しました
ドキュメントはここにあります http://underscorejs.org/ github 上のソースやその他のさまざまな情報も
そして最後に lodash の実装 https://lodash.com/docs#size
_.size(obj)
プロジェクトに Underscore.js が含まれている場合は、次のことができます。
_({a:'', b:''}).size() // => 2
または機能的なスタイル:
_.size({a:'', b:''}) // => 2
から: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
Object.defineProperty(obj, prop, 記述子)
すべてのオブジェクトに追加することもできます。
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 未満のブラウザでは動作しません。
この問題を解決する方法は、オブジェクトに格納されている項目の数を記録する基本的なリストの独自の実装を構築することです。とてもシンプルです。このようなもの:
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];
}
}
プロジェクトに Ext JS 4 がある場合は、次のことができます。
Ext.Object.getSize(myobj);
この利点は、すべての Ext 互換ブラウザ (IE6 ~ IE8 を含む) で動作することですが、他の提案されたソリューションと同様に、実行時間は O(n) よりも優れていないと思います。
使用できます Object.keys(data).length
キーデータを持つJSONオブジェクトの長さを調べる
上記の jQuery が機能しない場合は、試してください
$(Object.Item).length
OPはオブジェクトがnodeListであるかどうかを指定しませんでした。そうである場合は、単に使用できます 長さ メソッドを直接使用します。例:
buttons = document.querySelectorAll('[id=button)) {
console.log('Found ' + buttons.length + ' on the screen');
これは不可能だと思います (少なくとも内部機能を使用しない限り)。そして、これを最適化してもあまりメリットが得られるとは思えません。
次のようにすべてのオブジェクトで利用できるようにしようとします。
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
Google Closure にはこれに適した機能があります...goog.object.getCount(obj)
次のものが使用できます。 Object.keys(objectName).length;
& Object.values(objectName).length;