자바스크립트의 객체를 생성하는 방법에는 프로토타입 기반 그리고 클래스 기반 2가지가 있습니다.
자바스크립트의 모든 객체는 프로토타입 객체를 가지고 있으며,
프로토타입 객체로부터 속성과 메소드를 상속받습니다.
const fruits1 = ["Apple", "Banana", "Cherry"];
const fruits2 = new Array("Apple", "Banana", "Cherry");
// 프로토타입 속성
console.log(fruits1.length, fruits2.length); // 3 3
// 프로토타입 메소드
console.log(fruits1.includes("Banana"), fruits2.includes("Orange")); // true false
객체.prototype.메소드명 = function() { }
이고, 속성을 추가하는 방법은 객체.prototype.속성명 = 값;
입니다.Array.prototype.imchannel = function () {
console.log("Hello, imchannel!!");
};
const arr1 = [];
const arr2 = new Array();
arr1.imchannel(); // Hello, imchannel!!
arr2.imchannel(); // Hello, imchannel!!
// 생성자
function User(first, last) {
this.firstName = first; // 속성
this.lastName = last; // 속성
}
User.prototype.getFullName = function () { // 메소드
return `${this.lastName} ${this.firstName}`;
};
const hong = new User("gildong", "hong");
console.log(hong.getFullName()); // hong gildong
위에서 생성한 객체와 프로토타입은 ES6 클래스 기본문법으로 작성할 수 있습니다.
class User {
constructor(first, last) { // 생성자
this.firstName = first; // 속성
this.lastName = last; // 속성
}
getFullName() { // 메소드
return `${this.lastName} ${this.firstName}`;
}
}
const hong = new User("gildong", "hong");
console.log(hong.getFullName()); // hong gildong
Getter 는 객체의 속성값을 반환하는 메서드이며,
get 메서드명() { return 속성값; }
와 같이 정의합니다.
Setter 는 객체의 속성값을 설정하는 메서드이며,
set 메서드명(value) { 속성 = value; }
와 같이 정의합니다.
class User {
constructor(first, last) {
this.firstName = first;
this.lastName = last;
}
get fullName() {
console.log("Getting fullName!");
return `${this.lastName} ${this.firstName}`;
}
set fullName(value) {
console.log("Setting fullName!");
[this.lastName, this.firstName] = value.split(" ");
}
}
const hong = new User("gildong", "hong");
console.log(hong.fullName); // Getting fullName! \n hong gildong
hong.fullName = "hong gilzang"; // Setting fullName!
console.log(hong.lastName); // hong
console.log(hong.firstName); // gilzang
console.log(hong.fullName); // Getting fullName! \n hong gilzang
메소드에는 프로토타입 메소드와 정적 메소드 2가지가 있습니다.
프로토타입 메소드는 인스턴스화된 객체에서 사용하는 메소드이고,
정적 메소드는 클래스를 통한 객체생성 없이 호출할 수 있는 메소드입니다.
정적 메소드는 메소드 앞에 static
키워드를 추가하여 선언합니다.
class User {
constructor(first, last) {
this.firstName = first;
this.lastName = last;
}
getFullName() { // 프로토타입 메소드
return `${this.lastName} ${this.firstName}`;
}
static isUser(user) { // 정적 메소드
if (user.firstName && user.lastName) {
return true;
}
return false;
}
}
const hong = new User("gildong", "hong");
const kim = {
name: "kim yushin",
age: 100,
};
console.log(User.isUser(hong)); // true
console.log(User.isUser(kim)); // false
console.log(hong.isUser()); // Error
console.log(User.getFullName()); // Error
상속은 새로운 클래스(자식)에서 기존 클래스(부모)의 모든 속성과 메소드를 사용할 수 있는 것을 의미합니다.
extends
키워드를 사용해 클래스를 상속받습니다.
super()
키워드를 사용해 부모 클래스의 생성자를 호출합니다.
super
키워드를 사용해 부모 클래스의 속성 혹은 메소드를 호출할 수 있습니다.
자식 클래스는 부모 클래스의 메소드를 재정의할 수 있습니다. (오버라이딩)
class Vehicle {
constructor(acceleration = 1) {
this.speed = 0;
this.acceleration = acceleration;
}
accelerate() {
this.speed += this.acceleration;
}
decelerate() {
if (this.speed <= 0) {
console.log("정지!");
return;
}
this.speed -= this.acceleration;
}
}
// 자전거
class Bicycle extends Vehicle {
constructor(price = 100, acceleration) {
super(acceleration);
this.price = price;
this.wheel = 2;
}
}
const bicycle = new Bicycle(300);
console.log(bicycle); // Bicycle {speed: 0, acceleration: 1, price: 300, wheel: 2}
console.log(bicycle.speed); // 0
bicycle.accelerate();
console.log(bicycle.speed); // 1
bicycle.decelerate();
bicycle.decelerate(); // 정지!
console.log(bicycle.speed); // 0
// 자동차
class Car extends Bicycle {
constructor(license, price, acceleration) {
super(price, acceleration);
this.license = license;
this.wheel = 4; // 부모 속성 재정의
}
accelerate() { // 메소드 오버라이딩
if (!this.license) {
console.log("무면허!");
return;
}
super.accelerate(); // 부모 메소드 호출
}
decelerate() { // 메소드 오버라이딩
if (!this.license) {
console.log("무면허!");
return;
}
super.decelerate(); // 부모 메소드 호출
}
}
const carA = new Car(true, 7000, 10);
console.log(carA); // Car {speed: 0, acceleration: 10, price: 7000, wheel: 4, license: true}
console.log(carA.speed); // 0
carA.accelerate();
console.log(carA.speed); // 10
carA.decelerate();
carA.decelerate(); // 정지!
console.log(carA.speed); // 0
const carB = new Car(false, 6000, 20);
console.log(carB); // Car {speed: 0, acceleration: 20, price: 6000, wheel: 4, license: false}
carB.accelerate(); // 무면허!
carB.decelerate(); // 무면허!
객체가 특정 생성자 함수의 인스턴스인지 아닌지 확인할 때 사용하는 연산자입니다.
A instanceof B
객체 A 가 클래스 B 에 속하거나 상속받으면 true 를 반환합니다.
class A { constructor() { } }
class B extends A { constructor() { super(); } }
class C extends B { constructor() { super(); } }
const a = new A();
const b = new B();
const c = new C();
// instnaceof
console.log(a instanceof A); // true
console.log(a instanceof B); // false
console.log(a instanceof C); // false
console.log(b instanceof A); // true
console.log(b instanceof B); // true
console.log(b instanceof C); // false
console.log(c instanceof A); // true
console.log(c instanceof B); // true
console.log(c instanceof C); // true
객체를 인스턴스로 만들면 constructor 라는 속성이 자동으로 추가되는데,
이 속성은 해당 객체를 만든 생성자 함수를 가리킵니다.
class A { constructor() { } }
class B extends A { constructor() { super(); } }
class C extends B { constructor() { super(); } }
const a = new A();
const b = new B();
const c = new C();
// constructor
console.log(a.constructor === A); // true
console.log(a.constructor === B); // false
console.log(a.constructor === C); // false
console.log(b.constructor === A); // false
console.log(b.constructor === B); // true
console.log(b.constructor === C); // false
console.log(c.constructor === A); // false
console.log(c.constructor === B); // false
console.log(c.constructor === C); // true