앞서 for ... in vs for ... of
에 대한 비교글을 적은 적이 있다.
이번에 알고리즘 공부하면서 for .. in 사용시에 배열을 for in에 사용하고 key 즉 idx를 뽑아야겠다 라고 생각했는데 그 와중 당연히 idx가 number 인 줄 알았는데 알고 보니, string이라서 놀랬던(문제를 조졌던) 적이 있어 ㅠ
for ... in vs for ... of
를 좀더 알아보고자 글을 적는다.
이 과정에서 쇼킹한 것들이 몇 개 있어 정리해둔다. js를 몇년동안이나 사용했지만 깊게 한번 생각 안하고 넘어가니 뒤늦게 충격을 받는 듯하다.
우선 가볍게 for in,for of 차이
for ... in: 한 객체에 "Enumerable"(=열거 가능한) 프로퍼티들을 반복해주는 방식
for ... of: "iterable"(=반복 가능한)컬랙션을 반복해 주는 방식
출:https://bitsofco.de/for-in-vs-for-of/
for in은 순서가 지멋대로라 순서가 중요하면 사용하면 안된다.
for of는 순서대로 해준다.(당연한 소리, 배열이니깐)
for..in 에서 Objects
객체들은 배열의 forEach 같은 접근이 불가하므로, for in은 키를 제공해주니 직접적으로 key, value 사용을 가능케 해준다. (즉 대괄호 표기법 : object[key]로 value접근을 손쉽게 할수 있으므로..)
for..in 에서 Arrays
배열에서 value에 대한 key는 indexs 입니다. 그러므로 이러한 index 들은 객체의 key들과 같이 셀수있는 (=Enumerable) 프로퍼티들 인 것입니다.
(나중에 말하겠지만 index들이 number가 아닌 string인 것에 깜놀!!!)
즉 이건 다시말해, 이 index들을 활용해서 배열에서 value들에 충분히 접근할 수 있다는걸 의미합니다.const array = ['a', 'b', 'c', 'd']; for (const index in array) { console.log(array[index]) } // Result: a, b, c, d
for..in 에서 Strings
한 문자열 내에 각 문자는 각각 index를 가지고 있습니다. 그러므로, 배열과 유사하고, 그 index들은 정수 형태의 열거가능한 프로퍼티들이죠.(그니까 for in서 돌아간다는 그런뜻)
const string = 'Ire Aderinokun'; for (const index in string) { console.log(string[index]) } // Result: I, r, e, , A, d, e, r, i, n, o, k, u, n
for..of는 ES2015에 도입된 방식이고, "반복가능한 collection"을 반복해줍니다. 반복가능한 collection은 아래와 같이 있습니다(Array, Map, Set, String, TypedArray, arguments 객체 등을 포함). 이러한 object들은
[Symbol.iterator]
란 property를 가집니다.
[Symbol.iterator]
란 프로퍼티를 소개하자면, 해당 collection의 다음 item을 찾기 위해 Symbol.iterator.next() 를 호출함으로써 우리가 콜렉션을 반복하게 해줍니다.const array = ['a','b','c', 'd']; const iterator = array[Symbol.iterator](); console.log( iterator.next().value ) console.log( iterator.next().value ) console.log( iterator.next().value ) console.log( iterator.next().value ) // Result: a, b, c, d
for..of의 문법은 필수적으로 loop를 만들기 위한 [Symbol.iterator] 주변에 있는 하나의 wrapper입니다.(위에는 wrapper를 활용해 loop를 만드는 모습)
따라서 이것은 아래 문법으로 사용됩니다.for (variable of iterable) { // do stuff }
for.. of 에서 객체
for..of 루프는 일반 객체랑 작동하지 않습니다. 왜냐면 객체는 "iterable"하지 않습니다. ("enumerable" 하죠 후훗, 즉 반복적이지 않고 열거적이다 라는 느낌같은 느낌을 이해해!) 그러므로
[Symbol.iterator] property
를 가지고 있지 않습니다.
for.. of 에서 Arrays/Strings
for..of 반복문은 배열과 Strings에 잘 작동합니다. 그것들은 "iterable"하니깐요.
const array = ['a', 'b', 'c', 'd']; for (const item of array) { console.log(item) } // Result: a, b, c, d const string = 'Ire Aderinokun'; for (const character of string) { console.log(character) } // Result: I, r, e, , A, d, e, r, i, n, o, k, u, n
for..of 에서 NodeLists
for.. of의 또 하나 유용한 case는 NodeList들을 반복한다는 점입니다.
우리가 한 그룹의 요소들의 문서들을 탐색 할때, 우리가 받는 것은 하나의 배열이 아니라 NodeList입니다. 이것은 forEach와 같은 배열 메서드를 사용하는 방식으로 그 리스트를 반복할 수 없다는 걸 의미합니다.
그래서 우리는 이것을 배열로 바꾸거나, 또는 배열 이상에도 적용 가능한 for..of로 바꾸면 됩니다.const elements = document.querySelectorAll('.foo'); for (const element of elements) { element.addEventListener('click', doSomething); }
좀 찾아 봤는데 왜 in을 쓰고 뒤에는 왜 of를 쓰는지 영어 레퍼런스도 찾을 수가 없었다. 이건 혹시 글 읽는 독자 중에 아는 사람있으면 댓글 부탁드림. 왜 in이고 of로 네이밍을 했는지 알수가 없네.. 나름 해석하자면 Enumerable 영어 발음이 이누머러블이라 in을 사용하거나 또한 for... in 경우는 객체나 collection의 value를 사용하는게 아니라 프로퍼티명을 나열해주니 of가 소유의 느낌이 강하다면 약간 in 전치사가 소유 보단 상태를 나타내주는? 뉘앙스가 좀더 있어서 in을 쓴게 아닌지? for... of는 실제로 value를 나열해주니 소유 느낌으로 of를 사용하는게 아닌지? 뇌피셜이다.그치만 이렇게 이해하면 암기가 쉬움.
아 나랑 비슷한 생각을 하는 친구가 나타났다~!!
그렇지
for..in은 index in 배열이나 객체 를 보여주는데, 배열이나 객체에 index..즉 조사로 in이 적합하다 이말이여!!
for..of는 element of array 즉 배열의 요소를 보여주니 소유 형태의 of가 적합하다!!
(아 저친구가 약간 착각하는건 object가 for of 에 다 돌아가는건 아님. 객체중에 객체라 했지만 사실 object을 for of 돌리면 에러나니 배열로 설명하는게 적합할듯.)
출 : https://stackoverflow.com/a/62328579/12959959
정리
for... in : 객체, 배열, 콜렉션 모두 사용가능.
for... of : 객체 사용불가, 콜렉션만 사용가능.
단도직입적으로, 오직 실용주의적으로 말하자면!!배열에서 값만 순회할 땐, 다수 NodeList받을때 for... of 사용, 그 외엔 for... in 사용한다!
라고 생각하면 편하다. object에서 key-value 다 쓰거나, array에서 index-value 다 사용해야 하는 경우, 즉 대부분 경우엔 for.. in 사용이 압도적으로 많다
for..in | for..of | |
---|---|---|
사용 | Enumerable Properties | Iterable Collections |
일반객체랑(collections이 아닌) 사용가능? | Y | N |
배열은? | Y, 추천하진 않음 | Y |
String? | Y, 추천하진 않음 | Y |
말 그대로... array의 index는 string이었다.요것땜에 알고리즘에서 에러남..ㅜ
array[index] index는 무조건 number형만 넣어야 되는줄 알았는데 string도 넣어도 된다.
왜냐면 배열또한 단순히 객체고, 키가 인덱스, 또 'length'란 키가 있는 객체이다.
출:https://okky.kr/articles/871054
해석할때 열거가능한,셀수있는 등 다 맞는 표현인데 셀수 있는으로 해석하면
굉.장.히 헷갈릴것이다!! iterable collections들 array나 set 자료형도 셀수 있잖아!! 그래서 나름 생각해봤는데 "열거가능한" 말이 딱 좋다.
열거 가능하다라면 이름이 있어야 하잖아.. 즉 객체에 키가 보통 문자열로 변수명처럼 열거 편하게 나오니 enumerable 한 거고.. iterable한 건 반복가능한.. 즉 array나 set은 키 즉 인덱스에 별의미 없이 1,2,3.. 이잖아. 근데 열거라 말하면 조금 거시기한데 반복가능하다 하면 딱 이해가 되지.. 객체는 키가 뭐 'address', 'name', 'phone'이런 식이니 반복가능하다? 어색한 표현이지..
그래서 enumerable은 객체 개념이고, iterable은 collections 자료형 개념이다아!!
사실 아래 그림(출처는 맨 아래 주소)에 저자의 설명처럼 객체는 생성하면 writable, enumerable, cofigurable이란 숨겨진 키가 자동 생성되어 enumerable: true
면 key를 통해 열거가 가능하도, false
면 key로 불러도 열거가 불가능하게 만들어 졌다는게 정석 설명이긴하다~!!
그럼 writable, configurable도 설명안해도 짐작이 간다~
요렇게 시간은 걸리지만 나름 네이밍의 이유도 생각해보고 정리하니 앞으론 덜 헷갈리고 편하게 사용 가능할것이다~!부지런한 만큼 기본기가 되고 효율이 나중엔 더 좋아진다
출 :
https://bitsofco.de/for-in-vs-for-of/
https://shivamethical.medium.com/what-is-enumerable-in-javascript-e2b1c0fd0623