자바스크립트는 프로토타입 기반의 언어이다!
자바스크립트에서 프로토타입은 원본 객체를 복제해서 새로운 객체를 생성하는 것이다.
여기서 원본 객체란 무엇일까?
function Person(name, age){
this.name = name;
this.age = age;
}
일단 Person이라는 함수를 정의하면 Person이라는 객체가 생성된다.
이때 Person 객체가 생성됨과 동시에 Person의 prototype이라는 객체가 생성된다.
즉, 함수를 생성할 땐 반드시 프로토타입 객체도 함께 생성이 된다.
생성된 함수는 prototype이라는 프로퍼티를 가지는데 이는 프로토타입 객체를 가리킨다.
프로토타입 객체에 있는 constructor 프로퍼티는 객체가 생성시 선언된 함수를 가리킨다.
⇒ 각각의 프로퍼티는 상호참조를 하고 있다!
function User(){};
console.dir(User);
console.dir(User.prototype);
User 객체에 prototype 프로퍼티가 있고 User의 프로토타입 객체에 constructor 프로퍼티가 존재하는 것을 확인할 수 있다.
console.log(User === User.prototype.constructor); //true
이로 인해 constructor가 생성시 선언된 함수를 가리키는 것도 알 수 있다.
자 그럼 이제 새로운 객체를 만들어보자.
새로운 객체를 만든 뒤 console로 확인을 해보면 proto 프로퍼티가 존재하는걸 확인할 수 있다.
function Person(name, age){
this.name = name;
this.age = age;
}
const choi = new Person('정은', 24);
console.log(choi); // {__proto__: Object, name, age}
이 프로퍼티는 객체를 새로 생성할때 확인할 수 있다.
그렇다면 어떤 역할을 하는 것일까?
생성된 함수의 프로토타입 객체를 가리키고 프로토타입 객체와 연결이 되어 있는 것을 알 수 있다.
function Person(name, age){
this.name = name;
this.age = age;
}
const choi = new Person('정은', 24);
console.log(choi.__proto__); //Person의 prototype 객체를 확인할 수 있다.
Person의 prototype 객체를 가리키는 것을 확인할 수 있다.
위와 같은 그림으로 프로토타입의 구조를 알 수 있다.
여기서 Person Prototype이 원본 객체임을 알 수 있다!
이렇게 자바스크립트의 객체는 원본 객체(Person prototype)를 기반으로 복제가 되어지는 것을 알 수 있다. 또한 이로 인해 원본 객체와 연결되어 있다는 것도 알 수 있다. 이 연결을 프로토타입 링크라고 하며 proto에 이 링크가 담겨져있다.
자바스크립트 내의 사용되는 모든 객체들은 전부 이런 프로토타입 기반 방식으로 정의되고 생성되어진다. String
, Array
와 같은 객체들도 이와같은 방식으로 만들어졌다.
사진 참고(https://evan-moon.github.io/2019/10/23/js-prototype/)
이렇게 프로토타입으로 이루어진 객체들의 관계를 프로토타입 체인이라고 한다.
프로토타입 체이닝을 이용해서 해당 객체에서 프로퍼티를 찾을 수 있다.
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.say = function(){
console.log('Hi!');
}
const choi = new Person('정은', 24);
console.log(choi.say()); //Hi!
choi 객체에는 say 메소드가 존재하지 않는다. 하지만 Hi!라고 출력이 되는 것을 볼 수 있는데 이는 프로토타입 체이닝을 이용했기 때문이다.
__proto__
를 통해 원본 객체로 올라간다. Object.prototype
에 다다를때 까지 원본 객체를 따라서 올라간다.
자바스크립트에선 Object.create 메소드를 이용하여 상속을 할 수 있다. Object.create는 IE 8 이하는 지원을 하지 않기때문에 해당 메소드를 사용하지 않고 상속을 할 수도 있다. 자세한건 https://gist.github.com/evan-moon/a7e5a51e20d22016ea443a03480765b7 로...
Object.create() 메서드는 지정된 프로토타입 객체 및 속성(property)을 갖는 새 객체를 만든다.
Object.create(proto: Object, properties?: Object);
첫 번째 인자로 생성할 객체의 원본 객체가 될 객체
두 번째 인자로 생성할 객체에 추가할 프로퍼티를 객체 타입으로 받는다.
프로퍼티를 추가할땐 단순히 {number: 1} 객체로 넘기는 것이 아니라 Object.defineProperties 메소드를 사용할 때 처럼 데이터 서술자와 접근 서술자를 지정해줘야한다.
Object.create(Person.prototype, {
number: {
configurable: false,
enumerable: true,
value: 1
}
});
Object.create를 이용하여 상속을 해보자.
function SuperClass(name){
this.name = name;
}
SuperClass.prototype.say = function(){
console.log(`Hi I am ${this.name}`);
}
부모 클래스 역할을 할 SuperClass 함수를 생성하고 프로토타입 객체에 say 메소드를 선언했다.
SubClass에 SuperClass를 상속 시켜보자.
function SubClass(name){
SuperClass.call(this, name);
}
SubClass.prototype = Object.create(SuperClass.prototype);
SubClass.prototype.constructor = SubClass;
SubClass.prototype.jump = function(){
console.log(`${this.name} is jumping`);
}
SuperClass.call(this)
부모 생성자 함수의 생성자를 호출하되, 실행 컨텍스트를 자식 생성자 함수로 변경하라는 의미. super
키워드와 비슷하다.
SubClass.prototype 변경
Object.create를 이용하여 SuperClass.prototype을 원본 객체로 하는 새로운 객체를 만든다. 자식 생성자 함수의 프로토타입 객체와 부모 생성자 함수의 프로토타입 객체 간의 프로토타입 체인을 만들어 준다. (부모 자식 관계)
SubClass.prototype.constructor 변경
부모의 생성자 함수의 프로토타입 객체를 복제했기 때문에 현재 constructor는 부모 생성자 함수인 SuperClass일 것이다. 이를 SubClass로 바꿔주기 위해 SubClass로 변경해줘야한다.
(사진 참조 https://evan-moon.github.io/2019/10/27/inheritance-with-prototype/)
참고 자료
https://evan-moon.github.io/2019/10/23/js-prototype/
https://evan-moon.github.io/2019/10/27/inheritance-with-prototype/
https://ko.javascript.info/function-prototype