dovelet 문제를 사용한 with 사용기

With??

저는 dovelt 문제풀다가 with을 한번 써보자는 생각에 키보드에 손을 댔습니다…(토익공부해야하는데…)

속깊은 javascript 저자 양성익씨가 말씀하시길


with은 쓰지 말고 없는 것처럼 하라


라고 하셨죠. 정확히는 기억이 안납니다만 대충 이렇게 말씀하셨던 것 같습니다.

몇가지 이유가 있는데 일단 제가 쓴 코드를 보면서 설명해 볼까 합니다.


(function(){
     var inputA = 3, inputB = 20;
     var volume = inputB - inputA +1;
     with(Math){    //with은 인자값으로 객체를 받습니다.
         var result = volume - floor(sqrt(volume)); //with으로 받은 객체 이름을 쓰지 않아도
     }                                              //객체의 프로펄티를 사용할 수 있습니다.              
     console.log(result);    //with은 스코프를 생성하지 않습니다. 그래서 result를 사용할 수 있습니다.
 })();

코드만 봐서는 with이 굉장히 유용해 보입니다.

왜냐하면 인자값으로 객체를 넣어주기만 하면 객체의 이름없이도 프로펄티를 쓸 수 있는데다가

내부에서 선언한 변수는 스코프의 영향을 받지 않아 외부에서도 사용 할 수 있습니다.

반면 인자값으로 받은 객체는 스코프의 영향을 받아 외부에서는 사용할 수 없습니다.

내부 변수는 외부에서 사용가능하고, 인자로 받은 객체는 with 내부에서 밖에 사용할 수 없다는 점때문에

처음 봤을 때는 수륙양용 킥보드처럼 보여서, 오 멋있다 라고 생각했지만

책을 읽어보니 문제가 많다고 합니다.


문제점

  1. 좀 있으면 사라질 함수이다.

  2. 성능 문제가 있다.

  3. 사용방법이 매우 모호하다.


1. 좀 있으면 사라질 함수이다.

사라질 함수라서 사용했다가 나중에 후회할 수도 있으므로

지극히 당연한 이유로 사용하지 말자고 합니다.

2. 성능 문제가 있다.

아래의 두 코드를 보겠습니다.

첫번째 코드


(function(){
     var a ="with 안썼음";
     return function(){
        console.log(a); // 바로 상위 스코프를 찾아 a를 출력합니다.
     }
 })()();

단박에 a가 클로저에서 a를 찾았음을 알 수 있습니다.

두번째 코드

(function(){
    var a = "with 썼음";
    with({}){   
        console.log(a); //결과적으로는 a를 참고 하긴합니다만 성능에서 첫번째 코드만 못합니다.
                        //왜냐하면 a를 찾기 위해 제일 먼저 찾는 것은 상위 스코프가 아니라 인자값에서 a를 찾기 때문입니다.
    }
})();

with은 메모리와 성능 모두다 잡아먹게 되어 결과적으로 성능 저하를 보이게 됩니다.

위의 두번째 코드에서 with의 인자값으로 넣은 객체의 메모리가 유지될 뿐만 아니라

with 내부에서 변수를 찾을 때, 바로 상위 스코프를 탐색하는 것이 아니라 인자값에서

찾는 값이 있는지 없는지 확인한 다음 상위 스코프로 넘어가기 때문에, 첫번째 코드처럼

즉시 상위스코프를 찾아 올라가는 것에 비해 성능이 떨어질 수 밖에 없습니다.

공간 컴플렉스랑 시간 컴플렉스 둘다 떨어지는 기능을 굳이 사용해야 하느냐고 묻는다면

쓰지 않는다는 결론이 나올 수밖에요.

3. 사용방법이 매우 모호하다.

맨 처음 dovelet 문제를 풀었던 코드를 다시 생각해보자면

이해가 가는 문제입니다.

어느지점이냐면 바로 제가 수륙양용 킥보드 같다고 이야기 했던 부분입니다.

웬지 좋아보이지만 까딱 잘못했다간 배도아니고 물에 빠질 수도 있죠.

아래 코드가 약간 극단적인 예입니다만 어느정도 설명이 가능합니다.


(function(){
    var a = "완전 헷갈려";
    with({a:"더 헷갈려"}){
        console.log(a);  //더 헷갈려! 를 출력합니다.
        var b = "헤헷^^";
        var a = "더더더 헷갈려"; //scope는 생성 안되는 주제에 외부 변수는 변경 못합니다.
    }
    console.log(b); //헤헷^^ 을 출력합니다.
    console.log(a); //완전 헷갈려! 를 출력합니다.
})();

이 코드 작성하면서 저도 좀 헷갈렸습니다.

특히 a 가 매우 헷갈려 보입니다.

  1. 외부 스코프에 a가 선언되었고,

  2. with에 인자값으로 a를 가진 객체를 입력하고

  3. a를 with 내부에 변수 선언하였고

  4. 밖에서 a 랑 b를 출력했는데 둘다 똑같이 with 내부에 선언했는데
    b는 출력이 잘 되는데 a는 외부스코프의 a 값을 출력합니다.

. 일단 a가 그 a가 맞는지 아닌지 헷갈립니다.

with 밖에도 a가 있고

with 인자 값 객체안에도 a가 있는데

with 내부에서 객체의 이름을 쓰지 않아도 프로펄티를 사용 할 수 있으니

with 내부에 사용된 a가 외부에 있는건지 객체 안에 있던건지 헷갈립니다.

. 두번째로 with 자체는 스코프를 걸지 않는다고 해서 변수 a 와 b를 선언해 보았는데

a는 선언했음에도 불구하고 밖에서는 사용 불가능하고, b만 밖에서 사용 할 수있었습니다.

이와 같은 현상으로 다시한번 with의 안이 밖인지, 아니면 밖이 안인지 헷갈립니다.

무슨 호접지몽도 아니고 꿈꾸면서 코딩할것도 아닌데 말이죠.

이 예제가 다소 극단적인 상황이라고 말씀은 드렸습니다만,

with의 단점인 애매모호함을 설명하기에는 충분하지 않았나 생각해 봅니다.

–마무리–

결론은 with을 쓰지 말자입니다.

with에게 가장 어울리는 언어는 빛좋은 개살구 인것 같습니다.

당장은 뭔가 다 할 수 있는것 처럼 보이는 함수이긴 합니다만,

뚜껑 열어보면 꽝인거죠.

오늘의 교훈은, 겉모습만 보고 판단하지 말자. 함수든, 사람이든!

아… 시간을 너무 많이 썼네요.

토익 공부하러 가야겠습니다 …ㅠㅠ

1개의 좋아요