2016-11-17 16 views
6

次のコードでは、user.rolesの実際の長さは1です。ただし、ループは2回実行されます。Javascript:for..inループが予想よりも多く実行される

私がiの値を出力すると、2回目の反復では「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; 
           } 
          } 
         } 
        } 
       } 
      } 

更新:ユーザーはオブジェクトであり、rolesはオブジェクトの配列です。問題の原因となったロールのインスタンスは以下の通りである:

{ 
    "_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 
     }, 

     ] 
    } 
    ], 
} 
+0

ユーザー、ロール、アクセス許可、アクセスタイプを定義できますか?それらはオブジェクト、文字列、整数です。 – Teocci

+0

'user.roles'は配列/イテレータですか?たぶんあなたは 'for .. of'を使うべきです – zeronone

+0

' for 'をなぜ使うのですか? 'forEach'を使ってみてください。より便利です。 http://stackoverflow.com/questions/23614054/javascript-nuances-of-myarray-foreach-vs-for-loop –

答えて

2

user.rolesは配列のようです。そして

。あなたがのために使うべきではない配列のための簡単な例 MDNから

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

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

、オブジェクトの列挙可能なプロパティを超えるザ・用...文は繰り返し処理では、任意の順序で。異なるプロパティごとに、ステートメントを実行できます。場合は、イテレータの種類を選択する方法

は、ここで更新質問を1として参照iterators

EDIT

で、上記のコードだけでどこかdiffとしてプロパティを使用して来ることができます次は現在

Array.prototype.diff = ..... 
+0

ありがとうございます。しかし、この場合、user.rolesは1つの列挙可能なプロパティしか持たないようです。 つまり、オブジェクトには1つのオブジェクトしかありません。 ** i **の値をコンソールすると、2番目(予期しない)反復のために、値は** diff **となります。 –

+0

その場合、あなたのコードのどこかに 'Array.prototype.diff'がなければなりません。 – nikhil

+0

@AllenGJ - あなたは点検しましたか?さらに、 'delete Array.prototype.diff; 'で削除することができます。 – nikhil

2

私はこれがあなたが探していると思います。効率を改善するために、編集

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

: 私はあなたのaccessTypesは、次の項目を含む配列であることを前提としています。

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もまた、反復関数の引数として指定されているので、その範囲内のインデックス変数と値変数を宣言する必要がないという利点があります。

各配列エントリの関数呼び出しを実行する際のランタイムコストが心配されている場合は、そうでないようにしてください。 more technical details

forEachが基本的に遅いという印象がある場合は、別のmy answersで説明するように、単純なforループを使用することができます。

これがあなたに役立つことを願っています。

+0

パフォーマンスはどうですか?私はそれぞれのために根本的に遅いという印象を受けました。 –

+0

@AllenGJ 'forEach'が基本的に遅いという印象をまだ残しておけば、別の[回答](http://stackoverflow.com/questions/40647538/#40647652)で説明しているように単純なforループを使うことができます。 – Teocci

関連する問題