【问题标题】:How to iterate array keys in Javascript?如何在Javascript中迭代数组键?
【发布时间】:2011-01-31 08:28:31
【问题描述】:

我有一个使用此代码创建的数组:

var widthRange = new Array();
widthRange[46] = { min:0,  max:52 };
widthRange[66] = { min:52, max:70 };
widthRange[90] = { min:70, max:94 };

我想在循环中获取每个值 46、66、90。我试过for (var key in widthRange),但这给了我一大堆额外的属性(我假设它们是对象上的函数)。我不能使用常规的 for 循环,因为这些值不是连续的。

【问题讨论】:

  • 看起来你有数据,虽然它恰好有数字键,但实际上并不是数组数据。我会考虑在这里使用常规对象。
  • @Quentin 叫做稀疏数组。性能方面,最好在这里使用数组而不是对象。此外,在性能方面,甚至没有列出最佳答案:Array.prototype.forEach。在数组上调用Object.keys 性能不佳,因为浏览器不会针对它进行优化。 for(var key in array) 不好,因为它遍历原型并将遇到的每个数字键字符串化(将双精度数转换为 base10 非常慢)。然而,forEach 正是为迭代稀疏数组而设计的,与其他解决方案相比,它将为您的代码提供出色的性能

标签: javascript arrays key


【解决方案1】:

您需要调用hasOwnProperty 函数来检查该属性是否实际定义在对象本身(而不是其原型)上,如下所示:

for (var key in widthRange) {
    if (key === 'length' || !widthRange.hasOwnProperty(key)) continue;
    var value = widthRange[key];
}

请注意,您需要单独检查 length
但是,您根本不应该在这里使用数组。您应该使用常规对象。所有 Javascript 对象都作为关联数组起作用。

例如:

var widthRange = { };  //Or new Object()
widthRange[46] = { sel:46, min:0,  max:52 };
widthRange[66] = { sel:66, min:52, max:70 };
widthRange[90] = { sel:90, min:70, max:94 };

【讨论】:

  • 真的吗?哇,我每天都在这里学到一些东西,而且经常来自你的 SLaks :-) 我很惊讶 Array 会像这样跟踪它的明确设置的索引。也许我不应该。
  • @SLaks:谢谢,将其更改为对象似乎是最好的解决方案。还有一个问题:有没有办法逆序迭代?
  • 否;你需要自己做。
  • 为什么需要单独检查length?不是在所有浏览器中都标记为[[DontEnum]]吗?
  • @Roatin:我不知道。安全总比后悔好。
【解决方案2】:

可以使用Object.keys(array)查询字符串化的键。

【讨论】:

  • 这会将键返回为字符串,而不是数字,以便每个人都知道。
  • 最佳解决方案... TY
  • 让我开心! :D array.keys() 什么也没返回的问题。
  • 这就是解决方案
【解决方案3】:

如果您正在执行任何类型的数组/集合操作或检查,我强烈建议您使用Underscore.js。它很小,经过充分测试,可以为您节省数天/数周/数年的 javascript 头痛。这是它的按键功能:

按键

检索对象属性的所有名称。

_.keys({one : 1, two : 2, three : 3});
=> ["one", "two", "three"]

【讨论】:

    【解决方案4】:

    假设你的数组看起来像 arr = [ { a: 1, b: 2, c: 3 }, { a: 4, b: 5, c: 6 }, { a: 7, b: 8, c: 9 } ](或其他可能的键)你可以做

    arr.map((o) => {
        return Object.keys(o)
    }).reduce((prev, curr) => {
        return prev.concat(curr)
    }).filter((col, i, array) => {
        return array.indexOf(col) === i
    });
    

    ["a", "b", "c"]

    【讨论】:

      【解决方案5】:
      for (var i = 0; i < widthRange.length; ++i) {
        if (widthRange[i] != null) {
          // do something
        }
      }
      

      你不能真的只得到你设置的键,因为数组不是这样工作的。设置元素 46 后,您也设置了 0 到 45(尽管它们为空)。

      你总是可以有两个数组:

      var widthRange = [], widths = [], newVal = function(n) {
        widths.push(n);
        return n;
      };
      widthRange[newVal(26)] = { whatever: "hello there" };
      
      for (var i = 0; i < widths.length; ++i) {
        doSomething(widthRange[widths[i]]);
      }
      

      编辑好吧,可能我都湿透了……

      【讨论】:

      • 数组只记录长度,它们不会遍历并创建多少对象。基本上,当找到一个新索引时,它会检查该新索引是否大于长度......如果是该新索引成为新长度。因此,可以仅获取您使用 for-in 循环定义的索引
      【解决方案6】:
      widthRange.map(function(_, i) { return i });
      

      widthRange.map((_, i) => i);
      

      【讨论】:

        【解决方案7】:

        你原来的例子对我来说很好用:

        <html>
        <head>
        </head>
        <body>
        <script>
        var widthRange = new Array();
        widthRange[46] = { sel:46, min:0,  max:52 };
        widthRange[66] = { sel:66, min:52, max:70 };
        widthRange[90] = { sel:90, min:70, max:94 };
        
        var i = 1;
        for (var key in widthRange)
        {
            document.write("Key #" + i + " = " + key + "; &nbsp;&nbsp;&nbsp; min/max = " + widthRange[key].min + "/" + widthRange[key].max + "<br />");
            i++;
        }
        </script>
        </html>
        

        浏览器中的结果(Windows XP 上的 Firefox 3.6.2):

        Key #1 = 46;     min/max = 0/52
        Key #2 = 66;     min/max = 52/70
        Key #3 = 90;     min/max = 70/94
        

        【讨论】:

        • 我打赌他正在导入原型或类似的东西。一般来说,那些“in”循环是有风险的。
        • 嗯,我使用的是 jQuery,还有使用 mootools 的 Joomla,正在添加这些属性。
        【解决方案8】:

        我认为您应该为此使用对象 ({}) 而不是数组 ([])。

        一组数据与每个键相关联。它为使用一个对象而尖叫。做:

        var obj = {};
        obj[46] = { sel:46, min:0,  max:52 };
        obj[666] = { whatever:true };
        
        // This is what for..in is for
        for (var prop in obj) {
          console.log(obj[prop]);
        }
        

        也许像这样的一些实用工具可以提供帮助:

        window.WidthRange = (function () {
          var obj = {};
          return {
            getObj: function () {return obj;}
            , add: function (key, data) {
                obj[key] = data;
                return this; // enabling chaining
              }
          }
        })();
        
        // Usage (using chaining calls):
        WidthRange.add(66, {foo: true})
        .add(67, {bar: false})
        .add(69, {baz: 'maybe', bork:'absolutely'});
        
        var obj = WidthRange.getObj();
        for (var prop in obj) {
          console.log(obj[prop]);
        }
        

        【讨论】:

          【解决方案9】:

          似乎有效。

          var widthRange = new Array();
          widthRange[46] = { sel:46, min:0,  max:52 };
          widthRange[66] = { sel:66, min:52, max:70 };
          widthRange[90] = { sel:90, min:70, max:94 };
          
          for (var key in widthRange)
          {
              document.write(widthRange[key].sel + "<br />");
              document.write(widthRange[key].min + "<br />");
              document.write(widthRange[key].max + "<br />");
          }
          

          【讨论】:

            【解决方案10】:

            我写了一个函数,它适用于每个对象实例(数组就是那些)。

            Object.prototype.toArray = function()
            {
                if(!this)
                {
                  return null;
                }
            
                var c = [];
            
                for (var key in this) 
                {
                    if ( ( this instanceof Array && this.constructor === Array && key === 'length' ) || !this.hasOwnProperty(key) ) 
                    {
                        continue;
                    }
            
                    c.push(this[key]);
                }
            
                return c;
            };
            

            用法:

            var a   = [ 1, 2, 3 ];
            a[11]   = 4;
            a["js"] = 5;
            
            console.log(a.toArray());
            
            var b = { one: 1, two: 2, three: 3, f: function() { return 4; }, five: 5 };
            b[7] = 7;
            
            console.log(b.toArray());
            

            输出:

            > [ 1, 2, 3, 4, 5 ]
            > [ 7, 1, 2, 3, function () { return 4; }, 5 ]
            

            它可能对任何人都有用。

            【讨论】:

            • 扩展一个不是你创建的原型是一个非常糟糕的主意,不管你认为它多么方便。
            【解决方案11】:

            ... ????

            或者,如果您有想要使用的项目列表...

            var range = [46, 66, 90]
                , widthRange=[]
                , write=[];
            
                widthRange[46] = { min:0, max:52 }; 
                widthRange[66] = { min:52, max:70 }; 
                widthRange[90] = { min:70, max:94 }; 
            
            for(var x=0; x<range.length; x++){var key, wr;
            
                key = range[x];
            
                wr = widthRange[key] || false;
            
                if(wr===false){continue;}
            
                write.push(['key: #',key, ', min: ', wr.min, 'max:', wr.max].join(''));
            
                }
            

            【讨论】:

              【解决方案12】:

              对于您的输入数据:

              let widthRange = new Array()
              widthRange[46] = { min:0,  max:52 }
              widthRange[61] = { min:52, max:70 }
              widthRange[62] = { min:52, max:70 }
              widthRange[63] = { min:52, max:70 }
              widthRange[66] = { min:52, max:70 }
              widthRange[90] = { min:70, max:94 }
              

              声明式方法:

              const relevantKeys = [46,66,90]
              const relevantValues = Object.keys(widthRange)
                  .filter(index => relevantKeys.includes(parseInt(index)))
                  .map(relevantIndex => widthRange[relevantIndex])
              

              Object.keys 获取密钥,使用parseInt 将它们转换为数字。 filter 只得到你想要的。 map 仅从您所追求的索引的原始对象构建一个数组,因为Object.keys 丢失了对象值。

              调试:

              console.log(widthRange)
              console.log(relevantKeys)
              console.log(relevantValues)
              

              【讨论】:

                【解决方案13】:

                这个问题已经很老了,但现在你可以使用 forEach,它很有效并且会将键保留为数字:

                let keys = widthRange.map((v,k) => k).filter(i=>i!==undefined))
                

                这会循环通过 widthRange 并使用键的值创建一个新数组,然后通过仅获取已定义的值来过滤掉所有的空槽。

                (坏主意,但为了彻底:如果插槽 0 始终为空,则可以缩短为 filter(i=&gt;i)filter(Boolean)

                而且,它可能效率较低,但可以使用let keys = Object.keys(array).map(i=&gt;i*1) 转换数字

                【讨论】:

                  【解决方案14】:

                  要从数组的键生成数组,请使用

                  Array.from(Array(10).keys());
                  

                  上面的示例将给出一个 0 到 9 的数组。这不是您所要求的,但我希望这能让您深入了解这种方法。

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 2019-11-04
                    • 2021-12-20
                    • 1970-01-01
                    • 1970-01-01
                    • 2021-03-07
                    相关资源
                    最近更新 更多