在nodeJs中迭代具有嵌套对象的对象

3

我有一个JavaScript对象,其中包含多个嵌套的对象,如下所示:

 var stats = {
     bookServed: {
         redis: 90,
         s3: 90,
         signedUrl: 70
     },
     errors: {
         redis: {
             bookService: 70,
             mapi: 50,
             capi: 30
         },
         AWS: {
             signedUrl: 70,
             downloadBook: 50,
             searchBook: 10
         },
         decryption: 60
     }
 };

什么是最干净的方法来迭代所有属性并将每个值设置为0。例如,我写了这样的东西:
 for (var property in stats) {
     if (stats.hasOwnProperty(property)) {
         if (typeof property === "object") {
             for (var sub_property in property)
                 if (property.hasOwnProperty(sub_property)) {
                     sub_property = 0
                 }
         } else {
             property = 0;
         }
     }
 }

我愿意使用像underscore.js这样的库来正确完成任务。


你使用的任何库都将使用类似的递归循环方法。我假设你已经有了可行的解决方案,只是在寻找更加“简洁”的东西(不管这意味着什么)。 - Kevin B
我的解决方案仅适用于2级嵌套对象,在我的示例中有3级,因此我希望有一些递归的东西可以到达最深层,无论我的对象有多少级。 - Amaynut
因此,编写一个函数来执行此步骤,如果找到的是对象而不是数字,则在子对象上再次调用该函数。 - Kevin B
好的,我明白了,但如何将其变成递归的? - Amaynut
2
如果找到的是一个对象而不是一个数字,则在子对象上再次调用该函数,这将使其成为递归。 - Kevin B
3个回答

7

这是一个相对简单的递归问题,我会使用一个函数在找到子对象时调用自身。我也会避免使用for in循环,而是在对象的键上使用forEach(它更快,并且不需要hasOwnProperty检查)。

function resetValuesToZero (obj) {
    Object.keys(obj).forEach(function (key) {
        if (typeof obj[key] === 'object') {
            return resetValuesToZero(obj[key]);
        }
        obj[key] = 0;
    });
}

var stats = {
     bookServed: {
         redis: 90,
         s3: 90,
         signedUrl: 70
     },
     errors: {
         redis: {
             bookService: 70,
             mapi: 50,
             capi: 30
         },
         AWS: {
             signedUrl: 70,
             downloadBook: 50,
             searchBook: 10
         },
         decryption: 60
     }
 };

console.log(stats.errors.AWS.signedUrl); // 70
resetValuesToZero(stats);
console.log(stats.errors.AWS.signedUrl); // 0


请注意,如果对象嵌套得非常深,这可能会引发堆栈溢出异常,但我认为这只是一个极端情况。要克服这个问题,您需要将此函数变成异步的,但除非您真正遇到了这个问题,否则我不会费心去做,因为它肯定会使事情变得更加复杂。 - Kevin B
发布了一个使用迭代方法而不是递归的答案。同时请注意,此答案将遍历数组(从问题中无法确定是否有意这样做)。 - vincent

1
下面的解决方案使用 object-scan,它使用迭代实现来遍历输入。还要注意,这将遍历进入任何类似于被接受的答案的数组结构中。

// const objectScan = require('object-scan');

const rewriter = objectScan(['**'], {
  rtn: 'count',
  filterFn: ({ value, parent, property }) => {
    if (typeof value === 'number') {
      parent[property] = 0;
      return true;
    }
    return false;
  }
});

const stats = { bookServed: { redis: 90, s3: 90, signedUrl: 70 }, errors: { redis: { bookService: 70, mapi: 50, capi: 30 }, AWS: { signedUrl: 70, downloadBook: 50, searchBook: 10 }, decryption: 60 } };

console.log(rewriter(stats)); // returns count of replaces
// => 10

console.log(stats);
/* =>
{ bookServed: { redis: 0, s3: 0, signedUrl: 0 },
  errors:
  { redis: { bookService: 0, mapi: 0, capi: 0 },
    AWS: { signedUrl: 0, downloadBook: 0, searchBook: 0 },
    decryption: 0 } }
*/
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/object-scan@13.8.0"></script>

免责声明:我是object-scan的作者。


0
function checkNPE(obj) {
  for(const name in obj){console.log('name: ' + JSON.stringify(name, null, 4));
    if (typeof obj[name] === 'object') {console.log('object name: ' + JSON.stringify(name, null, 4));
      checkNPE(obj[name]);
    } // if (typeof obj[name] === 'object') {
  } // for(const name in obj){
}; // function checkNPE (obj) {

var stats = {
     bookServed: {
         redis: 90,
         s3: 90,
         signedUrl: 70
     },
     errors: {
         redis: {
             bookService: 70,
             mapi: 50,
             capi: 30
         },
         AWS: {
             signedUrl: 70,
             downloadBook: 'a',
             searchBook: 10
         },
         decryption: 60
     }
 };
checkNPE(stats);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接