Javascript:for..in 循环运行的次数超出预期

Posted

技术标签:

【中文标题】Javascript:for..in 循环运行的次数超出预期【英文标题】:Javascript: for..in loop running more number of times than expected 【发布时间】:2017-03-31 14:31:12 【问题描述】:

在下面的代码中,user.roles 的实际长度为 1。但是,循环运行了两次。

当我输出 i 的值时,它在第二次迭代中显示为 'diff'。 切换到普通的 for 循环解决了这种情况。 但是,我想知道 for..in 循环有什么问题。

 for (var i in user.roles) 
                if (user.roles[i].school.equals(schoolId)) 
                    for (var j in user.roles[i].permissions) 
                        for (var k in accessType) 
                            if (user.roles[i].permissions[j].feature == featureKey) 
                                if (user.roles[i].permissions[j][accessType[k]]) 
                                    return true;
                                
                            
                        
                    
                
            

更新:用户是一个对象,角色是一个对象数组。导致问题的角色实例如下所示:


  "_id": "582d3390d572d05c1f028f53",
  "displayName": "Test Teacher Attendance",
  "gender": "Male",
  "roles": [
    
      "_id": "57a1b3ccc71009c62a48a684",
      "school": "57a1b3ccc71009c62a48a682",
      "role": "Teacher",
      "__v": 0,
      "designation": true,
      "permissions": [
        
          "feature": "User",
          "_id": "57ac0b9171b8f0b82befdb7d",
          "review": false,
          "view": true,
          "delete": false,
          "edit": false,
          "create": false
        ,
        
          "feature": "Notice",
          "_id": "57ac0b9171b8f0b82befdb7c",
          "review": false,
          "view": true,
          "delete": false,
          "edit": false,
          "create": false
        ,

      ]
    
  ],

【问题讨论】:

你能定义用户、角色、权限、访问类型吗?这些是对象、字符串、整数。 user.roles 是一个数组/迭代器吗?也许你应该使用for .. of 你为什么使用for in?尝试使用 forEach 。它更方便。 ***.com/questions/23614054/… @Teocci user.roles 是对象数组,权限是 user.roles 中的对象数组。 accessType 是一个字符串数组。 @AllenGJ 你能把我的问题标记为答案吗? 【参考方案1】:

user.roles 似乎是一个数组。而对于数组,你不应该使用 for in。

简单示例

var arr = [2];
arr.s = 3;

for (var i  in arr) 
console.log("here"); // paints twice

来自MDN,for...in 语句以任意顺序迭代对象的可枚举属性。对于每个不同的属性,可以执行语句。

如何选择迭代器的类型,这里参考iterators

编辑

根据更新后的问题,如果以下代码中的某处存在,则上述内容只能带有 diff 属性

Array.prototype.diff = .....

【讨论】:

谢谢。但是,在这种情况下, user.roles 似乎只有一个可编号的属性,对吧?即,它只有一个对象。当我控制 i 的值时,对于第二次(意外)迭代,它保存值 'diff'。 如果是这种情况,那么您的代码中一定有Array.prototype.diff @AllenGJ - 你检查了吗?此外,您可以通过delete Array.prototype.diff; 将其删除【参考方案2】:

我想这就是你要找的。 我假设您的 accessTypes 是一个包含以下项目的数组:

var accessTypes = ["review", "view", "delete", "edit", "create"];

编辑以提高效率。

var schoolId = "57a1b3ccc71009c62a48a682";
var featureKey = "Notice";
var accessTypes = ["review", "view", "delete", "edit", "create"];

var user = 
  "_id": "582d3390d572d05c1f028f53",
  "displayName": "Test Teacher Attendance",
  "gender": "Male",
  "roles": [
    "_id": "57a1b3ccc71009c62a48a684",
    "school": "57a1b3ccc71009c62a48a682",
    "role": "Teacher",
    "__v": 0,
    "designation": true,
    "permissions": [
      "feature": "User",
      "_id": "57ac0b9171b8f0b82befdb7d",
      "review": false,
      "view": true,
      "delete": false,
      "edit": false,
      "create": false
    , 
      "feature": "Notice",
      "_id": "57ac0b9171b8f0b82befdb7c",
      "review": false,
      "view": true,
      "delete": false,
      "edit": false,
      "create": false
    ]
  ]
;

user.roles.forEach(function(roleItem) 
  // console.log('This is a role: ' + roleItem.school);
  if (roleItem.school == schoolId) 
    roleItem.permissions.forEach(function(permissionItem) 
      // console.log('This is a permission: ' + permissionItem.feature);
      // console.log('This is a accessType: ' + accessType);
      if (permissionItem.feature == featureKey) 
        accessTypes.forEach(function(accessType) 
          if (permissionItem[accessType]) 
            console.log('accessType: ' + accessType + ' -> true');
            return true;
          
        );
      
    );
  
);

forEach 接受迭代器函数。为数组中的每个条目调用迭代器函数,按顺序跳过稀疏数组中不存在的条目。

forEach 还有一个好处是,您不必在包含范围内声明索引和值变量,因为它们作为参数提供给迭代函数,因此很好地限定了该迭代。

如果您担心为每个数组条目进行函数调用的运行时成本,请不要担心;更多technical details.

如果您仍然认为forEach 的速度基本上较慢,您可以使用一个简单的for 循环,正如我在另一个my answers 中解释的那样。

希望对您有所帮助。

【讨论】:

性能怎么样?我的印象是 forEach 从根本上来说更慢。 @AllenGJ 如果您仍然觉得forEach 速度较慢,您可以使用一个简单的for 循环,正如我在另一个Answer 中解释的那样。

以上是关于Javascript:for..in 循环运行的次数超出预期的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript for...in 循环

JavaScript 循环:for...in 与 for

JavaScript for...in 循环

JavaScript-//FOR/IN循环。当使用for/in循环遍历关联数组时,就可以清晰地体会到for/in的强大之处。

为啥不建议数组使用 JavaScript 的 For...In 循环? [复制]

JavaScript中的for in 循环