JavaScript의 프로토 타입 및 상속 이해 - JavaScript guide
본문
목차
- JavaScript 개발자 콘솔을 사용하는 방법
- HTML에 JavaScript를 추가하는 방법
- JavaScript에서 구문 및 코드 구조 이해
- JavaScript로 주석을 작성하는 방법
- JavaScript에서 데이터 유형 이해
- JavaScript에서 문자열로 작업하는 방법
- JavaScript에서 문자열을 인덱싱, 분할 및 조작하는 방법
- JavaScript에서 데이터 유형을 변환하는 방법
- JavaScript에서 변수, 범위 및 게양 이해
- 연산자를 사용하여 JavaScript에서 수학을 수행하는 방법
- JavaScript에서 배열 이해
- JavaScript에서 배열 메서드를 사용하는 방법 : Mutator 메서드
- JavaScript에서 배열 메서드를 사용하는 방법 : Accessor 메서드
- JavaScript에서 배열 메서드를 사용하는 방법 : Iteration 메서드
- JavaScript에서 객체 이해
- JavaScript에서 날짜 및 시간 이해
- JavaScript에서 이벤트 이해
- JavaScript에서 JSON으로 작업하는 방법
- JavaScript로 조건문을 작성하는 방법
- JavaScript에서 Switch 문을 사용하는 방법
- JavaScript에서 While 및 Do ... While 루프 사용
- JavaScript에서 For 루프를 생성하는 방법
- JavaScript에서 함수를 정의하는 방법
- JavaScript의 프로토 타입 및 상속 이해
- JavaScript에서 클래스 이해
- JavaScript에서 객체 메소드를 사용하는 방법
- JavaScript에서 This, Bind, Call 및 Apply 이해
JavaScript의 프로토 타입 및 상속 이해
소개
JavaScript는 프로토 타입 기반 언어로, 객체 속성 및 메소드를 복제 및 확장 할 수 있는 일반화 된 객체를 통해 공유 할 수 있음을 의미합니다. 이것을 프로토 타입 상속이라고 하며 클래스 상속과 다릅니다. PHP, Python 및 Java와 같은 다른 주요 언어는 클래스 기반 언어이며 대신 클래스를 객체의 청사진으로 정의하기 때문에 널리 사용되는 객체 지향 프로그래밍 언어 중에서 JavaScript는 상대적으로 고유합니다.
이 튜토리얼에서는 객체 프로토 타입이 무엇인지, 생성자 함수를 사용하여 프로토 타입을 새로운 객체로 확장하는 방법을 배웁니다. 상속과 프로토 타입 체인에 대해서도 배웁니다.
자바 스크립트 프로토 타입
JavaScript의 객체 이해에서 객체 데이터 유형, 객체를 만드는 방법 및 객체 속성에 액세스하고 수정하는 방법을 살펴 보았습니다. 이제 프로토 타입을 사용하여 객체를 확장하는 방법을 배웁니다.
JavaScript의 모든 객체에는 [[Prototype]]이라는 내부 속성이 있습니다. 비어있는 새 객체를 만들어 이를 증명할 수 있습니다.
let x = {};
이것이 우리가 일반적으로 객체를 만드는 방법이지만, 이것을 달성하는 또 다른 방법은 객체 생성자를 사용하는 것입니다 : let x = new Object ().
[[Prototype]]을 묶는 이중 대괄호는 이것이 내부 속성이며 코드에서 직접 액세스 할 수 없음을 나타냅니다.
새로 작성된 이 객체의 [[Prototype]]을 찾기 위해 getPrototypeOf() 메소드를 사용합니다.
Object.getPrototypeOf(x);
출력은 몇 가지 기본 제공 속성과 메서드로 구성됩니다.
Output
{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, …}
[[Prototype]]을 찾는 또 다른 방법은 __proto__ 속성을 사용하는 것입니다. __proto__는 객체의 내부 [[Prototype]]을 노출하는 속성입니다.
.__ proto__는 레거시 기능이므로 프로덕션 코드에 사용해서는 안되며 모든 최신 브라우저에 있는 것은 아닙니다. 그러나 이 기사 전체에서 이를 설명 목적으로 사용할 수 있습니다.
x.__proto__;
getPrototypeOf()를 사용한 것처럼 출력이 동일합니다.
Output
{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, …}
JavaScript의 모든 객체는 둘 이상의 객체를 연결할 수 있는 방법을 만들기 때문에 [[프로토 타입]]을 갖는 것이 중요합니다.
생성 한 객체에는 날짜 및 배열과 같은 내장 객체와 마찬가지로 [[Prototype]]이 있습니다. 이 자습서의 뒷부분에서 볼 수 있듯이 프로토 타입 속성을 통해 한 객체에서 다른 객체로 이 내부 속성을 참조 할 수 있습니다.
프로토 타입 상속
객체의 속성이나 메서드에 액세스하려고 시도하면 JavaScript는 먼저 객체 자체를 검색하고 찾을 수 없으면 객체의 [[Prototype]]을 검색합니다. 객체와 [[Prototype]] 둘 다 참조한 후에도 여전히 일치하는 것이 없으면 JavaScript는 연결된 객체의 프로토 타입을 확인하고 프로토 타입 체인의 끝에 도달 할 때까지 계속 검색합니다.
프로토 타입 체인의 끝에는 Object.prototype이 있습니다. 모든 객체는 객체의 속성과 메서드를 상속합니다. 체인 끝을 넘어서 검색하려고 하면 null이됩니다.
이 예에서 x는 Object에서 상속되는 빈 개체입니다. x는 toString()과 같이 Object에있는 모든 속성 또는 메서드를 사용할 수 있습니다.
x.toString();
Output
[object Object]
이 프로토 타입 체인은 하나의 링크 길이입니다. x-> 객체. 두 개의 [[Prototype]] 속성을 함께 연결하려고 하면 null이 되기 때문에 이것을 알고 있습니다.
x.__proto__.__proto__;
Output
null
다른 유형의 물체를 살펴 보겠습니다. JavaScript에서 배열을 사용한 경험이 있다면 pop() 및 push()와 같은 내장 메서드가 많이 있다는 것을 알고 있습니다. 새 배열을 만들 때 이러한 메서드에 액세스 할 수 있는 이유는 생성 한 모든 배열이 Array.prototype의 속성 및 메서드에 액세스 할 수 있기 때문입니다.
새로운 배열을 만들어서 이것을 테스트 할 수 있습니다.
let y = [];
배열 생성자로 작성할 수도 있음을 명심하십시오. y = new Array ().
새로운 y 배열의 [[Prototype]]을 살펴보면 x 객체보다 더 많은 속성과 메서드가 있음을 알 수 있습니다. Array.prototype에서 모든 것을 상속했습니다.
y.__proto__;
[constructor: ƒ, concat: ƒ, pop: ƒ, push: ƒ, …]
프로토 타입에서 Array()로 설정된 생성자 속성을 확인할 수 있습니다. constructor 속성은 객체의 생성자 함수를 반환합니다.이 함수는 함수에서 객체를 구성하는 데 사용되는 메커니즘입니다.
이 경우 프로토 타입 체인이 더 길기 때문에 이제 두 개의 프로토 타입을 함께 연결할 수 있습니다. y-> 배열-> 객체처럼 보입니다.
y.__proto__.__proto__;
Output
{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, …}
이 체인은 이제 Object.prototype을 참조합니다. 생성자 함수의 prototype 속성에 대해 내부 [[Prototype]]을 테스트하여 동일한 것을 참조하고 있는지 확인할 수 있습니다.
y.__proto__ === Array.prototype; // true
y.__proto__.__proto__ === Object.prototype; // true
isPrototypeOf() 메소드를 사용하여 이를 수행 할 수도 있습니다.
Array.prototype.isPrototypeOf(y); // true
Object.prototype.isPrototypeOf(Array); // true
instanceof 연산자를 사용하여 생성자의 프로토 타입 속성이 객체의 프로토 타입 체인 내 어디에나 나타나는지 테스트 할 수 있습니다.
y instanceof Array; // true
요약하면, 모든 JavaScript 객체에는 숨겨진 내부 [[Prototype]] 속성이 있습니다 (일부 브라우저에서는 __proto__를 통해 노출 될 수 있음). 객체를 확장 할 수 있으며 생성자의 [[Prototype]]에 대한 속성과 메서드를 상속합니다.
이 프로토 타입은 체인으로 연결될 수 있으며 각 추가 객체는 체인 전체의 모든 것을 상속합니다. 체인은 Object.prototype으로 끝납니다.
생성자 함수
생성자 함수는 새 객체를 생성하는 데 사용되는 함수입니다. new 연산자는 생성자 함수를 기반으로 새 인스턴스를 만드는 데 사용됩니다. new Array() 및 new Date()와 같은 일부 내장 JavaScript 생성자를 보았지만 새 객체를 빌드 할 고유 한 사용자 지정 템플릿을 만들 수도 있습니다.
예를 들어, 매우 간단한 텍스트 기반 롤 플레잉 게임을 만들고 있다고 가정 해 봅시다. 사용자는 캐릭터를 선택한 다음 전사, 치료사, 도둑 등 캐릭터 클래스를 선택할 수 있습니다.
각 캐릭터는 이름, 레벨 및 적중률과 같은 많은 특성을 공유하므로 생성자를 템플릿으로 만드는 것이 좋습니다. 그러나 각 캐릭터 클래스마다 기능이 크게 다를 수 있으므로 각 캐릭터가 자신의 능력에만 액세스 할 수 있도록 해야 합니다. 프로토 타입 상속 및 생성자로 이 작업을 수행 할 수 있는 방법을 살펴 보겠습니다.
먼저 생성자 함수는 일반 함수일 뿐입니다. new 키워드를 가진 인스턴스에 의해 호출 될 때 생성자가 됩니다. JavaScript에서는 컨벤션에 따라 생성자 함수의 첫 글자를 대문자로 사용합니다.
// Initialize a constructor function for a new Hero
function Hero(name, level) {
this.name = name;
this.level = level;
}
이름과 레벨이라는 두 가지 매개 변수를 사용하여 Hero라는 생성자 함수를 만들었습니다. 모든 캐릭터는 이름과 레벨을 가지므로, 새로운 캐릭터마다 이러한 속성을 갖는 것이 좋습니다. this 키워드는 작성된 새 인스턴스를 참조하므로 this.name을 name 매개 변수로 설정하면 새 오브젝트에 name 특성이 설정됩니다.
이제 new로 새로운 인스턴스를 만들 수 있습니다.
let hero1 = new Hero('Bjorn', 1);
hero1을 콘솔 아웃하면 새 속성이 예상대로 설정된 새 개체가 생성 된 것을 볼 수 있습니다.
Output
Hero {name: "Bjorn", level: 1}
이제 hero1의 [[Prototype]]을 얻으면 생성자를 Hero()로 볼 수 있습니다. (이것은 hero1 .__ proto__과 같은 입력을 가지고 있지만 사용하기에 적합한 방법임을 기억하십시오.)
Object.getPrototypeOf(hero1);
Output
constructor: ƒ Hero(name, level)
생성자에 메소드가 아닌 속성 만 정의했음을 알 수 있습니다. 효율성과 코드 가독성을 높이기 위해 프로토 타입에서 메소드를 정의하는 것이 JavaScript에서 일반적입니다.
프로토 타입을 사용하여 Hero에 메소드를 추가 할 수 있습니다. greet() 메소드를 만듭니다.
...
// Add greet method to the Hero prototype
Hero.prototype.greet = function () {
return `${this.name} says hello.`;
}
greet()은 Hero의 프로토 타입에 있고 hero1은 Hero의 인스턴스이므로 hero1에서 이 메소드를 사용할 수 있습니다.
hero1.greet();
Output
"Bjorn says hello."
Hero의 [[Prototype]]을 검사하면 greet ()을 사용 가능한 옵션으로 볼 수 있습니다.
이것은 좋지만 이제는 영웅들이 사용할 캐릭터 클래스를 만들고 싶습니다. 클래스마다 능력이 다르기 때문에 모든 클래스의 모든 능력을 Hero 생성자에 넣는 것은 의미가 없습니다. 우리는 새로운 생성자 함수를 만들고 싶지만 원래의 Hero와 연결되기를 원합니다.
call() 메서드를 사용하여 한 생성자에서 다른 생성자로 속성을 복사 할 수 있습니다. 워리어와 힐러 생성자를 만들어 봅시다.
...
// Initialize Warrior constructor
function Warrior(name, level, weapon) {
// Chain constructor with call
Hero.call(this, name, level);
// Add a new property
this.weapon = weapon;
}
// Initialize Healer constructor
function Healer(name, level, spell) {
Hero.call(this, name, level);
this.spell = spell;
}
모두 새로운 생성자는 이제 영웅의 특성과 몇 unqiue 사람이 있다. 우리는 warrior에 attack() 메소드를, Healer에 heal() 메소드를 추가 할 것입니다.
...
Warrior.prototype.attack = function () {
return `${this.name} attacks with the ${this.weapon}.`;
}
Healer.prototype.heal = function () {
return `${this.name} casts ${this.spell}.`;
}
이제 두 가지 새로운 캐릭터 클래스를 사용하여 캐릭터를 만듭니다.
const hero1 = new Warrior('Bjorn', 1, 'axe');
const hero2 = new Healer('Kanin', 1, 'cure');
hero1은 이제 새로운 속성을 가진 전사로 인식됩니다.
Output
Warrior {name: "Bjorn", level: 1, weapon: "axe"}
Warrior 프로토 타입에서 설정 한 새로운 방법을 사용할 수 있습니다.
hero1.attack();
Console
"Bjorn attacks with the axe."
그러나 프로토 타입 체인에서 메소드를 더 사용하려고 하면 어떻게 됩니까?
hero1.greet();
Output
Uncaught TypeError: hero1.greet is not a function
call()을 사용하여 생성자를 연결하면 프로토 타입 속성 및 메서드가 자동으로 연결되지 않습니다. Object.create ()를 사용하여 프로토 타입을 연결하여 추가 메서드를 만들고 프로토 타입에 추가하기 전에 프로토 타입을 연결합니다.
...
Warrior.prototype = Object.create(Hero.prototype);
Healer.prototype = Object.create(Hero.prototype);
// All other prototype methods added below
...
이제 전사 또는 치료사의 인스턴스에서 Hero의 프로토 타입 방법을 성공적으로 사용할 수 있습니다.
hero1.greet();
Output
"Bjorn says hello."
캐릭터 생성 페이지의 전체 코드는 다음과 같습니다.
// Initialize constructor functions
function Hero(name, level) {
this.name = name;
this.level = level;
}
function Warrior(name, level, weapon) {
Hero.call(this, name, level);
this.weapon = weapon;
}
function Healer(name, level, spell) {
Hero.call(this, name, level);
this.spell = spell;
}
// Link prototypes and add prototype methods
Warrior.prototype = Object.create(Hero.prototype);
Healer.prototype = Object.create(Hero.prototype);
Hero.prototype.greet = function () {
return `${this.name} says hello.`;
}
Warrior.prototype.attack = function () {
return `${this.name} attacks with the ${this.weapon}.`;
}
Healer.prototype.heal = function () {
return `${this.name} casts ${this.spell}.`;
}
// Initialize individual character instances
const hero1 = new Warrior('Bjorn', 1, 'axe');
const hero2 = new Healer('Kanin', 1, 'cure');
이 코드를 사용하여 기본 속성으로 Hero 클래스를 만들고 원래 생성자에서 Warrior와 Healer라는 두 개의 문자 클래스를 만들고 프로토 타입에 메서드를 추가하고 개별 문자 인스턴스를 만들었습니다.
결론
JavaScript는 프로토 타입 기반 언어이며 다른 많은 객체 지향 언어에서 사용하는 기존 클래스 기반 패러다임과 다르게 작동합니다.
이 튜토리얼에서는 JavaScript에서 프로토 타입이 작동하는 방법과 모든 객체가 공유하는 숨겨진 [[Prototype]] 속성을 통해 객체 속성과 메서드를 연결하는 방법을 배웠습니다. 또한 사용자 정의 생성자 함수를 만드는 방법과 프로토 타입 상속이 속성 및 메서드 값을 전달하는 방법을 배웠습니다.
- 이전글JavaScript에서 클래스 이해 - JavaScript guide 19.10.28
- 다음글JavaScript에서 함수를 정의하는 방법 - JavaScript guide 19.10.28