📌 prototype과 상속
const user ={
name: ‘Mike’
}
console.log(user.name); // ‘Mike’
console.log(user.hasOwnProperty(‘name’));
- 만약 객체에 hasOwnProperty라는 이름의 메서드가 있다면 기존에 동작하던
hasOwnProperty
는 호출되지 않는다.
hasOwnProperty
는 객체에 매개변수로 받은 값이 프로퍼티(키)로 존재하는지 확인하는 메서드 이다.
function Car(color, wheels, navigation) {
this.color = color;
this.wheels = wheels;
this.navigation = navigation;
this.drive = function() {
console.log(‘drive…’);
}
}
const bmw = new Car(‘red’, 4, 1);
const benz = new Car(‘white’, 4);
const audi = new Car(‘blue’, 4);
console.log(bmw); // Car { color: ‘red’, wheels: 4, navigation: 1, drive: [Function (anonymous)] }
console.log(benz); // Car { color: ‘white’, wheels: 4, drive: [Function (anonymous)] }
console.log(audi); // Car { color: ‘blue’, wheels: 4, drive: [Function (anonymous)] }
- 현재 위 코드에서 중복되는 항목이 있다.
wheels
와 drive
는 모든 객체가 가지고있다.
- 이 경우
prototype
을 이용할 수 있다.
const vehicle = {
wheels: 4,
drive: function() {
console.log(‘drive…’);
}
}
function Car(color, navigation) {
this.color = color
this.navigation = navigation;
}
const bmw = new Car(‘red’, 4, 1);
const benz = new Car(‘white’, 4);
const audi = new Car(‘blue’, 4);
bmw.__proto__ = vehicle;
benz.__proto__ = vehicle;
audi.__proto__ = vehicle;
console.log(bmw.wheels); // 4
- 프로토타입이 될 객체
vehicle
을 선언하고 생성자로 만들어진bmw.__proto__
에 vehicle
을 할당한다.
- 기존에 선언해 놓은
vehicle
객체가 프로토타입이 되어 bmw
를 통해 프로토타입인 vehicle
의 프로퍼티에 접근 할 수있다.
console.log(bmw.wheels)
구문을 보면 프로토타입으로 선언한 vehicle
의 프로퍼티에 bmw
로 접근 하는것을 볼 수 있다.
- 프로토타입은 상위 개념의 객체이다.
__proto__
를 사용해 상위 개념을 상속 받는다.
- 상속은 계속 하위로 이어질 수 있다.
// 위 코드와 이어서
const x5 = new Car(‘yellow’);
x5.__proto__ = bmw;
x5.drive(); // ‘drive..’
console.log(x5.color); // yellow
vehicle
을 상속 받은 bmw
를 상속받은 x5
- 때문에
x5
에서 vehicle
이 보유한 drive
라는 프로퍼티에 접근 할 수 있다.
x5.color
는 color
프로퍼티를 x5
에서 먼저 만나기 때문에 yellow를 반환한다.
drive()
는 x5
찾고 없으니 bmw
에서 찾고 없으니 vehicle
에서 찾는다.
- 이를 Prototype Chain 이라고 한다.
🔔 상속 받은 하위 객체를 for in문으로 돌려보면?
// 위 코드에서 이어서
for (let key in x5) {
console.log(key); // color navigation, wheels, drive
}
📍Object 메서드로 찍어보면?
// 위 코드와 이어서
console.log(Object.keys(x5)); // [ ‘color’, ‘navigation’ ]
console.log(Object.values(x5)); // [ ‘yellow’, ‘undefined’ ]
Object
메서드로 접근시 상속받은 프로퍼티들을 출력하지 않는다.
💡 만약 for in문으로 순회 하면서 상속받은 객체를 구분하고 싶다면?
// 위 코드와 이어서
for (let key in x5) {
if (x5.hasOwnProperty(key)) {
console.log(‘O’, keys);
} else {
console.log(‘X’, keys);
}
}
O, color
O, navigation
X, wheels
X, drive
hasOwnProperty
와 if문의 조합으로 상속받은 값인지 아닌지 구분 할 수 있다.
📌 상위 객체를 만들지 않고 __proto__
를 사용하지 않는 방법
function Bmw (color) {
this.color: color
}
Bmw.prototype.wheels = 4;
Bmw.prototype.drive = function() {
console.log(“drive…”);
}
const z4 = new Bmw(‘red’);
console.log(z4.wheels); // 4
z4.drive; // ‘drive…’
- 최상단에 코드 처럼 상위 객체를 만들지 않았다.
__proto__
를 사용하지 않았다.
- 생성자
Bmw
의 프로토타입에서 상속받은 메서드도 잘 호출 되는 모습
📌instanceof: 인스턴스인지 구분
- JavaScript에서 생성자 함수가 새로운 객체를 만들어 낼때 그 객체는 생성자의 인스턴스라고 불려진다.
- JS는 이를 편리하게 확인할 수 있는
instanceof
연산자가 있다.
- 이를 통해 객체와 생성자를 비교할 수 있다.
- 해당 객체가 생성자로 부터 생성된 것 인지 판단해서
true
혹은 false
를 반환한다.
// 위 코드에 이어서
console.log(z4 instanceof Bmw); // true
z4
가 생성자 Bmw
로부터 만들어 졌기 때문에 true
를 반환한다.
🔔 constructor 프로퍼티
// 위 코드에 이어서
console.log(z4.constructor === Bmw); // true
z4
는 인스턴스 이기 때문에 생성자 프로퍼티가 자동으로 등록되어 있다.
Bmw
가 생성자 이기 때문에 이를 일치 연산자로 비교하면 true
를 반환한다.
📌 Closure
function Audi(color) {
this.color = color;
this.getColor = function() {
console.log(this.color);
}
}
let audi1 = new Audi(‘blue’);
audi1.getColor(); // ‘blue’
audi1.color = ‘green’;
audi1.getColor(); // ‘green’
- 생성자
Audi
로 만들어진 객체 audi1
의 color
에 접근하여 값을 변경하는게 가능하다.
- 이를 방지하기 위해 Closure(클로져)를 사용 할 수 있다.
// 클로저 적용
function Audi(color) {
const c = color;
this.getColor = function() {
console.log(c);
}
}
let audi1 = new Audi(‘blue’);
audi1.getColor(); // ‘blue’
// color에 접근 할 수 있는 방법은 없다.
- 생성자 함수가 실행 된 후
const c
는 사라지지만 여전히 이 변수에 this.getColor()
가 접근이 가능하다.
- 때문에 생성자로부터 객체가 생성된 이후에는
audi1
의 매개변수를 통해서만 const c
값을 변경할 수 있다.
- 위 예제는 클로저를 이용해서 audi1의 color를 조작하는 것을 방지한다.
getColor()
함수는 생성될 당시의 컨텍스트를 기억한다.