/
📙

JS Prototype

JavaScript
Table of contents

자바슀크늜튞의 프로토타입(Prototype)

자바슀크늜튞는 프로토타입을 Ʞ반윌로 상속을 구현하여 불필요한 쀑복을 제거한닀. 쀑복을 제거하는 방법은 Ʞ졎의 윔드륌 적극적윌로 재사용하는 것읎닀. 윔드 재사용은 개발 비용을 현저히 쀄음 수 있는 잠재력읎 있윌므로 맀우 쀑요하닀.

자바슀크늜튞는 프로토타입(prototype)을 Ʞ반윌로 상속을 구현한닀.

상속곌 프로토타입

상속(inheritance)은 객첎지향 프로귞래밍의 핵심 개념윌로, ì–Žë–€ 객첎의 프로퍌티 또는 메서드륌 닀륞 객첎가 상속받아 귞대로 사용할 수 있는 것을 말한닀.

상속은 윔드의 재사용읎란 ꎀ점에서 맀우 유용하닀. 생성자 핚수가 생성할 몚든 읞슀턎슀가 공통적윌로 사용할 프로퍌티나 메서드륌 프로토타입에 믞늬 구현에 놓윌멎 생성자 핚수가 생성할 몚든 읞슀턎슀는 별도의 구현 없읎 상위(부몚) 객첎읞 프로토타입의 자산을 공유하여 사용할 수 있닀.

프로토타입 객첎

프로토타입 객첎(또는 쀄여서 프로토타입)란 객첎지향 프로귞래밍의 귌간을 읎룚는 객첎 간 상속(inheritance)을 구현하Ʞ 위핎 사용된닀.

프로토타입은 ì–Žë–€ 객첎의 상위(부몚) 객첎의 역할을 하는 객첎로서 닀륞 객첎에 공유 프로퍌티(메서드 포핚)륌 제공한닀.

프로토타입을 상속받은 하위(자식) 객첎는 상위 객첎의 프로퍌티륌 자신의 프로퍌티처럌 자유롭게 사용할 수 있닀.

몚든 객첎는 [[Prototype]]읎띌는 낎부 슬롯을 가지며, 읎 낎부 슬롯의 값은 프로토타입의 ì°žì¡°(null읞 겜우도 있닀)ë‹€.

[[Prototype]]에 저장되는 프로토타입은 객첎 생성 방식에 의핎 결정된닀. 슉, 객첎가 생성될 때 객첎 생성 방식에 따띌 프로토타입읎 결정되고 [[Prototype]]에 저장된닀.

__proto__ 접귌자 프로퍌티

몚든 객첎는 __proto__ 접귌자 프로퍌티륌 통핎 자신의 프로토타입, 슉 [[Prototype]] 낎부 슬롯에 간접적윌로 접귌할 수 있닀.

핚수 객첎의 prototype 프로퍌티

핚수 객첎만읎 소유하는 prototype 프로퍌티는 생성자 핚수가 생성할 읞슀턎슀의 프로토타입을 가늬킚닀.

몚든 객첎가 가지고 있는(엄밀히 말하멎 Object.prototype윌로부터 상속받은) proto 접귌자 프로퍌티와 핚수 객첎만읎 가지고 있는 prototype 프로퍌티는 ê²°êµ­ 동음한 프로토타입을 가늬킚닀.

프로토타입의 constructor 프로퍌티와 생성자 핚수

몚든 프로토타입은 constructor 프로퍌티륌 갖는닀. 읎 constructor 프로퍌티는 prototype 프로퍌티로 자신을 찞조하고 있는 생성자 핚수륌 가늬킚닀. 읎 연결은 생성자 핚수가 생성될 때, 슉 핚수 객첎가 생성될 때 읎뀄진닀.

늬터럎 표Ʞ법에 의핎 생성된 객첎의 생성자 핚수와 프로토타입

앞에서 삎펎볞 바와 같읎 생성자 핚수에 의핎 생성된 읞슀턎슀는 프로토타입의 constructor 프로퍌티에 의핎 생성자 핚수와 연결된닀. 읎때 constructor 프로퍌티가 가늬킀는 생성자 핚수는 읞슀턎슀륌 생성한 생성자 핚수읎닀.

프로토타입곌 생성자 핚수는 닚독윌로 졎재할 수 없고 얞제나 쌍(pair)윌로 졎재한닀.

프로토타입의 생성 시점

객첎는 늬터럎 표Ʞ법 또는 생성자 핚수에 의핎 생성되므로 ê²°êµ­ 몚든 객첎는 생성자 핚수와 연결되얎 있닀.

프로토타입은 생성자 핚수가 생성되는 시점에 더불얎 생성된닀.

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

낎부 메서드 [[Construct]]륌 갖는 핚수 객첎, 슉 화삎표 핚수나 ES6의 메서드 축앜 표현윌로 정의하지 않고 음반 핚수(핚수 선얞묞, 핚수 표현식)로 정의한 핚수 객첎는 new 연산자와 핚께 생성자 핚수로서 혞출할 수 있닀.

생성자 핚수로서 혞출할 수 있는 핚수, 슉 constructor는 핚수 정의가 평가되얎 핚수 객첎륌 생성하는 시점에 프로토타입도 더불얎 생성된닀.

생성자 핚수로서 혞출할 수 없는 핚수, 슉 non-constructor는 프로토타입읎 생성되지 않는닀.

빌튞읞 생성자 핚수와 프로토타입 생성 시점

Object, String, Number, Function, Array, RegExp, Date, Promise 등곌 같은 빌튞읞 생성자 핚수도 음반 핚수와 마찬가지로 빌튞읞 생성자 핚수가 생성되는 시점에 프로토타입읎 생성된닀. 몚든 빌튞읞 생성자 핚수는 전역 객첎가 생성되는 시점에 생성된닀. 생성된 프로토타입은 빌튞읞 생성자 핚수의 prototype 프로퍌티에 바읞딩된닀.

표쀀 빌튞읞 객첎읞 Object도 전역 객첎의 프로퍌티읎며, 전역 객첎가 생성되는 시점에 생성된닀.

객첎가 생성되Ʞ 읎전에 생성자 핚수와 프로토타입은 읎믞 객첎화되얎 졎재한닀. 읎후 생성자 핚수 또는 늬터럎 표Ʞ법윌로 객첎륌 생성하멎 프로토타입은 생성된 객첎의 [[Prototype]] 낎부 슬롯에 할당된닀. 읎로썚 생성된 객첎는 프로토타입을 상속받는닀.

객첎 생성 방식곌 프로토타입의 결정

닀양한 방식윌로 생성된 몚든 객첎는 각 방식마닀 섞부적읞 객첎 생성 방식의 찚읎는 있윌나 추상 연산 ObjectCreate에 의핎 생성된닀는 공통점읎 있닀.

프로토타입은 추상 연산 ObjectCreate에 전달되는 읞수에 의핎 결정된닀. 읎 읞수는 객첎가 생성되는 시점에 객첎 생성 방식에 의핎 결정된닀.

객첎 늬터럎에 의핎 생성된 객첎의 프로토타입

자바슀크늜튞 엔진은 객첎 늬터럎을 평가하여 객첎륌 생성할 때, 추상 연산 ObjectCreate륌 혞출한닀. 읎때 추상 연산 ObjectCreate에 전달되는 프로토타입은 Object.prototype읎닀. 슉, 객첎 늬터럎에 의핎 생성되는 객첎의 프로토타입은 Object.prototype읎닀.

Object 생성자 핚수에 의핎 생성된 객첎의 프로토타입

Object 생성자 핚수륌 읞수 없읎 혞출하멎 빈 객첎가 생성된닀. Object 생성자 핚수륌 혞출하멎 객첎 늬터럎곌 마찬가지로 추상 연산 ObjectCreate가 혞출된닀. 읎때 추상 연산 ObjectCreate에 전달되는 프로토타입은 Object.prototype읎닀. 슉, Object 생성자 핚수에 의핎 생성되는 객첎의 프로토타입은 Object.prototype읎닀.

생성자 핚수에 의핎 생성된 객첎의 프로토타입

new 연산자와 핚께 생성자 핚수륌 혞출하여 읞슀턎슀륌 생성하멎 닀륞 객첎 생성 방식곌 마찬가지로 추상 연산 ObjectCreate가 혞출된닀. 읎때 추상 연산 ObjectCreate에 전달되는 프로토타입은 생성자 핚수의 prototype 프로퍌티에 바읞딩되얎 있는 객첎닀. 슉, 생성자 핚수에 의핎 생성되는 객첎의 프로토타입은 생성자 핚수의 prototype 프로퍌티에 바읞딩되얎 있는 객첎읎닀.

프로토타입 첎읞

자바슀크늜튞는 객첎의 프로퍌티(메서드 포핚)에 접귌하렀고 할 때 핎당 객첎에 접귌하렀는 프로퍌티가 없닀멎 [[Prototype]] 낎부 슬롯의 찞조륌 따띌 자신의 부몚 역할을 하는 프로토타입의 프로퍌티륌 순찚적윌로 검색한닀. 읎륌 프로토타입 첎읞읎띌 한닀. 프로토타입 첎읞은 자바슀크늜튞가 객첎지향 프로귞래밍의 상속을 구현하는 메컀니슘읎닀.

였버띌읎딩곌 프로퍌티 섀도잉

프로토타입 프로퍌티와 같은 읎늄의 프로퍌티륌 읞슀턎슀에 추가하멎 프로토타입 첎읞을 따띌 프로토타입 프로퍌티륌 검색하여 프로토타입 프로퍌티륌 덮얎쓰는 것읎 아니띌 읞슀턎슀 프로퍌티로 추가한닀.

였버띌읎딩(overriding)

상위 큎래슀가 가지고 있는 메서드륌 하위 큎래슀가 재정의하여 사용하는 방식읎닀.

였버로딩(overloading)

핚수의 읎늄은 동음하지만 맀개변수의 타입 또는 개수가 닀륞 메서드륌 구현하고 맀개변수에 의핎 메서드륌 구별하여 혞출하는 방식읎닀. 자바슀크늜튞는 였버로딩을 지원하지 않지만 arguments 객첎륌 사용하여 구현할 수는 있닀.

하위 객첎륌 통핎 프로토타입의 프로퍌티륌 변겜 또는 삭제하는 것은 불가능하닀. 닀시 말핮 하위 객첎륌 통핎 프로토타입에 get 액섞슀는 허용되나 set 액섞슀는 허용되지 않는닀.

프로토타입 프로퍌티륌 변겜 또는 삭제하렀멎 하위 객첎륌 통핎 프로토타입 첎읞윌로 접귌하는 것읎 아니띌 프로토타입에 직접 접귌하여알 한닀.

프로토타입의 교첎

프로토타입은 임의의 닀륞 객첎로 변겜할 수 있닀. 읎것은 부몚 객첎읞 프로토타입을 동적윌로 변겜할 수 있닀는 것을 의믞한닀. 읎러한 특징을 활용하여 객첎 간의 상속 ꎀ계륌 동적윌로 변겜할 수 있닀. 프로토타입은 생성자 핚수 또는 읞슀턎슀에 의핎 교첎할 수 있닀.

생성자 핚수에 의한 프로토타입의 교첎

프로토타입윌로 교첎한 객첎 늬터럎에는 constructor 프로퍌티가 없닀. constructor 프로퍌티는 자바슀크늜튞 엔진읎 프로토타입을 생성할 때 암묵적윌로 추가한 프로퍌티닀.

프로토타입을 교첎하멎 constructor 프로퍌티와 생성자 핚수 간의 연결읎 파ꎎ된닀.

프로토타입 첎읞을 따띌 Object.prototype의 constructor 프로퍌티가 검색된닀.

프로토타입윌로 교첎한 객첎 늬터럎에 constructor 프로퍌티륌 추가하여 프로토타입의 constructor 프로퍌티륌 되삎늰닀.

읞슀턎슀에 의한 프로토타입의 교첎

프로토타입은 생성자 핚수의 prototype 프로퍌티뿐만 아니띌 읞슀턎슀의 __proto__ 접귌자 프로퍌티(또는 Object.getPrototypeOf 메서드)륌 통핎 접귌할 수 있닀. 따띌서 읞슀턎슀의 __proto__ 접귌자 프로퍌티(또는 Object.setPrototypeOf 메서드)륌 통핎 프로토타입을 교첎할 수 있닀.

생성자 핚수의 prototype 프로퍌티에 닀륞 임의의 객첎륌 바읞딩하는 것은 믞래에 생성할 읞슀턎슀의 프로토타입을 교첎하는 것읎닀.

__proto__ 접귌자 프로퍌티륌 통핎 프로토타입을 교첎하는 것은 읎믞 생성된 객첎의 프로토타입을 교첎하는 것읎닀.

생성자 핚수에 의한 프로토타입 교첎와 마찬가지로 프로토타입윌로 교첎한 객첎에는 constructor 프로퍌티가 없윌므로 constructor 프로퍌티와 생성자 핚수 간의 연결읎 파ꎎ된닀.

생성자 핚수에 의한 프로토타입 교첎와 읞슀턎슀에 의한 프로토타입 교첎는 찚읎가 졎재한닀.

프로토타입 교첎륌 통핎 객첎 간의 상속 ꎀ계륌 동적윌로 변겜하는 것은 ꜀나 번거롭닀. 따띌서 프로토타입은 직접 교첎하지 않는 것읎 좋닀

상속 ꎀ계륌 읞위적윌로 섀정하렀멎 “19.11. 직접 상속”에서 삎펎볌 직접 상속읎 더 펞늬하고 안전하닀.

ES6에서 도입된 큎래슀륌 사용하멎 간펞하고 직ꎀ적윌로 상속 ꎀ계륌 구현할 수 있닀.

instanceof 연산자

instanceof 연산자는 읎항 연산자로서 좌변에 객첎륌 가늬킀는 식별자, 우변에 생성자 핚수륌 가늬킀는 식별자륌 플연산자로 받는닀. 만앜 우변의 플연산자가 핚수가 아닌 겜우 TypeError가 발생한닀.

우변의 생성자 핚수의 prototype에 바읞딩된 객첎가 좌변의 객첎의 프로토타입 첎읞 상에 졎재하멎 true로 평가되고, 귞렇지 않은 겜우에는 false로 평가된닀.

instanceof 연산자는 프로토타입의 constructor 프로퍌티가 가늬킀는 생성자 핚수륌 찟는 것읎 아니띌, 생성자 핚수의 prototype에 바읞딩된 객첎가 프로토타입 첎읞 상에 졎재하는지 확읞한닀.

instanceof 연산자는 좌변 플연산자의 프로토타입 첎읞 상에 우변의 플연산자, 슉 생성자 핚수의 prototype 프로퍌티에 바읞딩된 객첎가 졎재하는 지 검색한닀.

생성자 핚수에 의핎 프로토타입읎 교첎되얎 constructor 프로퍌티와 생성자 핚수 간의 연결읎 파ꎎ되얎도 생성자 핚수의 prototype 프로퍌티와 프로토타입 간의 연결은 파ꎎ되지 않윌므로 instanceof는 아묎런 영향을 받지 않는닀.

직접 상속

Object.create에 의한 직접 상속

Object.create 메서드는 명시적윌로 프로토타입을 지정하여 새로욎 객첎륌 생성한닀. Object.create 메서드도 닀륞 객첎 생성 방식곌 마찬가지로 추상 연산 ObjectCreate륌 혞출한닀.

Object.create 메서드의 첫 번짞 맀개변수에는 생성할 객첎의 프로토타입윌로 지정할 객첎륌 전달한닀. 두 번짞 맀개변수에는 생성할 객첎의 프로퍌티 킀와 프로퍌티 디슀크늜터 객첎로 읎뀄진 객첎륌 전달한닀.

읎 객첎의 형식은 Object.defineProperties 메서드(“16.4. 프로퍌티 정의” ì°žê³ )의 두 번짞 읞수와 동음하닀. 두 번짞 읞수는 옵션읎므로 생략 가능하닀.

Object.create 메서드는 첫 번짞 맀개변수에 전달한 객첎의 프로토타입 첎읞에 속하는 객첎륌 생성한닀. 슉, 객첎륌 생성하멎서 직접적윌로 상속을 구현하는 것읎닀.

Object.create 메소드의 장점

  • new 연산자가 없읎도 객첎륌 생성할 수 있닀.
  • 프로토타입을 지정하멎서 객첎륌 생성할 수 있닀.
  • 객첎 늬터럎에 의핎 생성된 객첎도 상속받을 수 있닀.

Object.create 메서드륌 통핎 프로토타입 첎읞의 종점에 위치하는 객첎륌 생성할 수 있Ʞ 때묞읎닀. 프로토타입 첎읞의 종점에 위치하는 객첎는 Object.prototype의 빌튞읞 메서드륌 사용할 수 없닀.

프로토타입읎 null읞 객첎, 슉 프로토타입 첎읞의 종점에 위치하는 객첎륌 생성한닀.

에러륌 발생시킬 위험을 없애Ʞ 위핎 Object.prototype의 빌튞읞 메서드는 닀음곌 같읎 간접적윌로 혞출하는 것읎 좋닀.

객첎 늬터럎 낎부에서 __proto__에 의한 직접 상속

Object.create 메서드에 의한 직접 상속은 앞에서 닀룬 것곌 같읎 여러 장점읎 있닀. 하지만 두 번짞 읞자로 프로퍌티륌 정의하는 것은 번거롭닀. 음닚 객첎륌 생성한 읎후, 프로퍌티륌 추가하는 방법도 있윌나 읎 또한 깔끔한 방법은 아니닀.

ES6에서는 객첎 늬터럎 낎부에서 __proto__ 접귌자 프로퍌티륌 사용하여 직접 상속을 구현할 수 있닀.

정적 프로퍌티/메서드

정적(static) 프로퍌티/메서드는 생성자 핚수로 읞슀턎슀륌 생성하지 않아도 ì°žì¡°/혞출할 수 있는 프로퍌티/메서드륌 말한닀.

정적 프로퍌티/메서드는 생성자 핚수가 생성한 읞슀턎슀로 ì°žì¡°/혞출할 수 없닀.

생성자 핚수가 생성한 읞슀턎슀는 자신의 프로토타입 첎읞에 속한 객첎의 프로퍌티/메서드에 접귌할 수 있닀. 하지만 정적 프로퍌티/메서드는 읞슀턎슀의 프로토타입 첎읞에 속한 객첎의 프로퍌티/메서드가 아니므로 읞슀턎슀로 접귌할 수 없닀.

앞에서 삎펎볞 Object.create 메서드는 Object 생성자 핚수의 정적 메서드고 Object.prototype.hasOwnProperty 메서드는 Object.prototype의 메서드닀. 따띌서 Object.create 메서드는 읞슀턎슀, 슉 Object 생성자 핚수가 생성한 객첎로 혞출할 수 없닀. 하지만 Object.prototype.hasOwnProperty 메서드는 몚든 객첎의 프로토타입 첎읞의 종점, 슉 Object.prototype의 메서드읎므로 몚든 객첎가 혞출할 수 있닀.

읞슀턎슀/프로토타입 메서드 낎에서 this륌 사용하지 않는닀멎 ê·ž 메서드는 정적 메서드로 변겜할 수 있닀. 읞슀턎슀가 혞출한 읞슀턎슀/프로토타입 메서드 낎에서 this는 읞슀턎슀륌 가늬킚닀. 메서드 낎에서 읞슀턎슀륌 ì°žì¡°í•  필요가 없닀멎 정적 메서드로 변겜하여도 동작한닀. 프로토타입 메서드륌 혞출하렀멎 읞슀턎슀륌 생성핎알 하지만 정적 메서드는 읞슀턎슀륌 생성하지 않아도 혞출할 수 있닀.

프로토타입 메서드

this륌 찞조하지 않는 프로토타입 메소드는 정적 메서드로 변겜하여도 동음한 횚곌륌 얻을 수 있닀.

프로토타입 메서드륌 혞출하렀멎 읞슀턎슀륌 생성핎알 한닀.

정적 메소드

정적 메서드는 읞슀턎슀륌 생성하지 않아도 혞출할 수 있닀.

프로퍌티 졎재 확읞

in 연산자

in 연산자는 객첎 낎에 프로퍌티가 졎재하는지 여부륌 확읞한닀.

in 연산자는 확읞 대상 객첎의 프로퍌티뿐만 아니띌 확읞 대상 객첎가 상속받은 몚든 프로토타입의 프로퍌티륌 확읞하므로 죌의가 필요하닀.

in 연산자 대신 ES6에서 새롭게 도입된 Reflect.has 메서드륌 사용할 수도 있닀. Reflect.has 메서드는 in 연산자와 동음하게 동작한닀.

Object.prototype.hasOwnProperty 메서드

Object.prototype.hasOwnProperty 메서드륌 사용핎도 객첎의 프로퍌티의 졎재 여부륌 확읞할 수 있닀.

전달받은 프로퍌티 킀가 객첎 고유의 프로퍌티 킀읞 겜우에만 true륌 반환하고 상속받은 프로토타입의 프로퍌티 킀읞 겜우 false륌 반환한닀.

프로퍌티 ì—Žê±°

for...in 묞

객첎의 몚든 프로퍌티륌 순회하며 ì—Žê±°(enumeration)하렀멎 for
in 묞을 사용한닀.

for
in 묞은 객첎의 프로퍌티 개수만큌 순회하며 for
in 묞의 변수 선얞묞에서 ì„ ì–ží•œ 변수에 프로퍌티 킀륌 할당한닀.

for
in 묞은 in 연산자처럌 순회 대상 객첎의 프로퍌티 뿐만 아니띌 상속받은 프로토타입의 프로퍌티까지 엎거한닀.

프로퍌티 얎튞늬뷰튞 [[Enumerable]]는 프로퍌티의 ì—Žê±° 가능 여부륌 나타낎며 불늬얞 값을 갖는닀.

for
in 묞은 객첎의 프로토타입 첎읞 상에 졎재하는 몚든 프로토타입의 프로퍌티 쀑에서 프로퍌티 얎튞늬뷰튞 [[Enumerable]]의 값읎 ture읞 프로퍌티륌 순회하며 ì—Žê±°(enumeration)한닀.

for
in 묞은 프로퍌티 킀가 심벌읞 프로퍌티는 엎거하지 않는닀.

상속받은 프로퍌티는 제왞하고 객첎 자신의 프로퍌티 만을 엎거하렀멎 Object.prototype.hasOwnProperty 메서드륌 사용하여 객첎 자신의 프로퍌티읞지 확읞핎알 한닀.

for
in 묞은 프로퍌티륌 ì—Žê±°í•  때 순서륌 볎장하지 않윌므로 죌의하Ʞ 바란닀. 하지만 대부분의 몚던 람띌우저는 순서륌 볎장하고 숫자(사싀은 묞자엎)읞 프로퍌티 킀에 대핎서는 정렬을 싀시한닀.

배엎에는 for
in 묞을 사용하지 말고 음반적읞 for 묞읎나 for
of 묞 또는 Array.prototype.forEach 메서드륌 사용하Ʞ륌 권장한닀. 사싀 배엎도 객첎읎므로 프로퍌티와 상속받은 프로퍌티가 포핚될 수 있닀.

Object.keys/values/entries 메서드

지ꞈ까지 삎펎볎았듯읎 for
in 묞은 객첎 자신의 고유 프로퍌티 뿐만 아니띌 상속받은 프로퍌티도 엎거한닀. 따띌서 Object.prototype.hasOwnProperty 메서드륌 사용하여 객첎 자신의 프로퍌티읞지 확읞하는 추가 처늬가 필요하닀.

객첎 자신의 고유 프로퍌티만을 엎거하Ʞ 위핎서는 for
in 묞을 사용하는 것 볎닀 Object.keys/values/entries 메서드륌 사용하는 것을 권장한닀.

Object.keys 메서드는 객첎 자신의 ì—Žê±° 가능한(enumerable) 프로퍌티 킀륌 ë°°ì—Žë¡œ 반환한닀.

ES8에서 도입된 Object.values 메서드는 객첎 자신의 ì—Žê±° 가능한 프로퍌티 값을 ë°°ì—Žë¡œ 반환한닀.

ES8에서 도입된 Object.entries 메서드는 객첎 자신의 ì—Žê±° 가능한 프로퍌티 킀와 값의 쌍의 배엎을 배엎에 ë‹Žì•„ 반환한닀.

reference

https://poiemaweb.com/

logo
Things I've Learned