티스토리 뷰


* 전문가들이 자바스크립트에 있지만 없는듯이 살라는 명령어가 2가지가 있다. 

    • eval
    • with

: eval은 보안상, 퍼포먼스상 문제가 있기 때문에 반드시 필요한것이 아니라면 사용하지 말라고 하는 것은 이해가 되지만, 솔직히 with란 놈은 한번도 써본적도 없고, 본적도 없는데 사용하지 말라고 한다. 한번도 본적이 없는 명령을 사용하지 말라고 하니까 이게 어떠한 명령인지 왠지 더 궁금해지고 사용해보고 싶은 법! 때문에 일단 이 with 명령에 대하여 한번 알아보고, 왜 사용하지 말아야 하는지 알아보자.


* with

- 설명: with 이후에 오는 구문을 위해 scope chain에 인자로 받는 object를 추가한다.

- 문법:

with (object)
    statement;

또는

with (object) {
    statement;
}

: 블럭 괄호{}는 if 처럼 생략이 가능하고, with의 인자로 받는 object는 그 이후의 statement나 블럭 {} 안에 scope chain이 추가되어서 실행이 가능하다. 이렇게 말하는 것보다는 실제 예를 보는 것이 이해가 빠를 것이다. 아래는 간단한 예이다.

var user = {
    name: "unikys",
    homepage: "unikys.tistory.com",
    language: "Korean"
}
with (user) {
    console.log(name === "unikys");
    console.log(homepage === "unikys.tistory.com");
    console.log(language === "Korean");
    language = "javascript";
}
console.log(user.language === "javascript");

: 위와 같이 user라는 객체를 scope chain에 새로 넣음으로써 속성들을 바로 접근 가능하도록 설정해주고 있다. 위보다 실용적인 예를 하나 살펴보면 아래와 같다.

with (document.getElementById("myDiv").style) {
    background = "yellow";
    color = "red";
    border = "1px solid black";
}
// 또는
var r = 10, a, x, y;
with (Math) {
    a = PI * r * r;
    x = r * cos(PI);
    y = r * sin(PI / 2);
}

: 위와 같이 style의 설정이 간단하게 가능하기도 하고, Math의 객체 안에 있는 변수와 함수들을 굳이 어렵게 접근을 하지 않아도 된다. 이렇게 편해보이긴 하지만 이미 수 많은 자바스크립트 전문가들은 with를 쓰지 말라고 권한다. 왜그럴까?



* with를 사용해서는 안되는 이유

: 우선적으로 들 수 있는 이유는 바로 새로운 scope를 생성함으로써 생기는 추가적인 자원 소모일 것이다. 새로운 인자로 들어온 scope에서만 데이터와 함수들을 이용할 경우 성능이 향상되겠지만 상위의 scope에서 데이터를 가져오는 경우 그때마다 추가적인 처리 시간이 들어가게 된다. 이것은 with 안의 구문들이 어떠한 구문들로 이루어졌느냐에 따라 성능의 차가 다르게 나올 것이다.


: 하지만 전문가들이 드는 가장 큰 이유는 바로 with로 인해서 생겨나는 모호성 때문이다. 바로 아주 간단한 예를 들어보겠다.

function doSomething(value, obj) {
    with (obj) {
        value = "which scope is this?";
        console.log(value);
    }
}

: 위의 경우 value가 어디에서 나온건지 알 수 있겠는가? 2가지중 하나이다. 인자인 "value"일수도 있고, obj 안의 속성인 "value" 일수도 있다. 이것을 아는 것은 이 함수를 짠 프로그래머 자신 이외에는 없다. 즉, 모든 작업을 본인이 하고, 문서화까지 철저하게 해놓는다면 위와 같은 상황에서 쓴다고 해도 큰 문제가 없겠지만, 만약 다른 사람과 같이 프로그래밍을 하던가 혼자서 하더라도 몇 개월이 지나서 다시 보게 되는 경우 헷갈리게 될 가능성이 매우 높다. 이러한 상황을 방지하기 위해 with문의 사용을 자제하라고 권하는 것이다. 그렇다면 위의 style을 설정하는 아주 매력적인 기능도 사용해서는 안되는 것일까?



* with의 대체제

: 물론 위의 사용자의 혼돈을 가져올 수 있는 위험성도 크지만 위의 style에서 가장 큰 문제 중 하나는 인자의 object에 없는 스타일을 설정하게 되는 경우 style로 들어가지 않고 바로 글로벌 변수로 설정되어버린다는 것이다. 이러한 상황이 빈번하게 있기 때문에 다소 곤란할지도 모른다. 그럼 위와 비슷하게 편하게 하고 싶을 때에는 아래와 같이 하면 된다.

var s = document.getElementById("myDiv").style;
s.background = "yellow";
s.color = "red";
s.border = "1px solid black";

: 위의 with보다 사용해야하는 글자 수는 조금더 많지만, 아주 직관적이고 with 처럼 자바스크립트를 오래 해왔던 사람들도 헷갈릴만한 요소도 하나도 없다. C나 자바만 해오던 사람들도 이 소스라면 바로 이해가 가능한 것이 이러한 방식을 이용하는 것이 여러 모로 좋고, 성능상 하나의 scope를 새로 만드는 것보다 로컬 변수에 대한 접근이 더 빠른 경우가 많기도 하다. 


: with 명령은 위와 같은 상황에서 거의 다 대체가 가능하다. 그렇다면 with는 정말로 사용할 수 있는 가능성은 전혀 없을까?



* with의 효용성

: 이전의 '속깊은 자바스크립트 강좌'에서 scope를 설명하면서 with의 유용한 활용법 한가지를 설명한 적이 있다.


- 참고

2012/12/17 - [속깊은 자바스크립트 강좌] 자바스크립트의 Scope와 Closure 기초


: 이때 언급했던 내용과 조금 다른 활용처로 써보면 for 안에 setTimeout과 함수 안에 for의 i값을 사용하는 경우일 것이다.

var i;
for (i = 0; i < 3; i++) {
    with ({index: i}) {
        setTimeout(function () {
            console.log("#" + index + " times");
        }, 1000);
    };
}

: 위와 같은 상황에서도 유용할 것이다. 위의 경우에서 왜 with를 사용해야하는지 이해가 잘 안된다면 위에 링크 해놓은 "속깊은 자바스크립트 강좌"를 읽어보면 이해가 갈 것이다. 이것은 위처럼 with와 object literal을 합쳐서 사용함으로써 그 모호함을 없애주기도 했고 scope에 대한 문제도 해결해줬기 때문에 사용가능할 것이지만 이 역시 closure로 극복이 가능한 문제이다.


: with를 활용함으로써 쉽게 해결할 수 있는 문제는 다음과 같은 경우도 있다.

with (mylibrary) {
    with (window) {
        console.log("do something while the global scope has priority");
    }
}

: 자신의 라이브러리에 있는 항목들보다 global scope에 우선순위를 두고 싶은 경우 위와 같이 활용이 가능할 것이다. 일반적으로는 mylibrary의 변수나 함수들이 더 우선순위가 높겠지만, 반대로 global의 변수와 함수들의 우선순위를 높이고 싶을 때 사용할 수 있다. 이러한 경우는 만약 Object객체 등에서 기본적으로 가지고 있는 prototype 함수인 경우 예를 들면 모든 Object들이 기본적으로 가지고 있는 toString과 똑같은 함수를 선언하고 사용하고자 한다면, with를 아래와 같이 사용하면 문제가 있다.

function toString(string) {
    console.log(string);
}
with ({test: "hello"}) {
    toString(test);
}

: 글로벌에 있는 toString 함수를 출력하고 싶어서 with 안에서 toString을 호출했지만, 이러한 경우 with의 object literal의 toString 함수를 호출하게 된다. 따라서 다음과 같이 이것을 회피할 수 있다.

function toString(string) {
    console.log(string);
}
with ({test: "hello"}) {
    with (window) {
        toString(test);
    }
}

: 번거롭기는 하지만 문제는 해결할 수 있다. 하지만 이 역시 toString 함수의 이름을 바꾸기만 한다면 간단하게 해결가능하다.



* 결론

: with는 전체적인 파일의 크기 등을 줄일 수 있고 read only의 목적으로 활용되는 경우 편리하게 사용은 할 수 있지만, 굳이 꼭 필요한 것이 아니라면 사용할 필요는 없다. 이러한 with의 활용 방법은 생성되는 scope chain을 활용하거나 글로벌 scope를 우선시 하고 싶을 때에는 활용할 수 있다.


: 그래도 전문가들이 사용하지 말라는건 이유가 있으니 사용은 자제하자.



끝.


공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함