자바스크립트 ➡️ 프로토타입 훑어보기!

진형욱·2022년 12월 27일
0

개발면접공부

목록 보기
8/8
post-thumbnail

JavaScript Prototype

🙋🏻‍♂️ 사전 내용 정리

1️⃣ 자바스크립트는 객체지향 프로그래밍 언어인가요?

자바스크립트는 객체지향 프로그래밍 뿐만 아니라 명령형, 함수형 프로그래밍을 지원하는 멀티 패러다임 프로그래밍 언어이다.

클래스 기반 객체지향 프로그래밍 언어와 달리 프로토타입 기반의 객체지향 프로그래밍이다.

2️⃣ 프로토타입이 뭔가요?

1. 프로토타입은 유전자

Javascript의 모든 객체(배열, 객체, 함수 등)는 상위 객체를 참조하며
이 상위 객체를 프로토타입이라고 말한다.

Javascript는 흔히 프로토타입 기반 언어라 불리며, 모든 객체들이 메소드와 속성을 상속 받기 위한 템플릿으로써 프로토타입 객체(prototype object)를 가진다는 의미이다.

2. 프로토타입은 붕어빵 틀이다.

프로토타입은 상속을 구현하기 위해 사용된다.
쉬운 예시로 붕어빵을 만들기 위한 붕어빵 틀이라고 생각하면 좋습니다.

기본적인 틀(프로토타입)에 우리가 원하는 앙금(인스턴스를 만들 때 생성자 함수에 들어갈 인수)을 넣어 기존에 만들어 놓은 프로퍼티에 바인딩하여 인스턴스(붕어빵)을 반환한다.

JavaScript에서 기본 데이터 타입을 제외한 모든 것은 객체이다.
객체가 만들어지기 위해서는 자신을 만드는 데 사용된 원형인 프로토타입 객체를 이용하여 객체를 만든다.

이때 만들어진 객체 안에 __proto__ 속성이 자신을 만들어낸 원형을 의미하는 프로토타입 객체를 참조하는 숨겨진 링크가 있습니다. 이 숨겨진 링크를 프로토타입이라고 합니다.

✔️ 모든 객체는 prototype을 가진다

자바스크립트에서의 함수는 객체이며, 객체는 property를 가진다.

function Person(name,first,second){
	this.name = name;
  	this.first = first;
  	this.second = second;
}

이러한 함수를 가정했을때 Person이라는 새로운 객체가 생성이된다.
(Javascript에서 함수는 객체라고 하였으므로)

Person 이라는 객체만 생성되는것이 아니라, Person의 prototype 객체도 같이 생성된다. 이 두 객체는 서로연관되어 있으며 서로가 서로를 알아야한다.

두 객체의 관계는 이렇게 된다.

Person 객체의 prototype 프로퍼티는 Person의 prototype 객체를 가리키고
Person의 prototype 객체는 constructor 라는 프로퍼티를 생성해 Person 객체를 가리킨다.

function Person(name,first,second){
	this.name = name;
  	this.first = first;
  	this.second = second;
}

Person.protytpe.sum = function(){}

let kim = new Person('kim',10,20);

만약 위 코드와 같이 선언했을땐

kim 이라는 새로운 객체를 생성하고, Person의 prototype 객체에 sum()이라는 함수를 추가해준 것이다.

그리고, 새로운 객체를 생성할때(kim) 객체의 프로퍼티와 함께 __proto__ 프로퍼티가 같이 생성된다.

__proto__ 는 kim 이라는 객체를 생성한 Person's prototype 객체를 가리킨다.

정리를 하자면

  • Person.prototype 을 통해 Person's prototype 객체에 접근할 수 있고
  • kim 객체의 __proto__ 를 통해서도 Person's prototype 객체에 접근 할 수 있다.

이 상태에서

console.log(kim.name)

kim 객체의 name을 출력하고자 한다면

name이 아주 잘 출력 될 것이다.

✔️ Summary

우리는 함수라는 객체를 생성했을 때 그 객체에는 prototype이라는 object가 자동으로 생성된다.

그 프로토타입에는 역시 constructor라는 객체가 자동으로 생성되어 서로를 참조한다.

Person.prototype.sum = function () {}

var kim = new Person('kim', 10, 20)
var lee = new Person('lee', 10, 10)

위 코드를 통해 prototype에 함수(sum)를 추가함으로써, 여러 객체를 생성했을 때 해당 함수를 사용할 수 있게 한다.

그림에서의 객체에서

kim.sum()
lee.sum()

둘 다 사용이 가능하다.

그렇다면 이렇게 두 객체가 sum 함수를 사용할 수 있는 이유는 무엇일까?

그건 바로 Person의 인스턴스를 새로 생성했을 때 해당 인스턴스의 Person의 prototype링크__proto__ object를 새로 부여받기 때문이다.

따라서 kim 객체에는 없는 sum 함수도 사용할 수 있게 된다.

Javascript가 kim.sum()을 찾아서 실행시키는 방법 순리

  1. kim 객체에 선언된 sum()함수를 찾는다. (sum 가져와!)
  2. 없다면 ➡️ __proto__ 에 sum()함수가 있는지 찾는다.
    (부모님 모시고 와서 sum 갖고와!)
  3. 만약 해당 객체의 Prototype 객체에 __proto__가 있다면
    해당 객체에 sum() 함수가 있는지 찾는다. (조부모님 모시고 와서 sum 가져와!)
  4. 더 있다면 있을 때까지 찾아서 결과를 도출한다.

이렇게 프로토타입이 __proto__ 링크로 연결되어 있는 형태를 프로토타입 체인 형태라고 한다.

예제 1

   var A = function () {
        this.x = function () {
             console.log('hello');
        };
    };

    A.prototype.x = function(){
        console.log('world');
    }

    var B = new A();
    var C = new A();
    
    B.x(); 	//hello 출력
    C.x(); 	//hello 출력

A라는 함수를 선언하여 생성자 x를 선언해주었다.
그 후 A의 프로토타입 x를 선언해 주었다.
이렇게 될 경우 hello가 출력이 되는 것을 볼 수 있다.

간단하게도 이는 객체 인스턴스를 생성할 때 생성자를 통해 B.x, C.x가 생성이 된다.
그래서 hello가 출력이 되는것을 알 수 있다. (자식이 갖고 있는걸 확인했으니 끝)

예제 2

 var A = function () {
    };

    A.prototype.x = function(){
        console.log('world');
    }

    var B = new A();
    var C = new A();
    
    B.x(); 	//world 출력
    C.x(); 	//world 출력

예제 1과 비슷하지만, 생성자를 따로 설정하지 않았다.

따라서 객체 인스턴스 생성시 x()함수가 존재하지 않아 해당 객체의 __proto__링크에 있는 A.prototype.x를 찾게 된다.

따라서 world가 출력이 되는 것을 볼 수 있다.


🗣 Prototype 특징

1️⃣ 배열과 객체의 프로퍼티

✔️ '배열'의 프로퍼티를 확인하는 예제

const array = [];

console.dir(array);

실행 결과

✔️ '객체'의 프로퍼티를 확인하는 예제

const obj = {};

console.dir(obj)

실행 결과

실행 결과에 공통적으로 존재하는 [[Prototype]] 프로퍼티가 바로 프로토타입이다.

프로토타입 체이닝에 의해 array는 ➡️ Array의 함수 및 프로퍼티
obj는 ➡️ Object의 함수 프로퍼티를 사용할 수 있다.


2️⃣ 변수 선언 ➡️ 배열 할당 ➡️ 객체 할당 시점 프로토타입

예제

let arr;  // 초기값 없음
console.dir(arr);

arr = []; // 배열 할당
console.dir(arr);

arr = {}; // 객체 할당
console.dir(arr);

결과

실행 결과에서 알 수 있듯이 초기값이 없으면 undefined, 값을 할당하면 할당된 값에 따라 프로토타입이 변경된다.

정리

  • JavaScript는 값을 할당하는 시점에 프로토타입이 정해진다.
  • 프로토타입은 상위 객체를 의미한다.

3️⃣ Prototype vs Class

Java, C++과 같은 클래스 기반 객체지향 프로그래밍 언어와 달리 Javascript는 프로토타입 기반 (객체지향 프로그래밍)언어라 불린다

클래스 기반 객체지향 언어는 객체 생성 이전에 클래스를 정의하고, 이를 통해 객체를 생성한다.
하지만 프로토타입 기반 객체지향 언어클래스 없이도 객체를 생성할 수 있다.

참고로 ECMA6 표준에서 Class 문법이 추가되었다. 하지만 문법이 추가되었다는것이지, 자바스크립트가 클래스 기반으로 바뀌었다는 것은 아니다.


4️⃣ Protoype chain

프로토타입 객체는 상위 프로토타입 객체로부터 메소드와 속성을 상속 받을 수 있고 그 상위 프로토타입 객체도 마찬가지이다.

이를 프로토타입 체인이라 부르며, 다른 객체에 정의된 메소드와 속성을 한 객체에서 사용할 수 있도록 한다

상속되는 속성과 메소드들은 각 객체가 아니라,
객체의 생성자의 prototype이라는 속성에 정의되어 있다.

JavaScript에서는 객체 인스턴스프로토타입 간에 연결이 구성
(prototype속성에서 파생된 __proto__속성으로 객체 인스턴스에 구현)되며
프로토타입 체인을 타고 올라가며 속성과 메소드를 탐색한다.


🌟 요약

예제

var student = {
  name: 'Lee',
  score: 90
};

// student에는 hasOwnProperty 메소드가 없지만 아래 구문은 동작한다.
console.log(student.hasOwnProperty('name')); // true

console.dir(student);

  • 자바스크립트의 모든 객체는 [[Prototype]]이라는 인터널 슬롯(internal slot)를 가진다.

  • [[Prototype]]의 값은 null 또는 객체이며 상속을 구현하는데 사용된다.

  • [[Prototype]] 객체의 데이터 프로퍼티는 자식 객체의 프로퍼티처럼 사용할 수 있다.

  • [[Prototype]]의 값은 Prototype 객체이며 __proto__ accessor property로 접근할 수 있다.

  • Student 객체는 __proto__ 프로퍼티로 자신의 부모 객체(프로토타입 객체)인 Object.prototype을 가리키고 있다.


참고 자료
https://poiemaweb.com/js-prototype
https://velog.io/@turtle601/Prototype%EC%9D%B4%EB%9E%80
https://hanamon.kr/javascript-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85%EA%B3%BC-%ED%94%84%EB%A1%9C%ED%86%A0%ED%83%80%EC%9E%85%EC%B2%B4%EC%9D%B8/
https://code-masterjung.tistory.com/m/137

profile
90% of my problems magically disappeared when I slept well, ate well and went on regular walks

0개의 댓글