-
[JavaScript] 문제를 통해 `실행 컨텍스트, 클로저, 스코프` 이해하기IT Study/FE 2023. 9. 15. 16:57728x90
1. 다음 코드 조각을 살펴보고, 각 console.log 라인에서 출력될 값과 그 이유를 설명하세요.
var a = 10; function outer() { var b = 20; function inner() { var c = 30; console.log(a); // 1번 라인 console.log(b); // 2번 라인 console.log(c); // 3번 라인 } inner(); console.log(a); // 4번 라인 console.log(b); // 5번 라인 console.log(c); // 6번 라인 } outer(); console.log(a); // 7번 라인 console.log(b); // 8번 라인 console.log(c); // 9번 라인
라인 답변 위치 접근 여부 1 10 전역 스코프에 위치 inner → 전역 접근 가능 2 20 outer 함수의 지역(함수) 스코프에 위치 inner → outer 접근 가능 3 30 inner 함수의 지역(함수) 스코프에 위치 inner → inner 접근 가능 4 10 전역 스코프에 위치 outer→ 전역 접근 가능 5 20 outer 함수의 지역(함수) 스코프에 위치 outer → outer 접근 가능 6 ReferenceError outer → inner 접근 불가 7 10 전역 스코프에 위치 전역 → 전역 접근 가능 8 ReferenceError 전역 → outer 접근 불가 9 ReferenceError 전역 → inner 접근 불가 2. 다음 코드를 보고 예상되는 출력과 그 이유를 설명하세요.
var foo = 10; function bar() { console.log(foo); var foo = 20; console.log(foo); } bar();
답변
undefined // bar 함수의 지역(함수) 스코프 내에 위치한 var foo;(선언)을 호이스팅 하여 undefined 출력
20 // bar 함수의 지역(함수) 스코프 내에 위치한 foo = 20;(초기화)로 20 출력3. 아래 코드를 분석하고, 각각의 console.log 문에서 출력될 값과 그 이유를 설명해 주세요.
function outer() { var a = 'outer'; var b = 'outer'; function middle() { var b = 'middle'; function inner() { var b = 'inner'; console.log(a); // 라인 1 console.log(b); // 라인 2 } inner(); console.log(b); // 라인 3 } middle(); console.log(a); // 라인 4 console.log(b); // 라인 5 } outer();
라인 답변 위치 접근 여부 1 ReferenceError
outerouter 함수의 지역(함수) 스코프에 위치 inner → middle → outer 순으로
스코프 체인을 따라 변수 a에 접근2 inner inner 함수의 지역(함수) 스코프에 위치 inner → inner 내 접근 가능 3 middle middle 함수의 지역(함수) 스코프에 위치 middle → middle 내 접근 가능 4 outer outer 함수의 지역(함수) 스코프에 위치 outer → outer 내 접근 가능 5 outer outer 함수의 지역(함수) 스코프에 위치 outer → outer 내 접근 가능 4. 다음 자바스크립트 코드를 보고 각각의 console.log에서 출력될 값과 그 이유를 설명하세요.
var a = 1; function first() { var b = 2; function second() { var c = 3; if(true) { var a = 4; let b = 5; console.log(a); // 라인 1 console.log(b); // 라인 2 console.log(c); // 라인 3 } console.log(a); // 라인 4 console.log(b); // 라인 5 console.log(c); // 라인 6 } second(); console.log(a); // 라인 7 console.log(b); // 라인 8 } first(); console.log(a); // 라인 9
라인 답변 위치 접근 여부 1 4 second 함수의 지역(함수) 스코프에 위치 second(if) → second(if) 접근 가능 2 5 second 함수의 지역(블록) 스코프에 위치 second(if) → second(if) 접근 가능 3 3 second 함수의 지역(함수) 스코프에 위치 second(if) → second 접근 가능 4 4 second 함수의 지역(함수) 스코프에 위치 second → second(if) 접근 가능 5 2 first 함수의 지역(함수) 스코프에 위치 second → first 접근 가능 6 3 second 함수의 지역(함수) 스코프에 위치 second → second 접근 가능 7 1 전역 스코프에 위치 first → 전역 접근 가능 8 2 first 함수의 지역(함수) 스코프에 위치 first → first 접근 가능 9 1 전역 스코프에 위치 전역 → 전역 접근 가능 5. 아래 코드 실행 시 결과와 그 이유를 설명해 주세요.
function asyncLoop() { for (var i = 0; i < 5; i++) { setTimeout(() => { console.log(i); }, i * 1000); } } asyncLoop();
*setTimeout : (특정 시간이 경과한 후 함수를 실행하도록 예약) 비동기적으로 실행되어, 각 반복에서 등록된 콜백 함수는 나중에 실행
오답 (더 보기 눌러서 확인하기)
더보기var로 선언된 변수 i는 전역적으로 사용되기 때문에
0과 1이 바로 출력되고, 1초 후 2, 2초 후 3, 3초 후 4가 출력됩니다.정답 (더 보기 눌러서 확인하기)
더보기1. asyncLoop 호출과 동시에 for 루프 실행
▶ i는 0부터 5까지 증가
▶ 마지막 i++ 후, i < 5이므로 i = 5에서 정지2. 각 루프 반복해서 setTimeout 함수 호출
▶ 콜백 함수와 타임아웃 시간을 전달3. setTimeout 함수는 지정된 시간이 경과한 후 콜백 함수를 태스크 큐에 추가 (실행 아님)
▶ 이벤트 루프 : 호출 스택이 비었을 때, 태스크 큐에서 함수를 가져와 호출 스택에 추가
▶ 따라서, for 루프가 완전히 실행된 후 setTimeout의 콜백 함수가 순차적으로 실행할 예정4. 이후 콜백 함수 내에서 i를 참조하는데, for 루프가 완료된 시점의 i인 5를 참조
5. 최종적으로, 콘솔에는 5가 5번 출력 (0, 1, 2, 3, 4초 후 각각)
Execution Context ┌───────────────────┐ │ │ │ Global Scope │ │ var i │ │ │ ├───────────────────┤ │ │ │ for loop (0-4) │ │ i = 0 to 5 │ │ │ ├───────────────────┤ │ │ │ setTimeout (0s) │ │ console(i) │ (5) │ │ ├───────────────────┤ │ │ │ setTimeout (1s) │ │ console(i) │ (5) │ │ └───────────────────┘
Q. var 대신 let 사용 시에는 어떤 결과가 나올까요? (더보기 눌러서 확인하기)
더보기1. asyncLoop 호출과 동시에 for 루프 실행
▶ i는 0부터 4까지 증가
▶ let 키워드는 각 반복마다 새로운 변수 인스턴스 생성
▶ 각 setTimeout 콜백 함수는 고유한 i 값 캡처2. 각 루프 반복해서 setTimeout 함수 호출
▶ 콜백 함수와 타임아웃 시간 전달3. setTimeout 함수는 지정된 시간이 경과한 후 콜백 함수를 태스크 큐에 추가 (실행 아님)
▶ 이벤트 루프 : 호출 스택이 비었을 때, 태스크 큐에서 함수를 가져와 호출 스택에 추가
▶ 따라서, for 루프가 완전히 실행된 후 setTimeout의 콜백 함수가 순차적으로 실행할 예정4. 이후 콜백 함수에서 i를 참조하는데, let을 사용했기 때문에 각 반복마다 고유한 i 값이 콜백 함수에 캡처되어 있는 상태
5. 최종적으로, 콘솔에는 0부터 4까지의 숫자 출력 (0, 1, 2, 3, 4초 후 출력)
Execution Context ┌───────────────────┐ │ │ │ Global Scope │ │ │ │ │ ├───────────────────┤ │ │ │ for loop (0-4) │ │ │ │ │ ├───────────────────┤ │ │ │ setTimeout (0s) │ │ console(i) │ (0) │ (let i = 0) │ ├───────────────────┤ │ │ │ setTimeout (1s) │ │ console(i) │ (1) │ (let i = 1) │ └───────────────────┘
6. greeting 함수의 동작 원리, greetJohn 변수가 참조하는 것, greetJohn() 호출 시 결과와 이유를 설명하세요.
function greeting(name) { let greetingMessage = "Hello, " + name; return function () { console.log(greetingMessage); }; } const greetJohn = greeting("John"); greetJohn();
답변
greeting 함수의 동작 원리
(1) name을 매개변수로 받아
(2) "Hello, "라는 문자열에 name을 붙여 greetingMessage라는 변수에 저장하고
(3) 콘솔 창에 출력하는 함수를 반환한다. 이때 클로저가 형성된다.
greetJohn 변수가 참조하는 것
greeting 함수에 John이라는 매개변수를 전달하여 호출한 결과로 *반환된 함수(클로저)를 참조한다.
greetJohn() 호출 시 결과와 이유
"Hello, John"
클로저 함수 덕분에, greeting 함수의 지역 변수 greetingMessage에 접근 가능하기 때문이다.7. 아래 코드의 실행 결과와 이유를 설명하세요.
function outer() { var a = 1; var b = { value: "first" }; function inner() { var a = 2; b.value = "second"; console.log(a); // 라인 1 console.log(b.value); // 라인 2 } inner(); console.log(a); // 라인 3 console.log(b.value); // 라인 4 } outer();
라인 답변 위치 접근 여부 1 2 inner 함수의 지역(함수) 스코프 내 위치 inner → inner 접근 가능 2 second outer 함수의 지역(함수) 스코프 내 위치 inner → outer 접근 가능 3 1 outer 함수의 지역(함수) 스코프 내 위치 outer → outer 접근 가능 4 second outer 함수의 지역(함수) 스코프 내 위치 outer → outer 접근 가능 객체 b의 경우, inner 함수 내에서 객체 b의 value 속성을 second로 변경한다.
이때, 객체가 참조형이므로 outer 지역(함수) 스코프 내 객체 b에도 영향을 미친다.
따라서 outer 함수 내에서도 b.value를 참조하면 변경된 값인 second가 출력된다.🏆 마무리
안녕하세요! 오랜만에 블로그로 돌아온 Three입니다.
'모던 자바스크립트 Deep Dive'를 통해 자바스크립트를 다시 공부 중인데,
실행 컨텍스트와 클로저 개념이 머리에 들어오지 않아
문제를 풀어보며 개념을 익힐 수 있도록 공부하였습니다.
창업경진대회와 함께, 네이버클라우드 캠프의 최종 프로젝트를 마무리하느라 약 1-2달간 블로그에 소홀했는데요,
꾸준히 공부하는 내용을 블로그에 업로드할 테니 쭉 지켜봐 주시길 바랄게요. 감사합니다 :)
'IT Study > FE' 카테고리의 다른 글
[CSS3] ID 셀렉터와 클래스 셀렉터를 구분하여 사용하는 이유는? (0) 2023.09.28 TypeScript 5.2의 새로운 키워드: 'using' - 자원 관리의 혁신 (0) 2023.09.18 [TypeScript] TypeScript의 필수 문법 (기본 개념) (2) 2023.07.17 [Next.js/코딩애플] 프로그램 만드는 법 (feat. 코딩애플) (0) 2023.07.10 [Next.js] MongoDB의 Error: querySrv ENODATA 해결하기 (0) 2023.07.03