자바스크립트 Scope 이해하기
자바스크립트 스코프는 총에서 쓰는 스코프와 개념이 비슷합니다.
즉 자신이 보이는 유효 범위를 나타내 주는 개념입니다!
코드로 예시를 보여드리겠습니다.
Example
function add(x, y) {
console.log(x, y);
return x + y;
}
add(2, 5);
console.log(x, y); // x is not defined
위 예시를 보면 함수 매개변수는 블록 안에서만 접근이 가능합니다.
즉 매개변수 유효 범위 (스코프)는 함수 몸체 내에서만 접근이 가능합니다!
유요한 스코프 바깥에서 매개변숭에 접근하면 선언되지 않았다고 y 가기 전에 x에서 바로 not defined 오류가 뜹니다.
변수는 자신의 선언된 위치에 따라서 유효범위가 결정된다!
var x = "global";
function scope() {
var x = "local";
console.log(x);
}
scope(); // local
console.log(x); // global
변수 스코프는 자신이 선언된 위치서부터 스코프를 타고 올라가는데 위 예시에는 scope() 함수가 실행되고 , scope() 함수에는 var x 가 선언되어 있고, console.log(x)는 자신 스코프 안에 있는 x가 있는지 찾아보고 있으면 '어? 발견했다 x!! ' 하면서 scope() 안에 x인 local이 찍히게 됩니다.
그러고 나서 바깥 console.log(x)는 자신이랑 동등한 위치인 스코프에서 변수 x를 찾고 global이 찍힙니다.!
🔑 정리
똑같은 이름의 x 변수중 어느것을 참조해야 할 것인지 결정해야 하는데 , 이를 식별자 결정 이라고 합니다.
scope() 내에서 식별자는 local이고 , 전역에서의 x 식별자는 global입니다.!
즉 이름이 같아도 스코프 가 다르면 다른 변수다. !
개념
* 렉시컬 환경: 코드가 어디서 실행되며 , 주변에 어떤 코드가 있는지를 확인
* 실행 컨텍스트콘텍스트 : 렉시컬 환경을 구현한 것 (모든 코드는 실행 콘텍스트에서 평가되고 실행된다.)
🤔 만약에 scope() 안에 var x 가 없다면 ??
var x = "global";
function scope() {
console.log(x);
}
scope(); // global
console.log(x); // global
위 코드 결과로는 global 이 두 번 찍히게 됩니다.
이유는? 순서로 한번 정리해 보겠습니다.
1. scope() 함수가 실행된다.
2. scope() 함수 내에서 console.log(x)가 실행된다.
3. x 변수를 출력하기 위해서 x를 찾습니다. 없으면? 그 상위 스코프를 타고 올라갑니다.
4. 전역에 있는 x 변수 'global을 발견' console.log(x)에 전역 변수 x를 출력합니다.
5. 전역에 있는 console.log(x) global을 출력하고 끝납니다.
식별자는 유일해야 한다!
스코프 안에 식별자는 유일해야 합니다!!
function scope() {
let x = 1; // Cannot redeclare block-scoped variable 'x'
let x = 2; // Cannot redeclare block-scoped variable 'x'
}
scope()
한 스코프 내에서 똑같은 변수를 두 번 선언할 수 없습니다. ex) const , let
위 예시 코드는 실행하면 에러가 발생합니다.
근데 예외 변종 같은 녀석이 있습니다.
그 이름은 바로 var
var는 중복 선언이 허용됩니다. 그래서 의도치 않게 위에서 이미 선언된 변수를 다시 재 선언해도
오류가 발생하지 않습니다. 이는 다른 사람들과 협업할 때 다른 협업자가 이미 똑같은 변수를 선언했을 때
오류를 발생시키지 않고 덮어씌워지는 치명적인 실수가 발생할 수 있습니다.
function scope() {
var x = 1;
var x = 2;
console.log(x);
}
scope();
위 코드는 오류를 발생시키지 않는 치명적인 단점이 있습니다.!!
var 보단 let , const를 쓰는 것을 생활화합시다 ~
스코프의 종류
* 전역
- 코드의 가장 바깥 영역 (전역 스코프)
* 지역
- 함수 몸체 내부 (지역 스코프)
🛠 Example
let x = "global x";
let y = "global y";
function outer() {
let z = "outer's local z";
console.log(x);
console.log(y);
console.log(z);
function inner() {
let x = "inner's local x ";
console.log(x);
console.log(y);
console.log(z);
}
inner();
}
outer();
console.log(x);
console.log(y);
내가 예측한 순서 console.log()
1. global x , global y , outer's local z
2. inner's local x , global y , outer's local z
3. global x , global y
실행 순서
1. outer() 함수 실행
- local z 선언
- console.log() 실행 , 각각 x , y , z 접근
- x , y는 스코프에 없기 때문에 , 스코프 체인을 타고 전역 스코프로 올라가서 전역 x , y 참조
출력
global x
global y
outer's local z
2. inner() 함수 실행
- local x 선언
- console.log() 실행 , 각각 x , y , z 접근
출력
inner's local x
global y
outer's local z
3. 전역 console.log() 실행
출력
global x
global y
📌 중요
1. 지역 변수는 전역 변수 접근이 가능하다.
2. 전역 변수는 지역변수 접근이 불가능하다.
지역변수가 전역 변수에 접근 가능한 이유!
-> 지역 변수는 유효 스코프 내에 참조하는 변수가 없을 시 스코프를 타고 바깥 스코프에 참조하려는 변수가 있는지 확인합니다! 이런 식으로 스코프를 타고 쭉쭉 올라가는 걸 스코프 체인이라고 합니다.
🎇 자바스크립트는 스코프에서 시작해서 상위 스코프 방향으로 계속 찾아간다! 🎇
* 스코프 체인은 실행 콘텍스트의 렉시컬 환경을 단방향으로 연결한 것이다.
스코프 체인에 의한 함수 검색
function foo() {
console.log("global function foo");
}
function bar() {
function foo() {
console.log("local function foo");
}
foo();
}
bar();
실행결과 예상해보기!!
1. bar() 함수가 실행된다.
2. bar() 함수 내에서 foo() 함수가 실행된다.
3. bar() 함수내에 foo() 함수가 실행된다
4. local function foo 가 찍힌다.
✨ 요시 ~ 정답
foo()가 실행될 때 제일 가까운 스코프에 있는 foo() 함수가 실행됩니다!
렉시컬 스코프
var x = 1;
function foo() {
var x = 10;
bar();
}
function bar() {
console.log(x);
}
foo();
bar();
실행결과 예상해보기!!
10
1
👎 땡!
틀렸습니다.
제가 답을 저렇게 생각한 이유는 bar() 함수가 실행될 때 가장 가까운 변수 x를 참조해서 10이 찍힌다고 생각했는데
답이 아니었다!
🎈 렉시컬 스코프 정리
1. 함수를 어디서 호출했는지 따라 함수의 상위 스코프를 결정한다. (동적 스코프)
2. 함수를 어디서 정의했는지에 따라 함수의 상위 스코프를 결정한다. (정적 스코프 , 렉시컬 스코프)
자바스크립트는 렉시컬 스코프를 따른다! 즉 어디서 정의했는지에 따라서 상위 스코프가 결정된다.
위 코드에서는 bar() 함수가 정의된 곳이 전역이기 때문에 스코프가 전역으로 잡힌다.
그래서 결과가
1
1
이렇게 찍힌 것이다.
나는 이때까지 정적 스코프로 이해했나 보다... 😅
Reference : modern javascript deep dive
'FrontEnd > JavaScript' 카테고리의 다른 글
[JS] 디스코드 봇 만든 후기 (0) | 2022.12.13 |
---|---|
[JS] 캘린더 클릭시 모달 닫히는 현상 해결(+이벤트 버블링) (0) | 2022.09.22 |
[JS] 비동기 예제를 직접 만들면서 공부 (0) | 2022.05.29 |
[JS] ProtoType (0) | 2022.05.26 |
[JS] Shallow Copy Deep Copy (0) | 2022.05.16 |