如何快速计算对象的键/属性数量?是否可以在不迭代对象的情况下完成?即,不执行以下操作:
var count = 0;
for (k in myobj) if (myobj.hasOwnProperty(k)) ++count;
(Firefox曾经提供了一个神奇的__count__
属性,但在4版本左右被移除了。)
如何快速计算对象的键/属性数量?是否可以在不迭代对象的情况下完成?即,不执行以下操作:
var count = 0;
for (k in myobj) if (myobj.hasOwnProperty(k)) ++count;
(Firefox曾经提供了一个神奇的__count__
属性,但在4版本左右被移除了。)
在任何兼容ES5的环境中,如Node.js、Chrome、Internet Explorer 9+、Firefox 4+或Safari 5+,执行以下操作:
Object.keys(obj).length
你可以使用这段代码:
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;
(Object.prototype.hasOwnProperty.call(obj, k))
的目的是什么? - styflefor
循环来迭代对象的属性,你也会得到原型链上的属性。这就是为什么需要检查hasOwnProperty
的原因。它只返回在对象本身上设置的属性。 - Renaat De Muynckobj.hasOwnProperty(k)
(我在原帖中实际上就是这么写的,但后来更新了)。hasOwnProperty
可以在每个对象上使用,因为它是 Object
原型的一部分,但在极其罕见的情况下,如果该方法被删除或覆盖,则可能会得到意外的结果。通过从 Object.prototype
调用它,使它更加健壮。使用 call
的原因是因为你想要在 obj
上调用该方法而不是在原型上调用。 - Renaat De Muynck如果你正在使用Underscore.js,你可以使用_.size(感谢Douwe):
_.size(obj)
或者你也可以使用_.keys,这可能更清晰一些:
_.keys(obj).length
我强烈推荐使用Underscore.js。它是一个紧凑的库,可以完成许多基本任务。尽可能地,他们与ECMAScript 5相匹配,并延迟到本地实现。
否则,我支持Avi Flax' answer。我编辑了它,添加了一个链接到MDC文档,其中包括您可以添加到非ECMAScript 5浏览器的keys()方法。
_.keys(obj).length
,因为返回对象有时是一个纯字符串,其中没有属性。 _.size(obj)
会返回字符串的长度,而_.keys(obj).length
则返回0。 - Jacob StammObject.keys
。如果未定义Object.keys
,Underscore还会将每个键复制到for..in
循环中的数组中。 - N. KudryavtsevObject.keys(obj).length;
通过内部迭代键来计算临时数组并返回其长度。
在这个主题的其他基于库的例子中,这些例子在其库的上下文中是有用的习语。然而,从性能的角度来看,与完美的无库代码相比,所有这些库方法实际上都封装了一个for循环或ES5 Object.keys
(本机或shimmed)没有任何收益。
这种for循环最慢的部分通常是.hasOwnProperty()
调用,因为函数调用开销很大。因此,当我只想要JSON对象的条目数时,如果我知道没有代码会扩展Object.prototype
,我就跳过.hasOwnProperty()
调用。
否则,您的代码可以通过使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 中声明新作用域。难道 in 循环是这个规则的例外吗? - Lars Gyrup Brink Nielsenfor (var k in myobj) hasOwn.call(myobj, k) && ++count;
即用简单的&&替换if语句? - Hamza KubbaObject.getOwnPropertyNames(obj).length
来获取对象属性数量,这样更简单。 - Wiltfor(var k in myobj)count += myobj.hasOwnProperty(k);
极小可能会更好,因为它将一个逻辑测试和分支替换为无分支(在不可预测分支的意义上)的代码,但这完全取决于引擎是否付出任何代价从bool转换为int,以及在不是自有属性时是否无条件写入“count”。但至少在Edge 113上的测试中,使用+=
速度略慢。 - ShadowRangerhasOwn.call(myobj, k) && ++count
比 if (hasOwn.call(myobj, k)) ++count
稍微慢一点。这是微不足道的差异(并且很容易被计时抖动所影响),但它绝对不是更好的选择。 - ShadowRanger这里有三种方法的性能测试结果;
https://jsperf.com/get-the-number-of-keys-in-an-object
每秒 20,735 次操作
它非常简单兼容且运行速度快,但是代价高昂,因为它会创建一个新的键数组,然后抛弃它。
return Object.keys(objectToRead).length;
每秒15,734次
let size=0;
for(let k in objectToRead) {
size++
}
return size;
虽然速度稍慢,但内存使用远低于对象,所以如果您想要针对移动设备或其他小型机器进行优化,这可能更好。
每秒 953,839,338 次操作
return mapToRead.size;
基本上,Map会跟踪自己的大小,因此我们只需返回一个数字字段。这比任何其他方法都要快得多。如果您控制着对象,请将它们转换为地图。
Object
和Map
的页面:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map。缺点似乎是缺少对`JSON.stringify`和`JSON.parse`的本地支持。包装器最终将`Map`-> Object
转换为JSON
函数,因此它在仅存在于序列化/反序列化的内容方面失去了意义。如果不需要序列化和实际对象功能,则Map
似乎是更优秀的选择。 - OXiGENa
到z
,在Edge 113上运行在一个薄客户端设置上(因此工作是在相当强大但共享的服务器上完成的),Object.keys().length
的吞吐量比for循环高出5倍以上,并且比任何使用hasOwnProperty
(缓存或未缓存,分支或不分支)的for循环变体高出10倍以上。 - ShadowRangerMap
而不是Object.keys().length
解决方案的吞吐量几乎是后者的两倍,因此排名没有改变,但成功程度有很大不同;Map
更好,但只是大约2倍,并非50倍。Object.keys().length
比for
循环好两倍,不仅仅是吞吐量高出三分之一。当然,我的微基准测试(重复使用相同的对象/Map
)可能会让JS引擎在不应该优化时进行优化,而相对性能显然取决于对象/Map
的大小(因为除了Map
解决方案外,所有解决方案都是O(n)
)。 - ShadowRanger如果您实际上遇到了性能问题,我建议将向对象添加/删除属性的调用包装在一个函数中,该函数还会适当命名(尺寸?)属性进行递增/递减。
您只需要计算初始属性数量一次,然后继续。如果没有实际的性能问题,请不要费心。只需将代码的那部分包装在一个名为getNumberOfProperties(object)
的函数中,完成它。
这适用于数组和对象
//count objects/arrays
function count(obj){
return Object.keys(obj).length
}
用循环计算对象/数组的数量
function count(obj){
var x=0;
for(k in obj){
x++;
}
return x;
}
计算对象/数组或字符串的长度
function count(obj){
if (typeof (obj) === 'string' || obj instanceof String)
{
return obj.toString().length;
}
return Object.keys(obj).length
}
Object.keys(obj).length
但是:由于ES6中现在有一个真正的Map类,我建议使用它来替代使用对象的属性。suggest
const map = new Map();
map.set("key", "value");
map.size; // THE fastest way
Object.keys(obj).length
https://dev59.com/tXVC5IYBdhLWcg3w-mZO#4889658 - Flavien Volken正如 Avi Flax所说,
Object.keys(obj).length
使用 Object.keys
可以处理对象上的所有可枚举属性,但如果您想包括不可枚举属性,可以使用 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
具有相同的浏览器支持。
然而,在大多数情况下,您可能不想在这些类型的操作中包含非枚举属性,但了解差异总是好的 ;)
Object.getOwnPropertyNames
,你是这里唯一的一个... - Wilt例如:
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
来计算文件中有多少个函数)
还有,是的,我在我的示例中使用了Node.js的_
或Underscore.js模块。
文档可以在这里找到,以及其在GitHub上的源代码和各种其他信息。
最后,Lodash实现:https://lodash.com/docs#size
_.size(obj)
Array(obj).length
的评论:
它不起作用。
http://jsfiddle.net/Jhy8M/ - Jamie Chongfalse
,尽管我还没有找到任何关于var obj = { a: true, b: true }
如何与var obj = {}; obj.a = true; obj.b = true;
不同或者是否采用了W3的不同解释/语义的文档。 - Nolo
Map
了。 - Константин Ван