daily

23.04.17. for...in, for...of

Juhyuck 2023. 4. 17. 15:38
728x90

Issue

알고리즘 문제를 풀다 보니, for문을 돌리는 일이 종종 발생하는데, array에 대해 for...in문을 쓸 때 index라고 생각한 것이, string이라 더하고 뺄 때 Number()로 감싸주거나, parseInt를 해야 해서 번거롭다.


Try&Error

파이썬만 알고 있다가 자바스크립트를 배우다 보니, 익숙해서 for...in 문과 for...of문이 손에 익은데,

for...in을 쓰면, string이나 array는 index를, object는 key값을 iterator로 사용할 수 있다. 근데, array의 index를 다루기 위해서 for...in을 쓰면 귀찮은 일이 많이 발생하는데, 이때 반복자로 사용되는 것이 string 타입이라서 그렇다.

 

배열의 index는 number인데 왜 string으로 반환되는지를 살펴봤다. 우선 MDN에서의 정의를 보면, "enumerable string properties"를 반복한다고 한다. enumerable string properties에 대해서 잠깐 문서를 읽어보면...

모든 자바스크립트 객체의 property는 "Enumerable or non-enumerable(열거 가능하거나 아니거나) / String or symbol(문자열이거나 심볼이거나) / Own property or inherited property from the prototype chain(자기 property거나 프로토타입 체인으로 상속받은 property거나)" 세가지로 나눌 수 있다고 한다. 

그 중 enumerable string properties는, 열거 가능 플래그가 true로 설정된 property를 말하고, for...in 이나 Object.keys는 이런 열거가능한 키를 가져온다는 것.

이때, for...in은 enumerable property를 string으로 반환하는데, 왜 string으로 반환하는지에 대한 설명은 찾지 못했다. 아마 객체 중 하나인 array로서, 객체로서 enumerable한 것을 리턴하는 방식으로는, 객체의 property의 key값이 string이나 symbol만 가능하기 때문이고, for...in 은 string만 반환하기때문이 아닐까 싶다. 그리고 array가 특별히 number로 zero-indexed 되어 있는 객체인 것으로 이해하자.


Solution

만약 반복문 안에서 인덱스를 더하고 빼고 할일이 있다면, for ( 초기화; 반복마다 평가할 식; 매 반복 후 평가할 식) 방식으로 선언하고, 초기화 때 index를 number로 정의해서 쓰는게 좋겠다.

혹은, array의 메서드인, forEach, reduce, map, filter를 쓰면, index는 number로 바로 사용할 수 있다.


Learned

 

 

실제 계산해야하는 상황에 맞게 메서드나 반복문을 사용해야한다.

 

+ 좀 더 문서를 읽어보니, for...in은 inherited까지 다 반환하기때문에... 객체에 잘못썼다가는 이상한걸 많이 받아올 수 있다.

그렇지 않으려면 Object.keys()/.values()/.entries() 나  Object.getOwnPropertyNames()를 써야한다. 물론 Object.getOwnPropertyNames()를 쓰면 non-enumerable까지 반환되니까 조심해야 할 것 같고...

 

아래 MDN 캡쳐를 보면, property를 불러올 때, string와 symbol를 구분하는 경우도 있다는 걸 알았다. symbol을 이용해서 객체에서 enumerable에서 제외하거나 그것만 포함하거나 할 수 있어 보이는데, symbol만 찾아오는 메서드는 없어 보이는 걸 봐서는 보통 제외하는 쪽으로 사용하는 것 같다.