변수에 접근할 수 있는 범위이다.
function add(x, y) {
// 매개 변수는 함수 몸체 내부에서만 참조할 수 있다.
// 즉, 매개변수의 스코프(유효범위)는 함수 몸체 내부다.
console.log(x, y); // 2 5
return x + y; // 7
}
add(2, 5);
// 매개 변수는 함수 몸체 내부에서만 참조할 수 있다.
console.log(x, y); // ReferenceError: x is not defined
예제)
var x = 'global';
function foo() {
var x = 'local'
console.log(x); // 1번
}
foo();
console.log(x); // 2번
- var x = 'global'은 전역변수이고 var x = 'local'은 foo 함수 내부에 있는 지역변수이다.
- 1번을 출력하면 local이고 2번을 출력하면 global이다.
자바스크립트에서 스코프를 구분해보면 다음과 같이 2가지로 나눌 수 있다.
모든 변수는 스코프를 갖는다. 변수의 관점에서 스코프를 구분하면 다음과 같이 2가지로 나눌 수 있다.
변수를 참조할 때 자바스크립트 엔진은 스코프 체인(스코프가 계층적 연결된 것)을 통해 변수를 참조하는 코드의 스코프에서 시작하여 상위 스코프 방향으로 이동하며 선언된 변수를 검색한다.
즉, 위를 따르면 상위 스코프에서 유효한 변수는 하위 스코프에서 자유롭게 참조 가능하지만 하위 스코프에서 유요한 변수는 상위 스코프에서 참조할 수 없다.
var x = 1;
if (true) {
var x = 10;
}
console.log(x); // 10
var i = 10;
for (var i = 0; i < 5; i++) {
console.log(i); // 0 1 2 3 4
}
console.log(i); // 5
var x = 1;
function foo() {
var x = 10;
bar();
}
function bar() {
console.log(x);
}
foo(); // 1
bar(); // 1
var x = 10; // 전역 변수
function foo () {
// 선언하지 않은 식별자
y = 20;
console.log(x + y);
}
foo(); // 30
y = 20을 window.y = 20으로 해석하여 프로퍼티를 동적 생성한다. 결국 y는 전역 객체의 프로퍼티가 되어 마치 전역 변수처럼 동작한다. 이러한 현상을 암묵적 전역(implicit global)이라 한다.
하지만 y는 변수 선언없이 단지 전역 객체의 프로퍼티로 추가되었을 뿐이다. 따라서 y는 변수가 아니다. 따라서 변수가 아닌 y는 변수 호이스팅이 발생하지 않는다.
function foo() { // 변수 x 생성
var x = 'local' // 변수 x에 값 할당
console.log(x); // local
return x; // 변수 x 소멸
}
foo();
console.log(x); // ReferenceError: x is not defined
전역 객체는 코드가 실행되기 이전 단계에 자바스크립트 엔진에 의해 어떤 객체보다도 먼저 생성되는 특수한 객체다.
브라우저 환경에서 전역객체는 window이므로 브라우저 환경에서 var키워드로 선언한 전역 변수는 전역 객체 window 프로퍼티다.
(function () {
var foo = 10; // 즉시 실행 함수의 지역 변수
// ...
}());
console.log(foo);
var MYAPP = {}; // 전역 네임스페이스 객체
MYAPP.name = 'Park';
console.log(MYAPP.name); // PARK
캡슐화는 객체의 상태를 나타내는 프로퍼티와 프로퍼티를 참조하고 조작할 수 있는 동작인 메서드를 하나로 묶는 것.
var Counter = (function() {
// private 변수
var num = 0;
// 외부로 공개할 데이터나 메서드를 프로퍼티로 추가한 객체를 반환한다.
return {
increase() {
return ++num;
},
decrease() {
return --num;
}
};
}());
// private 변수는 외부로 노출되지 않는다.
console.log(Counter.num); // undefined;
console.log(Counter.increase()); // 1
console.log(Counter.increase()); // 2
console.log(Counter.decrease()); // 1
console.log(Counter.decrease()); // 0
<script type="module" src="lib.mjs"></script>
<script type="module" src="app.mjs"></script>
var x = 1;
var y = 1;
// var 키워드로 선언된 변수는 같은 스코프 내에서 중복 선언을 허용한다.
// 초기화문이 있는 변수 선언문은 자바스크립트 엔진에 의해 var 키워드가 없는 것처럼 동작한다.
var x = 100;
// 초기화문이 없는 변수 선언문은 무시된다.
var y;
console.log(x); // 100
console.log(y); // 1
var x = 1;
if (true) {
// x는 전역 변수다. 이미 선언된 전역 변수 x 변수는 중복선언된다.
// 이는 의도치 않게 변수값이 변경되는 부작용 발생
var x = 10;
};
console.log(x); // 10
// 이 시점에는 변수 호이스팅에 의해 이미 foo 변수가 선언되었다.(1. 선언 단계)
// 변수 foo는 undefined로 초기화된다. (2. 초기화 단계)
console.log(foo); // undefined;
// 변수에 값을 할당(3. 할당 단계);
foo = 123;
console.log(foo); // 123
// 변수 선언은 런타임 이전에 자바스크립트 엔진에 의해 암묵적으로 실행된다.
var foo;
let bar = 123;
let bar = 456; // SyntaxError: Identifier 'bar' has already been declared
let foo = 1; // 전역 변수
{
let foo = 2; // 지역 변수
let bar = 3; // 지역 변수
}
console.log(foo); // 1
console.log(bar); // ReferenceError: bar is not defined
console.log(foo); // ReferenceError: foo is not defined
let foo
let 키워드로 선언한 변수는 호이스팅이 발생하지 않는 것처럼 보이지만 실제로는 그렇지 않다. 자바스크립트는 ES6에서 도입된 let, const를 포함해서 모든 선언을 호이스팅한다.
단, ES6에서 도입된 let, const, class를 사용한 선언문은 호이스팅이 발생하지 않는 것처럼 동작한다.
let foo = 1; // 전역 변수
{
console.log(foo); // ReferenceError: Cannot acces 'foo' before initialization
let foo = 2; // 지역 변수
}
{
// 변수 호이스팅이 발생하지 않는 것처럼 동작한다.
console.log(foo); // ReferenceError: Cannot acces 'foo' before initialization
const foo = 1;
console.log(foo); // 1
}
// 블록 레벨 스코프를 갖는다.
console.log(foo); // ReferenceError: foo is not defined
const foo = 1;
foo = 2; // TypeError: Assignment to constant varibable.
상수는 재할당이 금지된 변수를 말한다.
const 키워드와 객체
const person = {
name: 'Park'
};
// 객체는 변경 가능한 값이다. 따라서 재할당 없이 변경이 가능.
person.name = 'Lee'
console.log(person); // {name: "Lee"}
위에서 let과 const는 실제로 호이스팅이 되지만 호이스팅이 안되는 것처럼 동작한다고 했다.
즉, 호이스팅은 모든 변수, 함수에서 일어난다.
Temporal Dead Zone 에 의해서 let, const의 호이스팅은 에러를 발생시킨다.
Temporal Dead Zone 에 의해var
와 같은 실행을 막아주었다.
함수의 경우 호이스팅으로 가독성을 높일 수도 있다.
이번에 공부한 스코프와 var, let, const에 대해서 어느정도 알고 있다라고 생각했는데 책을 통해서 좀 더 깊게 공부해보니
자세히 몰랐던 내용도 새로 알 수 있었고 특히 호이스팅에 대해서 좀 더 자세하게 공부할 수 있었다.
참고 PoiemaWeb