[JS] for in/for of가 헷갈려서 다시 공부해봤다

·2022년 11월 19일
0

JavaScript

목록 보기
25/25

반복문

for... in
객체를 순환하고 싶을 때!
for... of
순환 가능한 것은 모두 순환시킬 수 있다.
순환 가능한 것? array, string, 함수 arguments, nodelist, set, map.
단 object는 순환할 수 없다.
아래에forEach() map() 뽀너스~

for ... in

const snack = {새우깡: 1000, 짱구: 1500, 홈런볼: 2000};
// 1. for문 안에 들어가는 프로퍼티를 담을 수 있는 키값 item이라는 변수 선언. snack이라는 객체 안에 있는
// 값에 접근하려면 키를 알아야 하니까 snack[item]
for (let item in snack) {
    console.log(`${item}의 가격은 ${snack[item]}원입니다.`);
} 
// 
새우깡의 가격은 1000원입니다.
짱구의 가격은 1500원입니다.
홈런볼의 가격은 2000원입니다.

잘 나온다 ~
for ... in문에는 hasOwnProperty를 써야한다던데 왜 쓰는 거지?
객체에 새 프로퍼티를 추가해보고 실행하면서 알아보자.

hasOwnProperty : 객체가 특정 프로퍼티를 가지고 있는지 확인한다. 프로토타입에 등록된 프로퍼티는 제외한다.

const snack = {새우깡: 1000, 짱구: 1500, 홈런볼: 2000};
// 3. const obj = new Onbject(); 오브젝트는 생성자 함수인데, 임의의 프로퍼티를 추가하고 싶다! 프로토타입을 추가하면 된다. 생성자 함수가 만드는 모든 인스턴스가 이 프로토타입을 공유한다. 프로토타입은 모든 인스턴스가 공유할 수 있는 하나의 공간.
Object.prototype.꼬북칩 = 3000;
// 4. 이렇게 꼬북칩 등록 가능

for (let item in snack) {
    console.log(`${item}의 가격은 ${snack[item]}원입니다.`);
} 
// 
새우깡의 가격은 1000원입니다.
짱구의 가격은 1500원입니다.
홈런볼의 가격은 2000원입니다.
꼬북칩의 가격은 3000원입니다.
// 5. 실행해보면 '꼬북칩의 가격은 3000원입니다' 까지 추가가 됐다!
// 6. snack이라는 객체는 Object라는 생성자 함수의 인스턴스. Object에 꼬북칩 추가했으니까 인스턴스에도 추가되어버린 것임.
const snack = {새우깡: 1000, 짱구: 1500, 홈런볼: 2000};
Object.prototype.꼬북칩 = 3000;
const drink = {콜라: 1000, 사이다: 2000}
// 7. 그럼 drink라는 객체를 만들고, for in문으로 순환해보자.

for (let item in drink) {
    console.log(`${item}의 가격은 ${drink[item]}원입니다.`);
} 
//
콜라의 가격은 1000원입니다.
사이다의 가격은 2000원입니다.
꼬북칩의 가격은 3000원입니다.

띠로리 ... 꼬북칩이 껴있다. 마음이 불편해진다.
for in문의 위험한 점! 나 편하겠다고 오브젝트에 임의의 프로퍼티를 추가해버리면, for in문을 썼을 때 이렇게 추가될 수 있다. 이런 문제를 방지하기 위해 hasOwnProperty를 써야하는 것!
왜? hasOwnProperty는 객체가 특정 프로퍼티를 가지고 있는지 확인해주고, 프로토타입에 등록된 프로퍼티는 제외해주는 애니까!

const snack = {새우깡: 1000, 짱구: 1500, 홈런볼: 2000};
Object.prototype.꼬북칩 = 3000;
const drink = {콜라: 1000, 사이다: 2000}

for (let item in drink) {
    if (snack.hasOwnProperty(item)){
        console.log(`${item}의 가격은 ${drink[item]}원입니다.`);
    }
} 
// 
새우깡의 가격은 1000원입니다.
짱구의 가격은 1500원입니다.
홈런볼의 가격은 2000원입니다.

결과 보니 꼬북칩 없음! 마음이 편-안하다.
누군가가 프로토타입에 등록한 거 말고~
처음에 만든 프로퍼티만 딱 나온다~

hasOwnProperty가 하는 일!
오브젝트 안에 자바스크립트를 개발한 사람들이 "개발자들이 이런 거 넣어주면 좋아하겠지..?"하고 프로토타입에 넣어놓은 메서드들과 프로퍼티들만 필터링을 해준다! 일종의 안전 잠금장치!
교훈 : 자스 개발자들이 만든 프로토타입을... 건들지 마시오 ...

for ... of

const heroes = ['captinmarvel', 'blackwidow']
// 배열의 원소들이 hero에 들어가고, 어떤 데이터인지는 of 뒤에
const newHeroes = [];
for (const hero of heroes){
    console.log(hero);
    newHeroes.push(hero + "!!");
}

console.log(newHeroes);
//
captinmarvel
blackwidow
['captinmarvel!!', 'blackwidow!!']
const heroes = ['captinmarvel', 'blackwidow']
for (const item of heroes[0]){
    console.log(item);    
}

function test(a, b, c) {
    for(const arg of arguments) {
        console.log(arg);
    }
}
// 
c
a
p
t
i
n
m
a
r
v
e
l

test(1,3,5);
//
1
3
5

문자열 자체를 순환하기 떄문에 알파벳 하나하나 나온다
arguments는 함수가 기본적으로 가지고 있는 프로퍼티
전달받는 아규먼트, 매개변수(여기서 a,b,c)에 대한 정보를 가지고 있다
함수가 실행될 때 전달되는 인자들을 찍고 싶을 때 인자들이 어떻게 들어왔는지 알고 싶을 때 for of로 순환할 수 있다

const mySet = new Set([1, 2, 3, 4, 5]);
console.log(mySet);

for (const item of mySet){
	console.log(item);
}
//
Set(5) {1, 2, 3, 4, 5}
1
2
3
4
5

set 순환하기
set은 배열의 진화형~ 더 괜찮은 메서드들을 제공한다

mySet.add(10);
console.log(mySet);
// Set(6) {1, 2, 3, 4, 5, 10}

알고리즘 테스트에서 중요하게 사용하곤 한다 ..

예) const testArr = [1,2,3,3,4,4,5,7,7,7,7]
중복되는 건 없애라~
const mySet2 = new Set(testArr);
console.log(mySet2)
// Set(6) {1, 2, 3, 4, 5, 7}
안에 중복된 값을 허용하지 않는 것이 특징!
결과값을 다시 배열로 만들어주면
Array.from(mySet2);
console.log(Array.from(mySet2))
// (6) [1, 2, 3, 4, 5, 7]

만 하고 가면 아쉬우니까

forEach(), map()

콜백함수를 이용하는 순환문까지 보자. ㅎㅎ
콜백함수 매개변수로 전달하는 함수
같은 함수도 전달되는 매개변수에 따라서 다른 결과값들이 나오는데 함수 역시 매개변수로 전달할 수 있다 오직 자바스트립트에만 존재하는 쏘 신기한 기능
function func1(arg1){
}

const list = [
	{name: '하나', age: '10'},
  	{name: '두리', age: '9'},
  	{name: '세리', age: '8'}
]

list.forEach(()=>{});
(()=>{})
이렇게 forEach의 매개변수로 함수를 넣을 수 있고 이녀석을 콜백함수라고 부른다~
콜백함수로 순환~

데이터에 있는 나이를 일괄적으로 1살씩 올리고 싶다면?

const list = [
	{name: '하나', age: 10},
  	{name: '두리', age: 9},
  	{name: '세리', age: 8}
]
list.forEach((item)=>{
	item.age += 1;
})
console.log(list);
//
(3) [{}, {}, {}]
0: {name: '하나', age: 11}
1: {name: '두리', age: 10}
2: {name: '세리', age: 9}

forEach문의 단점! 원본 데이터 자체가 변한다
html 요소를 순환하면서 이벤트를 붙일 때 사용 -> 이벤트를 붙여서 끝내는 거라 괜찮은데
순수한 데이터를 다룰 때는 원본 데이터를 손상시키지 않는 게 중요함!
보통 원본 데이터를 남겨두기 때문에
forEach문을 쓰면서 원본 데이터 남겨주기

const list = [
	{name: '하나', age: 10},
  	{name: '두리', age: 9},
  	{name: '세리', age: 8}
]
const newList = [];
list.forEach((item)=>{
	const newObj = { name: item.name };
    newObj['age'] = item.age + 1;
    newList.push(newObj);
})
console.log(list);
console.log(newList);

const list = [
	{name: '하나', age: 10},
  	{name: '두리', age: 9},
  	{name: '세리', age: 8}
]
list.map(()=>{})
// 배열 안에 있는 인자를 전달받고~
list.map((item)=>{
	const newObj = {name: item.name, age: item.age + 1};
    newObj['age'] = item.age + 1;
    return newObj;
})
console.log(list);
console.log(newList);

맵은 새로운 배열을 반환!!!
똑같이 배열 순환~~~ 맵이 원본 배열 유지가 더 쉬움

profile
주니어 프론트엔드 웹 개발자 🐛

0개의 댓글