14. 상속, prototype

조뮁·2022년 8월 1일
0

JS중급

목록 보기
14/18
post-thumbnail

prototype

  • obj.hasOwnProperty() 라는 메소드로 객체가 해당 프로퍼티를 가지고 있는지 여부를 알 수 있음
  • .hasOwnProperty()는 객체의 __proto__안에 기본적으로 들어있는 메소드임
    크롬 브라우저 콘솔창
const user = {
	name: '성원',
}

user.name  // '성원'
user.hasOwnProperty('name');  // true
user.hasOwnProperty('age'); // false

Q. 만약, 객체가 .hasOwnProperty() 메소드를 가지고있다면?

const user = {
	name: '성원',
    hasOwnProperty: function(){
        console.log('하하속았찌');
    }
}

user.hasOwnProperty();
// 하하속았찌
  • 객체에 해당 프로퍼티가 있으면 바로 탐색을 멈춤
  • 객체에 해당 프로퍼티가 없을때만, __proto__까지 탐색함

상속

const bmw = {
  color: 'red',
  wheels: 4,
  navigation: 1,
  drive(){
    console.log('부릉');
  }
};

const benz = {
  color: 'black',
  wheels: 4,
  drive(){
    console.log('부릉');
  }
};

const audi = {
  color: 'blue',
  wheels: 4,
  drive(){
    console.log('부릉');
  }
};
  • wheels 와 drive()는 모든 차들이 공통으로 가지는 메소드임
    --> __proto__으로 코드 줄이기
// car 라는 상위개념의 객체 생성
const car = {
  wheels: 4,
  drive(){
    console.log('부릉');
  },
};

const bmw = {
  color: 'red',
  navigation: 1,
};

const benz = {
  color: 'black',
};

const audi = {
  color: 'blue',
};

console.log(bmw);  // {color: 'red', navigation: 1}
bmw.drive();  // 에러발생! 'Uncaught TypeError: bmw.drive is not a function'

// car는 bmw의 프로토타입이 됨
// == bmw는 car의 상속을 받음
bmw.__proto__ = car;
benz.__proto__ = car;
audi.__proto__ = car;

console.log(bmw);  // {color: 'red', navigation: 1}
bmw.drive();  // 부릉
bmw.wheels  // 4
  • bmw의 __proto__안에 상속받은 drive()와 wheels 프로퍼티가 있음

Prototype Chain

: 자신에게 프로퍼티가 없을 경우, 상위 개념으로 올라가며 프로퍼티를 탐색하고 사용하는 것

  • 상속은 계속 이어질 수 있음
const car = {
  wheels: 4,
  drive(){
    console.log('부릉');
  },
};

const bmw = {
  color: 'red',
  navigation: 1,
};

bmw.__proto__ = car;

const x5 = {
  color: 'green',
  name: 'x5',
}

x5.__proto__ = bmw;
{color: 'red', navigation: 1}

x5.color  // 'green'
x5.drive()  // 부릉

  • x5는 color 프로퍼티를 갖고 있으므로, bmw의 __proto__까지 탐색하지 않음.
  • x5는 dirve() 프로퍼티가 없으므로, bmw의 __proto__까지 탐색 --> bmw에도 없으므로 상위 개념인 car의 __proto__까지 탐색

prototype 조회

const car = {
  wheels: 4,
  drive(){
    console.log('부릉');
  },
};

const bmw = {
  color: 'red',
  navigation: 1,
};

bmw.__proto__ = car;

const x5 = {
  color: 'white',
  name: 'x5',
};

x5.__proto__ = bmw;
  • for in 조회
    상속받은 프로퍼티들도 모두 조회 가능
for(p in x5){
  console.log(p);
}

/*
"color"
"name"
"navigation"
"wheels"
"drive"
*/
  • Object.keys() , Objects.valeus() 조회
    객체 내장 메소드로는 상속된 프로퍼티는 나오지 않음.
console.log(Object.keys(x5));  // ["color","name"]
console.log(Object.values(x5));  // ["white","x5"]
  • for in 문에서 프로토타입의 프로퍼티와 객체가 가지고있는 프로퍼티 구분하기 --> hasOwnProperty()
  • hasOwnProperty()는 객체가 프로퍼티를 직접 가지고 있는 경우에만 true 반환
for(p in x5){
  if(x5.hasOwnProperty(p)){
    console.log(`(O) - ${p}`);
  }else{
    console.log(`(X) - ${p}`);
  }
}

/*
"(O) - color"
"(O) - name"
"(X) - navigation"
"(X) - wheels"
"(X) - drive"
*/

생성자 함수 이용하여 객체 생성

/* wheels와 drive()는 동일하기때문에 분리 */
const car = {
  wheels: 4,
  drive() {
    console.log('부릉');
  },
}

const Bmw = function(color){
  this.color = color;
  /* wheels와 drive()는 동일하기때문에 분리 
  this.wheels = 4;
  this.drive = function(){
    console.log('부릉');
  }; */
};

const x5 = new Bmw('red');
const z4 = new Bmw('green');

// car 상속
x5.__proto__ = car;
z4.__proto__ = car;

console.log(x5.color);
console.log(x5.wheels);
x5.drive();

하지만, 상속을 위해 매번 x.__proto__ = y라고 해주는것은 번거롭기 때문에, 다음과 같이 설정해줄 수 있다.

const Bmw = function(color){
  this.color = color;
};

Bmw.prototype.wheels = 4;
Bmw.prototype.drive = function(){
  console.log('부릉');
}
//(생성자함수).prototype.(프로퍼티)
//: 생성자함수가 생성하는 객체에 __proto__.프로퍼티로 설정한다는 의미

const x5 = new Bmw('red');
const z4 = new Bmw('green');

console.log(x5.color);
console.log(x5.wheels);
x5.drive();

console.log(x5);

Bmw 생성자로 만들어진 객체들이 동일한 __proto__를 가짐을 볼 수 있다.
x5 출력 결과
y4 출력 결과


생성자함수가 새로운 객체를 만들 때, 그 객체는 생성자의 instance임.

instanceof

  • 객체와 생성자 비교 가능
  • 해당 객체가 생성자로부터 생성된것인지 판단 (t/f)
    - (상속 여부를 판단하는 것이 아님)
z4 instanceof Bmw
true

constructor

  • 생성자로부터 instance 객체가 생성되면 constructor라는 프로퍼티가 생김.
  • constructor는 생성자를 나타냄

    주의 : z4.constructor.name 을 해야 "Bmw"값을 얻을 수 있음.


.prototype 코드 함축

Bmw.prototype.wheels = 4;
Bmw.prototype.drive = function(){
  console.log('부릉');
}

위 코드는 다음과 같이 줄일 수 있음.

Bmw.prototype = {
  wheels: 4,
  drive(){
  	console.log('부릉');
  },
}
  • 단, 아래와 같이 코드를 작성할 경우 생성된 instance에서 constructor 프로퍼티가 사라짐.
const Bmw = function(color){
  this.color = color;
};

// Bmw생성자함수의 prototype을 한 번에 묶어서 정의
Bmw.prototype = {
  wheels: 4,
  drive(){
  	console.log('부릉');
  },
}

const x5 = new Bmw('red');
const z4 = new Bmw('green');

z4.constructor === 'Bmw'  // false
  • 이러한 현상을 방지하지 위해 prototype을 덮어쓰지 말고, .prototype을 하나씩 추가하는 것이 좋다.
  • 혹은, 다음과 같이 constructor을 수동으로 명시해 줄 수도 있다.
Bmw.prototype = {
  constructor: 'Bmw',
  wheels: 4,
  drive(){
  	console.log('부릉');
  },
}

z4.constructor === 'Bmw'  // true

단, 이와 같은 경우 constructor에 옳지 않은 값을 임의로 추가하여 오류가 발생할 수도 있음.

  • js 는 명확한 constructor를 보장하지 않음.

closure을 이용한 정보 은닉화

const Bmw = function(color){
  this.color = color;
}

const x5 = new Bmw('red');
console.log(x5.color);  // red

x5.color = 'black';
console.log(x5.color);  // black
  • 이런 같은 코드가 있을 때, 누구든지 자동차의 색상을 변경할 수 있다.
  • 코드를 아래와 같이 변경하여 색상을 얻을수만 있고, 초기에 설정된 색상을 변경하지 못하게 할 수 있다.
const Bmw = function(color){
  const c = color;
  this.getColor = function(){
    console.log(c);
  }
}

const x5 = new Bmw('red');
x5.getColor();

Q. 색을 변경할 수 있는 setColor()함수는 아래와 같이 작성하면 될까?

const Bmw = function(color){
  let c = color;
  this.getColor = function(){
    console.log(c);
  }
  this.setColor = function(color){
    c = color;
  }
}

const x5 = new Bmw('red');
x5.getColor();

// setColor()
x5.setColor('black');
x5.getColor();  // black

0개의 댓글