HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
📝
학습 TIL
/
📝
9일차 배운 것 정리 (1)
📝

9일차 배운 것 정리 (1)

대주제
JS
작성완료
작성완료
전날 정리 노트 이동
다음 정리 노트 이동
주제
JS 퀴즈
즉시실행함수
this
클로저
날짜
Mar 31, 2022

목차

목차1. javascript 사전 퀴즈1-1. 생성자함수와 일반 함수의 this 바인딩 차이1-2. 즉시실행함수의 결과1-3. functionscope와 this1-4. 오류가 발생하는 원인과 해결방안은?1-5. for문에서의 setTimeout 사용 시 출력값1-6. var, let , const의 차이는 무엇인가요?1-7. 클로저는 무엇인가요?

1. javascript 사전 퀴즈

1-1. 생성자함수와 일반 함수의 this 바인딩 차이

💡
생성자함수와 일반 함수의 this 바인딩 차이
  • new 키워드를 통한 생성자함수는 함수내부의 this가 선언된 객체를 가르키게 된다.
  • 해당 문제는 Cat() 함수의 리턴 값이 없기 때문에, tabby1 = undefined 가 할당되고, undefined의 name을 접근하기 때문에 오류가 발생하게 된다.

1-2. 즉시실행함수의 결과

즉시실행함수를 사용하는 이유
js에서 선언된 모든 변수나 함수는 전역 공간에 저장되고, 다른 파일에서 같은 변수명을 사용할 경우 오버라이딩 되는 경우가 발생한다.
  • 1. 따라서 함수스코프를 통해 이를 방지하고자, 특정 스크립트 파일이나 덩어리들을 하나의 함수로 묶어주어 변수공간을 제한하기 위해 사용했다.
  • 2. 즉시실행함수에서 특정 변수,함수만을 리턴하여, 내부의 변수를 private하게 관리할 수 있는 효과도 있다.

1-3. functionscope와 this

  • this는 함수 실행시 생성되는 실행컨텍스트에 속하며, 함수의 호출방법에 따라 this값이 다르다.
  • 일반적으로 전역객체(windows)를 가르킴
  • method 방식 호출시 this는 함수실행한 부모객체를 가르킴
  • new 키워드를 통한 생성자함수로 호출한다면, 새롭게 생성된 인스턴스를 가르킴
  • call / apply / bind로 지정 가능 (링크)
    • person2.study.call(person1) : person2가 가지고 있는 study함수를 person1이 사용할 수 있도록 해라
    • call / apply 첫번째 인자로 this 지정
      • 두번째 인자는 함수호출에 사용할 매개변수를 의미
      • call은 매개변수의 값을 각각 받음
      • apply는 매개변수를 배열형태로 받음
      • 실제 사용할 수 없는 method들 사용가능
        • Array.prototype.join.call(arguments)
        • 함수의 매개변수인 arguments는 유사배열형태이기 때문에 바로 배열메소드 사용불가 → Array.prototype을 빌려서 배열메소드 사용가능
    • bind
      • 새롭게 binding된 함수를 만들고 반환
      • 반환된 함수에는 this가 바뀌어 있다.
      • 따라서 변수에 할당하고, 호출하는 형태로 사용한다.
        • let student = person2.study.bind(person1); student()
  • 화살표함수에서의 this
    • 정적으로 항상 상위스코프의 this를 가르키게됨
    • call, apply, bind 메소드 사용불가

1-4. 오류가 발생하는 원인과 해결방안은?

나의답변
setTimeout()의 함수 내부에서 this가 전역객체를 가르키기 때문이다. this에 RockBand 를 연결시켜주어야 하는데, 가장 간단하게는 setTimeout의 콜백함수를 화살표함수로 바꾸어줄 수 있다. 화살표 함수는 내부적으로 this를 가지고 있지 않기 때문에, this는 스코프체인에 따라 RockBand를 가르킬 수 있게 된다.
해결방법
  1. 나의답변인 화살표함수
    1. 화살표함수에서의 this는 상위 스코프의 this를 바인딩하게 된다.
  1. bind()를 사용하여 this를 넘겨주기
    1. bind()를 통해 현재 스코프의 this를 setTimeout 함수안으로 넘겨줄 수 있다.
       
  1. 클로저를 활용하여 this 넘겨주기
      • 내부함수가 외부함수의 변수에 접근할 수 있도록 하는 것
      • 외부의 that이라는 변수에 현재 스코프의 this를 담아서, 내부함수가 이를 접근할 수 있도록 한다.

1-5. for문에서의 setTimeout 사용 시 출력값

💡
나의답변 먼저 변수 선언 키워드 var가 블록스코프가 아닌 함수스코프를 가지기 때문입니다. 이벤트루프의 관점에서 이 코드를 바라본다면, setTimeout은 비동기 함수로, for문의 모든 동작이 끝난 이후에 실행이 됩니다. 따라서 var는 for문을 거쳐 5가 된 상태로 setTimeout이 5번 실행되기 때문에 undefined가 5번 발생하게 됩니다. 이를 해결하기 위해선 var를 let으로 바꿔주어, 매 실행 시 마다 i값이 재생성되고, 해당하는 값을 setTimeout이 기억하고 있어(클로저) 올바른 값을 출력하도록 할 수 있습니다.
  • console.log()에서 i는 5로 다섯 번, numbers[i]는 undefined를 다섯 번 리턴한다.
    • setTimeout이 비동기함수로, for문이 모두 실행된 이후에 차례대로 다섯 번 실행되기 때문에
방지하기 위한 방법
  • 즉시실행함수로 콜백함수를 감싸준다.
  • var 대신 let 사용하기
    • let이 block 스코프를 가지기 때문에, for문의 블럭 안에서 변수가 새로 생성이되고 이를 참조하게 된다.
  • for대신 forEach 사용하기
    • forEach도 각 배열 요소마다 함수를 새로 만들어 실행시키기 때문

1-6. var, let , const의 차이는 무엇인가요?

var VS let, const
  • var - 함수스코프 (변수 재할당가능)
    • 호이스팅 현상으로, 네임스페이스 오염되기 때문에 사용 지양
  • let - 블록스코프 (변수재할당 가능)
    • TDZ - 함수스코프 최상단과 실제 변수 선언이 이루어지는 곳 사이의 공간
    • TDZ에서 변수 사용하지 말 것
  • const - 블록스코프 (변수재할당 불가능)
 
호이스팅
  • 변수와 함수가 function scope의 최상단으로 선언이 끌어올려지는 현상

1-7. 클로저는 무엇인가요?

💡
나의답변 클로저는 외부함수의 변수에 접근할 수 있는 내부함수, 혹은 그러한 동작을 의미합니다. 즉 외부함수에서 리턴된 내부함수가, 선언되었던 외부함수의 컨텍스트의 환경을 기억하여 외부함수의 변수에 접근할 수 있는 것을 의미합니다.
  • 클로저의 private 효과
    • private한 상태를 저장할 수 있다. (IIFE감싼 것과 같은 원리)
    • 외부에서 해당 변수 접근 불가
      • 오직 리턴된 해당 변수를 접근할 수 있는 내부함수를 통해 변경가능
  • 클로저 사용패턴은?
    • 커링 ,.. .
 
function Cat(name, age){ this.name = name; this.age = age; } const tabby1 = Cat('nana', 7); console.log(tabby1.name)
(function(name){ console.log(`hello ${name}`) }){'roto'}
const logger = (function () { let privateCnt = 0; function log(msg) { console.log(msg); privateCnt += 1; } function getLogCnt() { return privateCnt; } return { log: log, getLogCnt: getLogCnt, }; })(); // logger.privateCnt에 직접 접근할 수 없게 됨
var idiots = { name: "name", genre: "genre", members: { roto: { memberName: "roto", play: function () { console.log(this.name, this.memberName); }, }, }, }; idiots.members.roto.play(); // undefined, roto // play내부의 this는 this를 실행시킨 객체인 roto : {memberName: - , play: f} 이기때문
function RockBand(members) { this.members = members; this.perform = function () { setTimeout(function () { this.members.forEach(function (member) { member.perform(); }); }, 1000); }; } var sing = new RockBand([ { name: "outwater", perform: function () { console.log("sing a song~"); }, }, ]); sing.perform();
setTimeout(function () { this.members.forEach(function (member) { member.perform(); }); }.bind(this), 1000);
function RockBand(){ var that = this; this.perform = function () { setTimeout(function () { that.members.forEach(function (member) { member.perform(); }); }, 1000); }; }
const numbers = [0, 1, 2, 3, 4]; for (var i = 0; i < numbers.length; i++) { setTimeout(function () { console.log(i, numbers[i], new Date()); }, i + 1000); }
for (var i = 0; i < numbers.length; i++) { (function (i) { setTimeout(function () { console.log(i, numbers[i], new Date()); }, i + 1000); })(i); }
numbers.forEach((number, i) => { setTimeout(function () { console.log(i, number, new Date()); }, i + 1000); });