[javascript] 배열 반복과 함께“for… in”을 사용하는 것이 나쁜 생각 인 이유는 무엇입니까?

for...inJavaScript에서 배열과 함께 사용하지 말라고 들었습니다 . 왜 안돼?



답변

그 이유는 하나의 구성입니다.

var a = []; // Create a new empty array.
a[5] = 5;   // Perfectly legal JavaScript that resizes the array.

for (var i = 0; i < a.length; i++) {
    // Iterate over numeric indexes from 0 to 5, as everyone expects.
    console.log(a[i]);
}

/* Will display:
   undefined
   undefined
   undefined
   undefined
   undefined
   5
*/

때로는 다른 것과 완전히 다를 수 있습니다.

var a = [];
a[5] = 5;
for (var x in a) {
    // Shows only the explicitly set index of "5", and ignores 0-4
    console.log(x);
}

/* Will display:
   5
*/

또한 JavaScript 라이브러리는 다음과 같은 작업을 수행하여 생성하는 모든 배열에 영향을 줄 수 있습니다.

// Somewhere deep in your JavaScript library...
Array.prototype.foo = 1;

// Now you have no idea what the below code will do.
var a = [1, 2, 3, 4, 5];
for (var x in a){
    // Now foo is a part of EVERY array and 
    // will show up here as a value of 'x'.
    console.log(x);
}

/* Will display:
   0
   1
   2
   3
   4
   foo
*/


답변

for-in문장 자체는 “나쁜 습관”이 아니지만 배열이나 배열 같은 객체 를 반복 하는잘못 사용할 수 있습니다 .

for-in문장 의 목적은 객체 속성 을 열거 하는 것입니다. 이 문장은 프로토 타입 체인에서 올라가고 때로는 원하지 않는 상속 된 속성을 열거 합니다.

또한 스펙에 의해 반복 순서가 보장되지는 않습니다. 즉,이 명령문을 사용하여 배열 오브젝트를 “반복”하려는 경우 특성 (배열 색인)이 숫자 순서대로 방문되는지 확신 할 수 없습니다.

예를 들어, JScript (IE <= 8)에서 Array 객체에서도 열거 순서는 속성이 생성 될 때 정의됩니다.

var array = [];
array[2] = 'c';
array[1] = 'b';
array[0] = 'a';

for (var p in array) {
  //... p will be "2", "1" and "0" on IE
}

또한 상속 된 속성에 대해 말하면 (예를 들어 Array.prototypeMooTools와 같은 일부 라이브러리와 같이) 개체를 확장하면 해당 속성도 열거됩니다.

Array.prototype.last = function () { return this[this.length-1]; };

for (var p in []) { // an empty array
  // last will be enumerated
}

이전에 배열이나 배열과 같은 객체 를 반복 하기 위해 말했듯 이 가장 좋은 방법은 일반 낡은 / 루프 와 같은 순차적 루프 를 사용하는 것입니다 .forwhile

상속되지 않은 객체 의 고유 한 속성 만 열거 하려면 다음 hasOwnProperty방법을 사용할 수 있습니다 .

for (var prop in obj) {
  if (obj.hasOwnProperty(prop)) {
    // prop is not inherited
  }
}

그리고 어떤 사람들은 객체에 Object.prototype이름이 지정된 속성을 추가하는 경우 문제가 발생하지 않도록 직접 메서드를 호출하는 것이 좋습니다 hasOwnProperty.

for (var prop in obj) {
  if (Object.prototype.hasOwnProperty.call(obj, prop)) {
    // prop is not inherited
  }
}


답변

for..in배열 요소를 반복 하는 데 사용 해서는 안되는 세 가지 이유가 있습니다 .

  • for..in배열 객체가 아닌 상속받은 모든 속성을 반복합니다 DontEnum. 즉, 누군가가 특정 배열 객체에 속성을 추가하거나 (이에 대한 정당한 이유가 있습니다.) 직접 변경했거나 Array.prototype다른 스크립트와 잘 작동하는 코드에서는 나쁜 습관으로 간주됩니다. 또한 반복된다; 상속 된 속성은을 확인하여 제외 할 수 hasOwnProperty()있지만 배열 객체 자체에 설정된 속성으로는 도움이되지 않습니다.

  • for..in 요소 순서를 유지한다고 보장되지 않습니다

  • 배열 객체의 모든 속성과 전체 프로토 타입 체인을 걸어야하므로 속성 이름 만 가져옵니다. 즉, 값을 얻으려면 추가 조회가 필요합니다.


답변

for … in은 배열 자체가 아닌 배열을 보유하는 객체를 통해 열거하기 때문입니다. 배열 프로토 타입 체인에 함수를 추가하면 포함됩니다. 즉

Array.prototype.myOwnFunction = function() { alert(this); }
a = new Array();
a[0] = 'foo';
a[1] = 'bar';
for(x in a){
 document.write(x + ' = ' + a[x]);
}

이것은 쓸 것이다 :

0 = 푸
1 = 바
myOwnFunction = function () {경고 (this); }

프로토 타입 체인에 아무것도 추가되지 않을 것이라고 확신 할 수 없으므로 for 루프를 사용하여 배열을 열거하면됩니다.

for(i=0,x=a.length;i<x;i++){
 document.write(i + ' = ' + a[i]);
}

이것은 쓸 것이다 :

0 = 푸
1 = 바


답변

격리 된 배열에서 for-in을 사용하는 데 아무런 문제가 없습니다. For-in은 개체의 속성 이름을 반복하며 “기본 제공”배열의 경우 속성은 배열 인덱스에 해당합니다. (등 propertes 내장 length, toString등등 반복에 포함되지 않으며.)

그러나 코드 (또는 사용중인 프레임 워크)가 사용자 지정 속성을 배열 또는 배열 프로토 타입에 추가하는 경우 이러한 속성이 반복에 포함되며 이는 아마도 원하는 것이 아닙니다.

프로토 타입과 같은 일부 JS 프레임 워크는 어레이 프로토 타입을 수정합니다. JQuery와 같은 다른 프레임 워크는 그렇지 않으므로 JQuery를 사용하면 안전하게 사용할 수 있습니다.

확실치 않다면 아마도 for-in을 사용해서는 안됩니다.

배열을 반복하는 다른 방법은 for-loop를 사용하는 것입니다.

for (var ix=0;ix<arr.length;ix++) alert(ix);

그러나 이것은 다른 문제가 있습니다. 문제는 JavaScript 배열에 “구멍”이있을 수 있다는 것입니다. 다음 arr과 같이 정의 하면 :

var arr = ["hello"];
arr[100] = "goodbye";

그런 다음 배열에는 두 개의 항목이 있지만 길이는 101입니다. for-in을 사용하면 두 개의 인덱스가 생성되고 for-loop는 101의 인덱스를 생성하며 99의 값은 undefined입니다.


답변

2016 년 (ES6) 기준으로 for…ofJohn Slegers가 이미 알았 으로 배열 반복에 .

이 간단한 데모 코드를 추가하여 더 명확하게 만들고 싶습니다.

Array.prototype.foo = 1;
var arr = [];
arr[5] = "xyz";

console.log("for...of:");
var count = 0;
for (var item of arr) {
    console.log(count + ":", item);
    count++;
    }

console.log("for...in:");
count = 0;
for (var item in arr) {
    console.log(count + ":", item);
    count++;
    }

콘솔은 다음을 보여줍니다 :

for...of:

0: undefined
1: undefined
2: undefined
3: undefined
4: undefined
5: xyz

for...in:

0: 5
1: foo

다시 말해:

  • for...of0에서 5까지 계산하고을 무시합니다 Array.prototype.foo. 배열 값을 보여줍니다 .

  • for...in5정의되지 않은 배열 인덱스는 무시하고을 추가 하여 , 만 나열합니다 foo. 배열 속성 이름을 보여줍니다 .


답변

짧은 대답 : 가치가 없습니다.


더 긴 대답 : 순차적 요소 순서와 최적의 성능이 필요하지 않더라도 가치가 없습니다.


긴 대답 : 가치가 없습니다 …

  • 를 사용 for (var property in array)하면 객체array 로 반복 되어 객체 프로토 타입 체인을 통과하여 궁극적으로 인덱스 기반 루프 보다 느리게 수행 됩니다.for
  • for (... in ...) 예상대로 객체 속성을 순차적으로 반환한다고 보장 할 수는 없습니다.
  • 객체 속성을 필터링하는 데 사용 hasOwnProperty()하고 !isNaN()확인하면 추가 오버 헤드가 발생하여 성능이 더 느려지고 처음에 객체를 사용하는 주요 이유, 즉보다 간결한 형식으로 인해 무시됩니다.

이러한 이유로 성능과 편의성 사이에 적절한 균형이 존재하지 않습니다. 배열을 객체 로 처리하고 배열 의 객체 속성에 대한 작업을 수행 하지 않는 한 실제로 이점은 없습니다 .