JavaScript 프로토타입 —
생성자 함수로 객체 찍어내기
은행 계좌(Account)를 표현하는 객체를 만드는 코드다. 한 번 정의해두면 new만 붙여서 계좌를 몇 개든 찍어낼 수 있다. owner(주인), code(계좌번호), balance(잔액) 세 개의 프로퍼티와 inquiry(조회)·deposit(입금)·withdraw(출금) 세 개의 메소드가 들어 있다.
Account 프로토타입 만들기
account : 황기태, 111, 35000
10000원 저금 후 잔액은 45000
5000원 인출 후 잔액은 40000
계좌가 하나뿐이라면 객체를 { owner: "황기태", code: "111", balance: 35000 }처럼 직접 써도 된다. 하지만 계좌가 100개, 1000개 필요하다면? 매번 똑같은 구조를 손으로 반복해서 쓰는 건 비효율적이고 실수하기도 쉽다. 생성자 함수는 "이런 모양의 객체를 만들어라"는 틀(프로토타입)을 한 번만 정의해두고, 필요할 때마다 new로 찍어내게 해준다.
Account라는 틀 안에 owner·code·balance라는 재료를 넣으면 계좌 붕어빵(인스턴스)이 하나씩 나온다.생성자 함수 몸통 안에서 this는 아직 이름도 없는, 지금 막 만들어지고 있는 객체를 가리킨다. Account 함수를 정의하는 시점에는 그 객체가 account라는 이름을 가질지, myAccount라는 이름을 가질지 전혀 알 수 없다. 그래서 "누가 될지 모르는 그 객체 자신"을 가리키는 대명사가 필요한데, 그것이 바로 this다.
- 함수를 정의할 때는 this가 무엇인지 정해지지 않는다
new Account(...)로 호출하는 순간 this가 새 객체로 확정된다- 같은 함수를 여러 번 new 하면, 호출할 때마다 this가 매번 다른 새 객체를 가리킨다
JavaScript 객체는 미리 프로퍼티 목록을 선언할 필요가 없다. this.owner = owner;처럼 this에 값을 대입하는 순간, 그 이름의 프로퍼티가 즉석에서 생성된다. 매개변수로 받은 owner(지역 변수)를 this.owner(객체의 프로퍼티)에 옮겨 담는다고 생각하면 된다. 이름이 같아서 헷갈리지만 왼쪽은 "객체의 저장 공간", 오른쪽은 "함수에 잠깐 들어온 값"으로 서로 다른 존재다.
| 코드 | 왼쪽 (this.owner) | 오른쪽 (owner) |
|---|---|---|
this.owner = owner; |
객체에 새로 생기는 프로퍼티 | 매개변수로 전달받은 지역 변수 |
this.code = code; |
계좌번호 프로퍼티 | 전달받은 계좌번호 값 |
this.balance = balance; |
잔액 프로퍼티 | 전달받은 초기 잔액 값 |
JavaScript에서 함수는 값이다. 그래서 this.inquiry = function () { ... }처럼 함수 자체를 프로퍼티 값으로 대입하면, 그 순간 inquiry는 이 객체의 메소드가 된다. 이렇게 만든 메소드 안에서도 this를 쓰면 "이 메소드를 호출한 바로 그 객체"의 프로퍼티에 접근할 수 있다.
function() {...}을 새로 만들면, new Account(...)를 호출할 때마다 inquiry·deposit·withdraw 함수가 매번 새로 생성된다. 계좌를 1000개 만들면 똑같은 내용의 함수가 3000개(1000개 × 3개) 메모리에 생긴다는 뜻이다. 실무에서는 Account.prototype.inquiry = function() {...} 형태로 프로토타입에 메소드를 딱 한 번만 정의해 모든 인스턴스가 공유하도록 최적화한다.let account = new Account("황기태", "111", 35000); 한 줄 안에는 사실 여러 단계가 숨어 있다. new는 이 단계들을 자동으로 처리해주는 연산자다.
new 없이 Account("황기태", "111", 35000)처럼 일반 함수처럼 호출하면, 앞서 본 "빈 객체 생성 → this 바인딩" 단계가 통째로 생략된다. 이때 this는 새 객체가 아니라 브라우저의 전역 객체(window)를 가리키거나(비엄격 모드), strict 모드에서는 undefined가 되어 this.owner = owner;에서 즉시 에러가 난다.
undefined가 담긴다(함수가 return 문이 없으므로). 이후 account.owner를 읽으려 하면 "Cannot read properties of undefined" 에러가 난다.inquiry는 잔액을 "확인만" 하는 메소드라서 바꿀 값이 없다. 그래서 return this.balance;로 현재 값을 바깥으로 돌려주는 것이 전부다. 반면 deposit은 잔액 자체를 변경하는 게 목적이라 return이 필요 없다. withdraw는 잔액을 줄이면서 동시에 "실제로 얼마를 인출했는지"도 알려주고 싶어서 return money;를 추가했다.
| 메소드 | 하는 일 | 반환값 |
|---|---|---|
inquiry() |
현재 잔액을 조회만 함 | this.balance (숫자) |
deposit(money) |
balance를 money만큼 증가 | 없음 (undefined) |
withdraw(money) |
balance를 money만큼 감소 | money (인출한 금액) |
if (money > this.balance) return -1; 같은 방어 로직이 반드시 필요하다.| 실수 | 증상 | 해결 |
|---|---|---|
new를 빠뜨림 |
this가 window를 가리키거나 undefined 에러 | 객체를 만들 때는 반드시 new 생성자함수() 형태로 호출 |
| 생성자 함수 이름을 소문자로 시작 | 일반 함수인지 생성자인지 코드만 봐선 구분 불가 | 생성자 함수는 관례적으로 대문자로 시작 (Account, Person) |
| 메소드를 생성자 안에서 매번 새로 만듦 | 인스턴스마다 같은 함수가 중복 생성되어 메모리 낭비 | 공통 동작은 Account.prototype.메소드 = function(){...}로 한 번만 정의 |
| withdraw에서 잔액 검증 없이 차감 | balance가 음수로 내려가도 막지 못함 | 인출 전 money <= this.balance 조건 확인 |
| this와 지역 변수 이름이 같아 혼동 | this.owner와 owner를 헷갈려 대입 순서를 반대로 씀 | 왼쪽은 항상 "객체의 프로퍼티(this.xxx)", 오른쪽은 "받은 값"으로 구분해서 읽기 |
핵심 한 줄 요약
Tags
'php' 카테고리의 다른 글
| JavaScript DOM 기초 — DOM 트리·write·writeln·window.open 완전 정리 (0) | 2026.07.05 |
|---|---|
| 웹 개발 시작하기 — 기본 HTML 문서 구조 완전 정리 (1) | 2026.07.04 |
| JavaScript Array 메서드 — concat·join·reverse·sort 완전 정리 (0) | 2026.07.04 |
| JavaScript 배열 — [] 리터럴과 인덱스 완전 정리 (0) | 2026.07.03 |
| JavaScript 객체 생성 — new Date · String · Array 완전 정리 (0) | 2026.07.03 |
왕진 블로그

댓글