JS Study 3주차 ( 프로토타입 1 )

jaehan·2023년 4월 30일
0

JavaScript

목록 보기
20/33
post-thumbnail
post-custom-banner

프로토타입

자바스크립트는 명령형, 함수형, 프로토타입기반, 객체지향 프로그래밍을 지향하는 멀티 패러다임 프로그래밍( 좋아보이는건 다 가져다가 만든 ) 언어이다.
자바스크립트를 이루고 있는 거의 모든것이 객체이다 (원시 타입의 값을 제외하고 나머지)

객체란?

속성을 통해 여러개의 값을 하나의 단위로 구성한 복잡한 자료구조를 객체라 한다.

객체에 대해 설명할때 마다 메이플스토리 캐릭터를 예시로 든다.

무슨말이냐면 메이플스토리 캐릭터를 처음만들면 다 모험가이다.

그럼 처음 캐릭터들은 모두 모험가라는 객체로 만들어진다고 생각하면 된다.

그 뒤에 전직 할때마다 모험가라는 객체에 계속해서 능력치와 스킬들이 추가되어 우리의 캐릭터들이 변화한다고 생각하면 이해가 쉽다.

그럼왜 모험가라는 객체를 만들어서 쓸까?
👉 만약 모험가라는 객체를 만들지 않으면 캐릭터 생성할때 마다 똑같은 코드를 계속 쳐서 생셩해야 하기 때문에 생산성이 떨어진다
❗️ 객체는 재사용성을 높여 생산성을 높이기 위해 사용한다고 생각하면 된다.

자바스크립트에서의 객체

자바스크립트에서의 객체는 재사용성 없이 바로 선언할 수도 있고 재사용 하도록 생성할 수도있다.

const person = { // 바로 정의 후 사용
  name: 'kim',
  address: 'seoul'
  getFullInfo(){
    return this.name + this.address;
  }
};

function Person(name, address){ // 재사용하기 위해 정의
  this.name = name;
  this.address = address;
  this.getFullInfo = function(){
    return this.name + this.address
  }
}

위 처럼 바로 정의후에 사용할 수 있고, 아래처럼 선언해서 재사용할 수 도 있다.

여기서 name과 같은 속성을 프로퍼티라 하고 함수를 메서드라고 한다.

const person1 = new Person('kim', 'seoul');
const person2 = new Person('lee', 'seoul');

console.log(person1.getFullInfo === person2.getFullInfo); // false

이렇게 생성자 함수로 여러개의 객체를 생성해서 사용하게 된다.

여기서 name이나 address는 객체별로 고유의 값을 가지니 싱관없지만 gerFullInfo같은 경우에는 중복되어서 메모리 낭비가 일어나게 된다.

이건 자바스크립트의 프로토타입으로 해결할 수 있는데.

Person.prototype.getFullInfo = function(){
  return return this.name + this.address;
}

이렇게 선언해주면 중복되지 않고 하나의 getFullInfo를 다같이 사용하게 된다.

그럼이제 프로토타입을 자세히 살펴보자

프로토타입이란?

프로토타입 객체 (프로토타입) 이란 객체 간 상속을 구현하기 위해 사용된다.

모든 객체는 [[Prototype]]이라는 내부 슬롯을 가진다.
이 내부슬롯의 값은 프로토타입의 참조이다.
이 값은 객체 생성방식에 의해 결정된다.

객체와 프로토타입과 생성자 함수는 서로 연결되어 있다.

  • 객체 -> 프로토타입은 객체.__proto__
  • 생성자 함수 -> 프토로타입은 생성자 함수.prototype
  • 프로토타입 -> 생성자 함수은 프로토타입.constructor
    을 이용해서 접근할 수 있다.


위에서 말한것 처럼 person 객체의 프로토타입을 person__proto__를 사용해서 접근할 수 있다.

__proto__

__proto__는 접근자 프로퍼티다

__proto__는 앞에서 배운것 처럼 접근자 프로퍼티기 때문에 getter/setter로 이루어져 있다.

그래서 __proto__로 호출하면 getter, __proto__로 새로운 프로토타입을 할당하면 setter가 사용된다.

__proto__ 접근자 프로퍼티는 상속되는 것이다.

모든 객체의 최상위 객체는 Object이고 객체에서 __proto__를 호출하면 프로토타입 체인을 타고 올라가 최상위 객체인 Object.__proto__을 사용하는 것이다.

__proto__를 사용하는 이유는 프로토타입 체인때문이다.

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

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

이렇게 되면 프로토타입체인에 사이클이 생기기 때문에 무한루프에 빠질 수 있다.

__proto__말고 다른 함수 쓰자

__proto__를 사용할 수 없는 객체도 있으니
Object.getPrototypeOf(), Object.setPrototypeOf() 사용하자.

prototype 프로퍼티

함수 객체만이 소유하는 prototype 프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토타입을 가리킨다.

non-constructor인 화살표 함수, 축약표현으로 정의한 메서드는 prototype 프로퍼티를 소유하지 않으며 프로토타입도 생성하지 않는다.

__proto__, prototype 프로퍼티 차이

__proto__, prototype이란 말이 자꾸나와서 헷갈리는데 정리해보면

  • __proto__는 객체가 프로토타입에 접근할 때 사용하는 프로퍼티이다.
  • 모든 객체는 __proto__를 가진다.
  • prototype은 생성자 함수가 프로토타입에 접근할 때 사용하는 프로퍼티 이다.
  • constructor만 가진다.

📌 결국 객체가 가지는 프로토타입에 접근하기 위해 사용하는 프로퍼티 인것이다.

프로토타입

그래서 이렇게 접근하고 싶은 프로토타입은 뭐냐면 그냥 객체의 유전자라고 생각하면 된다.
이 설명은 코딩애플 유튜브로 배웠다

무슨말이냐면 동일한 생성자 함수로 만들어진 객체들은 각각의 고유 속성을 가지지만, 중복되지 않게 공통속성도 가져야 한다.
이는 부모님이 자식에게 고유의 속성을 물려주지만 공통적인 유전자를 물려주는 것과 같다고 생각해 볼 수 있다.

❗️ 따라서 같은 생성자 함수로 만들어진 객체는 공통적인 유전자 즉 프로토타입을 가지고 이 프로토타입은 객체와 프로토타입 체인으로 연결되어 있는 것이다.

앞에서 생성자 함수와 객체에서 프로토타입에 접근하기 위해서는 __proto__prototype을 사용한다 했는데 프로토타입에서는 constructor를 이용해서 생성자 함수에 접근할 수 있다.

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

const me = new Person('kim');

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

me객체와 프로토타입이 연결되어있기 때문에 me.constructor하면 프로토타입.constructor가 호출되는것이다.


그래서 같은 생성자 함수로 만든 객체 me 와 you의 프로토 타입은 같기 때문에 위와 같은 결과가 실제로 나온다.

참고 :
https://www.inflearn.com/course/%EB%AA%A8%EB%8D%98-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%94%A5%EB%8B%A4%EC%9D%B4%EB%B8%8C
https://www.youtube.com/watch?v=wUgmzvExL_E

post-custom-banner

0개의 댓글