본문 바로가기
Language/JavaScript

[JS] 프로토타입과 클래스

by 오우영 2021. 2. 26.

객체 생성자

  • 객체 생성자는 함수를 통해서 새로운 객체를 만들고 그 안에 넣고 싶은 값 혹은 함수들을 구현할 수 있게함
  • 인스턴스가 초기화될 때 실행하는 생성자 함수

 

function Animal(type, name, sound) { // 생성자 constructor
    this.type = type;
    this.name = name;
    this.sound = sound;
    this.say = function() {
        console.log(this.sound);
    };
}

let dog = new Animal('개', '멍멍이', '멍멍') // 인스턴스 instance
let cat = new Animal('고양이', '야옹이', '야옹');

dog.say(); // 멍멍
cat.say(); // 야옹

 

 

  • 객체 생성자를 사용할 때는 보통 함수의 이름을 대문자로 시작, 새로운 객체를 만들 때에는 new 키워드를 앞에 붙여줍니다
  • 같은 객체 생성자 함수를 사용하는 경우, 특정 함수 또는 값을 재사용 할 수 있는데 바로 프로토타입입니다

 

프로토타입

  • 모델의 청사진을 만들 때 쓰는 원형 객체(Orignial form)
  • 프로토타입은 객체 생성자 함수 아래에 .prototype.[원하는키] = 코드를 입력하여 설정 가능

 

function Animal(type, name, sound) { // 생성자
    this.type = type;
    this.name = name;
    this.sound = sound;
}

Animal.prototype.say = function() { // 프로토타입
    console.log(this.sound);
};
Animal.prototype.shareValue = 1; // 프로토타입

let dog = new Animal('개', '멍멍이', '멍멍') // 인스턴트
let cat = new Animal('고양이', '야옹이', '야옹');

dog.say(); // 멍멍
cat.say(); // 야옹

console.log(dog.shareValue); // 1
console.log(cat.shareValue); // 1

 

 

__proto__, constructor, prototype의 관계

 

 

 

 

var Human = function(name) { // constructor
    this.name = name;
}

Human.prototype.sleep = function() { // prototype
	console.log('zzz')
}; 

var steve = new Human('steve'); // instance

 

 

결과 화면은 이렇게 나온다

 

steve.__proto__ === Human.prototype // true

steve.sleep() // zzz

 

 

이런 관계를 가지고 있는것을 알 수 있다.

 

 

그렇다면 아래와 같이 Human이라는 부모 객체와 Student라는 자식 객체가 있는 경우에 Student 프로토타입에서 .sleep을 사용하려면 어떻게 해야할까?

 

 

var Human = function(name) { // constructor
    this.name = name;
}

Human.prototype.sleep = function() { // prototype
	console.log("zzz")	
};

var steve = new Human('steve'); // instance

var Student = function(name) { // constructor

}

Student.prototype.learn = function() { // prototype
	console.log("배우는중..")
}

var john = new Student('john'); // instance

john.learn();
john.sleep();

 

 

# case 1

john을 Human.prototype에 직접 연결

 

 

john.__proto__ = Human.prototype

 

사용하지 말아야한다. __proto__는 참조하는 용도로만 사용해야 한다.

 

 

# case 2

Student 프로토타입에 Human 프로토타입을 직접 대입

 

 

Student.prototype = Human.prototype

Student.prototype.learn = function () {}
// same as Human.prototype.learn과 같다

 

Human 프로토타입에도 learn이 생기게 된다

 

 

 

# case 3

Student 프로토타입에 Human 프로토타입의 복사본을 대입

 

 

Student.prototype = Object.create(Human.prototype); // 추가한 코드
Student.prototype.learn = function () {}

 

위 코드와 같이 Student 프로토타입 위에 Human 프로토 타입의 복사본을 넣어주면 된다

Human 프로토 타입의 복사본을 Student 프로토타입 아래에 넣으면 Student 생성자가 Human 생성자를 가리키고 learn이 인식되지 않는다.

 

위와 같이 해주면 Student.prototype과 Student 생성자의 연결고리가 끊어지게 된다

 

 

Student.prototype = Object.create(Human.prototype);
Student.prototype.constructor = Student; // 추가한 코드
Student.prototype.learn = function () {}

 

위와 같이 코드를 추가해서 직접 연결을 시켜줘야한다

자바스크립트가 OOP를 기반으로 만들어지지 않았기 때문에 OOP와 비슷하게 구현하기 위해 에러가 생길때마다 다양한 방법들로 구현하는 방식들 중 하나라고 생각하면 된다 (조금 깔끔하지 못해 보일 수 있다)

 

하지만 위와 같이 하게되도 Student의 context가 만들어질 뿐 john의 인스턴스가 Human까지 올라가지 못한다

Human의 this값이 undefined가 된다

 

 

var Student = function(name) {
	Human.call(this, name); // 추가한 코드
    // Human.apply(this, arguments)로 써도 된다
}

 

위와 같이 Sudent constructor안에 this를 올려주는 call, apply 함수를 사용해야 한다

 

 

var Human = function(name) { // constructor
    this.name = name;
}

Human.prototype.sleep = function() { // prototype
	console.log("zzz")	
};

var steve = new Human('steve'); // instance

var Student = function(name) { // constructor

}

Student.prototype = Object.create(Human.prototype); // 추가한 코드
Student.prototype.constructor = Student; // 추가한 코드

Student.prototype.learn = function() { // prototype
	Human.call(this, name); // 추가한 코드
	console.log("배우는중..")
}

var john = new Student('john'); // instance

john.learn(); // 배우는중..
john.sleep(); // zzz

 

 

위와 같이 코드를 추가해주면

steve instanceof Human === true;

john instanceof Student === true;
john instanceof Human === true;

 

잘 연결이 된것을 확인할 수 있다.

 

 

using class keyword

 

위 코드를 class를 사용해 아래 코드처럼 바꿀수도 있다

 

class Human { 
  constructor(name) {  
    this.name = name;
  }
  sleep() {
  }
}

var steve = new Human('steve');

class Student extends Human {
  constructor (name) { // 부모와 arguments가 같다면 생략가능
    super(name); // 부모와 arguments가 같다면 생략가능
  }
  learn() {
  }
}

var john = new Student('john');

john.learn();
john.sleep();

 

 

 

'Language > JavaScript' 카테고리의 다른 글

[JS] Iterable object, Array-like object  (0) 2021.06.23
[JS] ES6 특징  (0) 2021.06.22
[JS] OOP  (0) 2021.02.26
[JS] 구조 분해  (0) 2021.02.25
[JS] 화살표함수  (0) 2021.02.24

댓글