JSLint 오류 'for in의 본문은 if 문으로 묶어야합니다'는 무엇을 의미합니까?


242

내 JavaScript 파일에서 JSLint 를 사용했습니다 . 오류가 발생했습니다.

for( ind in evtListeners ) {

41 행의 문제 문자 9 : for의 본문은 if 문에 싸서 프로토 타입에서 원하지 않는 속성을 필터링해야합니다.

이것은 무엇을 의미 하는가?


5
기본적으로 'in'은 상속 된 속성을 반복합니다. 일반적으로 본문은 if (evtListeners.hasOwnProperty(ind))처리되어 소유 (비상 속) 속성 만 처리하도록 제한됩니다. 여전히 어떤 경우에는 상속 된 속성을 포함하여 모든 속성을 반복하려고합니다. 이 경우 JSLint는 if 문에 루프 본문을 감싸서 실제로 원하는 속성을 결정하도록합니다. 이것은 작동하고 JSlint를 행복하게 할 것입니다 : if (evtListeners[ind] !== undefined)
xorcus

1
대부분의 답변은 구식입니다. 업데이트 된 솔루션은 stackoverflow.com/a/10167931/3138375
eli-bd

답변:


430

우선 , 루프를 사용 하여 배열을 열거 하지 마십시오for in . 못. 좋은 오래된 것을 사용하십시오 for(var i = 0; i<arr.length; i++).

그 이유는 다음과 같습니다. JavaScript의 각 객체에는이라는 특수 필드가 prototype있습니다. 해당 필드에 추가 한 모든 항목은 해당 유형의 모든 개체에서 액세스 할 수 있습니다. 모든 배열에 filter_00을 걸러내는 멋진 새 함수를 갖기를 원한다고 가정하십시오 .

Array.prototype.filter_0 = function() {
    var res = [];
    for (var i = 0; i < this.length; i++) {
        if (this[i] != 0) {
            res.push(this[i]);
        }
    }
    return res;
};

console.log([0, 5, 0, 3, 0, 1, 0].filter_0());
//prints [5,3,1]

이것은 객체를 확장하고 새로운 메소드를 추가하는 표준 방법입니다. 많은 라이브러리가이를 수행합니다. 그러나 for in지금 어떻게 작동 하는지 봅시다 :

var listeners = ["a", "b", "c"];
for (o in listeners) {
    console.log(o);
}
//prints:
//  0
//  1
//  2
//  filter_0

당신이 보여요? filter_0이 또 다른 배열 인덱스라고 생각합니다. 물론 실제로는 숫자 인덱스가 아니라 숫자 인덱스뿐만 아니라 for in개체 필드를 통해 열거됩니다. 이제 모든 숫자 인덱스 와를 통해 열거 하고filter_0 있습니다. 그러나 filter_0특정 배열 객체의 필드는 아니며 모든 배열 객체에는이 속성이 있습니다.

운 좋게도 모든 객체에는 hasOwnProperty이 필드가 실제로 객체 자체에 속하는지 또는 단순히 프로토 타입 체인에서 상속되어 해당 유형의 모든 객체에 속하는지 확인 하는 메소드가 있습니다.

for (o in listeners) {
    if (listeners.hasOwnProperty(o)) {
       console.log(o);
    }
}
 //prints:
 //  0
 //  1
 //  2

참고,이 코드는 작동하지만 배열에 대한 예상대로, 당신이해야 결코, 결코 , 사용 for infor each in배열. for in배열 인덱스 나 값이 아니라 객체의 필드 를 열거합니다.

var listeners = ["a", "b", "c"];
listeners.happy = "Happy debugging";

for (o in listeners) {
    if (listeners.hasOwnProperty(o)) {
       console.log(o);
    }
}

 //prints:
 //  0
 //  1
 //  2
 //  happy

43
for in언어는 for in배열을 열거 하는 순서를 지키지 않기 때문에 배열을 반복 하는 데 사용 해서는 안됩니다 . 숫자 순서가 아닐 수 있습니다. 또한`for (i = 0; i <array.length; i ++) 스타일 구문을 사용하면 숫자 인덱스 순서대로 반복하고 영숫자 속성 은 없는지 확인할 수 있습니다 .
Breton

감사! 이것을 참조로 저장하겠습니다.
nyuszika7 시간

이 JSLint 비트가 깨 졌다고 확신했기 때문에이 답변을 다시보고있는 것을 알았습니다. 나는 대략 다음과 같은 코드를 가지고 있었다 : for (listeners.hasOwnProperty (i)) }} 문제는 ​​버그가 있고 변수 이름 i를 o로 바꾸고 참조를 놓쳤다는 것입니다. JSLint는 hasOwnProperty가 올바른 객체의 올바른 속성인지 확인하기에 충분합니다.
drewish

12
그러나 객체의 속성을 반복하는 것이 좋습니다. OP는 for in이 어레이에 적용되었다고 말하지 않았습니다. hasOwnProperty가 가장 좋은 방법이지만 원치 않는 경우가 있습니다. 예를 들어 객체가 다른 객체를 확장하고 객체와 '부모'속성을 모두 나열하려는 경우가 있습니다.
gotofritz

3
나는 사람들을 for-in루프 에서 멀어지게 만드는 대신 (정말 훌륭하지만) 어떻게 작동하는지 교육하고 (이 답변에서 올바르게 수행됨) 소개하여 Object.defineProperty()프로토 타입을 안전하게 확장하지 않고도 프로토 타입을 안전하게 확장해야한다고 생각합니다. 또한 기본 개체의 프로토 타입을 확장 하지 않고 확장하면 안됩니다Object.defineProperty .
Robert Rossmann

87

jslint의 저자 인 Douglas Crockford는이 문제에 대해 여러 번 글을 썼습니다. 그의 웹 사이트 의이 페이지에는 이것을 다루는 섹션 이 있습니다 :

성명서

문장 클래스의 형식은 다음과 같아야합니다.

for (initialization; condition; update) {
    statements
}

for (variable in object) {
    if (filter) {
        statements
    } 
}

첫 번째 형식은 배열과 미리 결정 가능한 반복 횟수의 루프와 함께 사용해야합니다.

두 번째 양식은 객체와 함께 사용해야합니다. 객체의 프로토 타입에 추가 된 멤버는 열거에 포함됩니다. hasOwnProperty 메소드를 사용하여 객체의 실제 멤버를 구별하여 방어 적으로 프로그래밍하는 것이 좋습니다.

for (variable in object) {
    if (object.hasOwnProperty(variable)) {
        statements
    } 
}

Crockford는 또한 YUI 극장에서 이에 대해 이야기하는 비디오 시리즈를 가지고 있습니다. 자바 스크립트에 대한 Crockford의 일련의 비디오 / 토크는 자바 스크립트에 대해 약간 진지한 지 반드시 확인해야합니다.


21

나쁨 : (jsHint에서 오류가 발생 함)

for (var name in item) {
    console.log(item[name]);
}

좋은:

for (var name in item) {
  if (item.hasOwnProperty(name)) {
    console.log(item[name]);
  }
}

8

바바의 대답은 표에있다. jQuery를 사용하면 $.each()함수가이를 처리하므로 사용하는 것이 더 안전합니다.

$.each(evtListeners, function(index, elem) {
    // your code
});

5
여기서 성능을 고려해야 할 경우 원시 루프를 피할 수 있다면 $.each(또는 underscore.js 's _.each)를 사용하지 않는 것이 좋습니다 for. jsperf에는 실행 가치 가 있는 몇 가지 눈에 띄는 비교 테스트 가 있습니다.
nickb dec

3
이것 ( jsperf.com/each-vs-each-vs-for-in/3 )은 기본 프로토 필터를 사용하기 때문에보다 현실적입니다
dvdrtrgn

7

@all-JavaScript의 모든 것은 객체 ()이므로 "객체에서만 사용"과 같은 문장은 약간 오해의 소지가 있습니다. 또한 JavaScript는 강력하게 입력되지 않으므로 1 == "1"은 true입니다 (1 === "1"은 아니지만 Crockford는이 값이 큽니다). JS에서 배열의 progromatic 개념에 관해서는, 정의에서 타이핑이 중요합니다.

@Brenton-용어 독재자가 될 필요는 없습니다. "연관 배열", "사전", "해시", "개체", 이러한 프로그래밍 개념은 모두 JS에서 하나의 구조에 적용됩니다. 이름 (키, 인덱스) 값 쌍입니다. 여기서 값은 다른 객체 일 수 있습니다 (문자열도 객체 임)

그래서, new Array()과 동일[]

new Object() 대략 비슷하다 {}

var myarray = [];

모든 인덱스 (일명 키)가 정수 여야한다는 제한이있는 배열 인 구조체를 만듭니다. 또한 .push ()를 통해 새 인덱스를 자동 할당 할 수 있습니다

var myarray = ["one","two","three"];

실제로 비아를 다루는 것이 가장 좋습니다 for(initialization;condition;update){

그러나 어떻습니까 :

var myarray = [];
myarray[100] = "foo";
myarray.push("bar");

이 시도:

var myarray = [], i;
myarray[100] = "foo";
myarray.push("bar");
myarray[150] = "baz";
myarray.push("qux");
alert(myarray.length);
for(i in myarray){
    if(myarray.hasOwnProperty(i)){  
        alert(i+" : "+myarray[i]);
    }
}

아마도 배열을 가장 잘 사용하지는 않지만 항상 명확한 것은 아닙니다.

키를 알고 있고 정수가 아닌 경우 구조 옵션과 같은 유일한 배열 옵션은 객체입니다.

var i, myarray= {
   "first":"john",
   "last":"doe",
   100:"foo",
   150:"baz"
};
for(i in myarray){
    if(myarray.hasOwnProperty(i)){  
        alert(i+" : "+myarray[i]);
    }
}

"객체에서만 이것을 사용한다"는 배열이나 객체를 확장하는 다른 어떤 것에도 사용하지 않는 것을 의미합니다. 그렇지 않으면 모든 것이 객체를 확장하므로 매우 어리 석을 것입니다
Juan Mendes

' "연관 배열", "사전", "해시", "개체", 이러한 프로그래밍 개념은 모두 JS에서 하나의 구조에 적용됩니다.' 아닙니다. 서로 다른 언어와 다른 개념으로 서로 유사 합니다. 그러나 당신이 그것들이 / 정확하게 동일하다고 가정하고 같은 방식으로 같은 목적으로 사용된다면, 당신은 언어가 어떻게 무지한지를 피함으로써 피할 수있는 정말 어리석은 실수를하도록 스스로를 설정하는 것입니다 당신은 작품을 사용하고 있습니다.
Breton

2

확실히 말하기에는 약간 극단적입니다

... for 루프를 사용하여 배열을 열거하지 마십시오. 못. 에 대한 오래된 것을 사용하십시오 (var i = 0; i <arr.length; i ++)

?

Douglas Crockford 추출물의 섹션을 강조 할 가치가 있습니다.

... 두 번째 형태는 객체와 함께 사용해야합니다 ...

숫자가 아닌 키 대신 이름이 지정된 연관 배열 (일명 hashtable / dictionary)이 필요한 경우이를 객체로 구현해야합니다 (예 :) var myAssocArray = {key1: "value1", key2: "value2"...};.

이 경우 myAssocArray.length(이 객체에는 '길이'속성이 없기 때문에) null이 i < myAssocArray.length되며 멀리 가지 않습니다. 배열 키는 유용한 속성 (예 : 배열 멤버의 ID 속성 또는 이름)이 될 수 있기 때문에 더 큰 편의성을 제공하는 것 외에도, 연관 배열은 많은 상황에서 성능 이점을 제공 할 것으로 예상됩니다. 배열을 반복해서 평가하여 원하는 배열 항목을 찾습니다.

어쨌든 JSLint 오류 메시지에 대한 설명 덕분에 무수한 연관 배열을 통해 간섭 할 때 'isOwnProperty'확인을 사용합니다!


1
당신은 깊이 혼란스러워합니다. 자바 스크립트에는 "연관 배열"과 같은 것이 없습니다. 그것은 엄격하게 PHP 개념입니다.
Breton

이러한 객체에는 length속성이 없지만 다른 방법으로 수행 할 수 있습니다.var myArr = []; myArr['key1'] = 'hello'; myArr['key2'] = 'world';
nyuszika7h

3
@ Nyuszika7H 그것은 잘못된 방법입니다. 정수 인덱스 배열이 필요하지 않은 경우을 사용하지 var myArr = []않아야합니다 var myArr = {}.PHP에서는 동일한 것이지만 JS는 아닙니다.
Juan Mendes

연관 "배열"은 배열이 아닙니다.
Vincent McNabb


0

in / for / $. each에 대한 주제를 추가하기 위해 $ .each vs. for http://jsperf.com/each-vs-for-in/2에 대한 jsperf 테스트 사례를 추가했습니다.

다른 브라우저 / 버전은 다르게 처리하지만 성능이 가장 저렴한 옵션은 $ .each 및 똑바로 나타납니다.

연관 배열 / 객체를 반복하고, 이후의 것을 알고 다른 모든 것을 무시하는 데 사용하는 경우 jQuery를 사용하거나 jQuery를 사용하거나 중단 한 경우 $ .each를 사용하십시오. 당신이 마지막 요소가되어야한다는 것을 알게되었습니다.)

배열을 통해 각 키 쌍으로 무언가를 수행하는 경우 jQuery를 사용하지 않으면 hasOwnProperty 메소드를 사용하고 jQuery를 사용하는 경우 $ .each를 사용해야합니다.

for(i=0;i<o.length;i++)하지만 연관 배열이 필요하지 않은 경우 항상 사용 하십시오. lol chrome은 for 또는$.each

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.