프로토타입

정민교·2023년 7월 15일
0

javascript

목록 보기
6/16

📒프로토타입

자바스크립트는 함수형, 프로토타입 기반 객체지향 프로그래밍 프로그래밍 언어다.

자바스크립트에서 원시 값을 제외한 모든 것은 객체다.

✔️상속과 프로토타입

자바스크립트는 프로토타입을 기반으로 상속을 구현한다.

생성자 함수가 생성한 모든 인스턴스는 생성자 함수의 prototype 프로퍼티가 가리키는 프로토타입 객체의 프로퍼티와 메서드를 상속한다.

📌프로토타입 객체

모든 객체는 [[Prototype]] 내부 슬롯을 가진다.

이 내부 슬롯은 프로토타입 참조 값을 갖는다. 자신의 상위 객체인 프로토타입 객체를 말하는 것이다.

[[Prototype]]에 저장되는 프로토타입은 객체가 생성될 때 객체 생성 방식에 따라 결정된다.

[[Prototype]]에 저장되는 값은 오직 null 혹은 자신의 프로토타입 참조 값이다.

👉proto 접근자 프로퍼티

모든 객체는 __proto__ 접근자 프로퍼티를 가지며 [[Prototype]] 내부 슬롯에 간접 접근하여 자신의 프로토타입에 접근할 수 있다.

__proto__ 접근자 프로퍼티는 객체가 직접 소유하는 프로퍼티가 아니다. Object.prototype의 프로퍼티이다.

모든 객체들은 이를 상속하여 __proto__ 접근자 프로퍼티를 사용할 수 있다.

프로토타입 체인은 순환 참조를 허용하지 않는다. 순환 참조 되는 프로토타입 체인을 구성하려고 하면 에러(TypeError: Cyclic __proto__ value)를 발생시킨다.

__proto__를 직접 사용하는 것은 권장하지 않는다. 프로토타입 참조 혹은 교체하고 싶은 경우Object.getPrototypeOfObject.setPrototypeOf 메서드를 사용하는 것이 좋다.

👉함수 객체의 prototype 프로퍼티

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

생성자 함수로 호출할 수 없는 non-constructor인 화살표 함수와 ES6 메서드는 prototype 프로퍼티를 소유하지 않으며 프로토타입도 생성하지 않는다.

👉정리

__proto__접근자 프로퍼티는 모든 객체가 소유한다.

prototype프로퍼티는 constructor인 함수 객체만 소유한다.

둘 다 프토토타입의 참조 값을 갖는다.

__proto__ 접근자 프로퍼티는 자신의 프로토타입에 접근하거나 교체하기 위해 사용한다.

prototype 프로퍼티는 생성자 함수가 생성할 인스턴스의 프로토타입을 할당하기 위해 사용한다.

📌프로토타입의 constructor 프로퍼티와 생성자 함수

모든 프로토타입은 constructor 프로퍼티를 갖는다. 이는 prototype 프로퍼티로 자신을 가리키고 있는 생성자 함수 객체를 가리킨다.

📌리터럴 표기법으로 생성한 객체의 생성자 함수와 프로토타입

리터럴 표기법생성자 함수프로토타입
객체 리터럴ObjectObject.prototype
함수 리터럴FunctionFunction.prototype
배열 리터럴ArrayArray.prototype
정규 표현식 리터럴RegExpRexExp.prototype

📌프로토타입 생성 시점

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

프로토타입은 생성자 함수가 생성되는 시점에 더불어 생성된다.

즉, constructor 함수([[Constructor]] 내부 메서드를 갖는 함수 객체) 정의가 평가되어 함수 객체를 생성하는 시점에 프로토타입도 더불어 생성된다.

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

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

모든 빌트인 생성자 함수는 전역 객체가 생성되는 시점에 생성된다.

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

👉객체 리터럴, Object 생성자 함수로 생성한 객체와 프로토타입

객체 리터럴, Object 생성자 함수로 생성한 객체의 프로토타입은 Object.prototype이다.

👉생성자 함수로 생성한 객체와 프로토타입

생성자 함수로 생성한 인스턴스의 프로토타입은 생성자 함수 객체가 생성될 때 더불어 생성된 프로토타입이다.

📌프로토타입 체인

객체의 프로퍼티(메서드 포함)에 접근할 때 해당 객체에 그 프로퍼티가 존재하지 않으면, 자신의 프로토타입에서 검색하고, 이래도 없으면 프로토타입의 프로토타입을 검색한다.

이를 프로토타입 체인이라고 하며, 자바스크립트가 객체지향 프로그래밍의 상속을 구현하는 메커니즘이다.

프로토타입 체인의 종점은 언제나 Object.prototype이다. Object.prototype의 프로토타입은 null이다.

📌오버라이딩과 프로퍼티 쉐도잉

프로토타입 프로퍼티와 인스턴스 프로퍼티가 있다.

프로토타입 프로퍼티와 동일한 이름의 인스턴스 프로퍼티를 정의하는 것을 오버라이딩이라고 하고, 이로 인해 프로토타입 프로퍼티가 상속관계에 의해 가려지는 것을 프로퍼티 쉐도잉이라고 한다.

🚨자바스크립트는 오버로딩을 지원하지 않지만 arguments 객체를 사용하여 구현할 수는 있다.

📌instanceof 연산자

객체 instanceof 생성자 함수

생성자 함수의 prototype 프로퍼티 값이 좌변 객체의 프로토타입 체인 상에 존재하면 true로 평가된다.

우변의 피연산자가 함수가 아닌 경우 TypeError가 발생한다.

📌직접 상속

👉Object.create에 의한 직접 상속

Object.create메서드는 명시적으로 프로토타입을 지정하여 새로운 객체를 생성한다.

메서드의 첫 번째 인수로 생성할 객체의 프로토타입으로 지정할 객체를 전달한다.

두 번째 인수로 생성할 객체의 프로퍼티 키와 프로퍼티 디스크립터 객체로 이루어진 객체를 전달한다.

ESLint에서는 Object.prototype의 빌트인 메서드를 객체가 직접 호출하는 것을 권장하지 않는다.

Object.prototype의 빌트인 메서드를 간접 호출하는 것을 권장한다.(Object.prototype.hasOwnProperty.call(obj, 'a')))

👉객체 리터럴 내부에서 proto에 의한 직접 상속

ES6부터 객체 리터럴 내부에서 __proto__로 직접 상속을 구현할 수 있다.

📌정적 프로퍼티/메서드

생성자 함수 객체로 참조/호출할 수 있는 프로퍼티/메서드를 말한다.

📌프로퍼티 존재 확인

👉in 연산자

in 연산자로 객채 내에 특정 프로퍼티가 존재하는지 확인할 수 있다.

객체가 상속한 모든 프로터타입의 프로퍼티를 확인하기 때문에 이에 유의해야 한다.

👉Reflect.has

in 연산자를 대신에 ES6에 도입된 Reflect.has 메서드를 사용할 수도 있다. in연산자와 동일하게 동작한다.

👉Object.prototype.hasOwnProperty

이 메서드를 사용해서 객체에 특정 프로퍼티가 존재하는지 확인 가능하다.

이 메서드는 객체가 가진 고유의 프로퍼티인 경우만 true를 반환한다.

📌프로퍼티 열거

👉for...in 문

for...in문은 객체의 프로토타입 체인 상에 존재하는 모든 프로퍼티를 열거한다.

하지만 프로퍼티 어트리뷰트 [[Enumerable]] 값이 true인 경우만 열거한다. 또한 심볼이 키인 프로퍼티는 열거 대상에서 제외된다.

for...in문은 프로퍼티 열거할 때 순서를 보장하지 않는다(하지만 대부분의 모던 브라우저에서 숫자 문자열이 키인 경우에 대해서는 정렬을 해서 열거해주기는 한다).

🚨따라서 for...in문 대신 for문이나 for...of문 또는 Array.prototype.forEach메서드를 사용하자.

👉Object.keys/values/entries

이 메서드는 객체 자신의 고유 프로퍼티만 열거한다.

Object.keys()는 객체 자신의 열거 가능한 프로퍼티의 키를 배열로 반환한다.

Object.values()는 객체 자신의 열거 가능한 프로퍼티의 값을 배열로 반환한다.

Object.entries()는 객체 자신의 열거 가능한 프로퍼티의 키:값 쌍의 배열을 배열에 담아 반환한다.

profile
백엔드 개발자

0개의 댓글