[자바스크립트] 프로토타입

zzzzzang_gu·2023년 3월 17일
0

자바스크립트

목록 보기
19/23

자바스크립트는 명령형, 함수형, 프로토타입 기반 객체 지향 프로그래밍을 지원하는 멀티 패러다임 프로그래밍 언어이다.

객체 지향 프로그래밍이란 여러개의 독립적 단위, 즉 객체의 집합으로 프로그램을 표현 하려는 프로그래밍 패러다임이다. 여기서 객체는 속성을 통해 여러개의 값을 하나의 단위로 구성한 복합적인 자료구조를 말한다. 객체는 상태 데이터 (프로퍼티)와 상태 데이터를 조작할 수 있는 동작(메서드)로 묶여있다.


상속과 프로토타입


function Person(name){
	this.name = name;
  	this.sayHello = function(){
    	return `Hello, ${this.name}!`
    }
}

const me = new Person("jin");
me.sayHello() // 'Hello, jin!'

위 생성자 함수로 인스턴스를 생성할 때마다 메서드를 중복 생성하고 모든 인스턴스가 메서드를 중복 소유 하며 메모리를 낭비하게 된다. 자바스크립트는 프로토타입 기반으로 상속을 구현하여 불필요한 중복을 제거한다.

function Person(name){
	this.name = name;
}
Person.prototype.sayHello = function(){
	return `Hello, ${this.name}!`
}

const me = new Person("jin");
const me2 = new Person("wan");

me.sayHello()  // 'Hello, jin!'
me2.sayHello()	// 'Hello, wan!'

프로토타입으로 상속을 구현하면, 생성된 모든 인스턴스는 자신의 프로토타입, 즉 상위(부모)객체 역할을 하는 Person.prototype의 모든 프로퍼티와 메서드를 상속 받는다.


프로토타입 객체

프로토타입 객체란?

객체지향 프로그래밍의 근간을 이루는 객체간 상속을 구현하기 위해 사용된다. 모든 객체는 [[prototype]] 내부 슬롯이 있고, 내부 슬롯의 값은 프로토타입 참조다. [[prototype]]에 저장되는 프로토타입은 객체 생성 방식에 의해 결정된다.

  1. 객체 리터럴에 의해 생성된 객체의 프로토타입은 Object.prototype이다.
  2. 생성자 함수에 의해 생성된 객체의 프로토타입은 생성자 함수의 prototype 프로퍼티에 바인딩되어 있는 객체다.

__proto__ 접근자 프로퍼티

모든 객체는 __proto__ 접근자 프로퍼티를 통해 자신의 프로토타입, 즉 [[Prototype]] 내부 슬롯에 간접적으로 접근할 수 있다.

const person = {name:"jin"};
person.__proto__ //아래 이미지 참고

이처럼 모든 객체는 __proto__ 접근자 프로퍼티를 통해 프로토타입을 가르키는 [[Prototype]] 내부 슬롯에 접근할 수 있다.

__proto__ 접근자 프로퍼티는 상속을 통해 사용된다. 즉, 객체가 직접 소유하는 것이 아니라 Object.prototype의 프로퍼티이다. 접근자 프로퍼티를 사용하는 이유는 상호 참조에 의해 프로토타입 체인이 생성되는 것을 방지하기 위해서다. 2개의 객체가 서로를 프로토타입으로 서로 참조한다면 비정상적인 프로토타입 체인이 만들어지기 때문에 __proto__ 접근자 프로퍼티는 에러를 발생시킨다.

__proto__ 는 Object.prototype에 의해 상속받는 프로퍼티이기 때문에 Object.prototype을 상속받지 않는 객체는 사용할 수 없는 경우가 있다. 따라서 아래 메서드를 사용 권장한다.

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

Object.getPrototypeOf(obj); // obj.__proto__
Object.setPrototypeOf(obj,parent); // obj.__proto__ = parent

함수 객체의 prototype 프로퍼티

함수 객체만이 소유하는 prototype 프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토타입을 가리킨다. 즉, non-constructor 인 화살표 함수와 ES6 축약 메서드는 prototype 프로퍼티를 소유하지 않으며 프로토타입도 생성하지 않는다.

모든 객체가 상속받거나 가지고 있는 __proto__접근자 프로퍼티와 함수 객체만이 가지고 있는 prototype 프로퍼티는 결국 동일한 프로토타입을 가르킨다.

하지만 함수 객체만이 가지고 있는 prototype 프로퍼티는 생성자 함수가 자신이 생성할 인스턴스의 프로토타입을 할당하기 위해 사용된다.


리터럴 생성 객체의 생성자 함수와 프로토타입

생성자 함수에 의해 생성된 인스턴스는 프로토타입의 constructor 프로퍼티에 의해 생성자 함수와 연결된다.
하지만 리터럴 표기법에 의해 생성된 객체의 경우 프로토타입의 constructor 프로퍼티가 가르키는 생성자 함수가 반드시 객체를 생성한 생정자 함수라고 단정할 수 없다.

Object 생성자 함수에 인수를 전당하지 않거나 null/undefined를 인수로 전달하여 호출하거나, 객체 리터럴의 평가는 내부적으로 추상연산을 호출하여 Object.prototype을 프로토타입으로 갖는 빈 객체를 생성한다.

리터럴 표기법에 의해 생성된 객체도 상속을 위해 프로토타입이 필요해 가상적인 생성자 함수를 갖는다. 프로토타입은 생성자 함수와 더불어 생성되며 prototype,constructor 프로퍼티에 의해 연결되어 있다. 즉 , 프로토타입과 생성자 함수는 단독으로 존재할 수 없고 언제나 쌍으로 존재한다.


프로토타입의 생성 시점

객체는 리터럴 표기법 또는 생성자 함수에 의해 생성되므로 결국 모든 객체는 생성자 함수와 연결되어있다. 프로토타입은 생성자 함수가 생성되는 시점에 더불어 생성된다.

생성자 함수는 사용자가 직접 정의한 사용자 정의 생성자 함수와 자바스크립트가 기본 제공하는 빌트인 생성자 함수로 구분할 수 있다.

사용자 정의 생성자 함수와 프로토타입 생성 시점

생성자 함수로서 호출할 수 있는 함수, 즉 constructor는 함수 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 더불어 생성된다.

함수 선언문은 런타임 이전 자바스크립트 엔진에 의해 먼저 실행된다. 따라서 함수 선언문으로 정의된 생성자 함수는 먼저 평가되어 함수 객체가 되고, 이때 프로토타입도 더불어 생성된다. 생성된 프로토타입은 생성자 함수의 prototype 프로퍼티에 바인딩된다.

생성된 프로토타입의 포로토타입은 언제나 Object.prototype이다.

빌트인 생성자 함수와 프로토타입 생성 시점

Object, String, Number, Function, Array, RegExp, Date, Promise 등과 같은 빌트인 생성자 함수도 일반 함수와 마찬가지로 빌트인 생성자 함수가 생성되는 시점에 프로토타입이 생성된다.

모든 빌트인 생성자 함수는 전역 객체가 생성되는 시점에 생성되고 생성된 프로토타입은 빌트인 생성자 함수의 prototype 프로퍼티에 바인딩된다.


프로토타입 체인

자바스크립트는 객체의 프로퍼티에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티가 없다면 [[Prototype]] 내부 슬롯의 참조를 따라 자신의 부모 역할을 하는 프로토타입의 프로퍼티를 순차적으로 검색한다. 이를 프로토타입 체인히라 한다. 프로토타입은 상속과 프로퍼티 검색을 위한 메커니즘이다.

스코프 체인은 자바스크립트 엔진에 함수 중첩 관계로 이루어진 스코프의 계층적 구조에서 식별자를 검색을 위한 메커니즘이다.

	me.hasOwnProperty('name');

위 코드이 경우 스코프 체인에서 먼저 me 식별자를 검색하고 me객체의 프로토타입 체인에서 hasOwnProperty 메서드를 검색한다.
스코프 체인과 프로토타입 체인은 서로 연관없이 별도로 동작하는 것이 아니라 서로 협력하여 식별자와 프로퍼티를 검색하는데 사용된다.

profile
프론트엔드 개발자가 되겠습니다🔥

0개의 댓글