Scope

  • 스코프의 목적
    • 범위를 제한하여 식별자를 해결하려는 것. 스코프에서 식별자를 해결
    • Identifier Resolution(식별자 해결)
      • 변수 이름, 함수 이름을 찾는 것
      • 이때 스코프를 사용
      • 이름을 찾게 되면 값을 구할 수 있음
      • 크게는 이름을 설정하는 것도 식별자 해결
    • 스코프는 식별자 해결을 위한 것
  • 스코프 설정
    • 엔진이 function book(){}을 만나면 function object가 생성되고 scope를 설정한다.
      • 생성한 function object의 [[Scope]]에 scope를 설정한다. 즉, 이 때 scope가 결정된다.
      • 내부 프로퍼티 [[Scope]]에 결정되는 것을 정적 스코프라 하고, 함수를 호출할 때 scope를 결정하는 것을 동적 스코프라고 한다.
      • 동적 스코프를 10000번 호출하면 10000번 스코프를 설정하지만 정적 Scope를 설정하면 한번만 스코프를 설정하면된다.
        function book() {
            var point = 123;
            function get() {
                console.log(point);
            };
            get();
        };
        book();
        
        • book()함수를 호출한다.
        • 엔진 컨트롤이 book function에 첫번째 줄로 이동한다.
        • 함수 선언을 먼저 찾는다. function get()을 만나게 되어 function object를 생성한다.
        • 스코프를 설정한다.
          • function object의 [[Scope]]에 스코프를 설정한다. 이 때 정적으로 스코프가 결정된다.
        • 표현식을 처리한다. - point 변수 선언(undefined)
        • 코드를 실행한다. - point 에 123 값을 대입, get() 함수를 호출한다.

Global Object

  • Global Object
    var value = 100;
    function book() {
        var point = 200;
        return value;
    }
    book();
    
    • var value = 100;
      • 100을 value 변수에 할당한 것은 value로 검색하여 값을 사용하기 위한 것(Identifier Resolution)
    • 함수 안에 변수를 선언하면 변수가 함수에 속하게 되지만
    • value 변수를 함수 안에 작성하지 않았다.
      • value 변수가 속하는 object가 없으며, 이 때, Global Object를 설정하게 된다.
      • point 변수는 함수 안에 선언했기 때문에 book이란 function object에 속하게 되지만 value 변수는 함수 안에 없고, 전역적인 위치에 선언되었기 때문에 Global Object에 설정된다.
    • 이런 메커니즘을 구현할 수 있는 것으 Global Object가 하나만 있기 때문이다.
  • Global Object 특징
    • JS 소스 파일 전체에서 Global Object는 하나만 있다.
      • new 연산자로 인스턴스 생성이 불가하다.
    • JS 소스 파일 전체 기준으로 에 작성된 모든 코드이며 모든 코드에서 사용가능하다.
      <script src="./abc.js">
      <script src="./def.js">
      
      // abc.js
      var value = 100;
      function book() {
        return value + 50;
      }
      
      // def.js
      console.log(value); // 100
      console.log(book()); // 150
      
      • def.js 파일의 코드에서
        • 글로벌 오브젝트에 작성된 변수 value 값을 출력하고 book() 함수를 호출한다.
  • Global Scope
    • Global Object가 Global Scope이다.
    • Object는 개발자 관점으로 오브젝트에 함수와 변수를 작성
      • Global Object는 Number, Math와 같은 Object는 아니다.
      • 함수와 변수를 작성하기 위해서는 Object가 있어야 하기 때문에 host object 개념으로 Window Object를 Global Object로 사용하여 함수와 변수가 작성된다.
    • Scope는 식별자 해결을 위한 것으로 엔진 처리 관점
      • 엔진이 식별자 해결을 위해 Scope를 사용하는 것
    • Global Scope는 최상위 스코프로 함수에서 보면 최종 스코프
      • 함수 스코프에 변수, 함수가 없으면 그 다음 스코프를 찾게 된다. 계층적으로 따라 올라가다가 최종적으로 Global Scope를 만나게 된다.
        var value = 100;
        function book() {
            return value;
        };
        book();
        
        • function book(){…}
          • book 함수가 속한 오브젝트가 없으므로, book 함수란 function object를 글로벌 오브젝트에 설정
          • book 함수는 글로벌 함수가 된다. (전역 함수)
        • var value = 100;
          • value 변수가 글로벌 오브젝트에 설정
          • 글로벌 변수 (전역 변수)
        • 글로벌 오브젝트에 설정된다는 것은 오브젝트 관점이다.
        • 스코프와 식별자 해결 관점은 Scope가 Global Scope라는 것
        • book();
          • book 함수를 호출하려면, “오브젝트.book()” 형태로 작성해야 하는데 오브젝트를 작성하지 않고 함수만 작성했다.
          • 오브젝트를 작성하지 않으면, 글로벌 오브젝트를 “오브젝트”로 간주하여 글로벌 오브젝트의 book() 함수를 호출한다.
          • 즉, 글로벌 스코프에서 book을 찾아 호출한다.
  • Scope Binding
    • 바인딩
      • 구조적으로 결속된 상태로 만드는 것.
        • 대상: 프로퍼티 이름 (변수, 함수의 이름)
      • 바인딩 목적
        • 스코프 설정, 식별자 해결
      • 바인딩 시점 구분
        • 정적 바인딩(Lexical, Static Binding) / 정적 스코프(Lexical Scope)
        • 동적 바인딩(Dynamic Binding) / 동적 스코프(Dynamic Scope)
    • 정적, 동적 바인딩
      • 정적 바인딩 (Lexical Binding)
        • 초기화 단계에서 바인딩
        • 함수 선언문 이름을 바인딩
        • 표현식(변수, 함수) 이름을 바인딩
        • Javascript는 대부분 정적 바인딩이다.
      • 동적 바인딩 (Dynamic Binding)
        • 실행할 때 바인딩
        • eval() 함수, with 문
    • 바인딩 시점의 중요성
      • 바인딩 시점이 중요한 이유: 바인딩할 때 스코프가 결정되기 때문
      • function object 생성 시점에 스코프 결정
        • 스코프를 function object의 [[Scope]]에 설정
        • 스코프가 변경되지 않음 (정적 스코프)
      • 함수 안의 모든 함수의 Scope가 같다.
        function book() {
            var point = 100;
            function add(param) { point += param; };
            var get = function() { return point; };
            add(200);
            console.log(get()); // 300
        };
        book();
        
        • 마지막 줄에서 book() 함수를 호출
          • 초기화 단게에서 함수와 변수 이름을 선언적 환경 레코드(DER)에 바인딩
        • function add(param) {…}
          • function object 생성
          • add 함수가 속한 스코프(영역)를 add 오브젝트의 [[Scope]]에 설정
          • add 이름을 레코드에 바인딩
        • var point = 100;
          • point 이름을 레코드에 바인딩 (point: undefined)
        • var get = function() {…}
          • get 이름을 레코드에 바인딩 (get: undefined)
        • 바인딩으로 함수와 변수의 식별자가 해결됨 == 코드 실행 ==
        • var point = 100;
          • point에 100 할당 (point: 100)
        • var get = function() {};
          • function object 생성, get에 할당
          • get 함수가 속한 Scope(영역)를 get object의 [[Scope]]에 설정 == add() 함수 호출 ==
        • add(200); 을 호출
        • point += param;
          • 먼저 add() 함수 안에 선언적 환경 레코드(DER)에서 point 이름을 찾습니다. point가 해당 스코프에 없으므로 다시 검색하게 되며 ( add() 함수 안에 선언적 환경 레코드는 아무런 값이 없다. 다만, add() 밖 book()에 있는 point는 외부 렉시컬 환경 참조(OLER)에 설정된다.)
          • add object의 [[Scope]]를 스코프로 사용하지만 없으므로 외부 스코프로 이동
          • book object가 스코프이며 point가 있으므로 값을 더한다.
        • console.log(get());
        • return point;
          • 레코드에 point가 없으므로 다시 검색
          • get 오브젝트의 [[Scope]]를 스코프로 사용
          • book 오브젝트가 스코프이며 point 가 있으므로 값을 반환한다.
    • 동적 바인딩
      • 코드를 실행할 때마다 바인딩
        • with 문
        • eval() 함수
      • with 문
        • “use strict” 환경에서 에러 발생
      • eval() 함수
        • 보안에 문제가 있다.

** 출처1. 인프런 강좌_자바스크립트 중고급: 근본 핵심 이해