【问题标题】:How to iterate over Object's property-value pairs?如何迭代对象的属性值对?
【发布时间】:2022-07-14 02:27:32
【问题描述】:

我有这样的结构:

var myMap = {
    partnr1: ['modelA', 'modelB', 'modelC'],
    partnr2: ['modelA', 'modelB', 'modelC']
};

我将遍历每个元素(partnr)及其关联对象(模型)。

我正在尝试双 $each() 迭代以实现此目的,但没有任何反应:

$.each(myMap, function (i, val) {
    $.each(i, function (innerKey, innerValue) {

        setTimeout(function () {
            $('#variant').fadeOut("slow", function () {
                $(this).text(innerKey + "-" + innerValue).fadeIn("slow");

            });

        }, i * 6000);

    });
});

我试图实现的淡入淡出效果在使用单值数组 (Object) 时工作​​正常,但当我需要像这里这样的每个键有多个值时就不行了。

如何成功完成本次迭代?在这种情况下,除了使用Object 之外,还有其他更好的方法吗?

【问题讨论】:

    标签: javascript dictionary


    【解决方案1】:

    2019 年问题的答案:

    这取决于您使用的 ECMAScript 版本。

    ES6 之前:

    使用以下任何答案,例如:

    for (var m in myMap){
        for (var i=0;i<myMap[m].length;i++){
        ... do something with myMap[m][i] ...
        }
    } 
    

    对于 ES6(ES 2015):

    您应该使用Map 对象,它具有entries() 函数:

    var myMap = new Map();
    myMap.set("0", "foo");
    myMap.set(1, "bar");
    myMap.set({}, "baz");
    
    for (const [key, value] of myMap.entries()) {
      console.log(key, value);
    }
    

    对于 ES8(ES 2017):

    Object.entries() 介绍:

    const object = {'a': 1, 'b': 2, 'c' : 3};
    for (const [key, value] of Object.entries(object)) {
      console.log(key, value);
    }
    

    【讨论】:

    • 我想问一个愚蠢的问题,当最终用户可能使用旧版浏览器时,为什么还要使用 ES8?
    • @Erik:JS 开发也发生在 Web 开发以外的领域。在那里,您可能不必担心旧的浏览器版本,并且可以享受 ES8 带来的改进。
    • @Erik 转译器(如 babel)帮助将较新版本的 js 转换为较旧版本的 js。所以即使用户使用的是旧版浏览器,我们转译后的 ES8 代码仍然可以在旧版浏览器上运行。
    • 经过最新的编辑(2021年12月10日),第三种方法是ES6 sn-p的副本。以前使用 Object.entries 的版本是正确的,因为它展示了如何迭代用作地图的 vanilla javascript 对象,而不是 ES6 Map 类型。
    • 感谢@TristanMacKinlay。我恢复了这个编辑
    【解决方案2】:

    我会使用标准的 javascript:

    for (var m in myMap){
        for (var i=0;i<myMap[m].length;i++){
        ... do something with myMap[m][i] ...
        }
    } 
    

    注意处理对象和数组的不同方式。

    【讨论】:

    • 为什么?你省略了必要的闭包……
    • 它更快,在我看来更干净。我跳过了其余部分,因为我不清楚它应该做什么。 #variant 是什么? #variant 最终应该做什么?
    • #variant 是一个 div 的 id,它将与地图中的信息一起显示(淡入)。对于每个合作伙伴,都应该在一个包含相应模型的列表中淡出。
    【解决方案3】:

    ES6+ 的函数式方法

    如果您想采用更实用的方法来迭代 Map 对象,您可以这样做

    const myMap = new Map() 
    myMap.forEach((value, key) => {
        console.log(value, key)
    })
    

    【讨论】:

      【解决方案4】:

      $.each() 的回调按顺序传递属性名称和值。因此,您试图在对$.each() 的内部调用中迭代属性名称。我想你想要:

      $.each(myMap, function (i, val) {
        $.each(val, function(innerKey, innerValue) {
          // ...
        });
      });
      

      在内部循环中,给定一个像地图这样的对象,值是数组。没关系,但请注意“innerKey”值都是数字。

      edit — 现在一旦理顺了,下一个问题就来了:

          setTimeout(function () {
      
            // ...
      
          }, i * 6000);
      

      第一次通过该循环时,“i”将是字符串“partnr1”。因此,该乘法尝试将导致NaN。您可以保留一个外部计数器来跟踪外部地图的属性计数:

      var pcount = 1;
      $.each(myMap, function(i, val) {
        $.each(val, function(innerKey, innerValue) {
          setTimeout(function() {
            // ...
          }, pcount++ * 6000);
        });
      });
      

      【讨论】:

      • 感谢您的回复。通过将 $.each(i... 更改为 $.each(val..最终迭代。
      • @user2374903 不,它没有跳到最后一个,尽管它似乎正在这样做。我没有仔细查看“setTimeout”调用,所以我将添加到我的答案中。
      • 通过将 pcount 从 1 更改为 0(这意味着它从第一个循环开始),代码可以工作,但只是一个一个地显示模型。我没有说清楚的错误,目标是让与该partnumer相对应的所有模型显示为淡入的列表。
      【解决方案5】:

      嗯,看起来这个旧的 JQuery 线程已被 ES6 Map 用户使用。

      如果这是您要查找的内容,我建议您使用Array.from() 函数将Map 转换为Array。这使您可以轻松链接转换,例如filter()map() 等。

      const map = new Map([
        ['key one', 'value one'],
        ['key two', 'value two'],
      ]);
      
      // Loop through key-value-pairs
      Array.from(map.entries()).map(([key, val]) => console.log(key, val));
      
      // Loop through map keys
      Array.from(map.keys()).map(key => console.log(key));
      
      // Loop through values
      Array.from(map.values()).map(value => console.log(value));
      

      【讨论】:

        【解决方案6】:

        不要使用迭代器来执行此操作。通过在回调中增加一个计数器来维护您自己的循环,并递归地调用下一项的操作。

        $.each(myMap, function(_, arr) {
            processArray(arr, 0);
        });
        
        function processArray(arr, i) {
            if (i >= arr.length) return;
        
            setTimeout(function () {
                $('#variant').fadeOut("slow", function () {
                    $(this).text(i + "-" + arr[i]).fadeIn("slow");
        
                    // Handle next iteration
                    processArray(arr, ++i);
                });
            }, 6000);
        }
        

        虽然您的代码中存在逻辑错误。您在(大致)同时将同一个容器设置为多个不同的值。也许您的意思是让每个人更新自己的容器。

        【讨论】:

        • 感谢您的建议。我试过你的代码,但你说得对,那就是容器有问题。下面的代码虽然有效,但这里只有一个值数组:
        • 这看起来是个不错的方法。
        • $.each(jArray, function(i, val) { setTimeout(function() { $('#reklame2').fadeOut("slow", function() { $(this). text(val).fadeIn("slow"); }); $('#reklame17').fadeOut("slow", function() { $(this).text(val).fadeIn("slow"); }); }, i * 6000); });
        • @user2374903:目的是什么?每个partnr 应该更新一个单独的容器,还是它们都意味着按顺序运行?或者应该是partnr1[0] -&gt; partnr2[0] -&gt; partnr1[1] -&gt; partnr2[1] -&gt; etc
        • 抱歉没有明确迭代对象。每次partnr出现时,所有对应的模型都会在那个时刻以列表的形式淡入。
        【解决方案7】:

        我们可以在 ES6 版本的地图上使用 forEach 方法。

        var myMap =new Map([
            ["partnr1", ['modelA', 'modelB', 'modelC']],
            ["partnr2", ['modelA', 'modelB', 'modelC']]
        ]);
        
        myMap.forEach(function(values,key){
          
          console.log(key);
          
          /*****Do something with the models***********/
          
          for(const [index,value] of values.entries()){
              console.log(`   ${key}[${index}] : ${value}`);
          }
          });

        【讨论】:

          【解决方案8】:

          这很容易使用 javascript Map 对象实现。您只需迭代Map,使用您正在迭代的地图作为参数包含在每个迭代调用中的事实。注意forEach 函数中的map 参数。这与您正在迭代的 Map 对象相同。

          
          // Define the map
          const myMap = new Map([
              ["key1", "value 1"],
              ["key2": "value 2"],
              ["key3": "value 3"]
          ])
          
          // Iterate over the map, updating each value
          myMap.forEach((value,key,map) => {
             map.set(key, value + "A")
          })
          
          /*
          Result: myMap now looks like this:
          [ 
              ["key1", "value 1A"],
              ["key2": "value 2A"],
              ["key3": "value 3A"]
          ]
          /*
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2023-03-24
            • 2011-07-22
            • 2015-11-07
            • 2016-02-26
            • 1970-01-01
            • 1970-01-01
            • 2020-05-18
            相关资源
            最近更新 更多