JavaScript는 흔히 프로토타입 기반 언어(prototype-based language)라 불립니다.— 모든 객체들이 메소드와 속성들을 상속 받기 위한 템플릿으로써 프로토타입 객체(prototype object)를 가진다는 의미입니다. 프로토타입 객체도 또 다시 상위 프로토타입 객체로부터 메소드와 속성을 상속 받을 수도 있고 그 상위 프로토타입 객체도 마찬가지입니다. 이를 프로토타입 체인(prototype chain)이라 부르며 다른 객체에 정의된 메소드와 속성을 한 객체에서 사용할 수 있도록 하는 근간입니다.
정확히 말하자면 상속되는 속성과 메소드들은 각 객체가 아니라 객체의 생성자의 prototype이라는 속성에 정의되어 있습니다.
JavaScript에서는 객체 인스턴스와 프로토타입 간에 연결(많은 브라우저들이 생성자의 prototype 속성에서 파생된 proto 속성으로 객체 인스턴스에 구현하고 있습니다.)이 구성되며 이 연결을 따라 프로토타입 체인을 타고 올라가며 속성과 메소드를 탐색합니다.
참고) constructor function 은 JS language의 특징 아님.
Instead, they are simply a pattern that has been developed by other developers. And now everyone simply uses this.
firstName과 birthYear은 Instace properties이다. Person이라는 constructor function을 통하여 만들어진 모든 instances들의 properties가 될 것이기 때문.
const Person = function (firstName, birthYear) {
// Instance properties
this.firstName = firstName;
this.birthYear = birthYear;
// Never do this - 절대 constructor function 내에 method 만들지 말 것!
여러개의 Person object 만들 시 method도 여러개 만들어짐 -> 좋지 못한 코드
// this.calcAge = function () {
// console.log(2037 - this.birthYear);
// };
};
const jonas = new Person('Jonas', 1991);
// Jonas is an instance of Person
console.log(jonas);
//Person
//{birthYear: 1991
//firstName: "Jonas"}
const matilda = new Person('Matilda', 2017);
const jack = new Person('Jack', 1975);
console.log(matilda, jack);
console.log(jonas instanceof Person); //true
console.log('jay' instanceof Person); //false
JS 내 모든 함수들은 자동적으로 prototype이라 불리는 property를 가진다. (constructor functions를 포함하여) 그렇기에 모든 constructor function을 통하여 만들어진 objects들은 모든 constructors prototype property의 methods와 properties에 접근가능하다.(상속 받는다.)
아래의 method를 만드는 방법은 단 한번의 복사로 다른 object들도 계속해서 이 method를 재사용할 수 있다는 장점이 있다.
Person.prototype.calcAge = function () {
console.log(2037 - this.birthYear);
};
jonas.calcAge(); //46 object는 만들어진 constuctor function의 prototype에 대한 접근이 가능하므로! (prototypal inheritance)
matilda.calcAge(); //20
console.log(jonas.__proto__); //{calcAge: ƒ, constructor: ƒ}
// prototype of the Jonas object is essentially the prototype property of the constructor function.
console.log(jonas.__proto__ === Person.prototype); //true
//주의사항. 꼭 알아둘 것!)
//Person.prototype 은 Person의 prototype이 아니다.
//모든 Person constructor function의 object들의 prototype으로 사용되는 것임.
console.log(Person.prototype.isPrototypeOf(jonas)); //true
console.log(Person.prototype.isPrototypeOf(matilda)); //true
console.log(Person.prototype.isPrototypeOf(Person)); //false
// .prototypeOfLinkedObjects
Person.prototype.species = 'Homo Sapiens';
console.log(jonas.species, matilda.species);
//Homo Sapiens Homo Sapiens
console.log(jonas);
//Person {firstName: 'Jonas', birthYear: 1991}
// species가 jonas자체의 property는 아님.
// 단순히 'species' property 에 접근할 수 있는 것임!
console.log(jonas.hasOwnProperty('firstName')); //true
console.log(jonas.hasOwnProperty('speices')); //false
Constructor function[Person()] ---.prototype --> Prototype[Person.prototype] <-- prototype inheritance / delegation-- .__proto object [jonas]
주의할 점) Person.prototype은 Person의 prototype이 아닌, Person으로부터 만들어진 새로운 객체들의 prototype을 가리킨다.
The new Operator
1. New {} (the empty object) is created
2. constructor function내의 this는 {}(새로 만들어진 객체)를 가리킨다.
3. 새로운 객체는 constructor function의 prototype에 대한 link를 갖는다.
4. function은 자동적으로 새로운 객체를 return한다.
[Object()] : Built-in constructor function for objects. This is used when we write an object literal.
{...} === new Object(...)
[person.prototype] 이 것 자체도 object. JS내에서 object는 모두 property를 가지고 있다.
ex) jonas.hasownproperty('name') // true
hasownproperty라는 method는 Object 자체 내에 있다. 그렇기에 이 함수를 사용할 수 있는 것! -> prototype chain
console.log(jonas.__proto__); //Person.prototype
console.log(jonas.__proto__.__proto__); //Object.prototype
console.log(jonas.__proto__.__proto__.__proto__); // null -> Object is the top of the prototype chain
console.dir(Person.prototype.constructor);
const arr = [3, 4, 4, 2, 1, 5, 5, 7, 8, 0]; // new Array === []
console.log(arr.__proto__); // array의 모든 methods
console.log(arr.__proto__ === Array.prototype); //true
console.log(arr.__proto__.__proto__); // Object.prototype
Array.prototype.unique = function () {
return [...new Set(this)];
};
console.log(arr.unique()); //[3, 4, 2, 1, 5, 7, 8, 0]
// 위의 방법 실제로 하는 것 좋은 건 아님 bugs
const h1 = document.querySelector('h1');
// h1의 prototype : htmlElement,
//htmlElement의 prototype : element, element의 prototype : node,
//node의 prototype : EventTarget Eventtarget의 prototype : Object
//=> huge prototype chain