프로토타입[Prototype]
let user = {
name: 'John',
age: 45,
email: 'john@example.com'
}
console.log(user.name);
console.log(user.hasOwnProperty('email'));
위 코드에서 user라는 객체에는 hasOwnProperty라는 메서드가 없지만 사용이 가능하다.
그럼 hasOwnProperty는 어디서 온걸까 ?
위 사진과 같이 모든 객체는 global Object prototype을 가진다.
그렇다면 prototype은 무엇일까 ?
프로토타입은 자바스크립트 객체가 다른 객체로부터 메서드와 속성을 상속받는 메커니즘을 말한다.
이것을 프로토타입 체인(prototype chain)이라고도 말한다.
위에서 보듯이 Prototype Object 안에 있는 hasOwnProperty 를 상속받아서 사용하고 있다.
이렇게 하므로 인해서 더 적은 메모리를 사용할 수가 있고 코드를 재사용 할수 있다.
function Person(name, email, birthday) {
this.name = name;
this.email = email;
this.birthday = new Date(birthday);
this.calculateAge = function () {
const diff = Date.new() - this.birthday.getTime();
const ageDate = new Date(diff);
return Math.abs(ageDate.getUTCFullYear() - 1970);
}
}
const john = new Person('john', 'john@example.com', '7-10-91');
const han = new Person('han', 'han@example.com', '2-11-91');
console.log(john);
console.log(han);
위 코드는 생성자(constructor) 함수를 사용해서 다른 객체들을 만든 예시이다.
그럼 아래와 같이 birthday와 email,name의 값은 다르지만 calculateAge의 함수는 같다.!
그러니 프로토 타입으로 옮겨서 상속을 통해 사용하는 것이 더 효율적이다.
프로토 타입으로 함수를 옮긴 예시 코드 1
function Person(name, email, birthday) {
this.name = name;
this.email = email;
this.birthday = new Date(birthday);
}
Person.prototype.calculateAge = function () {
const diff = Date.new() - this.birthday.getTime();
const ageDate = new Date(diff);
return Math.abs(ageDate.getUTCFullYear() - 1970);
}
const john = new Person('john', 'john@example.com', '7-10-91');
const han = new Person('han', 'han@example.com', '2-11-91');
console.log(john);
console.log(han);
프로토 타입으로 함수를 옮긴 예시 코드 2
Object.create() 메서드는 지정된 프로토타입 객체 및 속성을 갖는 새 객체를 만든다.
function Person(name, email, birthday) {
const person = Object.create(personsPrototype);
person.name = name;
person.email = email;
person.birthday = new Date(birthday);
return person;
}
const personsPrototype = {
calculateAge() {
const diff = Date.new() - this.birthday.getTime();
const ageDate = new Date(diff);
return Math.abs(ageDate.getUTCFullYear() - 1970);
}
}
const john = new Person('john', 'john@example.com', '7-10-91');
const han = new Person('han', 'han@example.com', '2-11-91');
console.log(john);
console.log(han);
그럼 이제 매번 객체를 생성할 때 마다 calculateAge메서드를 생성하는 것이 아닌 프로토 타입에서 꺼내서 사용하면 되기 때문에 재사용성이 상당히 올라간다.
클래스(Class)
ES6에서 나온 Class를 이용해서 더 쉽게 OOP을 구현할 수 있다.
OOP 방식을 이용하지만 내부에서 prototype을 사용하며 작동된다.
Constructor
constructor(생성자)를 사용하면 인스턴스화된 객체에서 다른 메서드를 호출하기 전에 수행해야 하는 사용자 지정 초기화를 제공할 수 있다.
클래스를 new 를 붙여서 ( new User("John") ) 인스턴스 객채로 생성하면 넘겨받은 인수와 함께 constructor가 먼저 실행된다.
이 때 넘겨받은 인자인 John이 this.name 에 할당된다.
- constructor는 인스턴스의 생성과 동시에클래스 필드의 생성과 초기화를 실행한다.
- this는 클래스가 생성할 인스턴스를 가리킨다.
- constructor은 생략할 수 있다.
- constructor()는 new에 의해 자동으로 호출된다.
class Person {
constructor(name, email, birthday) {
this.name = name;
this.email = email;
this.birthday = new Date(birthday);
}
introduce() {
return `Hello my name is ${this.name}`;
}
}
const john = new Person('john', 'john@example.com', '10-3-98');
console.log(john);
그럼 자동으로 introduce메서드는 프로토 타입에 들어간다.
Static
"prototype"이 아닌 클래스 함수 자체에 메서드를 설정할 수도 있다.
이런 메서드를 정적(static) 메서드라고 부른다.
constructor생성자 내부의 필드(name,email,birthday)를 사용하지 않고 독립적인 것을 정의할 때 static을 사용하며 이 static 메서드를 사용할 때는 인스턴스가 아닌 클래스 이름을 이용해서 사용한다.
즉, 클래스에만 남아 있고 각각의 인스턴스에는 없다 !
class Person {
constructor(name, email, birthday) {
this.name = name;
this.email = email;
this.birthday = new Date(birthday);
}
introduce() {
return `Hello my name is ${this.name}`;
}
static multipleNumbers(x, y) {
return x * y;
}
}
const john = new Person('john', 'john@example.com', '10-3-98');
console.log(john);
프로토 타입 내부의 constructor 자체가 해당 클레스 자체이다.
Sub Class
부모 클래스를 자식 클래스에 확장할 수 있다.
부모 클래스에 있던 기능을 토대로 자식 클래스를 만들 수 있다.
그렇게 하기 위해서는 extends 키워드를 사용해주면 된다.
class Person {
constructor(name, email) {
this.name = name;
this.email = email;
}
introduce() {
return `Hello my name is ${this.name}`;
}
}
class Client extends Person {
constructor(name, email, phone, address) {
super(name, email)
this.phone = phone;
this.address = address;
}
}
const john = new Client('John', 'john@example.com', '010-0000-0000', '서울');
console.log(john.introduce());
부모 클래스에게 상속받아 자식 클래스를 만들고, 자식 클래스에 부모 클래스의 속성을 불러올 때 super()를 사용한다.
john.introduce가 실행되는 순서
1. client 객체에 client.introduce 가 있는지 확인한다.
2. 없기 때문에 Client.prototype에 있는지도 확인하지만 introduce는 없다.
3. extends를 통해 관계가 만들어진 Client.prototype의 프로토타입인 Person.prototype에 메서드가 있는지 확인한다. 여기에 introduce가 있기 때문에 이것을 사용한다.
super()
- 자식 클래스 내에서 부모 클래스의 생성자를 호출할 때 사용된다.
- 자식 클래스 내에서 부모 클래스의 메소드를 호출할 때 사용된다.
class Car {
constructor(brand) {
this.carname = brand;
}
present() {
return "I have a " + this.carname;
}
}
class Model extends Car {
constructor(brand, mod) {
super(brand);
this.model = mod;
}
show() {
return super.present() + ", it is a " + this.model;
}
}
let mycar = new Model("Ford", "Mustang");
mycar.show()
super([arguments]); // 부모 생성자 호출
super.functionOnParent([arguments]); // 부모 메서드 호출
'모카스터디 > JavaScript' 카테고리의 다른 글
Closure (0) | 2024.03.01 |
---|---|
Document Object(DOM) (0) | 2024.03.01 |
window Object [Browser Object Model(BOM)] (0) | 2024.03.01 |
동기와 비동기 [싱글스레드, 논블로킹, Promise, async&await] (0) | 2024.02.29 |
비구조화할당, 스프레드 연산자 (0) | 2024.02.29 |