Prototype Chain / class(extends, super)

MihyunCho·2021년 4월 9일
0
post-thumbnail

자바스크립트는 엄밀히 따지면 객체지향 언어가 아닌, 프로토타입 기반의 언어이다.
자바스크립트에서 클래스를 이용하여 객체지향 형태로 프로그래밍을 할 수 있다.

class 키워드를 배우기 앞서, 상속에서의 this와 prototype, prototype chainning의 흐름 알아보자🤔

prototype, contructor, __proto__

prototype

인스턴스인 student는 Human이 가진 데이터를 공통적으로 갖게 되는데, 나중에 student가 많아지면 중복되는 값이 점점 많아진다.
이런 문제를 해결하기 위해서 Human 생성자 함수에서 나온 객체들이 공통된 속성을 공유하는 부모 객체를 Prototype 이라 한다.

contructor

생성자 함수 Human이 생길 때 Human의 프로토타입도 동시에 생기는데, *생성자 함수 내에는 prototype이란 속성안에 프로토타입 객체가 있고, 반대로 프로토타입 내부에는 constructor라는 속성안에 생성자 함수가 있어 둘이 연결되어 상호참조를 하게 된다.

__proto__

생성자 함수를 통해 만들어진 인스턴스들은 생성자 함수와 같은 구조를 가진다.
이 인스턴스들은 prototype속성 대신 _proto_라는 속성을 갖게 되며, 생성자 함수의 prototype을 바라본다.

❓상속 : this 와 prototype

function Human(){}
const student = new Human();

Human 함수를 생성자로 호출하면서 생성된 student 객체는 Human.prototype 객체를 원본 객체로 하여 복제된 객체이다.
새롭게 생성되는 객체들에게 프로퍼티나 메소드를 부여 할 수 있다.

1. this를 사용하여 선언

function Human(a){
	this.sleep = function(){
		console.log('이만 잘래요😴');
	}
}
const student = new Human();
console.log(student.sleep()); // 이만 잘래요😴

생성자 함수 안의 this는 새롭게 생성된 객체를 의미하기 때문에, 함수 내에서 this를 통해 정의한 프로퍼티나 메소드는 이 생성자 함수를 사용하여 객체가 생성될 때마다 새롭게 정의된다.
만약 employee 객체를 만들고 student와 employee의 sleep 을 비교하면 다르다고 평가된다

const student = new Human();
const employee = new Human();

console.log(student.sleep === employee.sleep); // false


student나 employee 객체를 출력해보면, 내부에 sleep 메소드가 정의 되어 있다.

다른 메모리에 있는 객체는 다르다고 판단하여 이 두객체의 메소드는 다른 메모리에 있는 전혀 다른 함수다.(자바스크립트의 완전일치연산자의 입장에서)

2. 프로토타입 객체에 선언

Human 생성자 함수의 프로토타입 객체 Human.prototype을 사용해 메소드를 정의하면 this와 정의하는 방법에 차이가 있다

function Human(a) {}
Human.prototype.sleep = function() {
	console.log('이만 잘래요😴');
}

const student = new Human();
console.log(student.sleep()); // '이만 잘래요😴'
const student = new Human();
const employee = new Human();

console.log(student.sleep === employee.sleep); // true

this와 달리 생성자 함수를 통해 만들어진 객체들이 해당 메소드 sleep을 공유하고 있다.

student, employee 객체를 출력하면 아무 메소드나 프로퍼티도 갖지 않은 빈 객체다.

this를 사용하지 않고 원본 객체 메소드나 프로퍼티를 정의하게되면 객체에는 해당 프로퍼티가 없고 원본 객체의 프로퍼티나 메소드를 참조하게 된다.

이 때, student 나 employee는 빈 객체인데 어떻게 sleep 메소드에 접근할 수 있을까?

이것은 프로토타입 룩업 때문인데, student 나 employee가 sleep 메소드를 갖고 있지 않으므로 모든 객체의 조상인 Object.prototype에 가서 sleep 메소드를 데려와 반환하게 된 것 이다.

→ 프로토타입을 사용한 상속으로 Object.create 메소드 사용법이 있는데 이것을 사용한 예시는 아래와 같다.(레거시한 방법)

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

Human.prototype.sleep = function(){
	console.log(this.name + '이는 꿈나라😴');
};

var mimi = new Human('mimi');

var Student = function(name){
	Human.call(this, name); 
} // Human의 this가 undefiend가 되기때문에 위로 올려줘야하므로

Student.prototype = Object.create(Human.prototype);
Student.prototype.constructor = Student;
Student.prototype.learn = function () {}

var dongdong = new Student('dongdong')
dongdong.learn();
dongdong.sleep(); // dongdong이는 꿈나라😴

→ 자바스크립트는 oop를 생각하지 않고 만들어진 언어이기 때문에, 상속을 할 때 이러한 편법(?)들이 생겨났다고 한다. ES6부터 class가 생기면서 더 간단하게 구현할 수 있게 되었다.

class 키워드를 사용한 상속

class Human {
	constructor(name){
		this.name = name;
	}
	sleep(){
		console.log(this.name + '이는 꿈나라😴');
	}
}

var mimi = new Human('mimi');

class Student extends Human {
	constructor(name){
		super(name);
	}
	learn(){
	}
}
var dongdong = new Student('dongdong');
dongdong.learn();
dongdong.sleep(); // dongdong이는 꿈나라😴

⚠️ 자식 클래스와 부모 클래스의 argument가 똑같으면 자식클래스 부분을 생략해줄 수 있다.

class Human {
	constructor(name){
		this.name = name;
	}
	sleep(){
		console.log(this.name + '이는 꿈나라😴');
	}
}

class Student extends Human {
// 이 부분 동일하므로 생략 가능
	learn(){
	}
}

extends

extends 키워드는 클래스를 다른 클래스의 자식으로 만들 때 class 선언식에 사용된다.

super

super 키워드는 부모 객체의 함수를 호출할 때 사용된다.

이처럼, extedns와 super는 부모에게서 상속을 받을 때 이용하는 키워드이다.

profile
Sic Parvis Magna 🧩

0개의 댓글