计算对象的键/属性数量的最快方法是什么?是否可以在不迭代对象的情况下做到这一点?即,不做:
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
浏览器兼容性
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;
(Object.prototype.hasOwnProperty.call(obj, k))
的目的是什么?
hasOwnProperty
是必要的。它只返回在对象本身上设置的属性。
obj.hasOwnProperty(k)
(我实际上在我的原始帖子中这样做了,但后来更新了它)。 hasOwnProperty
在每个对象上都可用,因为它是 Object
原型的一部分,但在极少数情况下,此方法会被删除或覆盖,您可能会得到意想不到的结果。通过从 Object.prototype
调用它,它变得更加健壮。使用 call
的原因是因为您想在 obj
而不是原型上调用方法。
如果您使用 Underscore.js,您可以使用 _.size (thanks 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。
Object.keys
。如果未定义 Object.keys
,Underscore 还会将每个键复制到 for..in
循环内的数组中。
标准对象实现 (ES5.1 Object Internal Properties and Methods) 不需要 Object
来跟踪其键/属性的数量,因此不应该有标准的方法来确定 Object
的大小,而无需显式或隐式迭代其键。
所以这里是最常用的替代方案:
1. ECMAScript 的 Object.keys()
Object.keys(obj).length;
通过内部迭代键来计算临时数组并返回其长度。
优点 - 可读和干净的语法。如果本机支持不可用,则不需要任何库或自定义代码,除非 shim
缺点 - 由于创建数组而导致的内存开销。
2. 基于库的解决方案
本主题其他地方的许多基于库的示例在其库的上下文中都是有用的习语。然而,从性能的角度来看,与完美的无库代码相比,没有任何好处,因为所有这些库方法实际上都封装了 for 循环或 ES5 Object.keys
(本机或填充)。
3.优化for循环
由于函数调用开销,这种 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 中声明了新的作用域。循环内是此规则的例外吗?
for (var k in myobj) hasOwn.call(myobj, k) && ++count;
即用简单的 &&? 替换 if 语句
Object.getOwnPropertyNames(obj).length
;简单得多。
以下是三种方法的一些性能测试;
https://jsperf.com/get-the-number-of-keys-in-an-object
Object.keys().length
每秒 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 会跟踪它自己的大小,所以我们只返回一个数字字段。它比任何其他方法都快得多。如果您可以控制对象,请将它们转换为地图。
如果您实际上遇到了性能问题,我建议您使用一个函数包装向对象添加/删除属性的调用,该函数还增加/减少适当命名的(大小?)属性。
您只需要计算一次属性的初始数量并从那里继续。如果没有实际的性能问题,请不要打扰。只需将那段代码包装在函数 getNumberOfProperties(object)
中即可。
如上一个答案中所回答:Object.keys(obj).length
但是:因为我们现在在 ES6 中有一个真正的 Map 类,我会 suggest 使用它而不是使用对象的属性。
const map = new Map();
map.set("key", "value");
map.size; // THE fastest way
Object.keys(obj).length
stackoverflow.com/a/4889658/532695
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
作为 stated here,它具有与 Object.keys
相同的浏览器支持。
但是,在大多数情况下,您可能不想在这些类型的操作中包含不可枚举,但知道它们的区别总是好的;)
Object.getOwnPropertyNames
,你是这里唯一的人......
要在 Avi Flax' answer 上进行迭代,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) 计算文件中有多少函数。长度)
另外,是的,我在示例中使用了 Node.js 中的 _
或 Underscore.js 模块。
可以在 here 上找到文档及其在 GitHub 上的来源以及各种其他信息。
最后是 lodash 实现 https://lodash.com/docs#size
_.size(obj)
Array(obj).length
的评论:它不起作用。 http://jsfiddle.net/Jhy8M/
false
)有关,尽管我还没有找到任何文档说明 var obj = { a: true, b: true }
可能与 var obj = {}; obj.a = true; obj.b = true;
有何不同,或者只是解释不同/ Chrome 采用了 W3 的语义。
我不知道有什么方法可以做到这一点。但是,为了将迭代保持在最低限度,您可以尝试检查 __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__
时,该函数都会触发并重新计算。
Object.prototype.__count__
:whereswalden.com/2010/04/06/…count-property-of-objects-is-being-removed/
Object.__count__
不见了,也摆脱了。
这适用于数组和对象
//count objects
function count(obj){
return Object.keys(obj).length
}
//count also String length
function count(obj){
if (typeof (obj) === 'string' || obj instanceof String)
{
return obj.length;
}
return Object.keys(obj).length
}
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
注意:它在 Internet Explorer 9 之前的浏览器中不起作用。
对于那些在项目中包含 Underscore.js 的人,您可以执行以下操作:
_({a:'', b:''}).size() // => 2
或功能风格:
_.size({a:'', b:''}) // => 2
我解决这个问题的方法是构建我自己的基本列表实现,该列表记录对象中存储了多少项目。这很简单。像这样的东西:
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];
}
}
var i = basiclist.count
while(i--){...}
add
是否替换旧项目或是否使用不存在的索引调用 remove
。此外,如果 undefined
是有效的项目值,则无法检查列表是否具有给定索引。
对于项目中有 Ext JS 4 的人,您可以执行以下操作:
Ext.Object.getSize(myobj);
这样做的好处是它适用于所有与 Ext JS 兼容的浏览器(包括 Internet Explorer 6 - Internet Explorer 8)。但是,与其他建议的解决方案一样,我相信运行时间并不比 O(n) 好。
您可以使用:
Object.keys(objectName).length;
和
Object.values(objectName).length;
OP 没有指定对象是否是 nodeList。如果是,那么您可以直接在其上使用长度方法。例子:
buttons = document.querySelectorAll('[id=button)) {
console.log('Found ' + buttons.length + ' on the screen');
如果先前答案中的 jQuery 不起作用,请尝试
$(Object.Item).length
Object.Item
似乎不存在
我认为这是不可能的(至少在不使用一些内部组件的情况下是不可能的)。我不认为你会通过优化这个获得太多收益。
我尝试使其可用于所有对象,如下所示:
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
不定期副业成功案例分享