Unit2 - [JavaScript] 객체 지향 프로그래밍 - 2

강성일·2023년 5월 12일
0
post-thumbnail

✅ TIL


프로토타입


JavaScript는 프로토타입(Prototype) 기반 언어입니다. 여기서 프로토타입은 원형 객체를 의미한다.

그리고 오늘 JavaScript가 사실 왜 객체인지 알게 된다.


프로토타입과 클래스


개발을 하다 보면 기존에 있는 기능을 가져와 확장해야 하는 경우가 생긴다.

사람에 관한 프로퍼티와 메서드를 가진 user라는 객체가 있는데,
user와 상당히 유사하지만 약간의 차이가 있는 admin과 guest 객체를 만들어야 한다고 가정해 보자.

이때 "user의 메서드를 복사하거나 다시 구현하지 않고 user에 약간의 기능을 얹어 admin과 guest 객체를 만들 수 있지 않을까?"

자바스크립트 언어의 고유 기능인 프로토타입 상속(prototypal inheritance) 을 이용하면 위와 같은 생각을 실현할 수 있습니다.


// Human이라는 클래스를 구현해보자.

class Human {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  sleep() {
    console.log(`${this.name}은 잠에 들었습니다`);
  }
}

let kimcoding = new Human('김코딩', 30);

// 실습해보세요
Human.prototype.constructor === Human; 
Human.prototype === kimcoding.__proto__; 
Human.prototype.sleep === kimcoding.sleep;


프로토타입 [[Prototype]]

자바스크립트의 객체는 명세서에서 명명한 [[Prototype]]이라는 숨김 프로퍼티를 갖는다.

이 숨김 프로퍼티 값은 null이거나 다른 객체에 대한 참조가 되는데,
다른 객체를 참조하는 경우 참조 대상을 '프로토타입(prototype)'이라 부른다.

따라서 JavaScript에서 모든 객체는 프로토타입을 가지고 있다.
프로토타입은 객체의 부모 역할을 하며, 해당 객체에 대한 속성과 메서드를 제공한다.
객체는 프로토타입 체인을 통해 상위 프로토타입의 속성과 메서드에 접근할 수 있다.

프로토타입의 동작 방식은 ‘신비스러운’ 면이 있다.

object에서 프로퍼티를 읽으려고 하는데 해당 프로퍼티가 없으면, 자바스크립트는 자동으로 프로토타입에서 프로퍼티를 찾기 때문이다.

프로그래밍에선 이런 동작 방식을 '프로토타입 상속’이라 부른다.

프로토타입은 객체를 생성할 때 자동으로 설정되며, proto 프로퍼티를 통해 접근할 수 있다.


클래스(Class)

클래스는 ES6부터 도입된 문법으로서, 객체 지향 프로그래밍을 구현하기 위해 사용된다.
쉽게 말하면, 객체를 생성하기 위한 템플릿 또는 설계도 역할을 한다.

자세히 역할을 정리해보겠다.

  • 속성과 메서드를 정의하고, 해당 클래스로부터 생성된 객체는 클래스의 정의에 따라 동작한다.
  • 클래스를 통해 여러 개의 객체를 생성할 수 있으며, 각 객체는 클래스의 인스턴스이다.
  • 생성자(constructor) 메서드를 사용하여 객체를 초기화하고, 메서드를 정의하여 객체의 동작을 구현한다.
  • 상속을 통해 다른 클래스로부터 속성과 메서드를 상속받을 수 있다.

프로토타입과 클래스는 함께 사용되어 JavaScript에서 객체 지향 프로그래밍을 구현하는 데 사용된다.
클래스는 프로토타입 기반의 상위 개념으로, 클래스로부터 생성된 객체는 해당 클래스의 프로토타입을 상속받는다.
프로토타입 체인을 통해 객체는 상위 프로토타입의 속성과 메서드에 접근할 수 있다.



⚙️ Human이라는 클래스와 인스턴스, 그리고 프로토타입의 관계


⚙️ Array(배열) 클래스와 인스턴스, 그리고 프로토타입의 관계

  • .prototype: 프로토타입도 하나의 객체로, 프로토타입 체인을 통해 상속하고자 하는 속성과 메소드가 담겨있다.
  • constructor: 생성자를 통해 인스턴스를 생성할 때 받은 전달인자를 내부의 속성, 즉 내부 변수에 할당할 수 있다.
  • new oprator: 인스턴스는 new 키워드로 생성하며, 프로토타입을 통해 클래스의 속성, 메서드를 상속받는다.
  • proto : 인스턴스의 프로토타입을 확인할 수 있다.
    ex. 임의의 배열을 생성하여 arr.proto로 확인해보면 클래스 Array로부터 상속받은 메서드들을 확인할 수 있다.



프로토타입 체인


class Human {
    constructor(name, age){
        this.name = name; 
        this.age = age;
    }
    sleep(){ return `${this.name}이(가) 잠을 잡니다.`}
}

class Student extends Human{
    constructor(name, age, grade){
        super(name, age);
        this.grade = grade;
    }
    study(num){
        this.grade = this.grade + num;
        return `${this.name}의 성적이 ${num}만큼 올라 ${this.grade}이 되었습니다.`
    }
}

class ForeignStudent extends Student{
    constructor(name, age, grade, country){
        super(name, age, grade);
        this.country = country;
    }
    speak(){
        return `${this.country} 언어로 수업을 진행합니다.`
    }
}

let americanStudent = new ForeignStudent('jake', 23, 80, '미국');

americanStudent는 ForeignStudent 클래스의 인스턴스 입니다.
ForeignStudent 클래스는 Human, Student 클래스를 상속받았기 때문에 study(), sleep()을 사용할 수 있습니다.


브라우저에서 DOM을 이용하면, document.createElement('div')로 새로운 div 엘리먼트를 만들 수 있다.
이렇게 생성된 div 엘리먼트는, HTMLDivElement라는 클래스의 인스턴스이다.

DOM 엘리먼트는 예를 들어 innerHTML과 같은 속성, 또는 append()와 같은 메서드가 있다.
각각의 엘리먼트가 해당 메서드나 속성이 있다는 것을 통해, Element라는 공통의 부모가 있음을 알 수 있다.

화살표 방향은 부모를 가리킵니다. EventTarget의 부모로는, 모든 클래스의 조상인 Object가 존재합니다.

인스턴스의 proto를 이용하면 이를 더 확실하게 확인할 수 있다.

const div = document.createElement('div');

//1. HTMLDivElement
console.log(div.__proto__);

//2. HTMLElement
console.log(div.__proto__.__proto__); 

//3. Element
console.log(div.__proto__.__proto__.__proto__); 

//4. Node
console.log(div.__proto__.__proto__.__proto__.__proto__); 

//5. EventTarget
console.log(div.__proto__.__proto__.__proto__.__proto__.__proto__); 

//6. constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …} ...
console.log(div.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__); 

//7. null
console.log(div.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__.__proto__); 

.__proto__를 이용하면 부모 클래스의 프로토타입, 혹은 '부모의 부모 클래스'의 프로토타입을 탐색할 수 있다.
profile
아이디어가 넘치는 프론트엔드를 꿈꿉니다 🔥

0개의 댓글