먼저 javascript는 객체지향 언어라는점을 확실히 하고 넘어가겠습니다.
javascript는 JIT 컴파일 프로그래밍 언어로, 일급 함수를 지원합니다. 또한 Prototype 기반의 동적 다중 패러다임 스크립트 언어로, 객제지향, 명령형, 선언형(함수평 프로그래밍 등) 등의 스타일을 지원합니다.
javascript의 Class문법은 ECMA6 표준에 추가되었습니다. 하지만 설명한 것 처럼 javascript는 쭈욱 객체 지향 언어였습니다.
https://velog.io/@dlghddlf1992/%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D
위 글의 Class 단락의 설명처럼 Class는 객체 지향 프로그래밍에서 객체를 생성하기 위한 설계도 입니다. 그러나 Class가 없었던 javascript는 어떻게 객체 지향 프로그래밍 페러다임을 지원했을까요?
javascript는 Class 가 아닌 prototype 이라는 개념을 이용한 객체 지향 프로그래밍을 지원합니다.
그럼 먼저 javascript는 Class 없이 어떻게 객체를 생성했는지 알아보겠습니다.
function Student1() {}
let Student2 = {}; // let Student2 = new Object();
모든 객체는 함수를 통해 생성됩니다.
Student2도 함수와는 상관 없을거 같지만 javascript에서 제공하는 Object 함수를 이용해 객체를 생성합니다.
이렇게 함수가 정의될 경우 두가지 일이 이루어집니다.
함수를 정의할 경우 함수만 생성되는 것이 아니라 prototype object 도 생성이됩니다.
function Student1() {}
{constructor: ƒ}
constructor: ƒ Student1()
__proto__: Object
function Student1() {}
let tom = new Stucent1();
constructor로 설정되었으니 new를 통해 객체를 생성할 수 있습니다.
종합하자면 함수를 정의할 경우 prototype object 도 같이 생성이 되며 prototype object의 constructor property에 정의한 함수를 설정하여 new 를 통해 객체를 생성할 수 있게 합니다.
그럼 이제 함수를 정의할 때 생성되는 prototype object에 대해 알아보겠습니다.
prototype object에는 constructor 와 __proto__ property를 가진 객체입니다.
여기서 constructor는 prototype object 가 생성될 때 정의한 함수를 가리키며 이 함수를 통해 객체를 생성할 수 있습니다.
__proto__ 는 prototype link 입니다.
이제 이 property들이 어떻게 사용되는지 설명해 보겠습니다.
function Student2() {}
Student2.prototype.age = 20;
Student2.prototype.sex = 'male';
먼저 Student2 라는 함수를 정의했습니다.
{constructor: ƒ}
constructor: ƒ Student2()
__proto__: Object
정의하는 순간 위와 같이 prototype object 가 생성되며 생성한 함수가 constructor 로 설정됩니다. 이제 우리는 new Student2()를 통해 객체를 생성할 수 있습니다.
이제 Student2의 property object에 값을 추가하고 접근해보겠습니다.
function Student2() {}
Student2.prototype.age = 20;
Student2.prototype.sex = 'male';
let john = new Student2();
console.log(john.age); //20
console.log(john.sex); //male
john 을 생성할 때 age, sex 를 정의하지 않았는데도 값이 표시되는걸 볼 수 있습니다.
여기에서 사용되는 것이 prototype link 입니다.
위의 코드에서 john이라는 이름의 객체를 생성할 때 age, sex 라는 속성이 없는데도 값을 참조할 수 있는 것을 볼 수 있습니다. prototype object 의 속성을 참고한 것인데, 이게 어떻게 가능할까요?
바로 john이 가진 __proto__라는 속성이 가능하게 해 줍니다.
john
Student2 {}
__proto__:
age: 20
sex: "male"
constructor: ƒ Student2()
__proto__: Object
__proto__속성은 객체를 생성한 함수의 prototype object를 가리킵니다.
prototype object 와 prototype link에 대해 알게되었으니 아래와 같이 코드를 통해 설명해 보겠습니다.
먼저 Student3 라는 함수를 정의한 순간 prototype object 가 생성됩니다.
function Student3() {}
{constructor: ƒ}
constructor: ƒ Student3()
__proto__: Object
함수를 정의하면서 생성된 Student3.prototype 에 age, sex라는 속성에 값을 할당합니다.
function Student3() {}
Student3.prototype.age = 20;
Student3.prototype.sex = 'male';
{age: 20, sex: "male", constructor: ƒ}
age: 20
sex: "male"
constructor: ƒ Student3()
__proto__: Object
이제 Student3 함수를 통해 객체를 생성하고 tom 이라는 객체에만 age, sex 라는 속성에 값을 할당하고 console.log를 통해 값을 확인합니다.
function Student3() {}
Student3.prototype.age = 20;
Student3.prototype.sex = 'male';
let john = new Student3();
let tom = new Student3();
tom.age = 21;
tom.sex = 'female';
console.log(john.age); //20
console.log(john.sex); //male
console.log(tom.age); //21
console.log(tom.sex); //female
신기한 일이 벌어졌습니다. tom.age, tom.sex는 값을 할당했기에 당연히 나올 것으로 보이지만 john 객체에는 아무런 속성이 없는 비어있는 객체인데 값이 출력됩니다. 이게 어떻게 가능한 것일까요?
바로 prototype link 를 통해 Student3 의 property object 의 값을 참조한 것입니다.
tom 과 달리 john 객체의 경우 비어있는 객체이기 때문에 age, sex 속성을 찾을 때 까지 __proto__ 와 연결된 prototype object를 참조합니다. 그리고 최상위의 prototype object 까지 도달했는데도 못찻았을 경우 undefined를 리턴합니다.
즉 prototype link는 객체를 생성한 함수의 prototype object를 가리키며 __proto__라는 이름으로 저장됩니다.
정리해보겠습니다. prototype는 함수를 정의할 때 object 형태로 생성되며 constructor 와 __proto__ 라는 속성을 갖습니다.
constructor 로 설정되면서 new 를 통해 객체를 생성 할 수 있으며 __proto__ 자기 자신을 생성한 function 의 prototype object 에 접근하기 위한 prototype 링크입니다.