[JS] 스코프의 모든 것

hahaha·2021년 8월 1일
0

JavaScript

목록 보기
6/24
post-thumbnail

스코프란?

: 식별자가 유효한 범위

  • 모든 식별자(변수 이름, 함수 이름, 클래스 이름 등)는 선언된 위치에 의해 자신을 참조할 수 있는 유효 범위가 결정된다.
  • 스코프 내에서 식별자는 유일해야 한다.
    - var 변수는 같은 스코프 내에서 중복 선언이 허용됨 <- 의도치 않은 변수 재할당 발생
  • 선언된 위치에 따라 전역 / 지역으로 구분된다.
  • 실행 컨텍스트와 깊은 관련이 있음

스코프 체인

: 스코프가 계층적으로 연결된 것

  • 모든 지역 스코프의 최상위 스코프는 전역 스코프
  • JS 엔진은 스코프 체인을 통해 현재 스코프에서 부터 상위 스코프 방향으로 이동하며 선언된 변수를 검색한다.
  • 상속과 유사한 구조

지역 스코프 결정 방식

1. 함수 레벨 스코프

  • 함수의 코드 블록(함수 몸체)만을 지역 스코프로 인정
  • 함수가 아닌 블록(if, for, ...)에서 선언된 변수도 모두 전역 변수
  • var 키워드로 선언된 변수
// case1
function foo() {
  var abc = 123;
  if(true) {
    var abc = 456;
  }
  console.log(abc);	// 456
}
foo();

//case2
function foo() {
  var abc = 123;
  function bar() {	// (abc = 123과는 다른 새로운 스코프)
    var abc = 456;
  }
  console.log(abc);	// 123
}
foo();

2. 블록 레벨 스코프

  • 함수 몸체 뿐만 아니라 모든 코드 블록을 지역 스코프로 인정
  • C, JAVA, .. 대부분의 프로그래밍 언어
  • let, const 키워드로 선언된 변수
  • 엄밀한 의미에서의 호이스팅 작동
    - 변수의 정의문이 평가되기 전에 참조할 경우, ReferenceError 발생
  • var와 달리, 동일한 변수명에 대한 선언은 한 블록 내에서 한 번만 가능

함수의 상위 스코프 결정 방식

1. 동적 스코프

  • 함수가 호출되는 시점에 동적으로 상위 스코프 결정

2. 렉시컬 스코프(정적 스코프)

  • 함수 정의가 평가되는 시점에 정적으로 상위 스코프 결정
  • JS를 비롯한 대부분의 프로그래밍 언어가 따르는 방식
  • 클로저와 깊은 관련이 있음

전역 변수

변수의 생명주기

  • 전역변수: 애플리케이션의 생명 주기
  • 지역변수: 함수의 생명 주기

변수 호이스팅

  • 변수의 선언과 초기화가 동시에 이뤄졌을 때,
    (자바스크립트 인터프리터가) 변수 선언을 스코프의 선두로 이동시킨 것 처럼 동작하는 것
  • 스코프 단위로 동작
function foo() {
  console.log(bar);	// undefined (호이스팅을 지원하지 않는 언어에서는 에러를 일으킬 것)
  var bar = 123;
}

// 위코드는 아래와 같이 동작한다.
function foo() {
  var bar;
  console.log(bar);
  bar = 123;
}

문제점

1. 암묵적 결합

  • 모든 코드가 전역 변수를 참조하고 변경할 수 있음
  • 코드의 가독성 저하
  • 의도치 않은 상태 변경의 위험성

2. 긴 생명 주기

  • 메모리 리소스도 오랜 기간 소비함
  • 상태 변경에 의한 오류 발생 확률 높음

3. 스코프 체인 상에서 종점에 존재

  • 변수를 검색할 때, 가장 마지막에 검색됨

4. 네임스페이스 오염

  • JS는 파일이 분리되어 있더라도 하나의 전역 스코프를 공유함

사용 억제 방법

1. 즉시 실행 함수

  • 함수 정의와 동시에 단 한 번만 호출 됨
(function () {
  var foo = 10;	// 즉시 실행 함수의 지역 변수
  //...
}());

2. 네임스페이스 객체

  • 전역에 네임스페이스 역할을 담당할 객체를 생성하여 전역 변수 사용
var MYAPP = {}; // 전역 네임스페이스 객체

MYAPP.name = 'Lee';
console.log(MYAPP.name); // Lee

3. 모듈 패턴

  • 클래스를 모방하여 관련 있는 변수와 함수를 모아 즉시 실행 함수로 감싸 하나의 모듈을 만듬
  • 클로저 기반으로 동작
  • 전역 변수 억제는 물론, 캡슐화 까지 구현 가능
var Counter = (function () {
  // private 변수 기능
  var num = 0;
  
  // 외부로 공개할 메서드 반환
  return {
    increase() {
      	return ++num;
    },
    decrease() {
      	return --num;
    }
  };
}());

console.log(Counter.num); // undefined
console.log(Counter.increase()); // 1

캡슐화

객체의 프로퍼티와 메서드를 하나로 묶는 것
정보 은닉의 목적으로 사용하기도 함

4. ES6 모듈

  • 파일 자체의 독자적인 모듈 스코프 제공
  • var 키워드로 선언한 변수는 더 이상 전역 변수가 아니며 window 객체의 프로퍼티도 아니게 된다.
  • type="module" 어트리뷰트 추가 시, JS 파일은 모듈로서 동작
  • 모듈의 파일 확장자는 mjs 권장
<script type="moudle" src"lib.mjs"></script>
profile
junior backend-developer 👶💻

0개의 댓글