인사이드 자바스크립트를 공부하며 정리하는 포스팅입니다.



1.prototype과 _proto_ 프로퍼티


자바스크립트에서는 프로토타입 기반의 객체지향 프로그래밍을 지원합니다.(ES6 부터는 클래스가 도입되었음.)

그 근간이 되는 것이 프로토타입과 프로토타입 체이닝입니다.


자바스크립트의 모든 객체는 자신의 부모인 프로토타입 객체를 가리키는 참조 링크 형태의 숨겨진 프로퍼티가 있습니다. ECMAScript에서는 이러한 링크를 암묵적 프로토타입 링크(implicit prototype link) 라 부르며이러한 링크는 모든 객체의 _proto_ 프로퍼티에 저장됩니다.


주의할 점이 _proto_ 프로퍼티와 prototype 프로퍼티가 다르다는 점입니다. 도대체 왜 이렇게 헷갈리게 네이밍을 했는지 모르겠어요..


자바스크립트에서 모든 객체는 자신을 생성한 생성자 함수의 prototype 프로퍼티가 가리키는 프로토타입 객체를 자신의 부모 객체로 설정하는 _proto_ 프로퍼티에 링크로 연결합니다.



var Person = function(name){
    this.name = name;
};

var song = new Person('song');


위와 같은 예제에서 Person() 생성자 함수로 생성된 song객체는 Person() 함수의 프로토타입 객체 즉 prototype 프로퍼티와 연결되어있는 객체를 자신의 _proto_ 프로퍼티에 링크로 연결합니다.


prototype 프로퍼티는 함수의 입장에서 자신과 링크된 프로토타입 객체를 가리키고,

_proto_ 프로퍼티는 객체의 입장에서 자신의 부모 객체인 프로토타입 객체를 내부의 숨겨진 링크로 가지고 있습니다.


Person() 생성자의 prototype 프로퍼티와 song 객체의 _proto_ 프로퍼티는 동일한 객체를 가리키는 겁니다.


정리하자면 자바스크립트에서 모든 객체는 자신을 생성한 생성자 함수의 prototype 프로퍼티가 가리키는 객체를 자신의 프로토타입 객체(부모 객체)로 취급합니다.


2.프로토타입 체이닝


자바스크립트에서 객체는 자기 자신의 프로퍼티뿐 아니라, 자신의 부모 역할을 하는 프로토타입 객체의 프로퍼티 또한 자신의 것처럼 접근할 수 있습니다. 이것을 가능하게 하는 것이 바로 프로토타입 체이닝입니다.


자바스크립트에서 특정 객체의 프로퍼티나 메서드에 접근하려고 할 때, 해당 객체에 접근하려면 프로퍼티 또는 메서드가 없다면 _proto_ 링크를 따라 자신의 부모 역할을 하는 프로토타입 객체의 프로퍼티를 차례대로 검색하는 것을 프로토타입 체이닝이라 합니다.

자바스크립트에서 모든 타입의 프로토타입 체이닝의 종점은 Object.prototype입니다.

자바스크립트의 기본 데이터 타입들도 표준 메서드를 가지고 있고, 이 표준 메서드들은 각각 Number.prototype, String.prototype, Array.prototype등과 같이 이들의 프로토타입 객체에 정의되어 있습니다.

그리고 결국 이러한 기본 내장 프로토타입 객체 또한 Object.prototype을 자신의 프로토타입으로 가지고 프로토타입 체이닝으로 연결됩니다. 때문에 모든 객체가 아닌 모든 타입의 프로토타입 종점이 Object.prototype이라고 한 것 입니다.

그리고 객체의 프로퍼티를 읽거나 메서드를 실행할 때에만 프로토타입 체이닝이 일어납니다. 당연한 말이지만 해당 객체에 없는 프로퍼티나 메서드를 접근할 때 프로토타입 체이닝이 일어납니다.




3.디폴트 프로토타입 변경


디폴트 프로토타입 객체는 함수가 생성될 때 같이 생성되며, 함수의 prototype 프로퍼티에 연결됩니다. 이렇게 자바스크립트에서 함수를 생성할 때 해당 함수와 연결되는 디폴트 프로토타입 객체를 다른 일반 객체로 변경할 수 있습니다.

이를 통해서 상속을 구현합니다.


프로토타입을 통한 상속 구현이 가능한 이유는 프로토타입 또한 객체이므로 프로퍼티와 메서드를 가질 수 있습니다. 때문에 사용자가 기존에 클래스를 통해 상속을 하듯이 물려주고 싶은 메서드와 프로퍼티를 프로토타입에 정의함으로써 상속을 구현할 수 있습니다. 상속에 관한 자세한 내용은 따로 포스팅 하도록 하겠습니다.







인사이드 자바스크립트를 공부하며 정리하는 포스팅입니다.



참조 타입(객체)


자바스크립트에서 기본 타입을 제외한 모든 값은 객체다.

따라서 배열, 함수, 정규표현식 등도 결국 자바스크립트 객체로 표현된다.

자바스크립트에서 객체는 단순 key : value 형태의 프로퍼티들을 저장하는 컨터이너로써, Hash와 유사하다. 
프로퍼티에는 기본 타입, 참조 타입(객체), 함수등 모든 타입을 포함할 수 있다.



1. 객체 프로퍼티 접근


객체 프로퍼티를 읽고, 쓰고, 갱신하기 위해 접근하는 방법은 두 가지가 있습니다.


- 대괄호([]) 표기법

- 마침표(.) 표기법


일반적으로는 C++, Java등의 언어와 유사하게 마침표 표기법을 많이 사용하지만 대괄호 표기법만을 사용해야하는 경우가 있습니다.

1) 프로퍼티 이름이 표현식인 경우 // foo['full-name'] = 'foo song';

2) 프로퍼티 이름이 예약어인 경우 




2. for in 문


for in 문을 사용하면, 객체에 포함된 모든 프로퍼티에 대해 루프를 수행할 수 있습니다.

var objA = {

val : 40

};



var objB = objA;



console.log(objA.val); // 40

console.log(objB.val); // 40



objB.val = 50;



console.log(objA.val); // 50

console.log(objB.val); // 50
for in 문을 수행하면서 변수에 객체의 프로퍼티가 하나씩 String 타입으로 할당됩니다.



3. 객체 프로퍼티 삭제


자바스크립트에서는 객체의 프로퍼티를 delete 연산자를 이용해 즉시 삭제할 수 있습니다.


delete foo.name;


4. 참조 타입의 특성


자바스크립트에서 객체는 참조 타입입니다. 

말그대로 객체의 모든 연산이 실제 값이 아닌 참조값으로 처리되기 때문입니다.

var objA = {

val : 40

};



var objB = objA;



console.log(objA.val); // 40

console.log(objB.val); // 40



objB.val = 50;



console.log(objA.val); // 50

console.log(objB.val); // 50

objB의 프로퍼티를 수정해도 objA의 프로퍼티가 같이 수정됩니다. 따라서 두 객체는 같은 객체를 가리키고 있다는 것을 알 수 있습니다.


var objA = {}; 


위와 같이 객체를 생성되면 objA 자체의 값이 객체인 것이 아니라 생성된 객체를 가리키는 참조값을 저장하고 있는 것입니다.

 

객체비교도 마찬가지 입니다.

var objA = {

val : 40

};



var objB = {

val : 40

};



var objC = objB;



console.log(objA == objB); // false

console.log(objB == objC); // true

변수는 객체의 값이 아닌 객체의 참조값을 가지고 있기 때문에 모든 값이 동일한 objA와 objB는 다른 객체이고, 참조값이 같은 objB와 objC는 같습니다.


* 다음 포스팅에 깊은복사와 객체간 값 비교를 통해 비교하는 함수를 만들어 보도록 하겠습니다. 



4. 참조에 의한 호출 방식 (call by reference)


기본 타입과 참조 타입의 경우는 함수 호출 방식도 다릅니다. 기본 타입의 경우는 call by value/ 참조 타입은 call by reference 입니다.


call by value: 함수를 호출할 때 인자로 복사된 값을 전달한다. 즉, 함수내에서 매개변수의 값을 변경해도 실제 값은 변경되지 않는다.

call by reference: 함수를 호출할 때 인자로 객체의 참조값이 전달된다. 즉, 함수내에서 매개변수의 값을 변경하면 실제 값이 변경된다.


위에서 4. 참조 타입의 특성으로 보면 알 수 있듯이 참조 타입은 값 자체가 아닌 가리키고 있는 참조값입니다. 때문에 함수 내에서 인자로 받은 객체의 프로퍼티를 수정하면 원본 객체의 프로퍼티가 수정됩니다.


c++을 하셨던 분들은 포인터를 생각하시면 이해가 빠를듯 합니다. 변수에 할당된 것은 값이 아니고 주소이고, 그 주소에 있는 값을 변경하는 것이라고 생각하시면 됩니다.



5. 프로토타입


자바스크립트의 모든 객체는 자신의 부모 역할을 하는 객체와 연결되어 있습니다. 마치 객체지향의 상속과 유사하게 부모 객체의 프로퍼티를 자신의 것처럼 사용할 수 있습니다. 자바스크립트에서는 이러한 부모 객체를 프로토타입이라고 부릅니다. 


ECMAScript 명세서에는 자바스크립트의 모든 객체는 자신의 프로토타입을 가르키는 [[Prototype]]이라는 숨겨진 프로퍼티를 가진다고 설명합니다. 이를 크롬 브라우저에서는 _proto_라 되어있습니다.



foo 객체의 프로토타입 객체는 Object.prototype 객체입니다. (객체의 최상위 프로토타입) 따라서 foo 객체는 Object.prototype에 정의된 프로퍼티들을 사용할 수 있습니다.


자바스크립트에서 굉장히 중요한 개념입니다. 이후에 따로 프로토타입, 프로토타입 체이닝, 상속에 관하여 심도있게 포스팅을 작성해볼 예정입니다^^.