본문으로 건너뛰기
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
)

관련 글

  • #turbopack#nextjs#bundler

    Next.js turbopack에서 싱글톤이 두 개가 됐다: scope hoisting 버그와 순환 import

    Next.js 16 turbopack 프로덕션 빌드에서 모듈 스코프 싱글톤이 런타임에 두 개가 됐다. 같은 동기 구간에서 조건 판정이 뒤집히고, 응답이 도착해도 타임아웃이 나는 증상을 번들 산출물로 추적한 기록. scope hoisting의 부분 병합, 순환 import, 이미 고쳐져 있던 upstream 버그, 그리고 뒤늦게 돌린 단일 변수 실험까지.

    2026-08-19·28분
  • #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분

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

RSS 구독 →

yceffort — 프론트엔드 엔지니어입니다.

← Back to the blogIssue on GitHub →