function add(){
//,,,
}
if(true){
//...
} else {
//...
}
for(let i=0; i<10; i++){
//...
}
위와 같이 함수선언문, if, else문, for문 등을 사용할 때 항상 {
, }
로 묶어와주었었다. 저 중괄호로 묶인 것을 스코프라고 부르고 변수의 유효범위를 나타내는 것이다.
=> 정리하자면 모든 식별자는 자신이 선언된 위치에 의해 다른 코드가 식별자 자신을 참조할 수 있는 유효 범위가 결정된다. 이를 스코프 라고 하며, 즉 스코프는 식별자가 유효한 범위를 말한다!
var a = 1;
function afk(){
var a = 10;
console.log(a);
};
afk(); //10
console.log(a); //1
위의 코드는 동일한 변수명이 각각 다른 값을 할당받고 있다. 스코프라는 개념이 없었다면 이 코드는 분명 에러가 났을 것이다.
자바스크립트 엔진은 이름이 같은 두 개의 변수 중에서 어떤 변수를 참조해야할 것인지 문맥에 따라 결정하는데 이것을 식별자 결정 이라고 한다! 코드의 문맥은 렉시컬 환경으로 이루어진다!
function afk() {
var a = 1;
var a = 3;
console.log(a);
}
afk(); // 3
function afk() {
let a = 1;
let a = 3; //SyntaxError: Identifier 'a' has already been declared
}
afk();
다음과 같은 코드가 있다.
var x = 1;
var y = 2;
function add(){
var z = 10;
function add2(){
console.log(x+y+z);
}
add2();
}
add(); //13
맨 바깥의 전역스코프에서 add 함수를 호출하고 있고 add 함수 내에는 변수 z만이 존재하며 또 함수 내에서 add2 함수를 호출하고 있다. 결과는
13
이 나온다. 왜일까? x와 y는 함수 내에서 선언되어있지 않은데 어떻게 참조를 한 것일까?
=> 자바스크립트에서는 참조할 변수가 해당 스코프 내에 없으면 상위스코프를 탐색한다. 그리고 또 없다면 다음의 상위스코프를 탐색한다. 최종적으로 전역스코프까지 탐색하게 되는 것이다. 이렇게 체이닝된 형식으로 변수를 찾아 참조하려고 한다. 이 것을 스코프체인 이라고 한다!
=> 변수를 참조할 때 자바스크립트 엔진은 스코프체인을 통해 변수를 참조하는 코드의 스코프에서 시작하여 상위 스코프 방향으로 이동하며 선언된 변수를 검색한다.
이게 var를 쓰지 않는 것을 권유하는 이유 중 하나인 개념이다.
다른 언어에서는 함수뿐만 아니라 if, for ,while 문 등 모든 코드 블록이 지역 스코프를 만든다. 이러한 특징을 블록 레벨 스코프 라고 한다! 하지만 var로 선언된 변수는 오직 함수의 코드 블록만을 지역 스코프로 인정하는데 이것을 함수 레벨 스코프 라고 부른다!
var x = 10;
if(true){
var x=20;
}
console.log(x); //20
위 코드의 결과는 20이다. 처음에 전역변수로 선언해주고 또 지역스코프 안에서 동일한 변수명으로 20을 선언해주었다. 일반적이라면 변수명 x로 선언된 것은 실질적으로 서로 다른 지역스코프 내에서 선언되었기 때문에 따로 움직여야 한다. 그러나 위의 코드는 일반 블록레벨스코프인 지역스코프를 무시하고 재할당이 되어버렸다. 이 것이 var 가 가지는 특징 중 하나인 함수 레벨 스코프 특성 때문이다. 그와 반대로 let과 const는 이 전에 말했다시피 블록 레벨 스코프를 따른다!
좋은 말할 때 var 쓰지 말자
var x=1;
function afk(){
var x=10;
hmm();
}
function hmm(){
console.log(x);
}
afk();
console.log(x);
=> afk 함수를 호출했을 때 변수 x는 10으로 할당이 되어있고 그 상태에서 함수 hmm을 호출하여 console에 x를 찍었기 때문에 당연히 지역스코프의 영향을 받아 x = 10 이라고 나올 것이라 생각했다.
하지만 내가 생각한 개념은 동적 스코프(dynamic scope) 일 때의 개념이다.
동적 스코프는 함수를 어디서 호출했냐에 따라 상위스코프를 결정한다.
동적스코프를 채택하고 있는 언어가 궁금해서 알아보았다!
1. Perl
2. PHP
3. Common Lisp
4. Emacs Lisp
5. Bash 스크립트
들어본 언어가 PHP 뿐이다..
자바스크립트는 기본적으로 렉시컬스코프(정적스코프) 를 채택하고 있으며 위의 코드는 정적스코프의 관점에서 바라봐야한다. 정적스코프는 함수를 어디서 호출했냐가 아니라 어디서 정의했는지에 따라 상위스코프를 결정한다. 따라서 둘 다 결과가 전역스코프내의 변수 x의 값 1이 출력되는 것이다!
정적스코프를 채택하고 있는 언어도 궁금해서 알아보았다!
1. C
2. C++
3. JAVA
4. Python
5. Ruby
오늘도 열심히 ...