개발/Javascript

[You don't know JS] Part2 - 2장. 렉시컬 스코프

lanace 2020. 9. 6. 06:25

스코프의 동작 방식에 따라 두가지로 나뉜다.

  1. 렉시컬 스코프
  2. 동적 스코프

렉시컬 스코프는 일반적으로 많은 프로그래밍 언어들이 사용하고 있음

동적 스코프는 Bash Scripting 이나 Perl의 일부 모드에서 지원함

function foo() {
    console.log(a);
}

function bar = {
    var a = 3;
    foo();
}

var a = 2;

bar();  // 레시컬인 경우: 2, 동적 스코프인 경우 3;

2.1 렉스타임


렉싱: 컴파일러의 첫 단계로, 토크나이징을 한다.

소스코드 문자열을 분석해 상태 유지 파싱의 결과로 생성된 토큰에 의미를 부여

렉시컬 스코프는 개발자가 코드를 짤 때 변수와 스코프 블록을 어디서 작성하는거에 따라서 렉서가 코드를 처리할 떄 확정됨.

function foo(a) {
    var b = a * 2;
    function bar(c) {
        console.log(a, b, c);
    }
    bar (b * 3);
}

foo(2);  // 2, 4, 12

위에 코드에선 3개의 스코프가 존재한다.

  1. 전체 범위
  2. foo 함수 내부의 3개
  3. bar 함수 내부에 1개

스코프는 겹치는게 아니라 포함관계이다.

2.1.1 검색

엔진은 스코프 버블의 구조와 위치를 통해 어디서 검색해야 변수를 찾을 수 있는지 알 수 있다.

섀도잉

더 안쪽의 변수가 더 바깥쪽의 변수를 가리키는것.

중첩된 스코프에 걸쳐 같은 변수명을 사용하는 것.

브라우저에선 global이 window이기 때문에 window.a 로 직접 접근이 가능하긴 하다.

  • window는 쉐도잉 될까?

2.2 렉시컬 속이기


렉시컬 스코프는 개발자가 작성할 때 함수를 어디에 선언했는지에 따라 결정됨

동적으로 렉시컬 스코프를 변경할 수 있는 방법은 아래 2가지뿐이다.

  • eval
  • with

2.2.1 eval

eval은 문자열을 받아 실행 시점에 문자열의 내용을 코드의 일부분 처럼 처리한다.

function foo(str, a) {
    eval(str);

    console.log(a, b);
}

var b = 2;
foo("var b = 3;", 1);  // 1, 3;
console.log(b);  // 2

eval은 그자리에 그 코드가 있는것처럼 그대로 실행된다.

따라서 foo 안에 있는 b 는 외부의 b를 수정하지 않는다.

strict mode에선 eval은 자체적인 스코프를 사용하고, 기존의 스코프를 변경하지 않는다.

eval과 비슷하게 setTimeout이나 setInterval의 첫번째 인자에 문자열 코드를 넣으면 실행된다.

함수의 생성자에도 마찬가지이다.

그러나 이러한 방법은 성능의 저하를 불러이르킨다.

따라서 쓰지 말자.

2.2.2 with

조만간 없어질 예정인 with를 사용하여 스코프를 동적으로 변경할 수 있다.

with는 한 객체의 여러 속성을 참조할 때 객체 참조를 매번 반복하지 않기 위해 사용하는 일종의 속기법이다.

var obj = {
    a: 1,
    b: 2,
    c: 3
}

with (obj) {
    a = 3;
    b = 4;
    c = 5;
}
function foo(obj) {
    with (obj) {
        a = 2;
    }
}

var o1 = {
    a: 1
}

var o2 = {
    b: 1
}

foo(o1);
o1.a  // 2

foo(o2);
o2.a;  // undefined;
a;  // 2???

실제로 obj는 a를 찾기위해 LHS 참조를 한다.

with는 독립적인 스코프를 생성한다.

a = 2 대입과정을 처리하기 위해

2.2.3 성능

eval이나 with때문에 성능이 저하된다.

컴파일 할때 엔진이 미리 확인해둔 변수의 위치가 달라질 수 있기때문에 최적화가 힘들어진다.

2.3 정리하기