러닝 자바스크립트 스터디 자료 - CHAPTER 7. 스코프

스코프는 변수와 상수, 매개변수가 언제 어디서 정의되는지 결정합니다.

변수가 존재하지 않으면 그 변수는 스코프안에 ‘있지않음’을 직관적으로 알수 있다.
즉 아직 선언하지 않은 변수나 함수가 종료되면서 존재하지 않게 된 변수는 분명 스코프안에 ‘있지 않다’

스코프존재를 구별해야 한다.
가시성이라고도 불리는 스코프는 프로그램의 현재 실행 중인 부분, 즉 실행 컨텍스트에서 현재 보이고 접근 할 수 있는 식별자들을 말한다. 반면 존재한다는 말은 식별자가 메모리에 할당된 무언가를 가리키고 있다는 뜻이다.

정적스코프와 동적스코프

자바스크립트의 스코프는 정적이다. 소스코드만 봐도 변수가 스코프에 있는지 판단 할 수 있다.
다만 소스코드만 봐도 즉시 스코프를 분명히 알 수 있다는 뜻은 아니다.

정적스코프

어떤 변수가 함수 스코프 안에 잇는지 함수를 정의 할 때 알 수 있다는 뜻 이다. 호출할 때 알 수 있는 것은 아니다.
자신이 정의 될 때 접근 할 수 있었던 식별자에는 여전히 접근 할 수 있지만, 호출 할 때 스코프에 있는 식별자에는 접근 할 수 없다.

전역스코프

전역스코프에서 선언한 것은 무엇이든 프로그램의 모든 스코프에서 볼 수 있다.
전역스코프에서 선언된 것들을 전역변수(global)라고 합니다.
전역스코프에 의존하는 것은 피해야한다.

블록스코프

letconst 는 식별자를 블록스코프에서 선언합니다.
블록스코프는 블록(문을 중괄호로 묶은것)의 스코프에서만 보이는 식별자를 의미한다.

변수 숨기기

1
2
3
4
5
6
7
8
9
10
11
12
{
// 외부블록
let x = 'blue';
console.log(x); // "blue"
{
// 내부블록
let x = 3;
console.log(x) // "3"
}
console.log(x); // "blue"
}
console.log(typeof x); // "undefined"; x는 스코프에 있지 않습니다.

내부블럭의 x는 외부 블록에서 정의한 x와 이름만 같을 뿐 다른 변수이므로 외부 스코프의 x를 숨기는 효과가 있다.
실행 흐름이 내부 블록에 들어가 새 변수 x를 정의 하는 순간 두 변수는 모두 스코프안에 있다.(외부 변수가 숨겨짐)
변수의 이름이 같으므로 외부 스코프에 있는 변수에 접근할 방법이 없다.

스코프 체인

스코프가 계속 연결됨(중첩), 스코프안에 스코프가 있는 형태
내부 함수에서는 외부 함수의 변수에 접근이 가능하지만 외부 함수에서는 내부 함수의 변수에 접근 할수 없다.
모든 함수들은 전역 객체에 접근 할 수 있다.

함수, 클로저, 정적스코프

클로저는 함수가 특정 스코프에 접근 할 수 있도록 의도적으로 그 스코프에서 정의 하는 경우, 스코프를 함수 주변으로 좁히는 것을 말한다.

1
2
3
4
5
6
7
8
let globalFunc;                   // 정의 되지 않는 전역 함수
{
let blockVar = "a" // 블록 스코프에 있는 변수
globalFunc = function(){
console.log(blockVar);
}
}
globalFunc(); // "a"

globalFunc는 블록 안에서 값을 할당받았습니다. 이 블록 스크로와 그 부모인 전역 스코프가 클로저를 형성합니다.
globalFunc를 어디서 호출하든 이 함수는 클로저에 들어있는 식별자에 접근 할수 있다.
globalFunc을 호출하면, 이 함수는 스코프에서 빠져나왔음에도 불구하고 blockVar에 접근 할 수 있습니다.

즉시실행함수

IIFE(즉시실행함수)는 함수를 선언하고 즉시 실행합니다.

1
2
3
(function(){
// 즉시실행함수 바디
})();

IIFE의 장점은 내부에 있는 것들이 모두 자신만의 스코프를 가지지만 IIFE 자체는 함수이므로 그 스코프 밖으로 무언가를 내보낼 수 있는 것이다.

내부 변수는 IIFE안에 안전하게 보관되어 있으므로 손댈 방법이 없다.
ES6에서 블록스코프 변수를 도입하면서 IIFE가 필요한 경우가 줄긴 했지만 여전히 널리 쓰인다.
클로저를 만들고 클로저에서 무언가 반환 받을 때에는 유용하게 쓸 수 있다.

함수스코프와 호이스팅

var로 선언된 변수들은 함수스코프라 불리는 스코프를 가진다.
var로 선언한 전역 변수는 명시적인 함수 안에 있지 않지만 함수 스코프와 똑같이 동작한다.

let으로 변수를 선언하면, 그 변수는 선언하지 전에는 존재하지 않습니다.
var로 선언한 변수는 현재 스코프 안이라면 어디서든 사용 할 수 있으며, 심지어 선언하기도 전에 사용할 수 있습니다.

1
2
3
4
5
let var1;
let var2 = undefined;
var1; // undefined;
var2; // undefinde;
undefinedVar; // ReferenceError:undefinedVar is not defined

let을 쓰면 변수를 선언하기 전에 사용하려 할때 에러가 일어 납니다.
반면 var로 변수를 선언하면 선언하기도 전에 사용 할 수 있습니다.

호이스팅

var로 선언한 변수는 호이스팅이라는 메커니즘을 따릅니다.
자바스크립트는 함수나 전역스코프 전체를 살펴보고 var로 선언한 변수를 맨 위로 끌어올립니다.(여기서 중요한 것은 선언만 끌어올려진다는 것이며, 할당을 끌어 올려지지 않는다는 것이다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 원래코드
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로 새 변수를 만들수 없으며 let으로 가능 했던 변수숨김도 불가능하다.
(블록 안에서 두번째 var문을 썻지만 변수x는 하나뿐이다.)

함수 호이스팅

함수 선언도 스코프 맨 위로 끌어올려집니다.
따라서 함수를 언언하기 전에 호출 할 수 있습니다.

1
2
3
4
f();                   // 'f'
function f(){
console.log('f');
}

단, 변수에 할당한 함수 표현식은 끌어올려지지 않습니다. 이들은 변수의 스코프 규칙을 그래도 따릅니다.

1
2
3
4
f();                   // ReferrenceError: f 는 정의되지 않았습니다.
let f = function(){
console.log('f');
}

사각지대

스코프안에서 변수의 사각지대는 변수가 선언되기 전의 코드입니다. ES6 이전에 주의 해야한다.

스트릭트 모드

스트릭트 모드에서는 암시적 전역 변수를 허용하지 않습니다.
스트릭트 모드를 사용하려면 문자열 “use strict”(작은 따옴표도 가능) 하나만으로 이루언진 행을 코드 맨 앞에 쓰면 됩니다.
전역스코프에서 사용하면 스크립트 전체가 스트릭트 모드로 실행되고, 함수 안에서 사용하면 해당 함수만 스트릭트 모드로 실행됩니다.

댓글

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×