Javascript scope TIL

Devback·2020년 8월 20일
1

위코드

목록 보기
3/4
post-thumbnail

Scope

Javascript에서 scope란 변수가 어디까지 쓰일 수 있는지의 범위를 의미합니다.

"is not defined"라는 에러 메시지를 보신적 있나요? 이는 변수가 아직 선언되지 않았다는 걸 말합니다.

쉽게 말하자면, 어떤 변수는 여기저기서 쓸 수 있는 반면에, 어떤 변수는 특정 함수 내에서만 쓸 수 있습니다. 이런 개념이 scope입니다.

Block

scope를 더 파헤치기 전에 먼저 알아야할 개념은 block입니다.

block이란 {}(중괄호, curly brace)로 감싸진 것을 block이라고 합니다.

global variable vs local variable

global variable(전역 변수)는 block밖에 있는 변수를 말합니다. 반대로 블록 안에 있는 변수는 local variable(지역 변수)는 block안에 있는 변수를 말합니다.

const color = 'red';
console.log(color);

function returnColor() {
  console.log(color);
  return color;
}

console.log(returnColor());

이 예에서 color는 전역 변수입니다. 전역변수는 블록 안에서 사용할 수 있지만 반대로 블록 안에 있는 지역변수는 블록 밖에서는 사용할 수 없습니다.

global namespace, scope pollution

function logSkyColor() {
  const dusk = true;
  let myColor = 'blue'; 

  if (dusk) {
    let myColor = 'pink';
    console.log(myColor); // pink
  }

  console.log(myColor); // blue 
}

console.log(myColor); // 에러!!

logSkyColor()함수 안에 myColor라는 변수를 선언했습니다. 그리고 logSkyColor함수 안 if문 블록 안에 myColorf변수를 다시 선언했습니다. if문 내에는 pink라고 할당하였고 if문 밖에는 blue라고 할당을 했습니다.

이는 scope namespace가 오염됐습니다. 이유는 같은 이름의 변수를 사용했기 때문입니다.

이렇게 새로운 block에 변수를 사용할 때는 항상 다른 이름으로 변수를 선언해야 하는 것을 주목해야합니다.

let, const의 블록 레벨 스코프

ES5까지 변수를 선언할 수 있는 유일한 방법은 VAR 키워드를 사용하는 것이었습니다. var 키워드로 선언된 변수는 몇 가지 특징이 있습니다.

  1. 함수 레벨 스코프(Function-level scope)
  • 함수의 코드 블록만을 스코프로 인정한다. 따라서 전역 함수 외부에서 생성한 변수는 모두 전역 변수이다. 이는 전역 변수를 남발할 가능성을 높인다.
    ex. for 문의 변수 선언문에서 선언한 변수를 for 문의 코드 블록 외부에서 참조할 수 있다.
  1. var 키워드 생략 허용
  • 변수를 만드는 키워드를 생략하다보니 전역 변수를 많이 만들 가능성이 높다.
  1. 변수 호이스팅
  1. 변수 중복 선언 허용
  • 의도하지 않은 변수값의 변경이 일어날 가능성이 높다.

이러한 var키워드의 단점을 보완하기 위해서 let과 const 키워들르 도입했습니다.

Block level scope vs Function level scope

Block level

let foo = "I'm foo";
if(true) {
    let bar = "I'm bar";
    console.log(foo);   //I'm foo
    console.log(bar);   //I'm bar
}

console.log(foo);   //I'm foo
console.log(bar);   //Uncaught ReferenceError: bar is not defined.

함수 레벨 스코프 (Function-level scope)
힘수 안에서 선언된 변수는 밖에서는 사용할 수 없습니다. 즉, 함수 내부에서 선언한 변수는 지역 변수이고 함수 밖에서 선언한 변수는 모두 전역 변수입니다.

블록 레벨 스코프 (Block-level scope)
블록{} 안에서 선언한 변수는 모두 지역 변수이고 이 변수는 블록 밖에서 사용한 변수는 모두 전역 변수입니다. 함수 레벨 스코프와 다르게 for, if, while과 같은 모든 블록 레벨에서 선언된 변수는 외부에서 참조할 수 없습니다.

var는 함수 레벨 스코프를 따르고 let, const는 블록 레벨 스코프를 따릅니다.

호이스팅

호이스팅(hoisting)이란 해당 스코프에서 선두로 옮기는 것처럼 동작하는 특성을 말합니다.
자바스크립트는 ES6에서 도입된 let, const를 포함하여 모든 선언(var, let, const, function, function*, class)을 호이스팅합니다.

하지만 var 키워드로 선언된 변수와 달리 let 키워드로 선언된 변수는 참조 에러가 발생합니다.

console.log(foo); // undefined
var foo;

console.log(bar); // Error: Uncaught ReferenceError: bar is not defined
let bar;

변수의 생성단계와 호이스팅이 어떻게 이루어지는지

선언단계(Declaration phase)
변수를 실행 컨텍스트의 변수 객체(Variable Object)에 등록한다. 이 변수 객체는 스코프가 참조하는 대상이 됩니다.

초기화 단계(Initialization phase)
변수 객체(Variable Object)에 등록된 변수를 위한 공간을 메모리에 확보한다. 이 단계에서 변수는 undefined로 초기화된다.

할당 단계(Assignment phase)
undefined로 초기화된 변수에 실제 값을 할당한다.

var,키워드로 선언된 변수는 선언 단계와 초기화 단계가 한번에 이루어집니다.

// 스코프의 선두에서 선언 단계와 초기화 단계가 실행된다.
// 즉, 변수 선언문 이전에 변수를 참조할 수 있다. 
console.log(name); // undefined

var name;
console.log(name); //undefined

name = 1; // 이 부분에서 할당 단계가 실행된다. 
console.log(name); // 1 

let 키워드로 선언된 변수는 선언 단계와 초기화 단계가 분리되어 진행됩니다. 즉, 스코프에 변수를 등록하지만 초기화 단계는 변수 선언문에 도달했을 때 이루어집니다. 따라서 스코프의 시작 지점부터 초기화 시작 지점까지는 변수를 참조할 수 없습니다.

console.log(name); // ReferenceError: foo is not defined

let name; // 변수 선언문에서 초기화 단계가 실행된다. 
console.log(name); // undefined 
name = 'jun'; // 할당문에서 할당 단계가 실행된다. 
console.log(name); // 1 

또, const는 반드시 선언과 할당이 동시에 이뤄집니다.

const hello; // SyntaxError: Missing initializer in const declaration

참고 문헌 :
https://poiemaweb.com/es6-block-scope

profile
나랑 같이 개발할 사람🖐

0개의 댓글