ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 자바스크립트(JS)의 prototype
    CS 2024. 8. 9. 02:52

    자바스크립트는 클래스 기반의 객체지향 언어가 아닌, 프로토타입 기반의 객체지향 언어이다.

     

    자바스크립트에서는 함수와 new 키워드를 사용하여 클래스를 흉내낼 수 있으며, 이는 객체 생성 시 기존 객체를 복사하여 새로운 객체를 만드는 프로토타입 기반의 메커니즘을 활용한다.

     

    이 자바스크립트 프로토타입에 대해서 자세히 알아보도록 하자.

     

    ❗️프로토타입 기반 언어 특징 ❗️

    자바스크립트 같은 프로토타입 기반 언어는 다음과 특징을 가진다.

    모든 객체들이 메소드와 속성들을 상속받기 위한 명세로 프로토타입 객체를 가진다는 의미이다.

     

    클래스처럼 객체의 인스턴스를 위한 명세와 같은 역할을 하는데, 객체 본인만이 가진 속성과 메서드에도 접근할 수 있으며, 프로토타입의 것들에도 접근할 수 있다는 것이 특징이다.

     

    자바스크립트에서 함수를 생성할 때 프로토타입 속성이 함수에 붙여지는데, 예를 들어 new 키워드로 함수를 호출할 때마다 생성되는 인스턴스는 함수 프로토타입의 모든 속성을 상속한다.

    const Hello = function(name) {
      this.name = name;
    }

     

    속성과 메소드들은 각 객체 인스턴스가 아니라 객체 생성자의 prototype 속성에 정의되어 있는데,

    Hello에 정의한 name 멤버 외에 프로토타입 객체인 Object의 다른 멤버들도 존재함을 알 수 있다.

     

    이렇게 자바스크립트의 모든 객체는 자신의 부모 역할을 하는 객체와 연결되어 있고, 이 부모 객체를 프로토타입이라고 한다.

     

    생성된 모든 객체는 이런 프로토타입 객체에 접근 할 수 있고 동적으로 런타임 시에 멤버를 추가할 수도 있다.

     

    🧐 프로토타입 구성요소 🧐

    Prototype 속성

    함수(특히 생성자 함수)에 기본적으로 존재하는 속성으로, 이 속성은 객체를 생성할 때 해당 객체의 프로토타입이 된다.

     

    생성자 함수를 통해 생성된 모든 객체는 이 prototype 객체를 자신의 프로토타입으로 가지며, 이를 통해 메소드와 속성을 상속 받는다.

    function Person(name) {
        this.name = name;
    }
    
    // Person의 prototype 속성에 메소드를 추가
    Person.prototype.greet = function() {
        console.log("Hello, " + this.name);
    };
    
    let minji = new Person("Minji");
    minji.greet(); // "Hello, Minji"

     

    여기서 Person.prototype은 Person 생성자 함수에 의해 생성된 모든 객체가 공유하는 프로토타입 객체이다.

     

    __proto__ 속성

    모든 자바스크립트는 객체가 가지고 있는 내부 속성으로, 객체의 프로토타입. 즉, 상속을 받은 부모 객체를 가리킨다. 이 속성은 ECMAScript 표준에 공식적으로 포함된 것은 아니지만, 대부분의 자바스크립트 엔진에서 지원한다.

     

    객체가 특정 속성이나 메소드를 가지고 있지 않을 때, 자바스크립트는 이 __proto__ 속성에 따라 프로토타입 체인 상에서 그 속성이나 메소드를 찾는다.

    console.log(minji.__proto__ === Person.prototype); // true

     

    minji 객체는 Person 생성자 함수를 통해 생성되었기에, minji.__proto__는 Person.prototype을 가리킨다.

     

    constructor 속성

    모든 프로토타입 객체는 기본적으로 constructor 라는 속성을 가지고 있다.

    이 속성은 해당 프로토타입을 사용해 생성된 객체의 생성자 함수를 가리킨다.

     

    이는 객체가 어떤 생성자 함수에 의해서 생성되었는지를 나타내며, 일반적으로 객체의 타입을 확인하거나 생성자를 호출하는 데 사용된다.

    console.log(minji.constructor === Person); // true

     

    minji 객체의 constructor 속성은 Person 생성자 함수를 가리킨다.

    이 속성은 프로토타입이 초기화될 때 자동으로 설정된다.

     

    Object.prototype

    자바스크립트 모든 객체는 최상위 프로토타입인 Object.prototype을 참조한다.

    이 프로토타입은 기본적으로 toString(), valueOf() 등의 메소드를 포함하고 있다.

     

    이는 최상위 프로토타입으로, 모든 객체에 기본 메소드와 속성을 제공한다. 프로토타입 체인의 끝에 위치하며, 이보다 상위 프로토타입은 없다.

    console.log(Object.prototype.isPrototypeOf(minji)); // true

     

    minji 객체는 Object.prototype을 프로토타입 체인의 끝에서 참조하게 된다.

     

    💡 프로토타입을 이용한 메모리 효율성 💡

    자바스크립트에서 객체를 생성할 때, 모든 인스턴스는 각각 독립적인 속성과 메소드를 갖는다.

    function Car(model, color) {
      this.model = model;
      this.color = color;
    }
    
    var car1 = new Car('Tesla Model 3', 'red');
    var car2 = new Car('BMW i8', 'blue');
    
    console.log(car1.model);  // => 'Tesla Model 3'
    console.log(car2.color);  // => 'blue'

     

    위 코드를 보면 car1과 car2 객체는 각각 고유의 model과 color 속성을 가지지만, 만약 객체가 공통으로 사용해야 하는 메소드가 있는 경우, 프로토타입을 활용하여 메모리를 절약할 수 있다.

     

    function Car(model, color) {
      this.model = model;
      this.color = color;
    }
    
    Car.prototype.drive = function() {
      console.log(`${this.model} is driving.`);
    };
    
    var car1 = new Car('Tesla Model 3', 'red');
    var car2 = new Car('BMW i8', 'blue');
    
    car1.drive();  // => 'Tesla Model 3 is driving.'
    car2.drive();  // => 'BMW i8 is driving.'

     

    여기서 drive 메소드는 Car.prototype에 정의되어 있으며, 이는 모든 Car 객체 인스턴스가 공유하여 사용할 수 있다. 이로 인해 메모리 사용을 최적화할 수 있다.

     

    ❗️ 프로토타입의 핵심 개념 ❗️

    프로토타입 체인

    자바스크립트의 모든 객체는 자신의 프로토타입을 참조하는 내부 링크인 [[Prototype]]을 가지고 있다. 이 프로토타입은 객체를 생성한 함수의 prototype 속성을 가리킨다. 예를 들어 아래 person 객체의 프로토타입은 기본적으로 Object.prototype을 참조한다.

    let person = {
        name: "Minji",
        greet: function() {
            console.log("Hello, " + this.name);
        }
    };
    console.log(person.__proto__ === Object.prototype); // true

     

    만약 객체에서 특정 속성이나 메소드를 찾을 수 없다면, 자바스크립트는 프로토타입 체인에 따라 상위 프로토타입에서 그 속성이나 메소드를 찾는다. 이 과정이 프로토타입 체인이다. 그리고, 프로토타입 체인을 따라가도 원하는 속성을 찾을 수 없다면, 최종적으로 undefined가 반환된다.

     

    프로토타입 객체와 생성자 함수

    함수를 정의하면 자바스크립트는 자동으로 해당 함수에 prototype 속성을 추가하며, 이는 해당 함수로 생성된 모든 객체의 공통 속성과 메소드를 정의하는 데 사용된다.

    function Book(title, author) {
      this.title = title;
      this.author = author;
    }
    
    Book.prototype.getDetails = function() {
      return `${this.title} by ${this.author}`;
    };
    
    const book1 = new Book('1984', 'George Orwell');
    console.log(book1.getDetails());  // => '1984 by George Orwell'

     

    여기서 getDetails 메소드는 Book 생성자 함수의 프로토타입 객체에 정의되었으며, 이 메서드는 book1 인스턴스를 포함한 모든 인스턴스에서 공통으로 사용 가능하다.

     

    ✅ 프로토타입을 사용하는 이유 ✅

    메모리 효율성

    • 자바스크립트에서 모든 객체는 프로토타입을 공유한다.
    • 객체는 자신의 메소드와 속성을 별도로 보유하는 대신, 여러 객체가 동일한 프로토타입 객체를 참조하여 공통의 메소드와 속성을 공유한다. 이를 통해 객체들이 동일한 기능을 제공하는 메소드와 속성을 중복하여 보유하지 않게 되어 메모리를 효율적으로 사용할 수 있다.

     

    객체지향적 설계

    • 자바스크립트의 프로토타입은 클래스 기반 언어의 상속과 유사한 역할을 한다. 객체는 프로토타입을 통해 다른 객체로부터 메소드와 속성을 상속받을 수 있으며, 이를 통해 코드 재사용성을 높일 수 있다.
    • 프로토타입 체인은 상위 프로토타입 객체에서 필요한 속성이나 메소드를 찾을 때까지 탐색하는 메커니즘을 제공한다. 이를 통해 객체지향적인 구조를 구현할 수 있다.

     

    개발 생산성

    • 프로토타입을 사용하면 동일한 메소드나 속성을 각 객체에 일일이 정의할 필요 없이, 프로토타입에 정의된 속성과 메소드를 여러 객체에서 쉽게 재사용할 수 있다. 이를 통해 코드를 보다 효율적으로 작성하고 유지보수하기 쉬워진다.
    • 특히, 대규모 프로젝트에서 동일한 기능을 가진 객체들을 쉽게 관리할 수 있어 개발 속도를 높이고 오류 발생 가능성을 줄일 수 있다.

     

    🔥 프로토타입과 React, Vue.js 🔥

    React와 프로토타입

    React는 기본적으로 함수형 컴포넌트와 클래스형 컴포넌트를 제공한다.

    클래스형 컴포넌트는 ES6 클래스 문법을 사용하지만, 이 클래스는 자바스크립트의 프로토타입 기반 상속을 사용하여 구현된다.

    class MyComponent extends React.Component {
      render() {
        return <div>Hello React</div>;
      }
    }

     

    MyComponent는 React.Component를 상속받으며, 이는 자바스크립트의 프로토타입 체인에 의해 이루어진다.

    즉, MyComponent 인스턴스는 React.Component의 메소드와 속성에 접근할 수 있다.

     

    Vue.js와 프로토타입

    Vue.js에서도 자바스크립트의 프로토타입을 활용하여 객체지향적인 접근을 한다.

    Vue 인스턴스는 내부적으로 Vue.prototype에 정의된 여러 유틸리티 메소드와 라이프사이클 훅을 사용한다.

    var vm = new Vue({
      data: {
        message: 'Hello Vue!'
      },
      methods: {
        greet: function() {
          console.log(this.message);
        }
      }
    });
    
    vm.greet(); // => 'Hello Vue!'

     

    vm 인스턴스는 Vue.prototype의 메소드들을 사용하며, 이는 프로토타입 체인을 통해 이루어진다.

    이러한 접근은 Vue.js의 재사용 가능한 컴포넌트 구조를 가능하게 하고, 메모리 효율성을 높이는 데 기여한다.

     

    🚨 (헷갈리는 개념)  [[Prototype]]과 __proto__ 🚨

    [[Prototype]]

    이는 자바스크립트 객체가 내부적으로 가지고 있는 숨겨진 링크로, 이 링크는 객체의 프로토타입을 가리킨다.

     

    자바스크립트 엔진이 객체의 속성이나 메소드를 찾을 때, 먼저 해당 객체에서 찾고, 없으면 이 [[Prototype]] 링크를 통해 프로토타입 체인을 따라 올라가며 찾는다.

     

    이 [[Prototype]]은 표준 자바스크립트에서 직접 접근할 수 있는 속성은 아니다. 대신 자바스크립트 엔진 내부에서 사용되는 개념이다.

    __proto__ 

    __proto__는 자바스크립트에서 객체의 [[Prototype]]에 접근하거나 설정할 수 있는 속성이다.

     

    객체의 프로토타입을 확인하거나 변경할 때 사용할 수 있는 접근자이다.

    이 속성을 통해 개발자는 객체의 프로토타입을 직접 조작할 수 있다.

     

    __proto__는 대부분의 자바스크립트 엔진에서 지원하는 비공식적인 속성이다.

    이는 [[Prototype]]에 접근하기 위한 인터페이스로서 기능한다.

     

    🐥 결론 🐥

    프로토타입은 객체 생성자 함수에 의해 생성되는 객체들이 공유하는 속성과 메소드를 저장하는 특수 객체이다.

     

    모든 자바스크립트 객체는 선언 할당을 하면 해당 생성자 함수의 프로토타입 객체와 연결되며 프로토타입 체이닝을 통해 해당 객체의 속성과 메소드에 접근 가능하는 점을 확실하게 알고 가는 것이 중요하다.

     

    'CS' 카테고리의 다른 글

    Webpack vs Vite  (0) 2024.08.16
    자바스크립트(JS)의 클래스  (0) 2024.08.16
    자바스크립트(JS)의 Closure  (0) 2024.08.09
    자바스크립트(JS)의 this  (0) 2024.08.08
    자바스크립트(JS)의 동작원리  (0) 2024.08.08
Designed by Tistory.