반응형
상속(inheritance)이란?
- 상속이란 새로운 클래스에서 기존 클래스의 모든 속성과 메소드를 사용할 수 있는 것을 의미한다.
- C#이나 C++과 같은 클래스 기반(class-based)의 객체 지향 언어와는 달리 자바스크립트는 프로토타입 기반(prototype-based)의 객체 지향 언어다.
- 클래스 기반 객체지향 프로그래밍 언어는 객체 생성 이전에 클래스를 정의하고 이를 통해 객체(인스턴스)를 생성한다. 하지만 프로토타입 기반 객체지향 프로그래밍 언어는 클래스 없이도 객체를 생성할 수 있다. (ECMAScript 6에서 클래스가 추가되었다)
- 프로토타입 기반이기 때문에 상속의 개념이 클래스 기반의 객체 지향 언어와는 약간 다른데, 자바스크립트에서는 현재 존재하고 있는 객체를 프로토타입으로 사용하여 해당 객체를 복제하여 재사용하는 것을 상속이라고 한다.
프로토타입(prototype)
- 자바스크립트의 모든 객체는 자신의 부모 역할을 담당하는 프로토타입(prototype) 객체와 연결되어 있다. 그리고 이것은 마치 객체 지향의 상속 개념과 같이 부모 객체의 프로퍼티 또는 메소드를 상속받아 사용할 수 있게 한다.
- 자바스크립트의 모든 객체는 최소한 하나 이상의 다른 객체로부터 상속을 받으며, 이때 상속되는 정보를 제공하는 객체를 프로토타입이라고 한다.
- 프로토타입 객체는 생성자 함수에 의해 생성된 각각의 객체에 공유 프로퍼티를 제공하기 위해 사용한다.
var student = {
name: 'Lee',
score: 90
};
// student에는 hasOwnProperty 메소드가 없지만 아래 구문은 동작한다
console.log(student.hasOwnProperty('name')); // true
console.dir(student);
// student 객체는 __proto__ 프로퍼티로 자신의 부모(프로토타입) 객체인 Object.prototype를 가리킨다
console.log(student.__proto__ === Object.prototype); // true

- 자바스크립트의 모든 객체는 [[Prototype]]이라는 가상 프로퍼티인 내부 슬롯(internal slot)를 가진다. [[Prototype]]의 값은 null 또는 객체이며 상속을 구현하는데 사용된다. [[Prototype]] 객체의 데이터 프로퍼티는 get 액세스를 위해 상속되어 자식 객체의 프로퍼티처럼 사용할 수 있지만 set 액세스는 허용되지 않는다.
- [[Prototype]]의 값은 Prototype(프로토타입) 객체이며 __proto__ accessor 프로퍼티로 접근할 수 있다. __proto__ 프로퍼티에 접근하면 내부적으로 Object.getPrototypeOf가 호출되어 프로토타입 객체를 반환한다.
- 객체를 생성할 때 프로토타입은 결정되며, 결정된 프로토타입 객체는 다른 임의의 객체로 변경할 수 있다. 이것은 부모 객체인 프로토타입을 동적으로 변경할 수 있다는 것을 의미하며 이러한 특징을 활용하여 객체의 상속을 구현할 수 있다.
내부 슬롯과 내부 메소드란?
- 자바스크립트 엔진의 내부 동작을 설명하기 위해 ECMAScript에서 정의한 가상 프로퍼티(pseudo property)와 가상 메서드(pseudo method)다.
- 내부 슬롯과 메서드는 자바스크립트 엔진의 내부 로직이므로 직접적으로 접근하거나 호출할 수 없는데, [[prototype]]과 같은 일부 내부 슬롯과 내부 메서드에 한하여 간접적으로 접근할 수 있는 수단을 제공한다. (ex : object.__proto__)
const o = {};
o.[[prototype]] // Error
o.__proto__ // Object.prototype
프로토타입 객체의 생성
- 객체 생성자 함수(object constructor function)를 작성하여 프로토타입을 생성할 수 있으며, 관례상 객체 생성자 함수 이름의 첫 문자만을 대문자로 작성한다.
- 생성자 함수를 작성하고 new 연산자를 사용해 객체를 생성하면, 같은 프로토타입을 가지는 객체들을 생성할 수 있다.
function Dog(color, name, age) { // 개에 관한 생성자 함수 작성
this.color = color; // 색에 관한 프로퍼티
this.name = name; // 이름에 관한 프로퍼티
this.age = age; // 나이에 관한 프로퍼티
}
var myDog = new Dog("흰색", "마루", 1); // 이 객체는 Dog라는 프로토타입를 가짐
document.write(myDog.color + myDog.name + " 강아지"); // 흰색 마루 강아지
일반 객체에 프로퍼티 및 메소드 추가
function Dog(color, name, age) {
this.color = color;
this.name = name;
this.age = age;
}
var myDog = new Dog("흰색", "마루", 1);
myDog.family = "시베리안 허스키"; // 품종에 관한 프로퍼티 추가
myDog.breed = function() { // 털색 포함한 품종 반환해주는 메소드 추가
return this.color + " " + this.family;
}
document.write(myDog.breed() + "입니다"); // 흰색 시베리안 허스키입니다
프로토타입 객체에 프로퍼티 및 메소드 추가
- 프로토타입의 경우에는 생성자 함수에 직접 추가해야만 이후에 생성되는 모든 다른 객체에도 적용할 수 있다.
function Dog(color, name, age) {
this.color = color;
this.name = name;
this.age = age;
this.family = "시베리안 허스키"; // 프로토타입에 프로퍼티 추가할 때 기본값 지정
this.breed = function() {
return this.color + " " + this.family;
};
}
var myDog = new Dog("흰색", "마루", 1);
var hisDog = new Dog("갈색", "콩이", 3);
document.write("우리 집 강아지는 " + myDog.family + "이고, 친구네 집 강아지도 " + hisDog.family + "입니다.");
// 우리 집 강아지는 시베리안 허스키이고, 친구네 집 강아지도 시베리안 허스키입니다.
프로토타입 프로퍼티
prototype 프로퍼티
- 프로토타입 프로퍼티를 이용하면 현재 존재하고 있는 프로토타입에 새로운 속성이나 메소드를 손쉽게 추가할 수 있다.
- 직접 생성한 프로토타입은 새로운 속성이나 메소드를 마음껏 추가하거나 삭제할 수 있으며, 자바스크립트 표준 객체의 프로토타입도 임의로 수정할 수 있으나 오류 발생가능성이 커서 수정해서는 안된다.
function Dog(color, name, age) {
this.color = color;
this.name = name;
this.age = age;
}
Dog.prototype.family = "시베리안 허스키"; // Dog 프로토타입에 family 프로퍼티 추가
Dog.prototype.breed = function() { // Dog 프로토타입에 breed 메소드 추가
return this.color + " " + this.family;
};
var myDog = new Dog("흰색", "마루", 1);
var hisDog = new Dog("갈색", "콩이", 3);
document.write("우리 집 강아지는 " + myDog.family + "이고, 친구네 집 강아지도 " + hisDog.family + "입니다");
// 우리 집 강아지는 시베리안 허스키이고, 친구네 집 강아지도 시베리안 허스키입니다
document.write("우리 집 강아지의 품종은 " + myDog.breed() + "입니다");
// 우리 집 강아지의 품종은 흰색 시베리안 허스키입니다
document.write("친구네 집 강아지의 품종은 " + hisDog.breed() + "입니다");
// 친구네 집 강아지의 품종은 갈색 시베리안 허스키입니다
- 모든 객체는 자신의 프로토타입 객체를 가리키는 [[Prototype]] 내부 슬롯(internal slot)을 갖으며 상속을 위해 사용된다. 함수도 객체이므로 [[Prototype]] 내부 슬롯을 갖는데 함수 객체는 일반 객체와는 달리 prototype 프로퍼티도 소유하게 된다.
- 주의해야 할 것은 prototype 프로퍼티는 프로토타입 객체를 가리키는 [[Prototype]] 내부 슬롯과는 다르다. prototype 프로퍼티와 [[Prototype]]은 모두 프로토타입 객체를 가리키지만, [[Prototype]]는 함수를 포함한 모든 객체가 가지고 있는 내부 슬롯이고 반면에 prototype 프로퍼티는 함수 객체만 가지고 있는 프로퍼티이다.
- [[Prototype]]은 객체의 입장에서 자신의 부모 역할을 하는 프로토타입 객체를 가리키며 함수 객체의 경우 Function.prototype를 가리키고 prototype 프로퍼티는 함수 객체가 생성자로 사용될 때 이 함수를 통해 생성될 객체의 부모 역할을 하는 객체(프로토타입 객체)를 가리킨다.
function Person(name) {
this.name = name;
}
var foo = new Person('Lee');
console.dir(Person); // prototype 프로퍼티가 있다.
console.dir(foo); // prototype 프로퍼티가 없다.
constructor 프로퍼티
- 프로토타입 객체는 constructor 프로퍼티를 갖는데, 이는 객체의 입장에서 자신을 생성한 객체를 가리킨다.
- 예를 들어 아래 Person() 생성자 함수에 의해 생성된 객체를 foo 일 때, foo 객체 입장에서 자신을 생성한 객체는 Person() 생성자 함수이며, foo 객체의 프로토타입 객체는 Person.prototype이다. 따라서 프로토타입 객체 Person.prototype의 constructor 프로퍼티는 Person() 생성자 함수를 가리킨다.
function Person(name) {
this.name = name;
}
var foo = new Person('Lee');
// Person() 생성자 함수에 의해 생성된 객체를 생성한 객체는 Person() 생성자 함수이다.
console.log(Person.prototype.constructor === Person);
// foo 객체를 생성한 객체는 Person() 생성자 함수이다.
console.log(foo.constructor === Person);
// Person() 생성자 함수를 생성한 객체는 Function() 생성자 함수이다.
console.log(Person.constructor === Function);
프로토타입 체인(prototype chain)
- 프로토타입이 상속되는 가상의 연결 고리를 프로토타입 체인이라고 한다.
- 자바스크립트에서는 객체 초기화를 사용해 생성된 같은 타입의 객체들은 모두 같은 프로토타입을 가지며, new 연산자를 사용해 생성한 객체는 생성자의 프로토타입을 자신의 프로토타입으로 상속받는다.
- Object.prototype 객체는 프로토타입 체인에서도 가장 상위에 존재하는 프로토타입으로, 어떠한 프로토타입도 가지지 않으며 아무런 속성도 상속받지 않는다. 자바스크립트의 모든 객체는 Object.prototype 객체를 프로토타입으로 상속받는다.
var obj = new Object(); // 이 객체의 프로토타입은 Object.prototype
var arr = new Array(); // 이 객체의 프로토타입은 Array.prototype
var date = new Date(); // 이 객체의 프로토타입은 Date.prototype
var date = new Date(); // 이 객체는 Date.prototype뿐만 아니라
Object.prototype도 프로토타입으로 가진다
- 자바스크립트는 특정 객체의 프로퍼티나 메소드에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티 또는 메소드가 없다면 [[Prototype]]이 가리키는 링크를 따라 자신의 부모 역할을 하는 프로토타입 객체의 프로퍼티나 메소드를 차례대로 검색하는데 이를 프로토타입 체인이라 한다.
var student = {
name: 'Lee',
score: 90
}
console.dir(student);
console.log(student.hasOwnProperty('name')); // true
console.log(student.__proto__ === Object.prototype); // true
console.log(Object.prototype.hasOwnProperty('hasOwnProperty')); // true
- student 객체는 hasOwnProperty 메소드를 가지고 있지 않으므로 에러가 발생하여야 하나 정상적으로 결과가 출력되었다. 이는 student 객체의 [[Prototype]]이 가리키는 링크를 따라가서 student 객체의 부모 역할을 하는 프로토타입 객체(Object.prototype)의 메소드 hasOwnProperty를 호출하였기 때문에 가능한 것이다.
반응형
'Language > JavaScript' 카테고리의 다른 글
[Javascript] 자바스크립트 웹 Request(요청)과 Response(응답) (0) | 2023.07.23 |
---|---|
[Javascript] 자바스크립트 예외 처리 - throw, try, strict (0) | 2023.07.19 |
[Javascript] 자바스크립트 객체 - 프로퍼티와 메소드 (0) | 2023.07.19 |
[Javascript] 자바스크립트 객체 - 정의, 참조, 생성, 삭제, 순회, 비교 (0) | 2023.07.19 |
[Javascript] 자바스크립트 함수 - 다양한 함수 종류 및 전역함수들 (0) | 2023.07.19 |