본문 바로가기

하늘기술

Lexical scoping

반응형

Lexical scoping(어휘적 범위 지정)

    • Scope가 함수 실행시점이 아닌 함수 정의 시점에 정해진다는 의미
  • 특징

    • 변수가 어디에서 사용 가능한지 알기 위해 그 변수가 소스코드 내 어디에서 정의(선언)되었는지 고려
    • 중첩된 함수는 외부 범위(scope)에서 선언한 변수에도 접근가능

    C/C++, Java, 그리고 JavaScript 같이 우리가 접하는 대부분의 언어들은 Lexical Scope를 사용한다. Lexical Scope는 Static Scope라고도 불린다. 반대의 방식으로는 Dynamic Scope가 있으며 Perl, Bash Shell, APL 같은 몇몇 오래된 언어들이 사용하는 방식이다. 두 방식의 정의는 다음과 같다.

Lexical scope: use environment where function [and variable] is defined
Dynamic scope: use environment where function [and variable] is called

Lexical Scope는 변수나 함수가 정의 된 곳의 context를 사용하며, Dynamic Scope는 변수나 함수가 불려진 곳의 context를 사용한다. Lexical Scope는 아주 익숙한 개념이므로 Dynamic Scope에 대해서만 간단히 설명하고, Lexical Scope가 JavaScript에서 어떻게 쓰이는 지 적어볼까 한다.

Dynamic Scope


// JavaScript with Dynamic Scope  
function foo() {  
  [console.log(x);](console.log(x);)  
}  

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

var x = 10;  
foo(); // 10  
bar(); // 15

위의 코드는 JavaScript에 Dynamic Scope가 적용되었다고 가정했다. – 실제로 실행할 경우 다른 결과값이 나온다. 모든 결과값은 Line 3의 x의 값을 읽은 타이밍에 따라서 – 이름 그대로 동적으로 – 달라진다. Line 12에서 처음으로 foo function이 호출될 때 x의 값은 10이므로 당연히 결과값은 10이 출력된다. Line 13에서도 x의 값은 10이지만 bar function내에서 x를 15으로 재선언 뒤 foo function을 호출하기 때문에 결과값이 15로 바뀌게 된다.

언어에 따른 Lexical Scope의 차이
Block Scope
C계열의 언어들은 모든 block이 자신의 scope를 가진다.


// C  
void main() {  
  int x = 1;  
  printf("%d", x); // 1  
  if(1) {  
    int x = 2;  
    printf("%d", x); // 2  
  }  
  printf("%d", x); // 1  
}  

if block 자체가 자신의 scope를 가지고 있으므로 main function의 scope에는 영향없이 따로 x의 값을 가질 수 있다. if block이 지난 뒤에는 다시 main function의 scope에 접근하게 된다.

Function Scope
JavaScript는 Function Scope를 사용한다. function만이 자신의 scope를 가진다.


// JavaScript  
function foo() { // foo   
  var x = 1;  
  [console.log(x);](console.log(x);) // 1  
  if(true) {  
    var x = 2;  
    [console.log(x);](console.log(x);) // 2  
  }  
  [console.log(x);](console.log(x);) // 2  
}  

foo();  

Block Scope와 JavaScript에서는 function만이 scope를 가지기 때문에 if block 안에서 x값을 수정하면 foo function의 scope의 x에 값이 바뀌게 된다 – 실제 JavaScript의 if block 안에서 var를 다시 선언하는 건 좋은 코딩스타일은 아니다. 그러므로, if block이 끝난 뒤에도 수정된 값을 가지게 된다.

그럼 JavaScript에서 새 Scope 생성은?
당연한 이야기지만 Function Scope를 생성해야 하므로 필요한 곳에 function을 추가하면 된다.


// JavaScript  
function foo() {  
  var x = 1;  
  if (true) {  
    (function () {  
      var x = 2;  
      [console.log(x);](console.log(x);) // 2  
    })();  
  }  
  [console.log(x);](console.log(x);) // 1  
}  

foo();  

예제와 같은 경우는 if block의 한정된 곳에서 한번만 실행 될 코드이므로 Immediately-Invoked Function Expression(IIFE)를 추가한다. IIFE는 만들어지자마자 바로 실행되며 동시에 새로운 scope를 가진다. 독립적인 scope를 가지므로 그 안에서 선언된 x는 foo function의 scope에 영향을 미치지 않는다.

JavaScript에서 function을 이용한 Lexical Scope는 Closure를 이해하는데 아주 중요한 요소 중 하나이며 그 외에도 모듈화를 하는데도 빈번히 사용된다.

Let keyword in ES6
이번에 제정된 ES6(ECMAScript 2015)에서는 let keyword가 새로 추가되었다. var과 비슷하게 변수를 선언하는 keyword이지만 많은 부분에서 차이를 보인다.

반응형

'하늘기술' 카테고리의 다른 글

스코프  (0) 2020.03.28
단축평가  (1) 2020.03.28
symbol  (1) 2020.03.27
this  (1) 2020.03.27
reduce 함수  (1) 2020.03.27