코린이의 개발 일지

[JavaScript] - Prototype(프로토타입) 본문

자바스크립트

[JavaScript] - Prototype(프로토타입)

폴라민 2022. 9. 8. 18:58
반응형

프로토타입 기반 언어

  • 자바스크립트는 흔히 프로토타입 기반 언어라고 부른다.

⇒ 이 말의 의미는 모든 객체들이 메소드와 속성들을 상속 받기 위한 템플릿으로써 프로토타입 객체를 가진다는 의미이다.

이 말이 처음에는 잘 이해가 가지 않았다. 부모 객체로부터 상속이 된다면 class와 뭐가 다르다는 걸까?

우선 객체지향 프로그래밍에서의 상속개념과 같이 js의 모든 객체는 부모의 property, method를 물려받아 사용할 수 있다.

이때 이 부모 객체를 가리켜 Prototype 객체 혹은 prototype 이라고 한다.

그러니까 프로토타입 기반 객체지향 프로그래밍 언어는 클래스 없이(Class-less)도 (ECMAScript 6에서 클래스가 추가되었다) 객체를 생성할 수 있다.

Prototype을 사용하는 이유

  • 생성자 함수로 생성된 객체 모두에 프로퍼티, 메서드를 공유하기 위해
  • 상속을 구현하기 위해

[[Prototype]] 과 prototype (두개는 다르다!!)

[[Prototype]] 과 prototype 은 프로퍼티 이며, 이 두 프로퍼티가 가르키는 객체를 prototype객체라고 한다.

[[Prototype]]

  • 자바스크립트의 모든 객체는 [[Prototype]]이라는 인터널 슬롯을 가진다.
  • [[Prototype]] 값은 prototype 객체이며 __ proto __ 로 접근할 수 있다.
var student = {
    name: 'Lee',
    score: 90
  }
console.log(student.__proto__); // [Object: null prototype] {}
console.log(Object.prototype); // [Object: null prototype] {}
console.log(student.__proto__ === Object.prototype); // true 

prototype

  • 함수 객체만 가지고 있는 프로퍼티
  • 함수 객체가 생성자로 사용될 때 이 함수를 통해 생성될 객체의 부모 역할을 하는 객체(prototype 객체)를 가리킨다.
var student = {
    name: 'Lee',
    score: 90
  }

function Person(name) {
    this.name = name;
}

var foo = new Person('Lee');

console.log(Person.prototype); // {}
console.log(foo.prototype); // undefined
console.log(student.prototype); // undefined

위 함수의 prototype 체인을 타고 올라가 보면

function Person(name) {
    this.name = name;
}

var foo = new Person('Lee');

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

위의 코드를 해석해보면

우선 foo 의 부모 객체는 누굴까? 바로 Person() 함수이다.

따라서 foo의 prototype 객체는 Person()이다.

이때 위에서 prototype 객체는 [[Prototype]] 값이라고 하였다.

[[Prototype]] 값에 접근 하려면 __ proto __ 를 사용하면 된다.

따라서

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

이 문장의 의미는

foo의 [[Prototype]] 값은 foo의 prototype 객체(즉 부모 객체)이고 따라서 Person함수 객체가 가진 prototype 프로퍼티 값인 것이다.

prototype 프로퍼티가 함수 객체가 생성자로 사용될 때 이 함수를 통해 생성될 객체의 부모 역할을 하는 객체(prototype 객체)를 가리킨다 고 했으니까.

⇒ Person 함수 객체가 생성자로 사용될 때

var foo = new Person('Lee');

이 함수를 통해 생성될 객체(foo)의 부모 역할을 하는 객체(Person)을 가리키는게 prototype 프로퍼티다.

따라서

자식.__proto__ === 부모.prototype

이런 것이다.

모든 함수는 Function이라는 prototype 객체를 가지니까

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

이것도 참이 되는 것이다.

constructor 프로퍼티

  • 객체 입장에서 자신을 생성한 객체를 의미한다.

prototype 객체는 constructor 프로퍼티를 갖는다.

위의 예시에서는 다음과 같다

// Person() 생성자 함수에 의해 생성된 객체를 생성한 객체는 Person() 생성자 함수이다.
console.log(Person.prototype.constructor === Person);

// foo 객체를 생성한 객체는 Person() 생성자 함수이다.
console.log(foo.constructor === Person);

// Person() 생성자 함수를 생성한 객체는 Function() 생성자 함수이다.
console.log(Person.constructor === Function);

prototype chain

  • 자바스크립트는 특정 객체의 프로퍼티나 메소드에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티 또는 메소드가 없다면 [[Prototype]]이 가리키는 링크를 따라 자신의 부모 역할을 하는 프로토타입 객체의 프로퍼티나 메소드를 차례대로 검색한다. 이것을 프로토타입 체인이라한다.
var student = {
  name: 'Lee',
  score: 90
}
console.dir(student);
console.log(student.hasOwnProperty('name')); // true
console.log(student.__proto__ === Object.prototype); // true
console.log(Object.prototype.hasOwnProperty('hasOwnProperty')); // true
console.log(student.__proto__.hasOwnProperty('hasOwnProperty')); // true

객체 생성 방법

이제는 우리가 객체를 생성한게 사실 Object() 생성자 함수를 호출한 거였다는 것을 알 수 있다.

Object() 생성자 함수는 물론 함수이다. 따라서 함수 객체인 Object() 생성자 함수는 일반 객체와 달리 prototype 프로퍼티가 있다.

var person = {
  name: 'Lee',
  gender: 'male',
  sayHello: function(){
    console.log('Hi! my name is ' + this.name);
  }
};

따라서 객체를 생성하면(Person) person의 프로토타입 객체는 Object.prototype이다.

위의 그림 순서를 설명하자면

  1. 객체 리터럴로 객체를 생성하는 코드 만남
  2. 자바스크립트 엔진은 내부적으로 Object() 생성자 함수를 사용하여 객체 생성

이때 Object() 생성자 함수는 함수이기 때문에 [[prototype]]이 Function.prototype이다.

함수 생성 방법

function Person(name, gender) {
  this.name = name;
  this.gender = gender;
  this.sayHello = function(){
    console.log('Hi! my name is ' + this.name);
  };
}

var foo = new Person('Lee', 'male');

foo객체의 prototype 객체는 Person.prototype이다.

이때 함수의 prototype 즉 Person.prototype의 prototype 객체는 Object.prototype 객체이다.

Function.prototype 의 prototype 객체도 Object.prototype 객체이다.

이는 객체 리터럴 방식이나 생성자 함수 방식이나 결국은 모든 객체의 부모 객체인 Object.prototype 객체에서 프로토타입 체인이 끝나기 때문이다. 이때 Object.prototype 객체를 프로토타입 체인의 종점(End of prototype chain) 이라 한다.

프로토타입 객체의 확장

function Person(name) {
  this.name = name;
}

var foo = new Person('Lee');

Person.prototype.sayHello = function(){
  console.log('Hi! my name is ' + this.name);
};

foo.sayHello();

위의 코드 대신 아래와 같이 적어도 똑같이 작동한다

function Person(name) {
    this.name = name;
}

var foo = new Person('Lee');

foo.__proto__.sayHello = function(){
console.log('Hi! my name is ' + this.name);
};

foo.sayHello();

출처:

https://poiemaweb.com/js-prototype

반응형
Comments