티스토리 뷰
이선 브라운의 러닝 자바스크립트 책을 학습하고 기억해둘 만 한 부분을 야생학습하여 정리하였습니다.
스코프는 변수와 상수, 매개변수가 언제 어디서 정의되는지 결정합니다. 스코프는 프로그램의 현재 실행 중인 부분, 즉 실행 컨텍스트에서 현재 보이고 접근할 수 있는 식별자들을 의미합니다.
정적 스코프
자바스크립트의 전역 스코프, 블록 스코프, 함수 스코프는 정적입니다.
const x = 3;
function f() {
console.log(x);
console.log(y);
}
{
const y = 5;
f();
}
x는 함수 f를 정의할 때 존재하지만 y는 그렇지 않습니다. y는 다른 스코프에 존재하기 때문에 다른 스코프에서 y를 선언하고 그 스코프에서 f를 호출하더라도 y는 스코프 안에 존재하지 않습니다. 함수 f는 자신의 정의 될 때 접근할 수 있었던 식별자에는 접근할 수 있지만, 호출할 때 스코프에 있는 식별자에 접근할 수는 없습니다.
전역 스코프
스코프는 계층적이기 때문에 맨 아래 바탕이 되는 무언가가 있어야 하기 때문에 프로그램을 시작할 때 암시적으로 주어지는 스코프가 전역 스코프입니다.
블록 스코프
let 과 const는 식별자를 블록 스코프에서 선언합니다. 같은 이름의 변수가 외부에 하나, 내부 블록에 하나가 있다면 외부 변수는 내부 변수에 가려지는 효과를 얻습니다.
함수 스코프, 그리고 클로저
함수는 여기서 정의하고 저기서 호출하는 식으로 사용하므로 좀 더 복잡합니다. 함수가 특정 스코프에 접근할 수 있도록 의도적으로 그 스코프에서 정의하는 경우가 많습니다. 이런 것을 클로저라고 부릅니다. (스코프를 함수 주변으로 좁히는 것)
let globalFunc;
{
let blockVar = 'a';
globalFunc = function() {
console.log(blockVar);
}
}
globalFunc(); // "a"
blockVar 변수는 원래 같았더라면 블록을 벗어나면 메모리에서 제거되었을 것입니다. 그러나 클로저를 만들었기 때문에 해당 스코프는 유지되어 blockVar 변수를 함수를 통해 사용할 수 있게 됩니다.
함수 스코프와 호이스팅
ES6에서 let을 도입하기 전에는 var를 써서 변수를 선언했고 이렇게 선언한 변수들은 함수 스코프를 가졌습니다. var로 선언한 변수는 현재 스코프 안이라면 어디서든 사용할 수 있으며 선언하기도 전에 사용할 수 있습니다. 이는 호이스팅이라는 매커니즘 때문인데 자바스크립트는 함수나 전역 스코프 전체를 훑어보고 var로 선언한 변수를 맨 위로 끌어올립니다. 중요한 것은 선언만 끌어올려지고 할당은 끌어올려지지 않습니다. 호이스팅을 코드로 표현하자면 이렇습니다.
//1.let과 const의 블록 스코프
x; // ERROR x는 정의되지 않았습니다.
let x = 3;
--------------------
//2. var의 함수 스코프, 그리고 호이스팅
x; // undefined
var x = 3;
x; // 3
--------------------
//3. 2번 예제의 호이스팅의 해석방식
var x; //선언이 끌어올려집니다.
x; // undefined
x = 3;
x; // 3
호이스팅으로 인해 생길 수 있는 다른 문제는 var를 이용해 변수를 선언하면 같은 이름의 변수를 여러번 정의하더라도 무시합니다.
// 원래 코드
var x = 3;
if(x === 3){
var x = 2;
console.log(x);
}
console.log(x);
// 자바스크립트가 해석한 코드
var x;
x = 3;
if(x === 3){
x = 2;
console.log(x);
}
console.log(x);
var는 혼란스러운 코드를 야기할 수 있기 때문에 ES6를 적용하기에는 이른 상황을 제외하면 사용하지 않는 것을 권장합니다.
함수 호이스팅
var로 선언된 변수와 마찬가지로 함수 선언도 스코프 맨 위로 끌어올려집니다. 즉 함수를 선언하기 전에 호출할 수 있습니다.
f();
function f() {
console.log('f');
}
그러나 변수에 할당한 함수 표현식은 변수를 어떻게 정의했느냐에 따라서 변수의 스코프 규칙을 그대로 따릅니다.
f() // ERROR f는 정의되지 않았습니다.
let f = function() {
console.log('f');
}
스트릭트 모드
ES5문법에서는 암시적 전역 변수라는 것이 생길 수 있었는데 var로 변수를 선언하는 것을 잊으면 전역 변수를 참조하려 한다고 간주하고 그런 전역 변수가 존재하지 않는다면 스스로 만들었습니다. 당연히 예상치 못한 결과가 나올 수 있기 때문에 스트릭트 모드를 도입했습니다.
스트릭트 모드를 사용하기 위해서는 "use strict" 하나만으로 이루어진 행을 코드 맨 앞에 작성하면 됩니다. 전역 스코프에서 사용하면 스크립트 전체가, 함수 안 스코프에서 사용하면 해당 함수만 적용됩니다.
전역 스코프에 스트릭트 모드를 적용하면 스크립트의 전체 동작 방식이 바뀌기 때문에 주의해야 합니다. 다양한 스크립트를 불러와 사용하는 웹사이트에서 전역 스코프에 스트릭트 모드를 사용하면 불러온 스크립트 전체가 스트릭트 모드가 되기 때문에 해당 스크립트에만 전역으로 적용시키고 싶다면 코드 전체를 즉시 실행하는 함수 하나로 감싼 뒤에 사용하면 됩니다,
'Running JS 요약' 카테고리의 다른 글
JS - 객체와 객체지향 프로그래밍 (0) | 2021.01.11 |
---|---|
JS - 배열 (0) | 2021.01.06 |
JS - 함수 (0) | 2021.01.04 |
JS - 제어문, 그리고 표현식과 연산자 (0) | 2021.01.03 |
JS - 리터럴과 변수, 상수, 데이터 타입 (0) | 2020.12.23 |