[JS] #4 Scope

simoniful·2021년 4월 21일
0

ES5 JS - Advanced

목록 보기
4/8
post-thumbnail

스코프 설정

목적

  1. 유효범위를 제한하여 식별자를 해결하려는 것(Identifier Resolution)
  2. 스코프 내에서 식별자를 해결하기 위해서!

식별자 해결(Identifier Resolution)

변수 이름, 함수 이름을 찾는 것으로 이 때 스코프를 사용합니다. 스코프 내에서 이름을 찾게 되면 값을 구할 수 있으며 식별자 해결의 궁극적인 목적은 결국 식별자를 통해 이름을 찾아 값을 구하는 것입니다. 그리고 크게는 이름을 설정하는것도 식별자 해결이라 할 수 있습니다.

왜냐하면, 변수 이름을 스코프에 등록한다는것은 다음에 사용하려는 목적과 식별자를 찾을 때 사용하는 등록검색이라는 두 가지 목적을 가지는데 이 두 목적을 식별자 해결(Identifier Resolution)이라 합니다. 결국, 스코프는 식별자 해결을 위해 있는 것입니다.

설정

function book() {
  var point = 123;
  function get(){
    console.log(point);
  };
  get();
};
book()
// 123
  1. 엔진이 function book() {}을 만나면 function 오브젝트를 생성 후
  2. 스코프를 설정합니다.
    생성한 function 오브젝트의 [[Scope]]에 스코프를 설정합니다. 즉, 이때 스코프가 결정됩니다.
  3. 이처럼 function 오브젝트를 만드는 시점에 스코프를 결정하는 것을 정적 스코프라고 합니다.
  4. 함수를 호출 할 때마다 스코프를 결정하는 것을 동적 스코프라 합니다(eval, with)

정리

function 오브젝트를 만날 때 스코프가 결정이 된다는 것은 book()함수가 호출되고 위에서부터 함수 선언문 → 변수 초기화 → 코드 실행함수 코드 해석 순서를 가지게 됩니다.

위의 예시를 예로 보았을 때, function get() {...}을 만나는 순간, function 오브젝트가 생성되며 스코프가 결정됩니다. 스코프에는 get() {...}를 포함한 book() {...} 내부 전체가 설정되면서 point가 포함됩니다. get 함수의 스코프 범위 내 point가 있기 때문에 Context 속에서 사용이 가능하게 됩니다.

스코프 체인이나 동적 스코프 환경에서 함수를 여러번 호출한다면 스코프는 호출 할 때마다 스코프가 새로 생성됩니다.

반면, 정적 스코프에서는 function 오브젝트를 생성할 때 한 번만 생성됩니다. 때문에 메모리 개념에서 더욱 효율적입니다.


Global 오브젝트

var value = 100;
function book() {
  var point = 200;
  return value;
};
book();

100을 value 변수에 할당한 것은 value로 검색하여식별자 해결을 통해 값을 사용하기 위함입니다.

함수 안에 변수를 선언하게 되면 변수는 함수에 속하게 됩니다. 하지만, 함수 밖에서 예시의 value처럼 종속하는 오브젝트가 없이 var 키워드를 사용하여 선언한 경우, 글로벌 오브젝트에 설정됩니다. 이런 식의 사용이 가능한 이유는 글로벌 오브젝트가 모든 스크립트 요소를 통틀어 하나만 있기 때문입니다.

특징

<script src="./abc.js">

var value = 100;
function book() {
  return value + 50;
};

<script src="./def.js">

console.log(value);//100
console.log(book());//150

JS 소스파일 전체 + <script> 태그 내 작성된 모든 코드에서 글로벌 오브젝트는 하나만 있습니다. 따라서, new 연산자로 인스턴스 생성이 불가능합니다.
예시를 보면 def.js 파일의 코드에서 글로벌 오브젝트에 작성된 변수 value값과 book()함수 호출이 모두 정상적으로 동작합니다.

Global 스코프

글로벌 오브젝트 = 글로벌 스코프

오브젝트는 개발자 관점으로 오브젝트에 {name:value} 형태로 함수와 변수를 작성하여 저장하는 것입니다.

⇒ 함수와 변수를 작성하기 위해서는 오브젝트가 필요한데 글로벌 오브젝트는 오브젝트가 없습니다. 그렇지만, window 오브젝트를 global 오브젝트로 보완하여 사용합니다. 따라서, 함수와 변수를 작성하면, 글로벌 오브젝트 개념으로 window 오브젝트에 설정됩니다.

스코프는 식별자 해결을 위한 수단으로 엔진 처리 관점입니다. 글로벌 스코프는 최상위 스코프로 함수에서 최종 스코프가 됩니다.

⇒ 함수 안에 A함수가 있고 그 안에 B함수가 있고 그 안에 C함수가 있다고 할 때, C함수에서 변수를 식별자해결을 위해 검색하였으나 해당 스코프에 잆을 경우, 상위 스코프인 B함수의 스코프, A함수의 스코프 그리고 여기에도 없으면 최종적으로 글로벌 오브젝트의 스코프에서 식별자 해결을 시도합니다.

var value = 100;
function book() {
  return value;
};
book()
  • function book() {...} :: 글로벌 함수
    book 함수가 속한 오브젝트가 없기에 book 함수는 글로벌 오브젝트에 설정됩니다.
  • var value = 100; :: 글로벌 변수
    • value 변수가 글로벌 오브젝트에 설정됩니다(개발자 관점)
    • 엔진과 식별자 해결 관점에서 볼 때는 Scope가 글로벌 스코프라는 것입니다.
  • book();
    • book 함수를 호출하려면 "오브젝트.book()"형태가 되야하는데, 오브젝트를 작성하지 않고 함수만 작성합니다.
    • 이렇게 오브젝트를 작성하지 않을 경우 글로벌 오브젝트를 "오브젝트"로 간주해 글로벌 오브젝트의 book()함수를 호출합니다.
    • 즉, 글로벌 스코프에서 book을 식별자 해결하여 호출합니다.

스코프 바인딩

프로퍼티 이름을 구조적으로 결속된 상태로 만드는 것 입니다. 스코프를 설정하여 식별자 해결하는 것을 목적으로 하며, 바인딩 시점에 따라 정적 바인딩과 동적 바인딩으로 구분 합니다.

구분

  • 정적(렉시컬) 바인딩
    • 초기화 단계에서 바인딩
    • 함수 선언문 이름을 바인딩
    • 표현식(함수, 변수) 이름을 바인딩
    • JS의 대부분
  • 동적(다이나믹) 바인딩
    • 실행할 때 바인딩
    • eval() : 문자열을 파싱 해석/실행할 때 마다, 보안문제 존재
    • with문 : 구문을 반복할 때 마다, "use strict" 환경에서 에러

바인딩 시점의 중요성

바인딩할 때 스코프가 결정되기 때문에 중요합니다.

function book() { 
  var point = 100;
  function add() { point += 200; };
  function get() { return point; };
};
  • function 오브젝트 생성 시점에 스코프를 결정
    • 스코프를 function 오브젝트의 [[Scope]]에 설정
    • 스코프가 변경되지 않음
  • 함수 안의 모든 함수의 스코프가 같음

과정

function book() { 
  var point = 100;
  function add(param) {
    point += param; 
  };
  var get = function() {
    return point;
  };
  add(200);
  console.log(get());
};
book();
// 300

<식별자 해결>

  1. 마지막 줄에서 book() 함수 호출
    • 초기화 단계에서 함수와 변수 이름을 선언적 환경 레코드에 바인딩
  2. function add(param) {...}
    • function 오브젝트 생성
    • add 함수가 속한 스코프를 add 오브젝트의 [[Scope]]에 설정
    • add 이름을 레코드에 바인딩
  3. var point = 100;
    • point 이름을 레코드에 바인딩
  4. var get = function() {...}
    • get 이름을 레코드에 바인딩
  5. 바인딩으로 함수와 변수의 식별자 해결 완료

<코드실행>

  1. var point = 100;
    • point 변수에 100 할당
  2. var get = function() {...}
    • function 오브젝트 생성, get에 할당
    • get 함수가 속한 스코프를 get 오브젝트의 [[Scope]]에 설정

<add() 함수 호출>

  1. add(200) 함수를 호출
  2. point += param;
    • 먼저 선언적 환경 레코드에서 point 이름 검색
    • point가 없기에 add 오브젝트의 [[Scope]]를 스코프로 사용하여 다시 검색
    • book 오브젝트가 스코프이며 point가 존재하므로 값을 산술

<get() 함수 호출>

  1. get() 함수를 호출
  2. return point;
    • 선언적 환경 레코드에서 point 이름 검색
    • point가 없기에 get 오브젝트의 [[Scope]]를 스코프로 사용하여 다시 검색
    • book 오브젝트가 스코프이며 point가 존재하므로 값을 반환
profile
소신있게 정진합니다.

0개의 댓글