최근 프론트엔드 경력자 면접을 봤습니다.
리액트를 사용하는 프론트엔드 개발자를 구하는 자리기에
리액트 관련 질문을 예상했지만, 보기 좋게 빗나갔습니다.
질문의 대다수가 웹개발의 기본인 JS, CSS에 대한 질문이었고 설명을 하려니 잘 안되는 부분이 있었습니다. 제가 받은 질문 중 저 스스로도 잘 모르거나 헷갈렸던 질문들에 대해 정리를 해보았습니다.
편의상 높임말을 사용하지 않고 작성하였습니다. 내용 중 틀린 내용이 있을 겁니다. 댓글로 알려주시면 찾아서 더욱 정확하게 수정하도록 하겠습니다.
웹표준을 지키는 문서타입이 여러 종류가 존재. HTML, XHTML 등이 있고, 각 문서들의 차이는 엄격하게 보냐 느슨하게 보냐의 차이
(내용 수정: 2019.01.27 : XHTML과 HTML의 차이점을 설명을 보충합니다.)
더욱 자세한 내용을 찾는 분은 wystan님의 블로그 를 참고해주세요.XHTML과 HTML의 차이점
- XHTML이 XML 문법을 따르므로 HTML과 문법 규칙이 약간 다르다.
- XHTML을 사용하면 할 수 있으나, HTML로는 불가능한 일이 있다.
- HTML을 사용하면 할 수 있으나, XHTML로는 불가능한 일이 있다.
- CSS를 이해하는 방식에 차이가 있다.
- 클라이언트 쪽의 스크립트(예: 자바 스크립트)를 다루는 방식에 차이가 있다.
아래는 HTML 방식. 태그가 닫히지 않았지만 이런 방식도 허용.
<!-- HTML 방식 -->
<img src="../img.png" alt="이미지는 그 스스로가 내용입니다.">
<p>HTML에서도 대부분의 p태그와 같이 태그를 닫아야 제대로 동작합니다.</p>
XHTML에서는 모든 태그는 닫혀있어야 한다. 아래는 img 태그도 닫은 것을 볼 수 있다. (우린 더 엄격한 방식인 XHTML에 익숙하다.)
<!-- XHTML 방식 -->
<img src="../img.png" alt="이미지는 그 스스로가 내용입니다."/>
<p>p 요소는 내용을 감싸기 때문에 열리고 닫힙니다.</p>
img태그는 br태그처럼 self closing tag로, 내부에 child를 가지지 않기 때문에 닫는 태그를 굳이 만들지 않아도 된다. w3schools에서는 empty elements라고 설명이 되어 있다.
/* self closing tag */
<br>
<img>
<meta>
<link>
<input>
<hr>
문서는 HTML5외에 대표적으로 아래의 것들이 있다. 문서 포맷이라고 볼수 있겠다.
Strict
엄격한 규격으로, 비표준 규격인 center, font 등을 사용할 수 없다.(css의 center와 font와 다른듯) 이러한 값은 css로 대체할 수 있고 그것을 권장한다.
Transitional
과도기적 규격으로, 표준이 정립되지 않은 때에 만들어진 문서들
Frameset
거의 사용하지 않는 타입인데, 나모웹에디터 시절 html안에 html을 분리해서 작성하는 방식
아래 그림의 예처럼 보면 header.html, menu.html, content.html을 따로 만들어 하나의 페이지를 구성하는 방식
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
html4.01 Transitional
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
HTML 4.01 Frameset
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" http://www.w3.org/TR/html4/frameset.dtd">
XHTML 1.0 Strict
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
XHTML 1.0 Transitional
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
XHTML 1.0 Frameset
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
XHTML 1.1
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
HTML5
<!DOCTYPE html>
크롬에서는 비표준일지라도 잘 보여준다. 비표준 문서
아래는 IE8에서 렌더링 한것으로, IE8에서 렌더링에서는 레이아웃이 깨지는 것을 볼 수 있다.
출처 : 웨버스터디 / doctype(독타입)
참고 : Hooney.net / HTML에서 문서형식(DocType)지정의 중요성
참고 : wystan님의 블로그 / XHTML과 HTML의 차이
HTML문서가 어떤내용을 담고 있고, 키워드는 무엇이며, 누가 만들었는지에 대한 정보. 즉, 문서 자체의 특성
대표적인 속서값으로는 subject, keywords, title, author 등이 있다.
페이지에 대한 메타정보로 검색 엔진에서 페이지에 대한 메타정보를 데이터 베이스화 해서 검색엔진에서 검색할 때 적절한 페이지를 보여주도록 한다.
또한, 모바일에 대한 처리인 viewport를 지정할 수 있다.
<title>HTML 태그의 속성 - ofcourse</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="태그는, 태그 내부에 값을 넣을 수 있을 뿐만 아니라, 태그마다 속성을 부여할 수 있습니다.">
<meta name="subject" content="태그의 속성">
<meta name="classification" content="html">
<meta name="keywords" content="www,web,world wide web,html,css,javascript">
<meta name="robots" content="ALL">
출처 : 홈짱닷컴
html에서 script 태그는 어느 위치에나 올수 있음
그러나 브라우저는 HTML의 구조와 CSS 스타일을 렌더링하는 도중 자바스크립트를 만나게 되면, 이에 대한 해석과 구현이 완료될 때까지 브라우저 렌더링을 멈추게 되는데, 이때 프리징 현상이 발생될 수 있다.
이렇게 때문에 자바스크립트의 삽입 위치에 따라 스크립트 실행순서와 브라우저 렌더링에 영향을 미치게된다.
앞에 둘 경우,
<head>
<script>
//코드내용
</script>
</head>
DOM이 해석되는 중에 스크립트를 읽기 때문에 장시간 완성되지 못한 화면을 노출 할 수 있다.
주로 문서를 초기화하는 가벼운 스크립트들이 사용되기를 권장한다.
DOM구조가 완성되지 않았기 때문에, 특정 엘리먼트의 참조가 실패할 수 있다.
그렇기 때문에 document.onload와 같은 로드 이벤트가 발생된 후 스크립트가 실행할 수 있도록 해야 한다.
....
<script>
//코드내용
</script>
</body>
브라우저가 렌더링이 완료된 상태에서 스크립트가 실행되기 때문에 화면이 뜬 후 스크립트를 읽는다.
document.onload 등을 사용하지 않기 때문에 대부분의 스크립트의 위치로 추천되는 위치다.
출처 : 흉내쟁이님의 블로그
이벤트 버블링 - 하위 엘리먼트에서 상위 엘리먼트로 이벤트가 전파되는 특성
<body>
<div class="one">
<div class="two">
<div class="three">
</div>
</div>
</div>
</body>
<script>
var divs = document.querySelectorAll('div');
divs.forEach(function(div) {
div.addEventListener('click', logEvent);
});
function logEvent(event) {
console.log(event.currentTarget.className);
}
</script>
이벤트 캡쳐링 - 버블링의 반대방향으로 진행
<body>
<div class="one">
<div class="two">
<div class="three">
</div>
</div>
</div>
</body>
<script>
var divs = document.querySelectorAll('div');
divs.forEach(function(div) {
div.addEventListener('click', logEvent, {
// 캡쳐링으로 설정. default는 false이므로 버블링으로 동작한다.
capture: true
});
});
function logEvent(event) {
console.log(event.currentTarget.className);
}
</script>
출처 : 캡틴 판교님의 블로그
실행가능한 코드를 형상화하고 구분하는 추상적인 개념
자바의 스택영역의 역할과 유사하다.
스코프 - 어떤 변수의 대한 유효범위
자바스크립트에서 스코프는 함수단위로 가졌는데, 보통의 언어들이 블락 스코프를 가지기 때문에 처음 자바스크립트를 배울 때 헷갈리는 요인이다.
자바스크립트에서 함수를 실행할 때 실행컨텍스트를 사용하는데, 이때 실행컨텍스트 별로 스코프를 가지기 때문이다.
6부터는 블락 스코프를 지원하는 변수들이 추가됐다. let, const
'인사이드 자바스크립트' 책과 등 실행컨텍스트를 설명하는 많은 곳에서 기준이 되는 버전은 es3 버전이라고 합니다. es5, 그리고 그 이후에도 몇가지 개념이 추가되었다고 합니다. 큰 틀에서는 벗어나지 않기 때문에 이 정도로 학습하여도 무방하다고 생각합니다.
실행 컨텍스트가 생성되어 코드가 실행되는 과정
1. 함수가 실행되면, 실행 컨텍스트를 생성한다.
실행 컨텍스트 |
---|
2. 컨텍스트가 생성된 후, 이 컨텍스트에서 실행에 필요한 정보들을 담을 객체인 활성 객체를 생성한다.
활성 객체가 형상화한 대상을 가지는 객체다.
실행 컨텍스트 |
---|
활성 객체 |
3. 활성 객체 내에, 매개변수의 정보를 갖는 arguments 객체를 생성하고, 함수가 호출될 때 사용된 인자들을 넣는다. arguments 객체는 유사배열 객체이다.
활성 객체 |
---|
|arguments --> [] (유사 배열)
4. 활성 객체 내에, 이 실행 컨텍스트의 스코프 체인을 생성한다.
스코프 체인은 리스트의 형태이며, 현재 함수를 호출한 함수의 스코프체인에 현재 활성객체를 마지막에 추가한 리스트를 현재 활성객체에 추가한다.
세바의 코딩교실 / 스코프 체인에 대한 설명
활성 객체 |
---|
|arguments -->
|[[scope]] --> [list]
5. 변수 객체가 생성되고, 함수가 가지고 있는 변수 및 객체 정보를 생성한다.
변수객체는 새로 생성되지만, 변수 객체와 활성 객체는 같다.
함수내에서 선언된 모든 변수를 생성한다. (코드가 실행되기 전에 변수에는 값이 할당되지 않기 때문에 생성한 변수, 함수들 모두 undefined가 된다.
활성 객체 == 변수 객체 |
---|
|arguments -->
|[[scope]] --> [list]
|foo : undefined
|var : undefined
|func : undefined
6. this에 대한 정보를 저장하며, 이 객체에 바인딩한다.
this에 바인딩할 대상이 없을 수도 있는데, 그때는 window로 바인딩한다.
브라우저의 경우 window 객체에 바인딩하지만 node라면 global 객체에 바인딩 --> 틀린 정보면 제보 부탁
활성 객체 == 변수 객체 |
---|
|arguments -->
|[[scope]] --> [list]
|foo : undefined
|var : undefined
|func : undefined
|this : object
7. 활성 객체(변수 객체)가 생성되면 코드를 실행할 준비를 마침. 코드를 실행시킨다.
실행 컨텍스트 |
---|
활성 객체 |
코드를 실행하면 할당하지 실제로 foo, var, func에 값이 할당된다.
8. 실행컨텍스트 파기. 코드를 실행 후 실행컨텍스트를 파기한다.
(추가 2019.01.27)
wonmin님께서 댓글로 실행컨텍스트를 시각적으로 확인할 수 있는 링크를 알려주셨습니다. tylermcginnis / 실행컨텍스트를 시각적으로 확인
자바스크립트의 큰 특징 중 하나가 '단일 스레드' 기반의 언어라는 점이다. 이벤트 루프는 이러한 자바스크립트가 '동시성'을 지원하는 방식이다.동기방식 프로그래밍(JAVA)에 익숙한 사람들이 비동기 방식의 이벤트 루프에 익숙치 않는 경우가 있다.
ES6 이전의 ECMAScript에는 이벤트 루프가 없다고 한다. 이런 동시성에 대한 처리는 브라우저나 Node.js가 담당한다고 한다.(그래서 js책에는 이벤트 루프에 대한 언급이 거의 없고 node.js 책에는 포함시키는 듯) V8같은 자바스크립트 엔진은 단순히 호출 스택을 사용하여 요청을 순차적으로 호출 스택에 담아 처리만 한다.
이벤트 루프는 아래의 그림으로 표현된다. setTimeout
, XMLHttpRequest
가 같은 함수들은 자바스크립트 엔진이 아닌 web APIs에 정의가 되어 있다.
잠깐 소개하자면 노드는 아래 그림과 같은 구조를 가지며, libuv
라는 라이브러리를 사용하여 이벤트 루프로 동작한다.
아래 예제를 보자.
function delay() {
for (var i = 0; i < 100000; i++);
}
function foo() {
delay();
bar();
console.log('foo!'); // (3)
}
function bar() {
delay();
console.log('bar!'); // (2)
}
function baz() {
console.log('baz!'); // (4)
}
setTimeout(baz, 10); // (1)
foo();
------------------ console -------------------
bar!
foo!
baz!
call stack
을 나타내면 아래오 와같다. 아시겠지만 setTimeout
에서 0.01초 후 실행되는 것을 보장하지 못했다. setTimeout
은 실행 시간을 보장하지 못한다.!
setTimeout
함수는 실행 후 callback
함수(여기선 bar
)를 task queue
에 넣는다. task queue
에 들어간 이벤트는 바로 실행되지 않는다.
그리곤 foo
, bar
가 위 그림 처럼 호출 스택에 쌓이게 되고, call stack
에 stack frame
(call stack
에서 하나의 스택을 스택 프레임이라 한다.)이 남아 있다면, event loop
는 아무것도 하지 않는다.
foo
함수가 실행된 후 call stack
은 비어있게 되고, event loop
는 task queue
에서 대기 중인 첫 번째 태스크를 꺼내 call stack
에 추가한다.
event loop
를 가상 코드로 나타내면 아래와 같다.
while(queue.waitForMessage()){
queue.processNextMessage();
}
비동기 api는 콜백 함수를 task queue
에 추가 한다.
그런데, micro task
라는 개념이 등장 한다. 아래 예제 코드를 보자.
setTimeout(function() { // (A)
console.log('A');
}, 0);
Promise.resolve().then(function() { // (B)
console.log('B');
}).then(function() { // (C)
console.log('C');
});
예상해보자.. A -> B -> C 일 까? B -> C -> A일 까?
Promise
가 바로 micro task
를 사용 한다. micro task
는 일반 task
보다 높은 우선순위를 가진다고 할 수 있다. 그렇기 때문에 B -> C -> A 순으로 출력하게 된다.
프라미스A+ 스펙문서를 보면
Promise
가micro task
와 일반task
모두 사용할 수 있다고 적혀있다
(추가 2019.01.27)
zerocho님의 Node.js 교과서에 참고 자료로 이벤트 루프에 대한 시각적 설명 링크가 있는데, 이벤트 루프를 이해하기 좋을 것 같습니다. latentflip / 이벤트 루프 시각적 표현
출처 : Toast Meetup
참조 : Huiseoul - v8 엔진, Huiseoul - js의 엔진, 런타임, 콜스택
장점은 코드가 간결하지만, 디버깅을 어렵게 한다.
id는 유일한 값, class는 여러번 중복이 가능하며, 여러 값을 띄어쓰기로 구분하여 넣을 수 있음.
문서내에 id를 통해 해당 위치로 이동할 수 있다. (href="#id"
)
이것을 응용하여 SPA를 만든다고 한다. 바닐라 스크립트로 SPA 만드는 예제
예제를 먼저 보면, container 내부에 left와 right 두개의 박스가 들어있는 태그다. 물론 left, right는 각각 float left, float right를 주었다.
<head>
<style type="text/css">
.container {
padding: 10px;
border: 10px solid #ddd;
background: #fff;
}
.red-box {
width: 55%;
padding: 10px;
border: 10px solid #000;
background: #f00;
}
</style>
</head>
<body>
<div class="container">
<p>container</p>
<div id="left" class="red-box" style="background:aqua; float:left">
<p><strong>left</strong></p>
</div>
<div class="red-box" style="float: right;">
<p><strong>#float-box {float:right;}</strong></p>
</div>
</div>
<div style="background:plum">
<p>footer</p>
</div>
</body>
</html>
이런 형태를 예상했지만, 아래 코드는 조금 다르게 그려진다
이런식으로 자식이 float속성을 가지면 부모의 너비는 자식의 너비를 계산하지 않고 그리는 것이다.
이러한 문제를 해결하는 4가지 방법이 존재하지만, 그 중 추천되는 방식 두 가지를 소개한다. 나머지 두 방법은 부분적으로 해결 가능하나 사이드 이펙트를 발생시킬 수 있기 때문에 소개하지 않는다.
(추가 2019.01.27)
제가 참고한 나라디자인에서 소개된 방식외에 제가 즐겨 쓰는 방법을 소개합니다.
부모 태그의 display를 inline-block으로 주면 자식 중에 float 속성을 가져도 크기를 제대로 계산할 수 있습니다.
첫 번째 방법 : float을 빈 엘리먼트로 clear하는 방법
float자식을 가지는 container의 마지막 자식에 빈 엘리먼트를 추가하고 clear: both
스타일을 준다.
<body>
<div class="container">
...
<div style="clear: both;"></div>
</div>
</body>
두 번째 방법 : :after에 clear속성 넣기
.container:after {
content: "";
clear: both;
display: block;
}
이 방법은 세가지 속성을 모두 추가 해야 동작 한다. 대신 불필요한 빈 엘리먼트가 추가 되지 않기 때문에 가장 추천되는 방식이다. (내부적으로 빈 텍스트 영역이 생긴다고 한다.)
출처 : 나라디자인
비교 대상 css 애니메이션, jquery 애니메이션, velocity.js 애니메이션
속도차이
velocity.js > css 애니메이션 > jquery 애니메이션
velocity.js, GSAP 등은 구글이나 어도비 같은 회사들이 모바일 페이지에서 최적화된 애니메이션을 위해 사용하는 라이브러리
jquery 애니메이션이 느린 이유는 애초에 jquery 가 성능에 초점을 두지 않았기 때문
jquery는 레이아웃 스레싱이나 가비지 콜렉션 트리거가 발생하기도 함
아래는 레이아웃 스레싱이 일어나는 상황과 아닌 상황을 보여줌
var currentTop, currentLeft;
// 레이아웃 스레싱 발생
currentTop = element.style.top; // 레이아웃을 계산
element.style.top = currentTop;
currentLeft = element.style.left; // 위에서 style.top을 설정했기 때문에 레이아웃을 다시 구함
element.style.left = currentLeft + 1;
// 레이아웃 스레싱이 없음
currentTop = element.style.top; // 레이아웃을 계산
currentLeft = element.style.left; // 변경 사항이 없기 때문에 레이아웃을 그대로 가져옴
element.style.top = currentTop;
element.style.left = currentLeft + 1;
jquery 애니메이션이 느린 또 다른 이유로는 requestAnimationFrame이 아닌 setInterval을 사용하는 것이다. (requestAnimationFame은 줄여서 RAF로 표기)
var startingTop = 0;
function tick () {
element.style.top = (startingTop += 1/60);
}
// 60fps를 만족하기 위해 16ms마다 실행. (16ms * 60 == 960ms, 약 1000ms)
setInterval(tick, 16);
// 브라우저가 기본적으로 60fps로 실행시킴. 브라우저가 알아서 상태를 판단하여, 때때로 몇몇 프레임을 스킵할 수 있음
window.requestAnimationFrame(tick);
setInterval의 경우 명령을 어떡해서든 실행시키기 때문에 성능이 좋지 않을 수 있습니다. 반면에, RAF는 조금 더 유연한 대처가 가능하죠.
google developers web group에서는 UI 요소에 대해 더 작은 자체 포함 상태가 있는 경우 CSS 애니메이션을 사용하고, 보다 세밀한 제어를 위해서는 자바스크립트 사용을 권장한다. 링크1
또, 가급적이면 애니메이션을 opacity
나 transform
로 제한할 것을 권장한다. 그 이유로는 애니메이션이 레이아웃(리플로우)을 자주 유발하기 때문이다. 링크2
레이아웃(리플로우)을 발생시키는 css 속성을 css 트리거라고 한다
다음은 velocity.js의 애니메이션 최적화 방법이다.
높은 수준의 최적화 애니메이션을 사용하기 위해서는 라이브러리를 사용하는 것이 제일 좋을 것 같다.
출처 : CyberImagination Blog
웹 개발시 주요한 이슈중 하나로, 웹 개발을 하다보면 어떤 경로던 이 이슈를 마주하게 된다.
동일 출처 정책(same-origin-policy)은 하나의 웹 페이지에서 다른 도메인 서버에 요청하는 것을 제한하는 것이다. 제한하는 이유는 간단한데, 내가 네이버라고 가정해보자.
누군가 다른 포탈 서비스를 만들고, 네이버에서 검색한 결과만 가져온다면 문제가 되지 않을까? 때문에 보통의 브라우저에서는 외부 도메인으로의 Ajax로 요청을 보낼 때, cors를 체킹한다.
아래는 크롬에서 발생하는 cors 에러창이다.
그런데 어떤 경우에는 이러한 제한이 또다른 문제를 발생시킨다는 것이다. 이번엔 내가 카카오라 하자. 카카오톡 앱에서는 #검색으로 다음에서의 검색 결과를 가져오는 서비스가 있다. 이때, 다음과 카카오는 다른 도메인을 사용하기 때문에 cors문제가 발생하게 된다. 특정 사용자에게는 허용을 해줘야 하는 경우가 생기게 된다.
(심지어 https://abc.com:8080과 https://abc.com:8888 사이에서도 CORS문제는 발생한다!!!)
이러한 문제를 해결할 수 있는 여러 방법들이 있지만, 제일 일반적인 방법인 헤더를 이용하는 방법과 jsonp에 대해서 소개한다.
먼저 헤더를 이용하는 방법이다.
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
HTTP Request 요청에 앞서 Preflight Request 라는 요청이 발생되는데, 이는 해당 서버에 요청하는 메서드가 실행 가능한지(권한이 있는지) 확인을 위한 요청. Preflight Request는 OPTIONS 메서드를 통해 서버에 전달된다. (위의 Methods 설정에서 OPTIONS 를 허용해 주었다.)
여기서 Access-Control-Max-Age 는 Preflight request를 캐시할 시간. 단위는 초단위이며, 3,600초는 1시간. Preflight Request를 웹브라우저에 캐시한다면 최소 1시간동안에는 서버에 재 요청하지 않음.
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
response.setHeader("Access-Control-Allow-Origin", "*");
출처: 이러쿵저러쿵
CORS를 해결하는 유명한 방법 중 하나가 JSONP를 사용하는 것이다
jsonp의 원리는 다음과 같다.
<script type="text/javascript" src="http://kingbbode.com/result.json"></script>
html 문서에 script태그는 보안 정책에 적용되지 않는 점을 이용한 것
<script type="text/javascript" src="http://kingbbode.com/result.json?callback=parseResponse"></script>
여기서 script 태그는 javascript 내용을 포함
시킨 것이 아니라 실행
시킨 것이다.
아래 코드는 jsonp를 호출할 script태그를 동적으로 생성하는 코드다. 물론 생성과 동시에 실행시킨다.
var script = document.createElement('script');
script.src = '//kingbbode.com/jsonp?callback=parseResponse';
document.getElementsByTagName('head')[0].appendChild(script);
function parseResponse(data){
//callback method
}
그러나 jsonp는 서버에서 지원하지 않으면 사용할 수 없다.
parseResponse함수가 실행되려면 script태그는 다음과 같아야 한다.
<script type="text/javascript">
parseResponse({"Name": "Foo", "Id": 1234, "Rank": 7})
</script>
서버에서는 요청된 내용을 json형태의 응답을 만들어 callback 파라미터로 전달 받은 콜백이름을 래핑하여 위와 같은 응답을 내려준 것이다.
출처: Seotory, 개발노트 - kingbbode
여기까지가 인터뷰에서 질문에 대한 정리입니다. 웹 개발자 면접을 준비하시는 분들에게 도움이 되었으면 좋겠습니다.
실행 컨텍스트는 이런 페이지에서 시각적으로도 볼 수 있습니다~^^
https://tylermcginnis.com/javascript-visualizer/
출처는 이 블로그 입니다~!!
https://tylermcginnis.com/ultimate-guide-to-execution-contexts-hoisting-scopes-and-closures-in-javascript/
스터디때 잘 들었습니다 감사합니다 ^^