【问题标题】:Length of a JavaScript objectJavaScript 对象的长度
【发布时间】:2010-09-05 12:50:45
【问题描述】:

我有一个 JavaScript 对象。是否有内置或公认的最佳实践方法来获取此对象的长度?

const myObject = new Object();
myObject["firstname"] = "Gareth";
myObject["lastname"] = "Simpson";
myObject["age"] = 21;

【问题讨论】:

  • javascript 中的对象字面量默认是关联数组,例如 object.propertyName.propertyValue 与 object[propertyName][propertyValue] 相同
  • 在 Underscore.js 中添加了一个单行代码:stackoverflow.com/a/11346637/11236
  • 一次答案是使用 Object.keys(myArray).length 正如@aeosynth 所说。
  • 好的,Object.keys(obj).length 怎么样
  • 为什么 object.length 无效?它为我返回正确的结果。

标签: javascript javascript-objects


【解决方案1】:

我不是 JavaScript 专家,但看起来你必须遍历元素并计算它们,因为 Object 没有长度方法:

var element_count = 0;
for (e in myArray) {  if (myArray.hasOwnProperty(e)) element_count++; }

@palmsey:为了公平起见,JavaScript 文档实际上明确地将以这种方式使用 Object 类型的变量称为“关联数组”。

【讨论】:

  • 不会起作用,因为它也会计算通过原型添加的方法。
【解决方案2】:

以下是检查属性是否不在原型链上的方法并且不要忘记:

var element_count = 0;
for(var e in myArray)
    if(myArray.hasOwnProperty(e))
        element_count++;

【讨论】:

    【解决方案3】:

    @palmsey:为了公平起见,JavaScript 文档实际上明确地将以这种方式使用 Object 类型的变量称为“关联数组”。

    公平地说,@palmsey 他说得很对。它们不是关联数组;它们绝对是对象 :) - 完成关联数组的工作。但就更广泛的观点而言,根据我发现的这篇相当不错的文章,您似乎肯定拥有它的权利:

    JavaScript “Associative Arrays” Considered Harmful

    但根据这一切,the accepted answer 本身就是不好的做法?

    为 Object 指定一个原型 size() 函数

    如果在 Object .prototype 中添加了任何其他内容,则建议的代码将失败:

    <script type="text/javascript">
    Object.prototype.size = function () {
      var len = this.length ? --this.length : -1;
        for (var k in this)
          len++;
      return len;
    }
    Object.prototype.size2 = function () {
      var len = this.length ? --this.length : -1;
        for (var k in this)
          len++;
      return len;
    }
    var myArray = new Object();
    myArray["firstname"] = "Gareth";
    myArray["lastname"] = "Simpson";
    myArray["age"] = 21;
    alert("age is " + myArray["age"]);
    alert("length is " + myArray.size());
    </script>
    

    我认为该答案不应该是公认的答案,因为如果您在同一执行上下文中运行任何其他代码,则无法信任它可以工作。要以稳健的方式执行此操作,您肯定需要在 myArray 中定义 size 方法并在遍历成员时检查成员的类型。

    【讨论】:

      【解决方案4】:

      更新答案

      这是 2016 年和 widespread deployment of ES5 及以后的更新。对于 IE9+ 和所有其他支持现代 ES5+ 的浏览器,您可以使用 Object.keys(),因此上述代码变为:

      var size = Object.keys(myObj).length;
      

      这不必修改任何现有原型,因为 Object.keys() 现在是内置的。

      编辑:对象可以具有无法通过 Object.key 方法返回的符号属性。因此,如果不提及它们,答案将是不完整的。

      符号类型被添加到语言中以创建对象属性的唯一标识符。 Symbol 类型的主要好处是防止覆盖。

      Object.keysObject.getOwnPropertyNames 不适用于符号属性。要退回它们,您需要使用Object.getOwnPropertySymbols

      var person = {
        [Symbol('name')]: 'John Doe',
        [Symbol('age')]: 33,
        "occupation": "Programmer"
      };
      
      const propOwn = Object.getOwnPropertyNames(person);
      console.log(propOwn.length); // 1
      
      let propSymb = Object.getOwnPropertySymbols(person);
      console.log(propSymb.length); // 2

      旧答案

      最可靠的答案(即捕捉您尝试做的事情的意图,同时导致最少的错误)是:

      Object.size = function(obj) {
        var size = 0,
          key;
        for (key in obj) {
          if (obj.hasOwnProperty(key)) size++;
        }
        return size;
      };
      
      // Get the size of an object
      const myObj = {}
      var size = Object.size(myObj);

      在 JavaScript 中有一种约定是 don't add things to Object.prototype,因为它可以破坏各种库中的枚举。不过,向 Object 添加方法通常是安全的。


      【讨论】:

      • @Tres - 如果有人过来覆盖 'size' 属性而不知道你已经在代码中的某个地方声明它,你的代码可能会被破坏,所以检查它是否已经定义总是值得的
      • @vsync 你说的很对。应该始终实施必要的健全性检查:)
      • 为什么大家都忽略这个:Object.keys(obj).length
      • @MuhammadUmer 可能是因为在编写此答案时甚至不存在该方法。即使在今天,使用它也可能需要针对旧浏览器的 polyfill。
      • @stonyau IE8、IE9、IE10 是没有得到微软支持的死浏览器。 IE8、IE9、IE10 用户收到来自 Microsoft 的通知,他们使用旧的、不受支持的浏览器,并且应该期望这些东西对他们不起作用。 support.microsoft.com/en-us/kb/3123303
      【解决方案5】:

      如果您知道不必担心hasOwnProperty 检查,您可以这样使用Object.keys() 方法:

      Object.keys(myArray).length
      

      【讨论】:

      • 为什么不呢?据我所知,这是一个标准:developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
      • 这不是一个通用的实现方法,但是你可以通过this table查看哪个浏览器支持它。
      • 是时候切换到 firefox = 不幸的是,您切换并不意味着您网站的用户会...
      • @ripper234 不支持 IE = 填充时间
      • @ripper234 关心 IE,没有人应该关心 IE 不标准,只关心标准。用户想使用 IE,那么他们将不会浏览我的网站,我不再关心。开发人员不应该填充不是由“开发人员”制定的标准
      【解决方案6】:

      为了不弄乱原型或其他代码,您可以构建和扩展自己的对象:

      function Hash(){
          var length=0;
          this.add = function(key, val){
               if(this[key] == undefined)
               {
                 length++;
               }
               this[key]=val;
          }; 
          this.length = function(){
              return length;
          };
      }
      
      myArray = new Hash();
      myArray.add("lastname", "Simpson");
      myArray.add("age", 21);
      alert(myArray.length()); // will alert 2
      

      如果你总是使用 add 方法,那么 length 属性是正确的。如果您担心自己或其他人忘记使用它,您也可以将其他人发布的属性计数器添加到 length 方法中。

      当然,您总是可以覆盖这些方法。但即使你这样做了,你的代码也可能会明显失败,从而很容易调试。 ;)

      【讨论】:

      • 我认为这是最好的解决方案,因为它不需要使用 'for' 循环,如果数组很大,这可能会很昂贵
      【解决方案7】:

      在某些情况下,最好将大小存储在单独的变量中。特别是,如果您要在一个位置将一个元素添加到数组中,并且可以轻松地增加大小。如果您需要经常检查尺寸,它显然会更快。

      【讨论】:

        【解决方案8】:

        这样的事情怎么样--

        function keyValuePairs() {
            this.length = 0;
            function add(key, value) { this[key] = value; this.length++; }
            function remove(key) { if (this.hasOwnProperty(key)) { delete this[key]; this.length--; }}
        }
        

        【讨论】:

          【解决方案9】:

          上面的一些变体是:

          var objLength = function(obj){    
              var key,len=0;
              for(key in obj){
                  len += Number( obj.hasOwnProperty(key) );
              }
              return len;
          };
          

          集成 hasOwnProp 是一种更优雅的方式。

          【讨论】:

            【解决方案10】:

            更新:如果您使用的是Underscore.js(推荐,它很轻量级!),那么您可以这样做

            _.size({one : 1, two : 2, three : 3});
            => 3
            

            如果不是,并且您不想因任何原因弄乱对象属性,并且已经在使用 jQuery,那么插件同样可以访问:

            $.assocArraySize = function(obj) {
                // http://stackoverflow.com/a/6700/11236
                var size = 0, key;
                for (key in obj) {
                    if (obj.hasOwnProperty(key)) size++;
                }
                return size;
            };
            

            【讨论】:

            • _.size() 是我的 Meteor 项目的完美解决方案,它支持 underscore.js。
            • 我使用了下划线,而这篇文章只是提醒我,我在这个项目中使用的不够多。如果你处理对象,你应该有 underscore.js 可用。
            • 下划线 > (all -['lo-dash'])
            • underscorejs,应该在js下的东西:)
            • @Babydead 区分对象的真实属性与继承的属性。 developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
            【解决方案11】:

            以下是 James Coglan 在 CoffeeScript 中为那些放弃直接使用 JavaScript 的人提供的答案:)

            Object.size = (obj) ->
              size = 0
              size++ for own key of obj
              size
            

            【讨论】:

            • 您可能想说size++ for own key of objown key 是 CoffeeScript 中的语法糖)。直接从对象中使用hasOwnProperty 是危险的,因为当对象实际上具有这样的属性时它会中断。
            • OP 没有要求 CoffeeScript 版本,也没有这样标记。这不是问题的有效答案。
            【解决方案12】:

            这是 James Cogan 答案的不同版本。无需传递参数,只需制作 Object 类的原型并使代码更简洁。

            Object.prototype.size = function () {
                var size = 0,
                    key;
                for (key in this) {
                    if (this.hasOwnProperty(key)) size++;
                }
                return size;
            };
            
            var x = {
                one: 1,
                two: 2,
                three: 3
            };
            
            x.size() === 3;
            

            jsfiddle 示例:http://jsfiddle.net/qar4j/1/

            【讨论】:

            • Object.prototype - 坏主意。
            • @tborychowski 你能解释一下原因吗?
            • 这是一篇文章:bit.ly/1droWrG。我并不是说一定不能这样做,只是在你这样做之前你需要知道所有的后果。
            • 如果你要扩展内置原型或填充一个属性(即猴子补丁),请正确:为了向前兼容,先检查属性是否存在,然后再制作属性不可枚举,这样构造对象的自己的键就不会被污染。对于方法,请使用 actual methods。我的建议:关注these examples,它演示了如何添加一个尽可能接近内置方法的方法。
            【解决方案13】:

            这是一个完全不同的解决方案,仅适用于更现代的浏览器(Internet Explorer 9+、Chrome、Firefox 4+、Opera 11.60+ 和 Safari 5.1+)

            this jsFiddle

            设置关联数组类

            /**
             * @constructor
             */
            AssociativeArray = function () {};
            
            // Make the length property work
            Object.defineProperty(AssociativeArray.prototype, "length", {
                get: function () {
                    var count = 0;
                    for (var key in this) {
                        if (this.hasOwnProperty(key))
                            count++;
                    }
                    return count;
                }
            });
            

            现在您可以按如下方式使用此代码...

            var a1 = new AssociativeArray();
            a1["prop1"] = "test";
            a1["prop2"] = 1234;
            a1["prop3"] = "something else";
            alert("Length of array is " + a1.length);
            

            【讨论】:

            • 我认为这不安全。例如它不能有一个键为“length”的元素,语句 a1["length"] = "Hello world";无法存储条目。还有语句 a1["hasOwnProperty"] = "some prop";完全破坏了功能
            • @PanosTheof 如果您使用 length 属性,我认为您不希望它存储该值,任何使用它的代码都必须确保它不会尝试和存储 @ 987654325@,但我想如果它也是一个标准数组,那也是一样的。在任何对象上覆盖 hasOwnProperty 很可能会产生不希望的结果。
            【解决方案14】:

            这是最跨浏览器的解决方案。

            这比接受的答案更好,因为它使用原生 Object.keys(如果存在)。 因此,它是所有现代浏览器中最快的。

            if (!Object.keys) {
                Object.keys = function (obj) {
                    var arr = [],
                        key;
                    for (key in obj) {
                        if (obj.hasOwnProperty(key)) {
                            arr.push(key);
                        }
                    }
                    return arr;
                };
            }
            
            Object.keys(obj).length;
            

            【讨论】:

            【解决方案15】:

            如果我们有哈希

            哈希 = {"a" : "b", "c": "d"};

            我们可以使用键的长度来获得长度,也就是哈希的长度:

            keys(hash).length

            【讨论】:

            • 这是一个很好的答案,但是我找不到任何有关此键功能的文档。所以我对跨浏览器支持没有信心。
            • 不幸的是,这并不是我最初想的那么好的答案!事实证明,keys 功能仅在 chrome 和 firefox web 控制台中可用。如果您将此代码放入脚本中,那么它将失败并出现 Uncaught ReferenceError: keys is not defined
            • 这与aeosynth's answer有何不同?
            【解决方案16】:

            像大多数 JavaScript 问题一样,有很多解决方案。您可以扩展像许多其他语言的字典(+ 一等公民)一样工作得更好或更坏的对象。这没有错,但另一种选择是构造一个满足您特定需求的新对象。

            function uberject(obj){
                this._count = 0;
                for(var param in obj){
                    this[param] = obj[param];
                    this._count++;
                }
            }
            
            uberject.prototype.getLength = function(){
                return this._count;
            };
            
            var foo = new uberject({bar:123,baz:456});
            alert(foo.getLength());
            

            【讨论】:

            • 不要修改原型 :)
            • 修改工厂函数的原型是你扩展它们的方式。
            【解决方案17】:

            此方法将对象的所有属性名称放在一个数组中,因此您可以获得该数组的长度,该长度等于对象的键长度。

            Object.getOwnPropertyNames({"hi":"Hi","msg":"Message"}).length; // => 2
            

            【讨论】:

            • @PatrickRoberts 键方法不会从原型链返回属性。那么这里为什么需要 hasOwnProperty。 getOwnProperty 也将返回隐藏属性,因为长度在数组等中。
            【解决方案18】:

            属性

            Object.defineProperty(Object.prototype, 'length', {
                get: function () {
                    var size = 0, key;
                    for (key in this)
                        if (this.hasOwnProperty(key))
                            size++;
                    return size;
                }
            });
            

            使用

            var o = {a: 1, b: 2, c: 3};
            alert(o.length); // <-- 3
            o['foo'] = 123;
            alert(o.length); // <-- 4
            

            【讨论】:

            • 如果你要扩展内置原型或填充一个属性(即猴子补丁),请正确:为了向前兼容,先检查属性是否存在,然后再制作属性不可枚举,这样构造对象的自己的键就不会被污染。对于方法,请使用 actual methods。我的建议:关注these examples,它演示了如何添加一个尽可能接近内置方法的方法。
            【解决方案19】:

            简单的解决方案:

              var myObject = {};      // ... your object goes here.
            
              var length = 0;
            
              for (var property in myObject) {
                if (myObject.hasOwnProperty(property)){
                  length += 1;
                }
              };
            
              console.log(length);    // logs 0 in my example.
            

            【讨论】:

              【解决方案20】:

              如果您使用的是AngularJS 1.x,您可以通过创建过滤器并使用任何其他示例中的代码(如下所示)以 AngularJS 的方式执行操作:

              // Count the elements in an object
              app.filter('lengthOfObject', function() {
                return function( obj ) {
                  var size = 0, key;
                  for (key in obj) {
                    if (obj.hasOwnProperty(key)) size++;
                  }
                 return size;
               }
              })
              

              用法

              在您的控制器中:

              $scope.filterResult = $filter('lengthOfObject')($scope.object)
              

              或者在你看来:

              <any ng-expression="object | lengthOfObject"></any>
              

              【讨论】:

              • OP 没有要求 AngularJS 版本。这不是问题的有效答案。
              【解决方案21】:

              您始终可以使用Object.getOwnPropertyNames(myObject).length 来获得与[].length 对普通数组给出的相同结果。

              【讨论】:

              【解决方案22】:

              如果您不关心是否支持 Internet Explorer 8 或更低版本,您可以通过应用以下两个步骤轻松获取对象中的属性数量:

              1. 运行Object.keys() 以获取仅包含enumerableObject.getOwnPropertyNames() 的属性名称的数组,如果您还想包含不可枚举的属性名称。
              2. 获取该数组的.length 属性。

              如果您需要多次执行此操作,可以将此逻辑包装在一个函数中:

              function size(obj, enumerablesOnly) {
                  return enumerablesOnly === false ?
                      Object.getOwnPropertyNames(obj).length :
                      Object.keys(obj).length;
              }
              

              如何使用这个特定的功能:

              var myObj = Object.create({}, {
                  getFoo: {},
                  setFoo: {}
              });
              myObj.Foo = 12;
              
              var myArr = [1,2,5,4,8,15];
              
              console.log(size(myObj));        // Output : 1
              console.log(size(myObj, true));  // Output : 1
              console.log(size(myObj, false)); // Output : 3
              console.log(size(myArr));        // Output : 6
              console.log(size(myArr, true));  // Output : 6
              console.log(size(myArr, false)); // Output : 7
              

              另请参阅this Fiddle 以获取演示。

              【讨论】:

                【解决方案23】:

                如果您需要一个显示其大小的关联数据结构,最好使用映射而不是对象。

                const myMap = new Map();
                
                myMap.set("firstname", "Gareth");
                myMap.set("lastname", "Simpson");
                myMap.set("age", 21);
                
                console.log(myMap.size); // 3

                【讨论】:

                  【解决方案24】:

                  用途:

                  var myArray = new Object();
                  myArray["firstname"] = "Gareth";
                  myArray["lastname"] = "Simpson";
                  myArray["age"] = 21;
                  obj = Object.keys(myArray).length;
                  console.log(obj)

                  【讨论】:

                    【解决方案25】:

                    该解决方案适用于多种情况和跨浏览器:

                    代码

                    var getTotal = function(collection) {
                    
                        var length = collection['length'];
                        var isArrayObject =  typeof length == 'number' && length >= 0 && length <= Math.pow(2,53) - 1; // Number.MAX_SAFE_INTEGER
                    
                        if(isArrayObject) {
                            return collection['length'];
                        }
                    
                        i= 0;
                        for(var key in collection) {
                            if (collection.hasOwnProperty(key)) {
                                i++;
                            }
                        }
                    
                        return i;
                    };
                    

                    数据示例:

                    // case 1
                    var a = new Object();
                    a["firstname"] = "Gareth";
                    a["lastname"] = "Simpson";
                    a["age"] = 21;
                    
                    //case 2
                    var b = [1,2,3];
                    
                    // case 3
                    var c = {};
                    c[0] = 1;
                    c.two = 2;
                    

                    用法

                    getLength(a); // 3
                    getLength(b); // 3
                    getLength(c); // 2
                    

                    【讨论】:

                      【解决方案26】:

                      您可以简单地在任何对象上使用Object.keys(obj).length 来获取其长度。 Object.keys 返回一个包含所有对象 keys (属性)的数组,可以方便地使用相应数组的长度来查找该对象的长度。你甚至可以为此编写一个函数。让我们获得创意并为它编写一个方法(以及更方便的 getter 属性):

                      function objLength(obj)
                      {
                        return Object.keys(obj).length;
                      }
                      
                      console.log(objLength({a:1, b:"summit", c:"nonsense"}));
                      
                      // Works perfectly fine
                      var obj = new Object();
                      obj['fish'] = 30;
                      obj['nullified content'] = null;
                      console.log(objLength(obj));
                      
                      // It also works your way, which is creating it using the Object constructor
                      Object.prototype.getLength = function() {
                         return Object.keys(this).length;
                      }
                      console.log(obj.getLength());
                      
                      // You can also write it as a method, which is more efficient as done so above
                      
                      Object.defineProperty(Object.prototype, "length", {get:function(){
                          return Object.keys(this).length;
                      }});
                      console.log(obj.length);
                      
                      // probably the most effictive approach is done so and demonstrated above which sets a getter property called "length" for objects which returns the equivalent value of getLength(this) or this.getLength()

                      【讨论】:

                      • 这和aeosynth's answer有什么不同?
                      • 这是因为它展示了如何使其成为一个函数和一个全局对象方法(更面向对象并使用某种形式的封装);但是aeosynth's answer 没有。
                      • 如果你要扩展内置原型或填充一个属性(即猴子补丁),请正确:为了向前兼容,先检查属性是否存在,然后再制作属性不可枚举,这样构造对象的自己的键就不会被污染。对于方法,请使用 actual methods。我的建议:关注these examples,它演示了如何添加一个尽可能接近内置方法的方法。
                      • 另外,如何写一个方法“更高效”?
                      【解决方案27】:

                      我们可以通过以下方式找到对象的长度:

                      const myObject = {};
                      console.log(Object.values(myObject).length);

                      【讨论】:

                      • 理论上,如果你有长值,他会比“keys”方法慢,因为它直接访问值然后计算它们。
                      【解决方案28】:

                      实现此目的的一个好方法(仅限 Internet Explorer 9+)是在长度属性上定义一个魔术 getter:

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

                      你可以像这样使用它:

                      var myObj = { 'key': 'value' };
                      myObj.length;
                      

                      它会给1

                      【讨论】:

                      • 除了反对原型修改的争论之外,我个人从未遇到过由它引起的错误,对我来说这是 JavaScript 的强项之一。
                      【解决方案29】:

                      只需使用它来获取length

                      Object.keys(myObject).length
                      

                      【讨论】:

                      • 请解释您的答案与stackoverflow.com/a/6700/8632727的不同之处
                      • 很好,最好根据变量的实际名称来命名变量。使您的代码对其他开发人员更具可读性。
                      • 在 "myArray" -> "myObject" 编辑之前,这与第二高投票的答案相同。
                      • 与过去的回复相同。
                      【解决方案30】:
                      var myObject = new Object();
                      myObject["firstname"] = "Gareth";
                      myObject["lastname"] = "Simpson";
                      myObject["age"] = 21;
                      
                      1. Object.values(myObject).length
                      2. Object.entries(myObject).length
                      3. Object.keys(myObject).length

                      【讨论】:

                      • 以上3个中哪个更快。
                      • Object.values(myObject).length
                      • 我们怎么能说它 Object.values(myObject).length 更快有没有例子谢谢,@tdjprog
                      • 在控制台试试这个:var myObject = {}; for (let i=0; i&lt;10000000; i++) myObject[i] = i;
                      • 为什么 Object.values(myObject).length 更快,而 Object.entries(myObject).length 即使经过一段时间也不给出输出,这是什么原因? 感谢@tdjprog
                      猜你喜欢
                      • 2017-03-29
                      • 1970-01-01
                      • 2018-07-16
                      • 1970-01-01
                      相关资源
                      最近更新 更多