JS - 프로토타입

정윤호·2024년 6월 7일
0

JS-Deep-Dive

목록 보기
5/7

일급객체

JS에서 함수는 일급 객체: 객체랑 똑같은 거야 => 덕분에 함수형 프로그래밍 가능
1. 값으로 취급 가능,
2. 어디든지 리터럴로 정의 가능,
3. 함수의 매개변수로 전달 가능,
4. 함수의 반환값으로 사용 가능

함수 객체의 프로퍼티

  1. arguments: 인자를 받아 이터러블(짭 배열, 순회만 되고, 배열 메서드 ㄴㄴ)에 저장. 레스트 파라미터 나오고는, 쓸 이유 없음.
  2. caller: 비사용 권장. 자신을 호출한 고차함수가 담김.
  3. length: param의 개수.
  4. name: 함수의 이름. 익명함수는 빈 배열.
  5. __proto__: 모든 객체가 갖는 접근자 프로퍼티. [Prototype] 내부 슬롯에 접근할 때 씀. hasOwnProperty 에는 안 걸림. 상속 받은거라.
  6. prototype: 생성자 함수만 가지는 프로퍼티. 인스턴스의 프로토타입 객체를 가리킴.

프로토타입

자바스크립트는 프로토타입 기반 언어. 클래스가 있긴 한데, 그거 프로토타입임 사실.

상속

객체의 프로퍼티나 메서드를 다른 객체가 물려받아, 그대로 제것인양 사용하는 특성. -> 코드 재사용!
1. 그냥 쌩 생성자 함수로 만들면... 새로운 인스턴스마다 새로운 메서드를 메모리 공간에 할당하는 꼴...
즉, 메모리 낭비 + 퍼포먼스 저하

function Calculator(){
  this.add = (x, y) => {
    return x + y;
  }
};
const cal1 = new Calculator();
const cal2 = new Calculator();
  1. 프로토타입을 쓰면? -> 부모인 Calculator.prototype 객체에서 공통된 메서드를 공유
function Calculator(){};
Calculator.prototype.add = (x, y) => x + y;

const cal1 = new Calculator();
const cal2 = new Calculator();

프로토타입 객체

객체간 상속을 구현해주는 멋진 녀석..!
모든 객체는 만들어질때, 프로토타입이 결정 (최상위 프로토타입 Object.prototype) 되고 이는 Prototype 이라는 내부슬롯에 저장

  • 생성자 함수와 프로토타입은 바인딩 됨. 서로가 서로를 가리키고 있음.
  • 이름이 비슷한 애들이 자꾸 나오는데, 사용하는 주체가 다름. __proto__ 는 객체가, 즉 인스턴스가. prototype은 생성자 함수가.
  1. __proto__: 객체가 프로토타입에 접근. 게터와 세터 함수가 있어서, 값에 접근, 할당 가능. -> 비표준이므로, 권장 ㄴㄴ
cal1.__proto__ === Calculator.prototype; // true
cal1.__proto__ = null; // 할당
Object.getPrototypeOf(cal2) === Calculator.prototype; // true
Object.setPrototypeOf(cal2, Calculator.prototype); // 할당
  1. prototype: 함수만 가지고 있는 프로퍼티. 생성자 함수가 만드는 인스턴스의 프로토타입 가리킴.
  2. constructor: 프로토타입이 가지고 있는 프로퍼티. 나를 prototype으로 쓰는 생성자 함수를 가리킴.
const calProto = Calculator.prototype;
calProto.constructor === Calculator;
Calculator.prototype === calProto;
Object.getPrototypeOf(cal2) === calProto;

프로토타입 생성 시점

프로토타입은 생성자 함수랑 쌍으로 존재. 둘이 동시에 태어남. 런타임 전에 만들어지고, 바인딩 됨.

console.log(Calculator.prototype);
function Calculator(name){
  this.name = name;
};

빌트인 생성자 함수의 경우: 전역 객체가 만들어지는 시점에 생성. 코드가 실행하기도 전에.

리터럴이나, Object 생성자 함수나, 사용자 정의 생성자 함수나~ 사실 다 똑같아. 체인의 깊이가 다를 뿐.

프로토타입 체인

|800
1. Person 생성자 함수의 프로토는 ~ Function.prototype. Function.prototype는 객체니까, 얘의 프로토는~ Object.prototype.
2. Person 객체의 프로토는 인스턴스니까 ~ Person.prototype. Person.prototype는 객체니까, 얘의 프로토는~ Object.prototype.
결국 체인의 꼭대기는 Object.prototype. 이런 부모 자식 관계 속에서 상속이 일어남.
왕엄마의 메서드 빌려. 그걸 또 딸이 빌려.
왕엄마는 빌릴데가 없지? 그래서 Object.prototype 의 프로토타입은 null

프로토타입 섀도잉 / 프로토타입 교체

  1. 오버라이딩: 동명의 메서드가 있을 때, (프로토타입 메서드 vs 인스턴스 메서드) 인스턴스 메서드 승! 프로토타입 메서드가 사라진건 아님.
Calculator.prototype.add = (x, y) => x + y;
cal1.add = (x, y) => x + 2 * y;
cal1.add(1, 1); // 3

// 삭제하면 정상적으로 프로토타입 메서드 호출 (인스턴스 레벨에서 프로토타입 메서드를 변경, 삭제할 수는 없음, 하위레벨에서 프로토타입은 리드 온리)
delete cal1.add;
cal1.add(1, 1); // 2

그저 체이닝 상, 인스턴스 메서드가 프로토타입 메서드보다 우선순위가 높아.

  1. 상속관계를 동적으로 변경 가능...! 근데 이렇게 프로토타입을 직접 변경하는거, 하지마...
  2. 프로토타입 객체에 직접 접근
Calculator.prototype = {
  add(...){...},
  constructor: Calculator, // 프로토타입 교체시 constructor 프로퍼티를 지정해줘야 바인딩이 유지
  };
  1. 인스턴스 레벨에서
Object.setPrototypeOf(cal1, {...}); 

인스턴스 레벨의 경우 Calculator 생성자 함수의 prototype property가 변경된 프로토타입을 가리키지 않는다.

instanceof

cal1 instanceof Object; // true
cal1 instanceof Calculator; // true

생성자함수랑 인스턴스가 프로토타입 체인 상에 존재해야.

getPrototypeOf(cal1) === Calculator.prototype; //

Object.create() 직접상속

const obj = Object.create(null); // obj 는 프로토타입 없어, Object.prototype 의 메서드나 프로퍼티 사용 불가

프로토타입을 지정하면서 객체 생성 가능, 리터럴로 만든 객체도 체이닝에 포함 가능, new 연산자 필요 x

function 도 객체라, 프로퍼티나 메서드 가질 수 있어 -> 정적 메서드, 정적 프로퍼티

이런 애들은 인스턴스가 참조 불가, 왜냐? 프로토타입 체인 상에 있는게 아니니까
Math.random() / Object.getPrototypeOf()

프로퍼티 존재 확인

  1. in: 프로토타입 포함 모든 프로퍼티
  2. Object.prototype.hasOwnProperty: 상속 받은 애들 제외, 찐퉁 자신의 것에 한해서 true 반환

프로퍼티 열거

  1. for in: Enumerable 이 true인, 열거가능한 프로퍼티를 순회하며 열거. 상속받은 프로퍼티 포함, 심벌은 열거 X
  2. Object.keys / values / entries: 열거가능한 애들 순회. 상속 ㄴ 자신의 프로퍼티만 순회. 키는 키만 순회 / 밸류는 키의 값 순회 / 엔트리는 쌍배열로

strict mode

암묵적 전역

전역객체에 있는 변수, 함수 -> 사실 전역객체가 진짜 객체 맞음... 프로퍼티 메서드 느낌이라

function(){
  x = 10; // 선언하지도 않은 x에 재할당
}
obj = {};

use strict

profile
우리 인생 화이팅~

0개의 댓글