JS는 객체지향언어이다. 그렇지만 JS에는 클래스라는 개념이 없다.
ES6 에서 Class 문법이 추가되었다. 그렇지만 문법이 추가되었을 뿐, JS가 클래스 기반으로 바뀐 것은 아니다.
대신 프로토타입이라는 것이 존재한다. 그래서 프로토타입을 기반으로 상속을 흉내내도록 구현한다.
JS에서 function과 생성자 함수 new를 통해 클래스를 비스무리하게 흉내낼 수 있다.
이전 글에 작성했듯이 생성자 함수(new)로 객체를 만드는 방법을 배웠다.
function Animal(type,name,sound){
this.type=type;
this.name=name;
this.sound=sound;
this.say = function() {
console.log(this.sound);
}
};
let dog = new Animal('dog','woong','멍멍');
dog.say();
//출력 : 멍멍
다음과 같이 Animal 객체를 만들고, 객체의 sound 변수를 출력하는 익명함수 say를 만들어주었다.
이때 우리가 만든 익명 함수 say는 프로토타입으로 대체해줄 수 있다.
function Animal(type,name,sound){
this.type=type;
this.name=name;
this.sound=sound;
};
Animal.prototype.say = function(){
console.log(this.sound);
}
let dog = new Animal('dog','woong','멍멍');
dog.say();
//출력 : 멍멍
Animal 바깥에 prototype.say로 함수를 지정해주었더니 똑같은 결과를 출력하는 것을 볼 수 있다.
이 프로토타입은 say라는 함수를 만들어서 모든 animal 객체에 함수를 넣어주는 역할 을 한다.
그래서 사실 위의 코드는 아래의 코드와 같다고 볼 수 있다!
function Animal(type,name,sound){
this.type=type;
this.name=name;
this.sound=sound;
};
let dog = new Animal('dog','woong','멍멍');
function say() {
console.log(this.sound);
}
//생성된 Animal 객체마다 say 함수를 할당해준다.
dog.say = say;
console.log(dog);
dog.say();
function Animal(){}
Animal.prototype.commonvalue = 1;
let dog = new Animal('dog','woong','멍멍');
console.log(dog.commonvalue);
//출력: 1
function Animal(type,name,sound) {
this.type = type;
this.name = name;
this.sound = sound;
}
//Animal이라는 객체 생성자를 만들었고, 프로토타입으로 say 함수를 넣어줬다.
Animal.prototype.say = function () {
console.log(this.sound);
};
//Animal.call (현재 객체생성자 this, [호출한 객체 생성자의 파라미터])
function Dog(name,sound){
Animal.call(this,'멍멍이',name,sound);
}
function Cat(name,sound){
Animal.call(this,'고양이',name,sound);
}
//Dog, Cat 객체 생성자가 Animal 프로토타입을 공유하도록 해주었다.
Dog.prototype = Animal.prototype;
Cat.prototype = Animal.prototype;
let dog = new Dog("woong", "멍멍");
dog.say();
let cat = new Cat("navi",'냐옹');
cat.say();
위에서 만들었던 Animal 객체와 생성자 함수 Dog의 관계를 그림으로 나타내보았다. ( 틀릴 수도 있슴니다 . . . 🙂🙃🙂)
모든 객체에는 prototype이라는 내부 property가 존재한다
const dog = {
sound: "멍멍"
};
// 최상위 프로토타입 연쇄인 Object
const cat = Object.create(dog);
console.log(cat.sound);
// 고양이가 짖게 되었다!
// 출력: 멍멍
객체 내부에 존재하지 않는 property를 호출하면 바로 prototype 링크
를 따라가 프로퍼티를 생성한다. 모든 일반 객체의 최상위 프로토타입 연쇄는 내장 Object.prototype
이다. 이 지점에서도 찾지 못하면 탐색이 종료된다.
function foo() {}
함수를 정의하면 함수뿐만 아니라 Prototype Object
도 같이 생성된다.
Prototype Object는 기본 속성으로 constructor
와 __proto__
를 가지고 있다.
constructor : 선언한 생성자 함수 Foo를 가리킨다. new 로 함수를 호출할 경우 constructor 함수를 실행하고, 객체가 생성된다.
생성자 함수가 아니라 함수를 생성하는 호출이라고 생각하자.
prototype : 생성자 함수에 정의한 모든 객체가 공유할 원형이다.
proto : Prototype 링크이다. 모든 객체가 빠짐 없이 가지고 있는 속성이다. 생성자 함수에 정의해두었던 prototype을 참조한다.
__proto__
는 new를 호출할 때 prototype을 참조해서 자동으로 만들어진다.생성자 함수엔
prototype
에, 생성자로부터 만들어진 객체에는__proto__
에 생성자의 prototype이 들어간다.
const f = new Foo();
new Foo()로써 만들어진 객체 f는 결국 Foo.prototype 객체와 내부적으로 prototype 링크로 연결된다.
결국 f와 Foo는 상호 연결된 두개의 객체가 된다.
이렇게 __proto__
속성을 통해 상위 프로토타입과 연결되어 있는 형태를 프로토타입 체인이라고 한다.
[참고]