본문으로 건너뛰기
yceffort
PostsSeriesTagsAbout🧪 Research
EN

Tweaks

theme
accent palette
film grain
minimal mode
BACK TO INDEX
◆ ESSAY
--min
--year
KOoriginal

mailMail icongithubtwitter
yceffort
•
© 2026
•
https://yceffort.kr
BACK TO INDEX
◆ ESSAY

Javascript Prototype

avatar
yceffort
2020-06-27 · 9분
9min
2020year
KOoriginal
javascript

Table of Contents

  • 프로토타입
    • 속성 상속
    • 메소드 상속
    • How to use
    • 여러가지 방법으로 객체를 생성하고 프로토타입 체인 결과를 보자
      • 문법 생성자
      • 생성자를 이용
      • Object.create 활용
    • [[prototype]] vs prototype
      • [[prototype]]
      • prototype 프로퍼티
      • 차이비교
    • Constructor
    • 정리!!!

프로토타입

상속이라는 관점에서 봤을 때, 자바스크립트의 유일한 생성자는 객체 뿐이다. 모든 객체는 [[prototype]] 이라는 private 속성을 가지고 있는데, 이는 자신의 프로토타입이 되는 다른 객체를 가리킨다. 이렇게 자신의 프로토타입의 프로토타입의 프로토타입을 따라가다보면, 결국 null을 프로토타입으로 가지는 오브젝트에서 끝난다. null은 프로토타입이 더 이상 없다고 정의되며 이는 프로토타입의 종점을 말한다.

var obj = {a: 'hello'}
console.dir(obj)

속성 상속

객체의 어떠한 속성에 접근하려고 할 때, 그 객체 자체의 속성 뿐만 아니라 객체의 프로토타입, 그 프로토 타입의 프로토 타입 등등등 앞서 말한 프로토타입의 종단 까지 갈 때가지 그 속성을 탐색한다.

let foo = function () {
  this.a = 1
  this.b = 2
}

let bar = new foo() // {a:1, b:2}

foo.prototype.b = 3
foo.prototype.c = 4

// bar가 a 속성을 가지고 있기 때문에 1
console.log(bar.a)
// bar가 a 속성을 가지고 있기 때문에 2
console.log(bar.b)
// bar가 c의 속성을 가지고 있지 않다. 그래서 프로토타입을 체크한다.
// foo.[[prototype]] 이 c를 갖고 있는지 확인하자.
// c가 있다.
// 4
console.log(bar.c)
// 프로토타입을 뒤져도 d는 나오지 않는다.
console.log(bar.d)

메소드 상속

var foo = {
  a: 2,
  b: function (c) {
    return this.a + 1
  },
}

// 3
// 여기서 this는 foo를 가리킨다
console.log(foo.b())

// bar는 프로토타입을 foo로 가지는 오브젝트다.
var bar = Object.create(foo)

bar.a = 4
// bar.b()를 호출 하면, this는 bar를 가리킨다.
// 따라서 foo의 함수 b를 상속 받으며,
// a는 foo.a가 아닌 bar에서 새로지정한 a를 보게된다.
// 5
console.log(bar.b())

How to use

function dummy() {}
console.dir(dummy.prototype)

여기에 속성을 추가해보자.

function dummy() {}
dummy.prototype.foo = 'bar'
console.dir(dummy.prototype)

foo가 bar값으로 추가된 것을 볼 수 있다.

function dummy() {}
dummy.prototype.foo = 'bar'
var d = new dummy()
d.hello = 'world'
console.log(d)

  1. d 의 속성에 접근할 때, 브라우저는 우선 d가 그 속성을 가지고 있는지 확인한다.
  2. 만약 d가 해당 속성을 가지고 있지 않다면, d.__proto__ (dummy.prototype)이 그 속성을 가지고 있는지 확인한다.
  3. 만약 dummy.__proto__가 그 속성을 가지고 있다면, dummy.__proto__가 갖고 있는 속성을 사용한다.
  4. 만약 dummy.__proto__마저 그 속성을 가지고 있지 않으면, dummy.__proto__.__proto__가 가지고 있는지 확인한다. 기본적으로 여기서 함수의 prototype의 __proto__는 window.Object.prototype이다.
  5. 그래서 이제 dummy.__proto__.__proto__ (dummy.prototype의 __proto__) (Object.prototype)에서 그 속성을 찾는다.
  6. 근데 이제 그 위의 dummy.__proto__.__proto__.__proto__를 찾으려고 하지만, 더 이상은 없으므로
  7. undefined로 결론 짓는다.

위의 지독한 과정을 (....) 코드로 살펴보자.

function dummy() {}
dummy.prototype.foo = 'bar'
var d = new dummy()
d.prop = 'some value'
console.log('d.prop:      ' + d.prop)
console.log('d.foo:       ' + d.foo)
console.log('dummy.prop:           ' + dummy.prop)
console.log('dummy.foo:            ' + dummy.foo)
console.log('dummy.prototype.prop: ' + dummy.prototype.prop)
console.log('dummy.prototype.foo:  ' + dummy.prototype.foo)
d.prop:      some value
d.foo:       bar
dummy.prop:           undefined
dummy.foo:            undefined
dummy.prototype.prop: undefined
dummy.prototype.foo:  bar

여러가지 방법으로 객체를 생성하고 프로토타입 체인 결과를 보자

문법 생성자

var foo = {bar: 1}
// foo의 프로토타입은 Object.prototype

var arrayFoo = ['please', 'go', 'home']
// arrayFoo의 프로토타입은 Array.prototype
// 그래서 map, index 등을 쓸 수 있다.

function functionFoo() {
  return 'fuck'
}
// Function.prototype을 상속받아서
// call, bind 등으르 쓸 수 있다.

생성자를 이용

function hello() {
  this.name = ''
  this.age = 0
}

hello.prototype = {
  setName: function (name) {
    this.name = name
  },
}

var h = new hello()
// h는 name과 age를 속성으로 갖는 객체다.
// 생성이 h.[[prototype]]은 Hello.prototype과 같은 값을 가진다.

Object.create 활용

var a = {a: 1}
// a --> Object.prototype --> null

var b = Object.create(a)
// b --> a --> Object.prototype --> null

var c = Object.create(b)
// c --> b --> a --> Object.prototype --> null

[[prototype]] vs prototype

모든 객체는 자신의 프로토타입을 가리키는 [[prototype]]이라는 인터널 슬롯을 가지며, 상속을 위해 사용된다. 함수도 객체이기 때문에, [[prototype]]를 갖는다. 그런데 함수는 일반 객체와는 달리 prototype 프로토타입도 갖게 된다. 중요한 것은 [[prototype]]과 prototype은 다르다는 것이다.

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

var foo = new Person('Lee')

console.dir(Person) // prototype 프로퍼티가 있다.
console.dir(foo) // prototype 프로퍼티가 없다.

function P(name) {
  return name
}

var bar = P('Lee')
console.dir(bar)

[[prototype]]

  • 함수를 포함한 모든 객체가 가지고 있는 인터널 슬롯
  • 객체 입장에서 봤을때, 자신의 부모역할을 하는 프로토타입 객체를 가리키며, 함수의 경우 Function.prototype을 가리킨다.

prototype 프로퍼티

  • 오직 함수만 가지고 있는 프로퍼티다.
  • 함수 객체가 생성자로 이용될때, 이 함수를 통해 생성될 객체의 부모역할을 하는 객체를 가리킨다.
  • 위 예제에서 new Person('Lee')는 이함수를 통해 foo가 나왔다. 이 foo의 __proto__를 가리킨다.

차이비교

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

var foo = new Person('Kim')

console.log(Person.__proto__ === Function.prototype)

console.log(Person.prototype === foo.__proto__)

Constructor

프로토타입 객체는 constructor 프로퍼티를 갖는다. 이 constructor 프로퍼티는 객체입장에서 자신을 생성한 객체를 가리킨다.

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

var foo = new Person('Lee')

// Person() 생성자 함수에 의해 생성된 객체를 생성한 객체는 Person() 생성자 함수이다.
console.log(Person.prototype.constructor === Person)

// foo 객체를 생성한 객체는 Person() 생성자 함수이다.
console.log(foo.constructor === Person)

// Person() 생성자 함수를 생성한 객체는 Function() 생성자 함수이다.
console.log(Person.constructor === Function)

정리!!!

  • [[Prototype]]은 자바스크립트의 모든 객체가 가진 값이며, __proto__로 접근할 수 있다. (혹은 Object.getPrototypeOf(obj))도 가능하다. 사실 똑같다.) 이것을 이용해 상속을 구현하며, 타고타고 올라가면 Object.prototype을 만나고 Object.__proto__는 null이다.
  • prototype은 new로 새로운 object를 만들었을때 (생성자로 사용될때), 이 함수로 생성될 객체의 부모 역할을 할 객체를 가리킨다. (XXX.prototype)
  • XXX.prototype 객체는 constructor를 갖는데, constructor는 자신의 입장에서 자신을 생성한 객체를 가리킨다. 따라서 XXX를 가리킨다.

Foo를 중심으로 설명해보자.

  • Foo는 함수다. 따라서 이 함수의 프로토타입은 Function.prototype이다.
  • Foo를 생성자 함수로 사용했을때, prototype프로퍼티를 갖게되며, Foo.prototype이 생긴다.
  • Foo.prototype의 프로토타입은 Object이다. (함수가 아닌 새로운 객체이므로
  • Foo를 생성자함수로, b와 c를 new를 이용하여 만들었다. b와 c의 프로토타입은 Foo.prototype이다.
// 생성자 함수
function Foo(y) {
  // Object를 생성한 뒤에, y 프로퍼티에 y값을 갖게 된다.
  this.y = y
}

// 또한 'Foo.prototype'은 Foo의 prototype에 할당되며,
// 이를 활용해서 프로퍼티나 메소드를 상속받거나 공유할 수 있으며,
// 위에서 제시한 예시와 같이 활용할 수 있다.
Foo.prototype.x = 10

// calculate 메소드를 상속받는다
Foo.prototype.calculate = function (z) {
  return this.x + this.y + z
}

// Foo 패턴을 활용하여 b와 c 오브젝트를 생성한다.
var b = new Foo(20)
var c = new Foo(30)

// 상속받은 메소드를 호출한다.
b.calculate(30) // 60
c.calculate(40) // 80

// 한번 확인해보자.
console.log(
  b.__proto__ === Foo.prototype, // true
  c.__proto__ === Foo.prototype, // true

  // Foo.prototype은 constructor라는 새로운 프로퍼티를 만드는데,
  // 이는 함수 그 자체의 생성자를 참조하게 된다.
  // b, c 생성자는 Foo 자체임을 알 수 있다.

  b.constructor === Foo, // true
  c.constructor === Foo, // true
  Foo.prototype.constructor === Foo, // true

  b.calculate === b.__proto__.calculate, // true
  b.__proto__.calculate === Foo.prototype.calculate, // true
)

관련 글

  • #javascript#animation#web-animations-api

    number-flow를 구형 브라우저로 이식하기: 다섯 가지 결정과 두 가지 번복

    number-flow가 애니메이션을 켜는 최소 버전은 Chrome 125, Safari 17.2다. 이 하한을 Chrome 66과 WebKit 16.4까지 내리는 포크를 만들면서 내린 결정들과, 뒤집게 된 판단 두 가지, 그리고 자동 강등을 포기한 Safari 버그 조사의 기록.

    2026-08-11·44분
  • #nodejs#security#javascript

    Node.js vm 모듈의 함정: 샌드박스가 아닌 이유

    집필 중인 Node.js Deep Dive의 5.2장(vm 모듈의 함정) 일부를 미리 공개합니다.

    2026-02-27·25분
  • #nodejs#javascript

    Node.js Deep Dive (가제) 베타 리더를 모십니다.

    많관부22

    2026-02-19·5분
  • #javascript#frontend#web-performance

    IntersectionObserver 싱글톤 패턴과 WeakMap으로 메모리 누수 방지하기

    수백 개의 요소를 효율적으로 관찰하면서 메모리 누수도 방지하는 방법

    2026-01-17·20분

새 글을 놓치고 싶지 않으시다면 RSS로 구독해 주세요.

RSS 구독 →

yceffort — 프론트엔드 엔지니어입니다. 발표·기술 자문·기고 문의는 이곳에서 받고 있습니다.

← Back to the blogIssue on GitHub →