자바스크립트에서 점(.)은 어떤 역할을 할까요? 


var a = {

     name: '지돌스타 - 쿠키랩', 

     getName: function(){

          return this.name;

     }

};


위 구문은 new Object() 대신 {} 리터럴 문법을 사용해 Object 객체의 인스턴스를 만들어 줍니다. Object 객체의 실체는 Key-Value로 이뤄진 Hash맵입니다. 여기서 new 키워드는 자바스크립트에서 heap 메모리 공간을 별도의 컨텍스트(Context)를 만들 수 있는 유일한 수단입니다. new 또는 리터럴 표기법 외에는 컨텍스트를 생성할 수 없습니다. 여기서 컨텍스트란 독립된 heap 메모리 공간으로 보통 OOP에서 인스턴스를 생성했을 때 할당되는 메모리 공간과 거의 흡사한 개념입니다. 이렇게 만들어진 컨텍스트는 함수가 실행될 때 this를 바인딩하는 목적으로 사용됩니다. 


한가지 더 알아야할 것은 자바스크립트에서 Object는 고유명사입니다. 일반명사가 아니라는 말이지요. 하지만 많은 자바스크립트 문서 및 책에서 이것을 일반명사인 것처럼 잘못 해석합니다. 명확한 의미를 파악하지 못한채 영어를 한국어로 표현하는데 있어서 오류를 만들어내는 것에 비롯되지요. 그러므로 여러분은 이제 Object는 고유명사이다라고 항상 인지하세요. Object의 다른 이름을 짓는다면 그냥 '사과' 정도인겁니다. Object는 고유명사 '사과'다라고 이해하면 더 편할지 모르겠습니다.


각설하고, 이렇게 만들어진 a 인스턴스를 좀 더 봅시다. 다음과 같은 코드가 있다면 여러분은 어떻게 해석하시겠습니까? 더 정확하게 물어본다면 점(.) 구문이 하는 역할은 도데체 무엇일까요? 


console.log(a.name);

console.log(a.getName());


물론 결과는 예상했듯이 둘다 '지돌스타-쿠키랩'이 나옵니다. OOP에 익숙한 분들이라면 a.name을 했다면 a에 name 속성이 정의되어 있으니깐 당연한거 아닌가? a에 getName() 메서드가 정의되어 있으니깐 그냥 그거 호출한거 아니야? 뭐 이런식으로 해석할 것입니다. 하지만 전혀 그렇지 않습니다. 일단 자바스크립트에는 클래스가 없습니다. 자바스크립트는 단순히 Object 객체의 key-value공간과 Function 객체의 스코프 공간외에는 메모리에 만들지 않습니다. 그 이상도 그 이하도 아니기 때문에 클래스를 만들었다고 생각하면 큰 오산입니다. 그리고 var a = {}은 바로 인스턴스를 만들어내는 리터럴 표기법일 뿐입니다. 자바스크립트는 동적인 언어기 때문에 저 표기를 바꾸면 다음과 같습니다.


var a = new Object();

a.name = '지돌스타-쿠키랩';

a.getName = function(){

     return this.name;

};


즉, 클래스에 속성과 메서드를 정의했다고 생각한 것 자체가 잘못되었다는 것을 인지해야 합니다. 속성, 메서드 모두 동적으로 생성된 것이지요. 결국 리터럴 표기법인 {}가 마치 클래스 문법인 것마냥 느껴짐으로 인해 발생되는 인지적 오류겠습니다. 


new Object()는 뭐냐고요? Object 클래스잖아? 라고 보신다면 다음 글을 보세요.

http://zero.diebuster.com/zero/?p=36


자 그럼, 다시 점(.) 구문으로 돌아가 봅시다. 미리 언급했듯이 Object 객체는 key-value로 이뤄진 hash맵입니다. new를 통해서 hash 맵을 생성하고 동적으로 'name'과 'getName'이라는 key에 대해 각각 '지돌스타 - 쿠키랩'과 Function객체를 value로 삼은 것입니다. 그렇다면 여기까지 점(.) 구문은 key-value 검색을 한다는 의미입니다. 좀더 나아가자면 자바스크립트는 Object 객체의 인스턴스가 new를 통해 생성될 때 자동으로 __proto__라는 key를 만들어 value로 Object.prototype을 참조시킵니다. 그래서 만약 앞서 a 인스턴스에서 'name' 또는 'getName'이라는 키를 발견하지 못하면 Object.prototype에 정의된 key-value 검색도 자동으로 이뤄집니다. 성능상 문제를 일으키는 프로토타입 체인 검색이 일어나는 순간입니다. 아무튼 정리한다면 점(.)구문은 key-value 검색을 발동하고 없으면 프로토타입 체인(prototype chain) 검색을 해줍니다. 


그럼 지금부터 반드시 기억해야할 키 포인트 언급해 보겠습니다. 그럼 검색은 그렇다 치고 a.name, a.getName() 에 사용된 점(.)은 모두 같은 동작을 할까요? 결론적으로 앞의 점(.)과 뒤의 점(.) 구문은 전혀 다른 동작을 합니다. key-value 검색이 들어가는 것은 동일하나 a.name의 경우는 일종의 값이 value로 참조되어 있는 경우입니다. 이런 경우에는 바로 value가 반환되는 동작을 할 뿐입니다. 하지만 a.getName()을 통해 찾은 value인 getName은 함수입니다. 뒤에 ()이 있다는 것을 명심하십시오. 만약 ()이 없이 getName만 썼다면 a.name과 같은 동작을 할 것입니다. 결과적으로 a.getName()은 다른 동작을 하게 되는데 key-value검색 후에 a.getName()은 다음과 같은 동작을 합니다.


f = a.getName;

f.apply(a);


f는 Function 객체입니다. 이 객체에는 apply() 또는 call() 메서드가 정의되어 있습니다. 두 메서드의 차이점은 두번째 인자가 rest냐 배열이냐 차이 뿐입니다. 동작은 같습니다. 중요한 것은 첫번째 인자인데 a객체를 첫번째 인자로 자동으로 넘겨줍니다. 이 말은 실행 컨텍스트(execution context)를 a로 하고 여기에 this를 바인딩 시켜준다는 의미입니다. 즉, 실행된 함수내에서 this를 사용한다면 그 this는 바로 a를 가리키게 됩니다(이게 this가 a로 바인딩된다는 말입니다). 그러므로 함수내에서 this.name은 a.name과 동일하지요. f.apply(a)가 호출되는 순간은 a가 바로 실행 컨텍스트가 되는 순간인겁니다. 


그러므로 점(.) 구문은 a.name과 a.getName()이 전혀 다른 것임을 인지해야 합니다.


자 여기서 갑자기 궁금해지는 것이 있을 수 있겠네요. 그럼 점(.) 구문을 사용하지 않는 경우는 어떻게 되는거죠?

가령, <script> 태그내에 바로 함수와 변수를 정의했다면요.


<script>

a = '지돌스타-쿠키랩';

getName = function() {

     return this.a;

};

console.log(a); //지돌스타-쿠키랩

console.log(getName());  //지돌스타-쿠키랩

</script>


갑자기 지금까지 한 말이 거짓말처럼 들리는 순간입니다. ㅎㅎ 


많은 책에서 저렇게 만들면 전역변수 a와 전역함수 getName을 정의했다고 합니다. 하지만 이 말은 잘못된 말입니다. 자바스크립트에서는 전혀 다른 것이지요. 위 코드는 다음처럼 바뀝니다.


window.a = '지돌스타-쿠키랩';

window.getName = function() {

     return this.a;

};

console.log(window.a);

console.log(window.getName());


감잡으셨나요? 자바스크립트가 단지 2개의 공간으로만 이뤄졌다고 설명했습니다. 자바스크립트가 구동될 때, 제일 먼저 new없이도 생성하는 유일한 객체가 바로 window입니다.(브라우저마다 조금씩 다릅니다만…). window도 결국 Object일 뿐이며 key-value공간일 뿐입니다. 그래서 자바스크립트 엔진은 암묵적으로 점(.) 구문이 없이 사용했다면 그건 window객체와 함께 점(.)구문을 사용한 것처럼 해석합니다. 물론 window.getName()이 window.getName.apply(widow) 인 것도 아시겠지요?


<script> 내에 아래코드처럼 사용된다면 return name는 도데체 뭘 말하는 것일까요? 


name = '지돌스타-쿠키랩';

getName = function(){

   return name;

};


여기서 예외사항이 있는데 window에 key-value로 잡힌 getName 함수에 this.를 쓰지 않은 경우에는 자동으로 this. 구문을 쓴 것처럼 해석됩니다. 즉, 이때 name은 this.name와 같으며 결국 window.name를 가리킵니다. window가 아닌 나머지 객체에서는 반드시 this를 써야겠지요. 이건 예외사항!


몇가지 더 언급한다면 점(.) 구문은 ['']와 완벽하게 대체됩니다. 다음처럼요.


window['a'] = '지돌스타';

window['getName'] = function() {

     return this['a'];

};

console.log(window['a]);

console.log(window['getName']());


그리고 Object의 key-value로 잡힌 것은 나중에 delete연산자를 통해서 삭제할 수 있습니다.


delete window['a'];

delete window['getName']; 


당연히 이것도 동일한 거겠지요?


delete window.a;

delete window.getName;


또 당연히 다음과 같이 암묵적으로 써도 같겠지요?


delete a;

delete getName; 


점(.) 구문 설명하려고 하는데, 여러가지가 다 튀어 나오네요. 아무튼, 자바스크립트 코드가 결국 C로 만들어진 엔진에서 해석되어 동작한다는 것을 알고 결국 2가지 메모리 공간에서 이뤄진 hash 맵일 뿐이다라고 인식하는 순간 우리는 이런거 외우지 않고도 자연스럽게 받아들이고 성능 및 메모리를 최적화 할 수 있는 스킬을 가지게 되는 것이 아닌가 생각합니다. ^^  


글쓴이 : 지돌스타(http://blog.jidolstar.com/808)