일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- AR
- vuetify
- CI/CD
- PDO
- Component
- version mismatch
- PHP
- WebVR
- vuex
- auth0
- JavaScript
- Three.js
- 상태관리
- Node
- package-lock.json
- 3d
- javscript
- bootstrap
- npx
- vue
- VR
- EM6
- promise
- array
- vue-template-compiler
- aframe
- JS
- A-Frame
- WebXR
- web
- Today
- Total
대가는 결과를 만든다
스코프, 호이스팅, 클로저 정리하기 본문
1. 스코프란?
- scope란 사전적 의미로 '범위'라는 의미를 지닌다.
- 자바스크립트에서 변수에 접근할 수 있는 범위 혹은 변수가 영향을 끼칠 수 있는 범위라고 생각하면 된다.
- 크게 나누면 전역, 지역 스코프로 나눌 수 있지만 스코프 레벨을 좀더 자세하게 나누자면, 함수 레벨 스코프, 블록 레벨 스코프(ES6), 렉시컬 스코프로 나눌 수 있다.
1-1. 함수레벨 스코프
- 자바스크립트에서 var 키워드로 선언된 변수, 함수 선언식으로 만들어진 함수는 함수 레벨 스코프를 지닌다.
- 변수는 함수 내부 전체에서(만) 유효한 식별자가 된다.
1-2. 블록 레벨 스코프
- ES6의 let, const 키워드는 블록레벨 스코프 변수를 만들어 준다.
- 여기서 블록이란 if/else, while/for 내부로 정해지는 범위를 말한다.
- ES6에서 let, const가 도입되면서 var는 사용하지 않는다. let으로 대체가 가능하고, var는 함수 전체에 대한 스코프를 가지므로, 혼란을 야기할 수 있다.
1-3. 렉시컬 스코프
- 호출스택과 관계없이 각각의 소스코드가 작성된 그 문맥을 기준으로 데이터를 대응하고, 그 대응이 런타임에서 변하지 않는다.
* this는 제외
var x = 'global';
funtion foo(){
var x = 'local';
bar();
}
function bar(){
console.log(x);
}
foo(); //global 출력
bar(); //global 출력
2. 호이스팅
- 호이스팅은 사전적 의미로 '끌어올림' 이라는 의미를 지닌다.
- 자바스크립트 엔진은 코드를 컴파일-> 인터프리팅의 순으로 처리하는데,
컴파일 단계에서 var a = 2; 라는 코드를 두개의 구문으로 분리하여 본다.
=> var a; //변수 선언 단계
=> a=2; //변수 초기화 단계
- 선언 단계에서는 그 선언이 코드에서 어디에 위치하든 해당 스코프의 컴파일 단계에서 처리한다.
- 따라서 선언 단계가 스코프의 꼭대기로 끌어올려지는 것을 호이스팅이라고 한다.
- 하지만 해당 값을 선언하기도 전에 참조 가능한 것이랑 햇갈리면 안된다.
//선언부가 호이스팅되므로 2를 정상적으로 출력하는 함수
function foo() {
a=2;
var a=2;
console.log(a);
}
//선언 전 참조되는 경우에는 undefined를 반환
function foo(){
console.log(a);
var a=2;
}
* 블록 스코프인 ES6의 let도 호이스팅 되지만, 선언 전에 참조할 경우 undefied를 반환하지 않고 ReferenceError를 발생시킨다.
3. 클로저
- (Closure)클로저는 사전적인 의미로 '포섭'
- 클로저 = 함수 + 함수를 둘러싼 환경(렉시컬 환경)
- 자바스크립트에서 클로저는 함수가 생성되는 시점에 생성
즉, 함수가 생성될 때 그 함수의 렉시컬 환경을 포섭하여, 실행될 때 함께 이용된다.
개념적으로는 이해가 되는 것 같다. 그러면 코드로 클로저와 클로저가 아닌 것을 구별해보자.
아래 두 예제는 모두 blue를 출력하지만, 첫번째는 클로저의 예시가 아니고, 두번째는 클로저의 예시다.
클로저가 아닌 예시 : bar()는 foo안에서 실행되었지 foo밖에서 실행되는 것이 아니므로 정확히 클로저의 예라고 볼 수 없다.
function foo(){
var color = 'blue';
//foo 스코프를 외부 렉시컬 환경으로 참조하여 저장한다.
function bar(){
console.log(color); //foo의 color 값인 'blue'를 참조한다.
}
bar();
}
foo(); //blue를 출력
클로저 예시 : bar()s는 자신이 생성한 렉시컬 스코프를 벗어나 호출되었고, 현재 실행 스택과 관련 없는 foo를 거쳐 color 값을 참조했다. bar()와 같은 함수를 클로저라고 한다.
var color = 'red';
function foo(){
var color = 'blue';
//bar는 외부 렉시컬 환경 참조로 foo의 color를 저장
function bar(){
console.log(color)
}
return bar;
}
var baz = foo(); //foo가 반환한 bar() 함수는 baz로 재명명된다.
baz(); //blue를 출력
//bar는 자신의 스코프에서 color를 먼저 찾고, 그다음 외부 렉시컬 환경을 참조해서 color를 찾는다.
참고 : https://meetup.toast.com/posts/86
'개발 > Javascript' 카테고리의 다른 글
window 혹은 특정 element에서 scroll top (0) | 2020.06.03 |
---|---|
js로 html의 class를 추가/제거/토글하기 (0) | 2020.05.20 |
iterator/iterable, generator에 대한 정리 (0) | 2020.03.24 |
자주 햇갈리는 javascript ES, ECMA 표기법 정리 (0) | 2020.03.23 |
async & await을 정리해보자 (ECMA 2017) (0) | 2020.03.16 |