JS: 변수선언과 Scope

이윤지·2023년 9월 24일
1

자바스크립트에서 변수, 함수를 선언할 때, 해당 변수 또는 함수가 아무데서나 유효한 것이 아니다. 어떻게, 어디에 선언되었는지에 따라 유효한 범위가 있는데 이를 Scope 라고 한다.

Scope

식별자 접근 규칙에 따른 유효 범위이다.

  • 식별자에(변수,함수,클래스)에 접근할 수 있는 범위가 있다.
  • 범위는 블록 또는 함수에 의해 나뉘어진다. (Block Scope, Function Scioe)
  • 즉 스코프란 변수 또는 함수가 유효한 범위를 의미한다.

Scope의 종류

  • Global (전역) Scope: 코드의 모든 범위에서 사용 가능
    • 전역스코프를 제외한 모든 스코프는 지역 스코프이다.
  • Local (지역) Scope:
    • Function (함수) Scope: 해당 함수 안에서만 사용 가능
      • 화살표 함수는 블록 스코프
    • Block (블록) Scope: 특정 블록(중괄호) 안에서만 사용 가능

JS에서 스코프의 특징

  • 안쪽 스코프에서 바깥쪽 스코프로만 접근할 수 있다.
    • 바깥쪽 스코프에서 선언한 식별자는 안쪽 스코프에서 접근할 수 있다.
    • 안쪽에서 선언한 식별자는 바깥쪽 스코프에서 사용할 수 없다.
  • 정적 스코프를 따른다.
    • 선언 시점에 따라 스코프가 결정된다.
  • 스코프 체인
    • 스코프는 중첩이 가능하다 → 스코프 체인이 형성된다.
    • 변수를 찾을 때 현재 스코프에서 시작해 해당 변수를 찾을 때까지 상위 스코프로 이동한다.
  • 지역변수는 전역변수보다 우선순위가 높다.

var, let, const

자바스크립트에서는 var, let, const 이렇게 세가지의 키워드가 있다. 각각 다른 특징을 가지고 있다.

const

  • 값 재할당 x
  • 재선언 x

let

  • 값 재할당 o
  • 재선언 x

var

  • 값 재할당 o
  • 재선언 o

var, let, const 와 스코프

변수를 어떤 키워드로 선언하느냐에 따라서 다른 유효범위를 가진다.

전역에 선언된 전역변수는 전역 스코프를 가지기 때문에 하위의 모든 곳에서 참조가 가능하다.

지역(블록,함수)에 선언된 지역변수는 지역스코프를 가져 해당 지역과 하위의 지역에서 참조가 가능하다.

let, const

  • 블록레벨 스코프를 가진다.
  • 블록스코프에서 지역변수가 된다.
  • 예시
let foo = 123; // 전역 변수
let foo2 = 1 //전역 변수

function a() {
	let variable = 1; //지역변수
}
cosole.log(variable) // ReferenceError: variable is not defined

{
  let foo = 456; // 지역 변수
  let bar = 456; // 지역 변수
	foo2 = foo + 1 //전역변수 참조, foo2는 457이 됨.
}

console.log(foo); // 123(젼역변수 foo)
console.log(bar); // ReferenceError: bar is not defined
console.log(foo2) // 457

블록 스코프이기 때문에 중괄호(코드블록) 밖에서는 사용이 불가능하다.

함수안, 블록 안에 선언된 변수 모두 지역변수가 된다.

또한 foo2는 블록 안에서 정의되지 않았으므로 전역 스코프에서 해당 변수를 검색하여 사용해 1+456 즉 457이 된다.

해당 스코프에서 정보를 찾지 못하고 이렇게 바깥 스코프에서 변수를 검색하는 것이 스코프 체인이다.

var

  • 함수레벨 스코프를 가진다
  • 함수 스코프에서만 지역변수가 된다.
  • 예시
function a() {
  var variable = 1; // 지역변수
}
console.log(variable) // ReferenceError: variable is not defined

if (true) {
  var variable = 1; // 전역변수
}
console.log(variable) // 1

함수 내에서 선언된 변수 variablefunction a의 지역변수 이기 때문에, 해당 함수 밖에서 사용할 수 없다.

하지만 블록스코프는 무시하기 때문에 블록에서 선언되었더라도 블록 밖에서 사용이 가능하다.

var value = 'hello!';

function myFunction() {
  var value = 'bye!';
  if (true) {
    var value = 'world';
    console.log('block scope: ');
    console.log(value);
  }
  console.log('function scope: ');
  console.log(value);
}

myFunction();
console.log('global scope: ');
console.log(value);

var는 function scope이기 때문에, if문 블록 스코프를 무시하고 블록 밖의 valuer값에도 영향을 준다. 그러므로

다음과 같은 결과가 나온다. 그리고 마지막 value는 전역변수 value인 hello가 나온다.

만약 var가 아닌 let,const 였다면 블록 스코프이기 때문에 world, bye, hello가 나왔을 것이다.

만약 if 문이 아닌 아래와 같이 함수일 경우

var value = 'hello!';

function myFunction() {
  var value = 'bye!';
 function a() {
    var value = 'world';
    console.log('block scope: ');
    console.log(value);
  }
  a()
  console.log('function scope: ');
  console.log(value);
}

myFunction();
console.log('global scope: ');
console.log(value);

위와같이 함수 내에서 밖의 value에 영향을 미치지 않아 bye가 출력된다.


렉시컬 스코프

아까도 특징과 예시에서 봤듯이 스코프는 안쪽(하위) 스코프에서 바깥쪽 (상위)스코프로만 접근할 수 있다. 이때 상위 스코프를 결정하는 방법으로 두가지가 있다.

  • 동적 스코프
    • 함수를 어디서 호출 하였는지에 따라 상위 스코프를 결정
  • 렉시컬 스코프
    • 함수를 어디서 선언 하였는지에 따라 상위 스코프를 결정

이 중에서 자바스크립트는 렉시컬 스코프를 따른다. 즉 함수를 선언한 시점에 상위 스코프가 결정된다는 말이다.

그러므로 가지는 두가지의 특징이 있다.

  • 함수를 어디에서 호출했는지는 스코프 결정에 의미가 없다.
  • 중첩된 함수 그룹에서 내부 함수가 상위 범위의 변수 및 리소스에 접근할 수 있다. (스코프 체인)
var x = 1;

function foo() {
  var x = 10;
  bar();
}

function bar() {
  console.log(x);
}

foo(); // 1
bar(); // 1

위와같이 하수 bar는 전역에 선언되었다. 그러므로 함수 bar의 상위 스코프는 전역 스코프 이며 모두 1이 출력된다.

profile
isy's blog

0개의 댓글

관련 채용 정보