스코프(Scope)
영어 단어로 scope는 '범위'라는 뜻이다. JavaScript에서는 코드 내에서 식별자(변수, 함수명과 같이 어떤 대상을 다른 대상과 구분하여 식별이 가능한 이름)를 찾아내기 위한 규칙으로, 식별자에 접근할 수 있는 유효범위를 의미한다. 모든 스코프는 하나의 계층 구조로 연결되어 최상위의 전역 스코프와 연결된다. JavaScript의 스코프 종류는 다음과 같다.
- 전역 스코프
코드의 최상위 범위로 프로그램 전체에 접근하여 사용이 가능하다. 하지만 전역 스코프가 많아질수록 브라우저가 무거워지기 때문에 전역 스코프 사용을 최소화하는 것이 좋다. - 지역 스코프
함수 또는 특정 코드 블록 내에서만 접근해서 사용할 수 있다. 해당 스코프와 하위 스코프에서만 참조가 가능하며, 외부에서는 접근 할 수 없다. 함수 내에서 선언된 변수의 유효 범위를 '함수 스코프', {}내에서 선언된 변수의 유효 범위를 '블록 스코프'라고 한다. 지역 스코프의 경우에는 지역 컨텍스트가 실행되고 끝나기 전까지만 유효하다.
var로 선언된 변수의 경우 함수 레벨 스코프로, 함수 내부만 스코프로 인정하고 코드블럭내에서 선언되었을 경우 전역변수로 간주한다. let과 const로 선언된 변수는 블록 레벨 스코프를 지원한다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// var은 함수 레벨 스코프로 코드블럭{}내에 선언된 경우 전역변수로 간주한다.
{var a = 1;}
function func1(){
console.log(a);
}
func1(); // 1
// let은 블록 레벨 스코프로 코드블럭{}내에 선언된 경우 블록스코프로 간주되어, 외부에서 접근이 되지 않는다.
{let b = 2;}
function func2(){
console.log(b);
}
func2(); // ReferenceError: b is not defined
</script>
</body>
</html>
스코프체인
스코프체인은 지역 스코프들이 계층적으로 연결된 것을 의미한다. 자신이 속해있는 지역 스코프에 참조값이 없다면, 스코프체인을 통해 상위 지역 스코프를 참조하여 값을 찾는다. 하위 스코프의 경우 상위 스코프에 접근할 수 있으나, 상위 스코프의 경우 하위 스코프를 참조할 수 없다. 최상위 스코프는 전역 스코프이다.
스코프 방식 종류
- 동적 스코프
함수를 어디서 호출했는지에 따라 상위 스코프가 결정된다. 즉 호출된 곳을 기준으로 스코프가 생성이 된다. - 정적(렉시컬) 스코프
JavaScript의 경우 렉시컬 스코프 방식을 따른다. 렉시컬 스코프는 함수를 어디서 선언했는지에 따라 상위 스코프가 결정된다. 즉, 선언한 곳이 기준이 되어 스코프를 생성하기 때문에 선언한 위치가 스코프에 영향을 끼친다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
var a = 1;
function outer() {
var a = 2;
// console.log(`outer의 a : ${a}, outer의 b: ${b}`); => ReferenceError: b is not defined
// b는 outer()의 하위 스코프에 선언되어있기 때문에, b를 참조할 수 없다.
console.log(`outer의 a : ${a}`);
function inner() {
var b = 3;
console.log(`inner의 a : ${a}, inner의 b : ${b}`);
}
inner(); // inner의 a : 2, inner의 b : 3
console.dir(inner);
}
outer(); // outer의 a : 2
console.dir(outer);
</script>
</body>
</html>
각자 function을 확인해보면, inner()의 경우 [[scope]]를 통해서 outer()를 참조하고 그 뒤 순서로 global scope를 참조하고 있는 것을 볼 수 있고, outer()의 경우에는 global scope를 참조하고 있는 것을 알 수 있다.
실행 컨텍스트(Execution Context)
코드가 작동하는 작업 영역을 의미한다. JavaScript는 실행 컨텍스트를 콜스택에 쌓아올린 후 실행하여 코드의 환경 및 순서를 보장한다. 자동으로 전역컨텍스트가 생성된 후에 eval(), 함수로 인해 실행 컨텍스트가 형성이 되고, 컨텍스트 생성이 완료된 후에 함수가 실행된다.
활성객체
실행에 필요한 여러 정보를 담은 객체로, 실행 컨텍스트가 생성이 되면 JavaScript는 해당 컨텍스트에서 활성객체를 생성한다. 이 객체에 앞으로 사용하게 될 변수, 매개변수, 전달인자 등을 저장하고, 새로 만들어진 컨텍스트로 접근한다. 활성객체가 생성이 되고, 새로 만들어진 컨텍스트로 접근해서 제일 먼저 호이스팅에 의해 끌어올려진 변수 및 함수를 확인하여 저장한다. 위의 예제에서 inner()의 a가 undefined인 이유도, 호이스팅에 의해 끌어올려진 a가 undefined로 초기화가 되어 저장되었기 때문이다.
클로저
클로저는 그 함수와 그 함수가 선언된 환경과의 관계를 의미한다. 클로저는 사용자의 위변조를 방지하기 위해서 생겨났는데, 스코프를 공부하면서 (1)외부함수 스코프에서 내부함수 스코프로는 접근이 불가능하고, (2)내부함수에서는 외부함수 스코프로 접근이 가능하다는 것을 공부했다. 이를 이용하여 함수 안에 변수를 선언해놓고, 변수에 접근할 수 없도록 범위를 지정한다. 클로저를 통해 데이터 보존 및 활용, 정보의 접근 권한 제어 및 지역변수를 보호할 수 있다는 장점이 있다.
outer함수에 name 변수를 선언하고, inner 함수를 정의하여 name을 콘솔에 출력할 예정이다. const func1 = outer();를 통해 outer 함수를 호출하여 inner 함수를 반환받아 func1에 저장한다. func1을 호출하면 inner함수가 시행되고, name 값은 외부 함수 스코프에 접근하여 'codingji'라는 값을 사용하게 된다. 이와 같이 클로저를 이용하여 외부에서 직접적으로 접근할 수 없도록 범위를 지정할 수 있다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Closure Example</title>
</head>
<body>
<script>
function outer() {
let name = "codingji";
function inner() {
console.log(`안녕하세요, 제 이름은 ${name} 입니다.`);
}
return inner;
}
const func1 = outer();
func1(); //안녕하세요, 제 이름은 codingji 입니다.
console.dir(func1);
</script>
</body>
</html>
outer 함수를 호출해서 inner함수를 반환받은 func1의 경우에 scope에 Closure(outer)가 있는 것을 볼 수 있다.
'Frontend > JavaScript' 카테고리의 다른 글
JavaScript의 class를 사용해보자 (0) | 2024.07.30 |
---|---|
JavaScript 프로토타입(prototype)과 생성자 함수 (0) | 2024.07.30 |
JavaScript 콜백함수란? (0) | 2024.07.29 |
JavaScript : sort()와 localeCompare()을 이용해 정렬해보자 (0) | 2024.07.29 |
JavaScript : DOM에서 class를 설정해보자 (0) | 2024.07.29 |
JavaScript : DOM의 이벤트를 설정해보자 (0) | 2024.07.29 |
JavaScript : DOM을 통해 input 값 받아오기 (0) | 2024.07.29 |
JavaScript에서 this는 무엇을 가리키는걸까? (0) | 2024.07.29 |