딥다이브 스터디 19(프로토타입)

김영현·2023년 10월 9일

서론

대망의 프로토타입. 사실 이전에 OOJS를 다루며 설명해놓은 글이 있긴하다.
더 간략히 요약해보는 시간을 가져보자.


JS는 사실 객체지향

클래스 기반 객체지향이 아닌 프로토타입 기반 객체지향
=> 원시타입을 제외한 모든 것이 객체.

객체지향 프로그래밍(OOP)

명령,함수 목록으로 보는 절자치향에서 벗어나 여러개의 독립적 단위(객체)의 집합으로...
=> 쉽게 말해 클래스에서 기능을 다 묶고 객체를 생성(인스턴스화) 하면, 사용할땐 현실처럼 내부 동작을 몰라도 사용할 수 있다.

내부 데이터(상태)는 프로퍼티, 객체의 내부 데이터를 조작하는 함수(동작)을 메소드라고 함.

객체는 독립적일 수도있고, 다른 객체와 관계를 맺을수도, 다른 객체의 상태나 동작을 상속받아 사용할수도 있다.
=> 재사용성이 용이하고, 의존성 주입이 쉽다.

오버라이딩, 섀도잉

객체지향에서 자주쓰는 말이다. 살짝 헷갈린다.

  • 오버라이딩 : 상속받아온 프로퍼티를 재정의해서 사용함.
  • 섀도잉 : 오버라이딩해서 상위 프로퍼티가 숨겨짐.

그렇다.


상속, 프로토타입

클래스 기반 객체지향에선 상속을 통해 부모 클래스의 프로퍼티와 메소드를 받아옴.
이를 JS에선 프로토타입으로 구현함.
둘 다 불필요한 중복을 제거.
But, 프로토타입은 자식클래스가 직접 상속받는 것이 아님. 프로토타입이 갖고있는걸 나눠쓴다.
따라서 클래스 기반 객체지향보다 메모리 낭비를 덜함.

프로토타입 객체

프로토타입 객체지향이라는 뜻은, 우리가 사용하는 객체타입도 결국프로토타입이 존재함을 뜻함.
=> [[Prototype]] 내부 슬롯.


__proto__접근자로 접근 가능.
ES6이후에는 get, setPrototypeOf()를 사용
참고로 이렇게 프로토타입을 수정하는건 권장되지 않음.
Object.create()로 새로운 참조를 생성해야한다.
=> 프로토타입체이닝을 모두 바꿔야하기때문

접근자는 곧 get,set을 사용한다는 뜻.
read-write가 가능하게 만든 이유는 내부적으로 상호참조를 방지하기 위해서.
a,b가 서로를 프로토타입으로 참조하면 순환참조 에러.

나머지 사항은 이렇다.

  • 생성자 함수객체의 prototype은 생성될 인스턴스의 프로토타입
  • 모든 프로토타입은 constructor프로퍼티를 가짐. 생성자함수를 가리킴.
  • 리터럴표기법으로 생성한 객체{}는 생성자함수로 생성된 건 아니지만, constructor가 제대로 들어가있다.

객체 생성방식-프로토타입 결정

  • 객체 리터럴{} : Object.prototype
  • Object 생성자 함수Object() : Object.prototype
  • 생성자함수function(){this...}: 생성자함수 prototype에 바인딩 되어있는 객체

프로토타입 체인

스코프체인처럼 프로토타입도 계속해서 프로토타입 참조를 타고(상위) 호출한 프로퍼티를검색한다.
=> 상위의 모든 프로토타입은 전부 상속받았다고 보면 된다.

최상위 프로토타입 객체는 Object.prototype이다.
따라서 모든 객체가 이를 상속받는다.
=> 그 위는 null이다

프로토타입 변경


본래는 생성자함수의 constructor인 Person이 프로토타입이어야함.
__proto__로 변경할수도있다.
둘다 권장x

instance of 연산자

객체 instanceof 생성자함수 이렇게 사용함.
=> 이 인스턴스가 생성자함수로 만든것이냐~
생성자함수의 prototype에 바인딩된 객체가 프로토타입 체인상에 존재하면 true다.

직접 상속

아까 설명했던 Object.create()은 명시적으로 프로토타입을 선언하여 새로운 객체를 생성한다.

Object.create(프로토타입);
  • new연산자가 없이도 객체생성 가능
  • 프로토타입 지정하면서 객체 생성 가능
  • 객체 리터럴에 의해 생성된 객체도 상속가능

장점이 많다.
여담으로 ESlint는 빌트인 메소드를 바로 사용하는걸 권장하지 않음
Object.create(null)로 종점 프로토타입을 가진 객체생성이 가능하기때문.
=> 이렇게 생성한 객체로 빌트인 메소드를 호출하면 에러가난다.

정적 메소드

클래스에서 static을 사용하여 선언한 정적 메소드는 사실 이렇게 구현된다.

function Person(name){
	this.name = name;
}
Person.staticMethod = function (){
	return "hi";
}
Person.staticProp = "bye";
const person = new Person("kim");
person.staticprop // ...undefined
person.staticMethod() // is not a function...

인스턴스에서는 참조 불가. 생성자함수에서 참조 가능.

프로퍼티 존재 확인

  • in연산자를 사용하여 확인한다.
    즉, for...in메소드는 객체를 순회하며 [[Enumrable]]한 프로퍼티를 열거함.(상속받은 프로퍼티도 가능).
  • Object.keys, values, entries()는 고유한 객체 프로퍼티만 열거.
  • hasOwnProperty는 상속받지 않은 고유한 객체의 프로퍼티인지 확인

참고로 모던 브라우저는 숫자인 프로퍼티 키에 대해서 정렬함!

profile
모르는 것을 모른다고 하기

0개의 댓글