오늘은 javascript에서 prototype과 상속에 대해 정리해 두려고 한다.
prototype 이란?
javascript에서는 객체를 복사하여 새로운 객체를 생성하는 prototype 기반의 언어이다.
프로토타입 기반의 언어란 객체 원형인 프로토타입을 이용해 새로운 객체를 만들어준다. 이렇게 생성된 객체는 또 다른 객체의 원형이 될 수도 있다.
이 프로토타입을 이용해서 javascript에서 상속을 사용해 객체지향 프로그래밍을 할 수가 있다.
일단 아래 예시를 보자.
user 라는 객체를 생성해서 내부를 보면 Prototype이라는 것이 보인다.
실제로 hasOwnProperty (해당 키가 객체의 프로퍼티인지 아닌지 체크해주는 기능을 수행) 라는 것을 써보면 위처럼 true, false 로 결과가 잘 리턴 되는 것을 볼 수 있다.
만약에 별도로 hasOwnProperty를 정의해서 사용하면 어떻게 될까?
아래 예시를 보자.
Prototype의 hasOwnProperty가 아니라 별도로 객체에서 정의한 메서드를 읽는다.
우리는 여기서 객체에서 프로퍼티를 읽는데 , 만약에 프로퍼티가 없으면 프로토타입에서 해당 내용을 찾는다는 것을 알 수 있다.
Prototype을 이용한 상속 구현
앞에서 prototype을 이용해서 상속을 사용할 수 있다고 했다.
아래 예시를 보자.
const cat = {
name: "나비",
feetNum: 4,
bell: 1,
move() {
console.log("움직이다");
},
eat() {
console.log("먹다");
},
};
const dog = {
name: "하루",
feetNum: 4,
move() {
console.log("움직이다");
},
eat() {
console.log("먹다");
},
}
const cow = {
name: "아지",
feetNum: 4,
move() {
console.log("움직이다");
},
eat() {
console.log("먹다");
},
}
객체지향 프로그래밍을 조금이라도 해본사람은...! 위에서 feetNum, move, eat 같이 중복되어 있는 놈들을 제거하고 싶어 죽을 것이다.
이번에는 prototype을 이용해 이 중복을 없애 보도록하겠다.
const mammal = {
feetNum: 4,
move() {
console.log("움직이다");
},
eat() {
console.log("먹다");
},
}
const cat = {
name: "나비",
bell: 1,
};
const dog = {
name: "하루",
}
const cow = {
name: "아지",
}
//mammal이 cat, dog, cow의 프로토타입이 되는거,
// 다르게 말해서 cat,dog,cow 가 mammal의 상속을 받는거
cat.__proto__ = mammal;
dog.__proto__ = mammal;
cow.__proto__ = mammal;
포유류를 뜻하는 mammal 객체를 하나더 만들어 중복이 되던 feetNum , move, eat 은 mammal로 빼서 넣었다.
그리고 맨 아래에 mammal이 각 객체의 프로토타입이 되도록 해주면서, mammal의 상속을 받도록 만들어 줬다.
이제는 cat, cow, dog 가 공통적으로 feetNum , move, eat을 사용할 수 있다.
cat.move();
cat.eat();
console.log(cat.feetNum);
dog.move();
dog.eat();
console.log(dog.feetNum);
cow.move();
cow.eat();
console.log(cow.feetNum);
그리고 프로토타입은 이어서 구성할 수가 있다.
아래 예시를 보자.
const persian = {
age: 5,
type: "persian",
};
persian.__proto__ = cat;
위의 persian 객체까지 그림으로 표현해보면 아래와 같이 표현될 것이다. 이를 프로토타입 체인이라 부른다.
하위 객체에서 프로퍼티를 찾고 없으면 프로토타입(부모 객체)를, 또 없으면 그 객체의 프로토타입(부모 객체)을 찾아보게 되는 것이다.
for ~ in 문을 이용해서 객체의 프로퍼티값을 뽑아보면 이렇게 모든 프로퍼티에 접근이 가능한것을 확인할 수 있다.
다만 객체 그 자체를 출력해보거나, key나 value값 만 출력을 해보면 prototype은 별도로 나오지 않는다.
만약에 prototype에 있는 값을 가져오고싶으면 맨 처음의 예에 있는 hasOwnProperty를 이용해서 if문으로 체크후 가져오면 된다.
자..! 이제 프로토타입에 대해 어느정도 이해가 되셨다고 생각을 한다.
그런데 보통 실무에서는 이런식으로 프로토타입을 사용하진 않는다. 보통 상속의 개념을 사용할 때는 생성자를 이용해서 사용한다.
아래 예시를 보자.
// const mammal = {
// feetNum: 4,
// move() {
// console.log("움직이다");
// },
// eat() {
// console.log("먹다");
// },
// }
const Cat = function (name, type) {
this.name = name;
this.type = type;
};
Cat.prototype.feetNum =4;
Cat.prototype.move = function() {
console.log("움직이다");
}
Cat.prototype.eat = function() {
console.log("먹다");
}
const persian = new Cat("나비", "persian");
const sphynx = new Cat("코코", "sphynx");
// persian.__proto__ = mammal;
// sphynx.__proto__ = mammal;
위처럼 생성자를 이용해서 상속의 개념을 구현할 때, prototype용 객체를 만들지 않고 별도로 prototype 값을 개별적으로 넣어준다.
위에서 주석처리 해놓은 것처럼 프로토타입전체를 묶어서 셋팅해주면 constructor가 사라지니
이렇게 하나씩 명시적으로 해주는게 좋다.
만약 묶어서 해줄거면 constructor : Cat 이런식으로 수동으로 명시해줘도 된다.
그리고 instanceof나 === 을 이용해서 확인해보면 true 가 나온다.
console.log(persian instanceof Cat); //true
console.log(persian.constructor === Cat); //true
마지막으로 클로저를 통해서 상속 받은 객체의 값을 셋팅 하는 것을 보자.
상속 받은 객체의 값을 클로저로 셋팅해놓으면 누군가 해당 프로퍼티 값을 변경하는 것을 방지 할 수가 있다.
const Cat = function (name) {
const n = name;
this.getName = function() {
console.log(n);
};
};
const persian = new Cat("나비");
console.log(persian.getName());
만약에 위의 구현 내용이 이해가 잘 안된다면 먼저 클로저에 대한 개념부터 알고 오도록 하자.
https://devkingdom.tistory.com/331
오늘은 여기까지 포스팅하도록 하겠다.
'Programming > WEB' 카테고리의 다른 글
[js] javascript 에서 async 와 await를 이용해 비동기 처리하기 (0) | 2022.02.22 |
---|---|
[js] javascript 에서 class 사용하기 (0) | 2022.02.20 |
[JS] javascript에서 함수 호출 방식과 상관없이 this 를 지정하는 방법 (0) | 2022.02.19 |
[JS] javascript에서 시간 제어하기 (0) | 2022.02.19 |
[JS] javascript Closure(클로저) 정리 (1) | 2022.02.19 |
댓글