참조: Reference - OOP JavaScript

from 프로자바스크립트테그닉

자바스크립트에서 중요한 개념 중 하나가 바로 참조(reference)다. 참조는 객체의 실제 위치를 가리키는 포인터다. 참조는 매우 강력하다. 자바스크립트에서 실제 객체 그 자체는 절대로 참조가 될 수 없다. 문자열은 항상 문자열이고 배열은 항상 배열이다. (문자열이 참조이거나 배열이 참조가 될 수 없다는 말인가?) 그렇지만 서로 다른 변수들이 동일한 객체를 가리킬 수 있다. 자바스크립트는 이렇게 참조들로 구성된 구조에 기반하고 있다. 자바스크립트는 객체들에 대한 참조 집합을 관리함으로써 유연하게 작동한다.

객체는 또 프로퍼티의 집합을 가질 수 있다. 모든 프로퍼티는 그저 다른 객체(문자열, 숫자, 배열 같은)에 대한 참조다. 여러 변수가 한 객체를 가리키고 있을 때 이 객체를 수정하면 해당 사항은 이 객체를 가리키는 모든 변수에 반영된다. 아래의 코드는 이에 관한 예이다. 아래 코드에서 두 변수가 한 객체를 가리키고 있는데 이 객체를 수정하면 수정 사항이 전역적으로 두 변수에 모두 반영된다.



동일한 객체를 가리키는 여러 변수들에 대한 예

							// obj를 빈 객체로 설정한다.
							var obj = new Object();

							// 이제 objRef는 앞의 빈 객체를 가리킨다.
							var objRef = obj;

							// 앞에서 생성했던 객체의 프로퍼티를 수정한다.
							obj.oneProperty = true;

							// 이제 이 수정 사항이 두 변수에 모두 나타남을 볼 수 있다.
							// (두 변수 모두 동일한 객체를 가리키고 있기 때문이다.)
							alert(obj.oneProperty == objRef.oneProperty); // true						
						

앞에서 자바스크립트에는 그 내용을 수정할 수 있는 객체가 드물다고 말했다. 이와 관련해서 흔히 나타나는 예를 살펴보자. 배열 객체에는 push() 메서드로 새로운 아이템을 추가할 수 있다. 이 경우 Array 객체 안에서 값들이 객체 프로퍼티로서 저장되므로, 객체가 전역적으로 수정되었던(여러 변수의 내용이 동시에 바뀌는 결과를 낳았다.) 상기의 코드에 나온 예와 비슷한 상황이 벌어질 수 있다. 아래의 코드는 그 예다.



스스로를 수정할 수 있는 객체에 대한 예

							// 아이템 배열을 생성한다.
							var items = new Array("one","two","three");

							// 아이템 배열에 대한 참조를 하나 생성한다.
							var itemsRef = items;

							// 원본 배열에 아이템을 하나 추가한다.
							items.push("four");

							// 두 변수가 동일한 배열 객체를 가리키기 때문에
							// 각 배열의 크기가 같아야 한다.
							alert(items.length == itemsRef.length);				
						

참조는 최종적으로 참조되는 객체를 가리키며, 참조 자체를 가리키지는 않는다는 사실을 기억해야 한다. 예를 들어, 펄에서는 한 참조가 역시 참조인 다른 변수를 가리킬 수 있다. 그러나 자바스크립트에서 참조는 항상 참조 체인(reference chain)을 따라간 후 만나는 최종 객체를 가리킨다. 아래의 코드는 이와 관련된 예다. 아래 코드에서 items 참조가 가리키는 객체가 변했지만 itemsRef는 여전히 예전 객체를 가리키고 있다.

(상기의 예제를 한번 살펴 보자. 최초 items라는 변수는 Array 객체를 참조하고 있다. 그리고 itemsRef는 items라는 변수를 참조하고 있는가? 아니다. 앞의 설명에 따르면 itemsRef는 items에 대한 참조가 아니라 최종적으로 만나게 되는 Array 객체을 참조하고 있다. 참조 변수를 참조하는 변수가 아니라 참조 변수가 가리키는 객체를 다시 참조하고 있다는 말이다. 하나의 Array 객체에 대해서 2개의 참조 변수가 있다는 말이다. )



원래 객체는 그대로 두고 한 객체의 참조를 변경

						// items가 문자열 배열을 가리게 한다.
						var items = new Array("one", "two", "three");

						// itemsRef가 items 참조를 가리키게 한다.
						var itemsRef = items;

						// items가 새로운 객체를 가리키게 한다.
						items = new Array("new", "array");
						
						// items와 itemsRef는 이제 서로 다른 객체를 가리킨다.
						// items는 new Array("new", "array")를 가리키고,
						// itemsRef는 new Array("one", "two", "three")를 가리킨다.
						alert(items != itemsRef);		
						

마지막으로, 내용을 수정할 수 있는 객체에 대한 예인 듯 하지만 결국은 참조할 수 없는 새로운 객체를 만드는 예를 살펴보자. 문자열을 이어붙이면 그 결과는 원본 문자열을 바꾼 것이 아니라 항상 새로운 문자열이 된다. 아래의 코드가 그 예이다.



내용을 수정할 수 없는 새로운 객체를 만드는 객체 수정에 대한 예

						// item이 새로운 문자열 객체를 가리키게 한다.
						var item = "test";

						// itemRef는 이제 동일한 문자열 객체를 가리킨다.
						var itemRef = item;

						// 문자열 객체에 새로운 텍스트를 이어붙인다.
						// 주목: 이렇게 하면 원본 객체를 수정하지 않고,
						// 새로운 객체를 만든다.

						item +="ing";
						
						// 완전히 새로운 객체를 생성했기 때문에
						// item과 itemRef은 서로 다르다.
						alert(item != itemRef);  // true
						alert(item); // "testing"
						alert(itemRef); // "test"	
						

참조라는 개념을 처음 접한다면 이해하기 어려울 수도 있다. 그렇지만 좋은 코드, 깔끔한 코드를 작성할 때 참조가 어떻게 도움이 되는지를 이해하는 일은 매우 중요하다. 이어지는 절들에서는 새롭거나 흥미롭지는 않더라도 좋은 코드, 깔끔한 코드를 작성하고 싶을 때 중요한 기능 몇 가지를 살펴본다.