[Effective JavaScript] with를 사용하지

김범식·2023년 6월 19일
0

Effective JavaScript

목록 보기
16/33
post-thumbnail

with란?


javascript의 키워드중 하나로 객체의 속성에 접근할 때 코드를 간결하게 작성할 수 있도록 도와주는 기능이다.

with(객체){
	//객체의속성에 접근하여 코드 작성
}

“객체” 는 접근할 객체를 나타내는 표현식이다. with 문 내부에서 객체의 속성에 접근할 때 해당 객체의 이름을 생략하고 바로 속성 이름을 사용할 수 있다.

const person = {
  name: "John",
  age: 30,
  city: "New York"
};

with (person) {
  console.log(name); // "John"
  console.log(age); // 30
  console.log(city); // "New York"
}

위코드에서 with(person) 문을 사용하면 person 객체의 속성에 접근할 때 객체의 이름을 생략하고 속성 이름만 사용할 수 있다.

주의할점

with문은 일부 상황에서 코드를 이해하기 어렵게 만들 수 있고, 성능 저하와 관련된 문제가 있어 사용을 권장하진 않는다. 또한 strict mode에서는 with 문의 사용이 금지되어 있다.

때문에 with문을 사용하는 대신 명시적으로 객체 이름을 사용하여 속성에 접근하는것이 좋다.



with를 사용하지 마라


with는 편리함을 제공하기는 하지만 그로 인해 얻는 이득보다 더 많이 신뢰도를 떨어뜨리고 비효율적이다. with의 필요성은 이해할 법도 하다. 프로그램은 종종 하나의 객체에서 여러 매서드를 호출해야하는데 with를 사용하는 편이 편리하기 때문이다.

function status(info){
	var widget = new Widget();
	with(widge){
		setBackground("blue")
		setForeground("white")
		setText("Status : " + info); //모호한 참조
		show();
	}
}

모듈로 제공되는 객체의 변수를 불러들이기 위해 with를 사용하기도 한다.

function f(x,y){
	with(Math){
		return min(round(x), sqrt(y)); //모호한 참조

위 예제들은 흥미로워 보일지 모르나 실제로는 잘 동작하지 않는다. setBackground, show, round, sqrt 와 같이 with 객체의 프로퍼티를 참조하기를 기대하는 변수와 외부 바인딩으로 참조하기를 기대하는 info, x, y 같은 변수가 있다.

이 두종류의 변수들을 구별할 방법이 없다. 이들은 모두 그냥 변수 처럼 보인다.

자바스크립트는 모든 변수를 동일하게 처리한다. 변수를 스코프 내에서 찾을 때, 가장 안쪽에서부터 시작해 바깥쪽으로 넓혀가면서 찾는다. with 블록 내부에서는 주어진 변수 이름을 가진 프로퍼티 부터 찾기 시작한다. 객체 내에서 프로퍼티가 발견되지 않는다면 그때는 외부 스코프로 이어서 탐색한다.

변수 스코프와 객체 네임스페이스 사이의 충돌은 with 블록을 극도로 불안정 하게 만든다.

status("abc"); // Status : abc
Widget.prototype.info = "changed"
status("abc"); // Status : changed

이처럼 widget 객체가 info 프로퍼티를 가지게 된다면, status 함수의 info 파라미터 대신 widget 객체가 info 프로퍼티를 가지게 된다면 status 갑자기 status 함수의 info파라미터 대신 widget 객체의 info 프로퍼티를 사용하게 된다.

또한 런타임시 Widget 의 prototype 객체에 info 프로퍼티를 추가할 수 있고, 이렇게 되면 status 함수가 예측 불가능한 상황으로 망가지기 시작한다.

Math.x = 0;
Math.y = 0;

f(2,9) // 0

Math 객체에 x y 프로퍼티가 추가된다고 가정한다면 f() 함수는 제대로 동작하지 않게 된다.

물론 말도 안되는 상황이지만 어떤 특정 객체가 수정될지, 혹으 ㄴ알지 못하는 프로퍼티르 ㄹ가지고 있을 지 예측하기란 언제나 쉽지 않다.



대안

javascript에는 with의 대안으로 사용할 만한 직접적인 대체 기능은 없다. 어떤 경우에는 객체를 단순히 짧은 이름의 변수로 바인딩하는게 치선의 대안이다.

function status(info){
	var w = new Widget();
	w.setBackground("blue");
	w.setForeground("white");
	w.addText("Status : "+info);
	w.show();
}

이 예제의 동작은 훨씬 예측하기 쉽다.

status("abc"); // Status : abc
Widget.prototype.info = "changed"
status("abc"); // Status : abc

이제 Widget의 prototype을 수정하더라도 status함수는 기대대로 동작할 것이다.

function f(x,y){
	var min = Math.min;
	var round = Math.round;
	var sqrt = Math.sqrt;
	return min(round(x), sqrt(y));
}

Math.x = 0;
Math.y = 0;
f(2,9) // 2

다른 경우에는, 지역 변수를 명시적으로 연관된 프로퍼티와 바인딩하는 것이 최선의 방법이다.



기억할 점

  • with를 사용하지 말자
  • 객체로의 반복되는 접근을 위해 짧은 변수 이름을 사용하자
  • with 선언문으로 암묵적으로 바인딩하는 대신 명시적으로 지역 변수를 객체 프로퍼티에 바인딩하라
profile
frontend developer

0개의 댓글