JavaScript에 대한 깊은 이해를 하기 위해서는 클로저(Closure), 스코프(Scope), 호이스팅(Hoisting)에 대해 알아야한다.
scope의 사전적인 의미는 범위(유효 범위).
전역 스코프는 변수가 함수 바깥이나 {}바깥에서 선언되어 있는 것을 뜻함.
var global = 'global';
function test(){
console.log(global); // global
};
console.log(global); // global
함수 내에서 선언된 변수는 함수 내에서만 유효하며 함수 외부에서는 참조할 수 없다. 즉, 함수 내부에서 선언한 변수는 지역 변수이며 함수 외부에서 선언한 변수는 모두 전역 변수이다.
var global = 'global'; // 전역변수
(function () {
var local = 'local'; // 지역변수
})();
console.log(global); // global
console.log(local); // "local" is not defined
최소 권한 노출의 원칙을 확장하여 정보를 함수 안에 숨기고 나아가 정보를 코드 블록안에 숨기기 위한 도구다.
우리가 변수를 {} 괄호 안에 const나 let키워드로 선언했을 때, 우리는 {}괄호 안에서만 이 변수에 접근할 수 있다. (ES6에서 새롭게 등장)
{
const block = 'block-level-scope!'
console.log(block) // 'block-level-scope!'
}
console.log(block) // Error, block is not defined
흔히 "정적 범위", "정적 스코프"라고 번역. 렉시컬 스코프란, 함수를 어디서 호출하는지가 아니라 어떤 스코프에 선언하였는지에 따라 결정된다는 것이다.
var global = 'global';
function foo() {
console.log(global); //
}
function bar() {
var global = 'local';
foo();
}
bar(); // global
bar()실행 값이 local로 나올것 같지만, foo()는 bar()에서 호출되든 어떤 함수 안에서 호출되든지 상관없이, 무조건 자기 자신의 스코프를 찾아보고 그 이후에는 전역 스코프를 찾기 때문에 global로 출력.
local이 나오게 하고싶으면 지역변수 var를 선언할 것이 아니라 전역변수 var의 값을 바꾸면 된다.
var global = 'global';
function foo() {
console.log(global); //
}
function bar() {
global = 'local';
foo();
}
bar(); // local
클로저는 반환된 내부함수가 자신이 선언됐을 때의 환경(Lexical environment)인 스코프를 기억하여 자신이 선언됐을 때의 환경(스코프) 밖에서 호출되어도 그 환경(스코프)에 접근할 수 있는 함수이다.
쉽게 자신이 생성될때의 환경을 기억하는 함수.
var js = 'javascript';
function outer(){
var js = 'js';
function inner(){
console.log(js)
}
return inner;
}
let fn = outer();
fn(); //js를 출력
let fn = outer(); 부분에서 outer함수는 실행 되고 종료 되어 콜스택에서 사라졌기 때문에 변수 js도 없어야한다. 하지만 fn에 할당된 inner함수를 실행 시켯을때 변수 js값이 잘 출력된다.
즉, 어떠한 외부 함수가 특정 내부 함수를 포함하고 있을 때, 외부 함수보다 내부 함수가 더 오래 살아있는 경우에는 외부 함수 밖에서 내부 함수를 호출해도 외부 함수의 지역 변수에 접근할 수 있다는 뜻이다.
함수 안에 있는 선언들을 모두 끌어올려서 해당 함수 유효 범위의 최상단에 선언하는 것을 말한다.
var 키워드를 사용해 선언했을때만 이루어진다.
console.log(hoisting); //undefined
var hoisting = "hoisting";
console.log(hoisting); // 'hoisting'
함수 선언식일 경우에만 이루어진다.
fnHoisting1(); // fnHoisting1
fnHoisting2(); // Uncaught TypeError
// 함수 선언식
function fnHoisting1() {
console.log("fnHoisting1");
};
// 함수 표현식
var fnHoisting2 = function() {
console.log("fnHoisting2");
}