데브코스 프론트엔드 5기/VanillaJS를 통한 자바스크립트 기본 역량 강화 1
231004 [Day12] VanillaJS를 통한 자바스크립트 기본 역량 강화 1 (1)
코딩하는 키티
2023. 10. 5. 12:03

강의를 듣기 전 JS 사전 퀴즈 7문제를 풀어보았다.
오류를 찾고 해결방법을 물어보는 문제와 출력값 구하는 문제들이 나왔는데 '이게 뭐가 문제지?'라는 생각과 한참 생각해야 답이 나오는 문제들이었다. 찍은 것도 있었다.. 여전히 기초와 기본이 부족한 것 같다. 틈틈이 기초 강의들을 들어야겠다는 생각이 들었다.
JS 사전 퀴즈 문제 1
Q) 다음 코드의 실행결과는?
- 'cherry'가 출력된다.
- 빈 문자열이 출력된다.
- undefined가 출력된다.
- 오류가 발생한다. ✅
function Cat(name, age) {
this.name = name;
this.age = age;
}
const cat1 = Cat('cherry', 6);
console.log(cat1.name);
함수(Cat) 내에 함수를 return하는 코드가 없다. -> cat1에 undefined 값이 들어감 -> undefined.name을 찾을 수 없기에 오류
함수 안에 있는 this는 window를 가르키기에 window.name을 찍으면 cherry 가 나온다.
this가 window를 가르키는 이유
- 함수를 new 키워드를 통해 생성하지 않았기 때문이다.
- new를 사용하지 않고 함수를 선언할 시 함수 내부의 this는 window를 가르킨다.
- new를 사용하면 this는 새로운 Cat함수의 새로운 객체를 가르키게 된다.
this를 사용하여 객체지향 흉내내기 가능
function Cat(name, age) {
this.name = name;
this.age = age;
this.printCat = () => {
console.log(`${this.name}은 ${this.age}살 고양이에요!`);
}
}
const cat1 = new Cat('cherry', 6);
const cat2 = new Cat('angdu', 3);
const cat3 = new Cat('mimi', 4);
cat1.printCat()
cat2.printCat()
cat3.printCat()
//cherry는 6살 고양이에요!
//andgu는 3살 고양이에요!
//mimi는 4살 고양이에요!
JS 사전 퀴즈 문제 2
Q) 다음 코드의 실행결과는?
- 함수가 선언되기만 하고 아무일도 일어나지 않는다.
- 'Hello,'만 출력된다.
- 'Hello, kitty'가 출력된다. ✅
- 오류가 발생한다.
(function(name){
console.log(`Hello, ${name}`)
})('kitty');
위 코드는 'Hello, kitty' 가 출력된다.
위 처럼 작성하는 함수 방식을 IIFE(즉시실행함수)라고 한다.
1. 전역(window)에 필요 없는 변수 생성을 막을 수 있다.
- 즉시실행함수 내부에 변수를 선언할 시, 내부 변수는 전역 변수가 아닌 지역변수로 남는다.
- 따라서 전역스코프가 오염되는 것을 줄일 수 있다.
2. privte 변수를 생성할 수 있다.
const animal = (function(){
// age는 밖에서 접근할 수 없다. -> private 효과
let age = 6;
function Age(){
return age;
}
return {Age : Age}
})();
위 코드에서 age는 직접적인 변경이 불가능하며, 접근자함수(Age)로만 age를 확인할 수있다.
JS 사전 퀴즈 문제 3
Q) 다음 코드의 실행결과는?
A) undefined jinah
var obj1 = {
name : "kitty",
color : "pink"
obj2 : {
obj3 : {
memberName : "jinah",
play : function(){
console.log(`${this.name} ${this.memberName}`)
}
}
}
}
obj1.obj2.obj3.play()
play 함수내 this는 obj3 객체를 가르키기 때문에 kitty는 undefined가 나오고 jinah가 나온다.
- undefined가 나오지 않으려면 ${this.name}을 ${obj1.name}으로 바꾼다.
JS 사전 퀴즈 문제 4
Q) 다음 코드를 실행하면 오류가 발생한다. 오류가 발생하는 원인은 무엇이고 어떻게 해결할 수 있을까?
function zoo(animals){
this.animals = animals;
this.kind = function () {
setTimeout(function(){
this.animals.forEach(function(animal){
animal.kind();
})
}, 1000)
}
}
var cats = new zoo([
{
animal: 'cherry',
kind: function() {
console.log('sound: m e o w m e o w')
}
}
});
cats.kind();
this의 범위에 대한 문제
setTimeout() 함수 내 this는 setTimeout() 내 function 을 가리킨다.
-> this안에 animals가 없기때문에 에러 발생(undefined)
해결 방법
1. Arrow Function 이용하기
- Arrow Function은 자기 자신의 함수 스코프를 만들지 않고 해당 Arrow Function 상위의 Scope를 가진다.
- 따라서 this는 zoo 객체를 가르키게 된다.
setTimeout(() => {
this.animals.forEach(function(animal){
animal.kind();
})
}, 1000)
2. bind() 사용하기
- bind() 메서드를 사용하면 this를 지정해 줄 수 있다.
- bind는 새로운 함수를 생성하는 메서드로 아래 코드에서 bind 내부 this는 zoo를 가르키기 때문에 내부 함수에서 this가 zoo를 가르키게 된다.
setTimeout(function(){
this.animals.forEach(function(animal){
animal.kind();
})
}.bind(this), 1000)
3. 클로저 이용하기
- zoo를 가르키는 속성을 선언해주고 내부에서 사용해주는 방식이다.
- this를 다른 변수에 담아두고 클로저를 통해 접근
function zoo(animals){
var that = this;
this.animals = animals;
this.kind = function () {
setTimeout(function(){
that.animals.forEach(function(animal){
animal.kind();
})
}, 1000)
}
}
JS 사전 퀴즈 문제 5
Q) 다음 코드를 실행하면 숫자가 0부터 4까지 출력이 되지 않고 undefined가 다섯 번 출력이 된다. 그 이유는?
const numbers = [0, 1, 2, 3, 4]
for(var i = 0; i < numbers.length; i++) {
setTimeout(function(){
console.log(`[${i}] number ${numbers[i]} turn!`)
}, i * 1000)
}
클로저(closure)와 setTimeout 함수의 작동 방식 때문이다.
setTimeout 함수는 비동기적으로 동작하며, 콜백 함수가 실행되기까지 일정 시간이 소요된다.
따라서 for 루프가 반복될 동안 setTimeout 함수가 호출되고, 그 후에 콜백 함수가 실행된다.
여기서 주의해야 할 점은 setTimeout 콜백 함수 내에서 사용되는 i 변수이다.
var 키워드로 선언된 변수 i는 함수 스코프를 가지기 때문에, 콜백 함수가 실행될 때의 i 값이 아니라 반복문이 종료된 후의 i 값(즉, numbers.length인 5)이 사용된다.
이로 인해 모든 콜백 함수에서 numbers[5]를 참조하게 되고, numbers[5]는 정의되지 않았기 때문에 undefined가 출력된다.
해결법 1 : IIFE(즉시 실행 함수 표현)
- i가 0, 1, 2, 3, 4일 때를 각각의 function scope로 가두어서 처리한다. (index)
- setTimeout 실행 시점에 참고하는 index는 IIFE에서 인자로 넘긴 i의 값을 쓰기 때문에 문제 해결
const numbers = [0, 1, 2, 3, 4]
for(var i = 0; i < numbers.length; i++) {
(function(index) {
setTimeout(function(){
console.log(`[${index}] number ${numbers[index]} turn!`)
}, i * 1000)
})(i)
}
해결법 2 : var 대신 let 쓰기 (매 루프마다 클로저 생성하게 하기)
- let으로 선언할 경우 setTimeout 내에서 let i가 0일 때, 1일 때 각각 참조되기 때문에 정상 동작
- IIFE로 해결한 것과 유사한 케이스
const numbers = [0, 1, 2, 3, 4]
for(let i = 0; i < numbers.length; i++) {
setTimeout(function(){
console.log(`[${index}] number ${numbers[index]} turn!`)
}, i * 1000)
}
해결법 3 : for 대신 forEach 메서드 사용하기
- forEach로 numbers를 순회하면서 각각 function을 만들기 때문에 i의 값이 고유해진다.
const numbers = [0, 1, 2, 3, 4]
numbers.forEach(function (number, i) {
setTimeout(() => {
console.log(`[${i}] number ${numbers} turn!`)
}, i * 1000)
})
JS 사전 퀴즈 문제 6
Q) var, let, const의 차이
| var | function scope 변수 재할당 가능 호이스팅 O |
| let | block scope 변수 재할당 가능 |
| const | block scope 변수 재할당 불가능 |
- 호이스팅 : function scope상 맨 위로 var 선언이 끌어올라지는 현상
- 함수 선언부 위로 끌어올려지기 때문에 값 할당 전에 호출될 수 있다.
- 이 부분을 잘 생각하지 않으면 버그 만날 수 있음

- block scope는 if, for, while 등 block 구문 단위로 범위를 갖는다.
- let과 const가 hosting이 일어나지 않는 것은 아니다.
- 스코프에 변수가 만들어지고 TDZ(Temporal Dead Zone)이 생성되지만, 코드 실행 변수 실제 위치에 도달할 때까지 액세스 할 수 없는 것 (할당되기전에 호출 시 에러남)
JS 사전 퀴즈 문제 6
Q) 클로저란?
- 함수가 선언된 환경의 스코프를 기억하여 함수가 스코프 밖에서 실행될때에도 기억한 스코프에 접근할 수 있게 함
- 은닉화 : 클로저를 이용하여 내부 변수와 함수를 숨길 수 있음
function makeFunc() {
const name = "Mozilla";
function displayName() {
console.log(name);
}
return displayName;
}
const myFunc = makeFunc();
myFunc();
displayName() 내부 함수가 실행되기 전에 외부 함수에서 반환된다.
클로저는 함수와 함수가 선언된 어휘적 환경의 조합.
이 환경은 클로저가 생성된 시점의 유효 범위 내에 있는 모든 지역 변수로 구성된다.
예시의 경우, myFunc은 makeFunc이 실행 될 때 생성된 displayName 함수의 인스턴스에 대한 참조이다.
displayName의 인스턴스는 변수 name 이 있는 어휘적 환경에 대한 참조를 유지한다.
이런 이유로, myFunc가 호출될 때 변수 name은 사용할 수 있는 상태로 남게 되고 "Mozilla" 가 console.log 에 전달된다.