프로토타입이란

Dorogono·2022년 6월 8일
0

JS 알아보기

목록 보기
15/19
post-thumbnail

JS는 프로토타입 기반의 객체지향 언어다.

프로토타입 기반의 객체지향 프로그래밍은 다른 언어의 객체지향 언어보다 더 효율적이고 강력하다.

자바스크립트는 원시적 타입(숫자, 문자열 등)을 제외한 모든 것이 객체다.
그래서 기본적으로 자바스크립트를 두고 객체지향 언어라고 한다.

const circle = {
  radius: 5,
  
  getDiameter() {
    return 2 * this.radius;
  },
  
  getArea() {
    return Math.PI * this.radius ** 2;
  }
}

console.log(circle);
// circle : {
  radius: 5,
  getDiameter: ƒ getDiameter(),
  getArea: ƒ getArea()
}

console.log(circle.getDiameter()); // 10
console.log(circle.getArea()); // 78.5398...

이처럼 class를 굳이 쓰지 않더라도, 객체만 만들어준다면 된다.

객체의 상태를 나타내는 데이터 = radius,
상태 데이터를 조작할 수 있는 동작 메서드 = 함수를 위 코드와 같이 묶을 수 있다.

상속과 프로토타입

function Circle(radius) {
  this.radius = radius;
  this.getArea = function() {
    return Math.PI * this.radius ** 2;
  };
}

const circle1 = new Circle(1);
const circle2 = new Circle(2);

console.log(circle1.getArea === circle2.getArea) // false

생성자 함수를 이용해 만든 circle1, circle2는 모두 같은 getArea라는 메서드를 갖는다.

그렇다면 생성된 모든 인스턴스(circle1, circle2)는 동일한 메서드를 갖게 되면서 메모리를 낭비한다.

function Circle(radius) {
  this.radius = radius;
}

Circle.prototype.getArea = function() {
  return Math.PI * this.radius ** 2;
}

const circle1 = new Circle(1);
const circle2 = new Circle(2);

console.log(circle1.getArea === circle2.getArea) // true

하지만 프로토타입을 사용하면, 중복이 제거된다.
모든 인스턴스는 getArea 메서드를 상속받아 사용할 수 있다.

프로토타입은 상위 부모 요소(Circle) 프로퍼티를 자신 프로퍼티처럼 자유롭게 사용이 가능하다.

proto 접근자 프로퍼티

const person = {name:"Lee"};

console.log(person.__proto__); // [Object: null prototype] {}

이처럼 자바스크립트의 모든 객체는 자신의 프로토타입에 접근이 가능하다.

const obj = {};
const parent = {x : 1};

// get __proto__ 호출
obj.__proto__; // [Object: null prototype] {}

// set __proto__ 호출
obj.__proto__ = parent; // { x: 1}

console.log(obj.x); // 1

할당도 가능하다.

const child = {};
const parent = {};

child.__proto__ = parent;
parent.__proto__ = child;

// TypeError: Cyclic __proto__ value

이렇듯 순환이 되면, 무한 루프가 되기 때문에 에러가 발생한다.
__proto__는 단방향 링크드 리스트로 구현되야 한다.

get, set Prototype

const obj = Object.create(null);

console.log(obj.__proto__); // undefined

console.log(Object.getPrototypeOf(obj)); // null

__proto__ 접근자는 종점인 Object.__proto__를 상속받을 수 없다.

그래서 참조하고 싶거나 교체하고 싶다면, Object.getPrototypeOf 혹은 Object.setPrototypeOf를 사용하는 게 좋다.

Prototype 프로퍼티

(function() {}).hasOwnProperty('prototype'); // true
({}).hasOwnProperty('prototype'); // false

함수 객체만이 prototype 프로퍼티를 소유한다.

const Person = name => {
  this.name = name;
}

console.log(Person.hasOwnProperty('prototype')) // false

하지만 화살표 함수 객체는 프로퍼티를 소유하지 않는다.

__proto__ 접근자 프로퍼티

  • 모든 객체가 소유 및 사용
  • 프로토타입 참조값
  • 객체가 자신의 프로토타입에 접근 및 교체 위함

prototype 프로퍼티

  • constructor가 소유
  • 생성자 함수가 사용
  • 프로토타입 참조값
  • 생성자 함수가 자신이 생성할 객체 프로토타입 할당 위함

리터럴 표기법과 생성자 함수

function foo(){}
const arr = [1,2,3];

console.log(foo.constructor === Function); // true
console.log(arr.constructor === Array); // true

foo 함수는 Function 함수로 생성하지 않았다.
arr 배열도 Array 함수로 생성하지 않았다.

하지만, 이런 리터럴 객체도 프로토타입의 constructor 프로퍼티를 통해 연결되어 있다.

다시 말해, 프로토타입과 생성자 함수는 언제나 쌍으로 존재한다는 것을 알 수 있다.

profile
3D를 좋아하는 FE 개발자입니다.

0개의 댓글