원본글 : http://howtonode.org/object-graphs

최고의 JavaScript 개발자가 되는 비밀중에 한가지는 언어의 semantic을 이해하는 것이다. 이번 article은 많은 그림들을 활용해서 JavaScript의 기본적인 부분들을 설명하려고 한다.

References Everywhere

JavaScript에서 변수는 메모리 어딘가의 값을 가리키는 단순한 라벨일 뿐이다. 이 값들은 프리미티브 형태(strings, numbers, booleans)를 가질 수 있다. 물론 오브젝트 나 function이 될 수 있다.

Local Variables

아래의 예제에서처럼, top-level scope에서 4개의 로컬 변수를 만들 것이고 그것들은 어떤 프리미티브 값들을 가르킬 것이다.

// Let's create some local variables in the top scope
var name = "Tim Caswell";
var age = 28;
var isProgrammer = true;
var likesJavaScript = true;
// Test to see if the two variables reference the same value
isProgrammer === likesJavaScript;

// output ==> true

두개의 Boolean 변수들은 메모리에서 값은 값을 가르키고 있다. 프리미티브 값들은 변경되지 않고 VM에서 최적화를 해서 모든 레퍼런스들이 특정 값을 참조하게해 하나의 인스턴스를 공유하게 한다.

두개가 같은 값을 참조하는지 체크하기 위해서 === 를 사용해서 테스트 하였고 결과는 true 였다.

박스 밖은 가장 바깥쪽 closure 영역이다. 이 변수는 탑레벨의 local 변수이고 Global/Window 오브젝트 속성과 혼돈하면 안된다.

Objects and Prototype Chains

Object는 새로운 Object와 prototype을 참조하는 모음이다. 특별한 것은 추가된 기능은 Prototype chain이라는 것이고 이것은 property에 접근하려고할때 로컬 Object에 없다면 Object에 있는 property를 접근가능하게 해준다.

// Create a parent object
var tim = {
   name: "Tim Caswell",
   age: 28,
   isProgrammer: true,
   likesJavaScript: true
}
// Create a child object
var jack = Object.create(tim);
// Override some properties locally
jack.name = "Jack Caswell";
jack.age = 4;
// Look up stuff through the prototype chain
jack.likesJavaScript;

// Output ==> true

tim 변수에 의해서 참조되며 4개의 property를 가지고있는 Object가 있다. 또한 새로운 Object를 생성하는데 그것은 첫 Object를 상속하고 있으며 jack에 참조된다. 그 다음에 우리는 두 property를 로컬 Object에서 overrode 한다. 이제 jack.likesJavaScript를 보면, 우리는 jack을 참조하고 있는 object를 찾는다. 그러면 우리는 likesJavaScript의 property를 보게 된다. 이것이 없기 때문에 우리는 부모 object를 보게되고 그곳에서 찾게 된다. 그리고 우리는 이것이 참조하고 있는 true를 발견한다.

The Global Object

jslint 같은 툴들은 변수 앞에 var를 사용하라고 이야기한다. var를 사용하지 않을 경우는 아래와 같다.

var name = "Tim Caswell";
var age = 28;
var isProgrammer = true;
// Oops we forgot a var
likesJavaScript = true;

likesJavaScript 는 밖의 closure에 있는 자유 변수가 아니라 global Object의 property이다. 이것은 실제로 몇몇의 script를 섞어서 사용할 때 문제가 된다. 그렇지만 실제 프로그램에서는 하게 되는 일일 것이다.

저곳에 저런 var 문구를 사용할때는 자신의 변수의 영역을 지금의 closure와 children으로 부터 지켜야한다는 것을 기억해야한다. 이 간단한 규칙을 따르는 것으로 매우 행복해질 것이다.

만약에 global Object에 무언가 올리고 싶다면 브라우저에서는 window.woo 이고 node.js에서는 global.goo와 같이 명시적으로 적어야한다.

Functions and Closures

Javascript는 단지 자료구조 연결들의 모음이 아니다. 이것은 executable, callable code(function으로 알려진)와 같은 것들을 포함하고 있다. 이런 function은 chained scope와 clousure를 생성한다.

Visualizing Closures

Function은 executable code 뿐만 아니라 property를 가지고있는 특별한 Object로 그려진다. 모든 Function은 이것이 정의될때의 환경을 나타내는 특별한 [scope] property를 가지고있다. 만약에 function이 다른 function으로 부터 반환 된다면 이것은 옛날의 환경은 Closure에 의해서 닫히게 된다.

이번 예제에서 closure를 생성하고 function을 반환하는 간단한 factory 메소드를 만들도록 하겠다.

function makeClosure(name) {
   return function () {
      return name;
   };
}

var description1 = makeClosure("Cloe the Closure");
var description2 = makeClosure("Albert the Awesome");
console.log(description1());
console.log(description2());

// Output
// Cloe the Closure
// Albert the Awesome

description1()을 호출할 때, VM은 참고하고 있는 곳이나 실행하고 있는 곳에서 function을 찾는다. funtion이 로컬 변수인 name를 찾고 있기 때문에 closure 영역에서 찾게 된다.이 factory 메소드는 각각 만들어진 function이 자신의 로컬 변수영역을 가지고 있기 때문에 잘 만들어진 것이다.

보다 자세한 내용이 알고싶으면 다음 문서를 보면 why use closure 된다.

Shared Functions and this

퍼포먼스의 이유 혹은 선호하는 스타일 때문에 JavaScript는 this라는 키워드를 제공하고 function Object를 다른 scope에서 불리는 방법에 따라 재사용하기도 한다. 공통 function을 공유하는 몇가지 Object를 생성한다. 이 function은 this를 참조하고 내부적으로 호출마다 어떻게 바뀌는 지를 보여준다.

var Lane = {
   name: "Lane the Lambda",
   description: function () {
      return this.name;
   }
};

var description = Lane.description;
var Fred = {
   description: Lane.description,
   name: "Fred the Functor"
};
// Call the function from four different scopes
console.log(Lane.description());
console.log(Fred.description());
console.log(description());
console.log(description.call({
   name: "Zed the Zetabyte"
}));

// Output
// Lane the Lambda
// Fred the Functor
// undefined
// Zed the Zetabyte

다이어그램에서는 Fred.descriptionLande.description으로 설정되었지만 이것은 단지 function을 참조하는 것 뿐이다. 그래서 3개의 참조는 anonymous 함수에 똑같은 소유권을 가지고 있다. 이런 이유 때문에 나는 컨스트럭터의 프로토 타입 형태의 메소드인 경우 function을 부르려고 하지 않는다. 왜냐면 어떤 종류의 함수의 바인딩과 클래스를 의미 하기 때문이다.(무슨 소리일까 -_-;;)(what is this에 dynamic nature of this에 대한 자센한 이야기를 보면 된다.)

Conclusion

다이어그램을 사용해서 자료구조를 시각화 하는게 정말 재미있었다. 내 바램은 이 문서가 JavaScript Semantic을 이해하는데 도움이 되었으면 하는 것이다. 나는 과거에 프론트 엔드의 설계와 개발 경력 그리고 서버쪽 구조 설계 경력을 가지고 있다. 나의 독특한 관점이 JavaScript언어를 이해하는데 도움이 되었으면 좋겠다. (NOTE, all the diagrams are graphviz dot files and can be seen here)