본문 바로가기

비개발자의 개발 일지

현장 팀장에서 수출 ERP까지 — AI와 함께 시스템을 만든 기록

시리즈 보기
php

JavaScript 프로토타입 — 생성자 함수·this·메서드 완전 정리

by 왕진 2026. 7. 4.
반응형

 

 

Web Development · JavaScript

JavaScript 프로토타입 —
생성자 함수로 객체 찍어내기

this로 프로퍼티·메소드를 만들고 new 연산자로 인스턴스를 생성하는 방법 (은행 계좌 예제)
시작 오늘 분석할 코드

은행 계좌(Account)를 표현하는 객체를 만드는 코드다. 한 번 정의해두면 new만 붙여서 계좌를 몇 개든 찍어낼 수 있다. owner(주인), code(계좌번호), balance(잔액) 세 개의 프로퍼티와 inquiry(조회)·deposit(입금)·withdraw(출금) 세 개의 메소드가 들어 있다.

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>프로토타입으로 객체 만들기</title> <script> // 프로토타입 만들기 : 생성자 함수 작성 function Account(owner, code, balance) { // 프로퍼티 만들기 this.owner = owner; // 계좌 주인 프로퍼티 만들기 this.code = code; // 계좌 코드 프로퍼티 만들기 this.balance = balance; // 잔액 프로퍼티 만들기 // 메소드 만들기 this.inquiry = function () { return this.balance; } this.deposit = function (money) { this.balance += money; } this.withdraw = function (money) { this.balance -= money; return money; // 예금 인출, money는 인출하는 액수 // money가 balance보다 작다고 가정 } } </script> </head> <body> <h3>Account 프로토타입 만들기</h3> <hr> <script> // new 연산자 이용하여 계좌 객체 생성 let account = new Account("황기태", "111", 35000); // 객체 활용 document.write("account : "); document.write(account.owner + ", "); document.write(account.code + ", "); document.write(account.balance + "<br>"); account.deposit(10000); // 10000원 저금 document.write("10000원 저금 후 잔액은 " + account.inquiry() + "<br>"); account.withdraw(5000); // 5000원 인출 document.write("5000원 인출 후 잔액은 " + account.inquiry() + "<br>"); </script> </body> </html>
실제 출력 미리보기

Account 프로토타입 만들기


account : 황기태, 111, 35000

10000원 저금 후 잔액은 45000

5000원 인출 후 잔액은 40000

용어 용어 정리
프로토타입객체를 찍어내는 "틀"이자 원형(原型). 여기서는 생성자 함수 Account가 그 틀 역할
생성자 함수new와 함께 호출해 객체를 만드는 전용 함수. 관례상 대문자로 시작
this지금 만들어지고 있는 바로 그 객체를 가리키는 키워드
new빈 객체를 만들고 this를 그 객체에 연결한 뒤 함수를 실행시키는 연산자
인스턴스생성자 함수로 실제로 만들어진 개별 객체 (예: account)
프로퍼티객체가 가진 데이터 항목. owner, code, balance
메소드객체에 붙어있는 함수. inquiry, deposit, withdraw
캡슐화데이터(프로퍼티)와 그 데이터를 다루는 동작(메소드)을 하나의 객체로 묶는 것

1 생성자 함수란 무엇인가
왜 함수로 객체를 만드는가?

계좌가 하나뿐이라면 객체를 { owner: "황기태", code: "111", balance: 35000 }처럼 직접 써도 된다. 하지만 계좌가 100개, 1000개 필요하다면? 매번 똑같은 구조를 손으로 반복해서 쓰는 건 비효율적이고 실수하기도 쉽다. 생성자 함수는 "이런 모양의 객체를 만들어라"는 틀(프로토타입)을 한 번만 정의해두고, 필요할 때마다 new로 찍어내게 해준다.

※ 생성자 함수 = 붕어빵 틀. Account라는 틀 안에 owner·code·balance라는 재료를 넣으면 계좌 붕어빵(인스턴스)이 하나씩 나온다.
※ 관례: 생성자 함수 이름은 대문자로 시작한다 (Account, Person, Car...). 일반 함수와 구분하기 위한 약속일 뿐 문법 규칙은 아니지만, 지키지 않으면 다른 개발자가 헷갈린다.

2 this — 새로 만들어질 객체를 가리키다
this는 대체 무엇을 가리키는가?

생성자 함수 몸통 안에서 this아직 이름도 없는, 지금 막 만들어지고 있는 객체를 가리킨다. Account 함수를 정의하는 시점에는 그 객체가 account라는 이름을 가질지, myAccount라는 이름을 가질지 전혀 알 수 없다. 그래서 "누가 될지 모르는 그 객체 자신"을 가리키는 대명사가 필요한데, 그것이 바로 this다.

function Account(owner, code, balance) { this.owner = owner; // this = "나중에 new로 만들어질 바로 그 객체" // account.owner = owner 를 미리 써둔 것과 같은 효과 }
※ this가 결정되는 순간
  • 함수를 정의할 때는 this가 무엇인지 정해지지 않는다
  • new Account(...)호출하는 순간 this가 새 객체로 확정된다
  • 같은 함수를 여러 번 new 하면, 호출할 때마다 this가 매번 다른 새 객체를 가리킨다

3 this.owner = owner — 프로퍼티 만들기
대입만 해도 프로퍼티가 생기는 이유

JavaScript 객체는 미리 프로퍼티 목록을 선언할 필요가 없다. this.owner = owner;처럼 this에 값을 대입하는 순간, 그 이름의 프로퍼티가 즉석에서 생성된다. 매개변수로 받은 owner(지역 변수)를 this.owner(객체의 프로퍼티)에 옮겨 담는다고 생각하면 된다. 이름이 같아서 헷갈리지만 왼쪽은 "객체의 저장 공간", 오른쪽은 "함수에 잠깐 들어온 값"으로 서로 다른 존재다.

코드 왼쪽 (this.owner) 오른쪽 (owner)
this.owner = owner; 객체에 새로 생기는 프로퍼티 매개변수로 전달받은 지역 변수
this.code = code; 계좌번호 프로퍼티 전달받은 계좌번호 값
this.balance = balance; 잔액 프로퍼티 전달받은 초기 잔액 값

 

반응형

 

4 메소드를 this에 함수로 붙이기
메소드도 결국 "함수를 담은 프로퍼티"

JavaScript에서 함수는 값이다. 그래서 this.inquiry = function () { ... }처럼 함수 자체를 프로퍼티 값으로 대입하면, 그 순간 inquiry는 이 객체의 메소드가 된다. 이렇게 만든 메소드 안에서도 this를 쓰면 "이 메소드를 호출한 바로 그 객체"의 프로퍼티에 접근할 수 있다.

this.inquiry = function () { return this.balance; } // 조회: 값을 바꾸지 않고 balance를 그대로 돌려준다 this.deposit = function (money) { this.balance += money; } // 입금: balance를 늘리기만 하고 return 값은 없다 this.withdraw = function (money) { this.balance -= money; return money; } // 출금: balance를 줄이고, 실제로 인출한 금액을 되돌려준다
※ 이 코드처럼 생성자 함수 안에서 매번 function() {...}을 새로 만들면, new Account(...)를 호출할 때마다 inquiry·deposit·withdraw 함수가 매번 새로 생성된다. 계좌를 1000개 만들면 똑같은 내용의 함수가 3000개(1000개 × 3개) 메모리에 생긴다는 뜻이다. 실무에서는 Account.prototype.inquiry = function() {...} 형태로 프로토타입에 메소드를 딱 한 번만 정의해 모든 인스턴스가 공유하도록 최적화한다.

5 new 연산자가 하는 일
new는 눈에 안 보이는 4단계를 대신 해준다

let account = new Account("황기태", "111", 35000); 한 줄 안에는 사실 여러 단계가 숨어 있다. new는 이 단계들을 자동으로 처리해주는 연산자다.

1
빈 객체 생성아무 프로퍼티도 없는 텅 빈 객체 {}를 하나 만든다
2
this를 그 객체에 바인딩Account 함수 안의 this가 방금 만든 빈 객체를 가리키게 연결한다
3
함수 몸통 실행this.owner = owner 같은 코드가 실행되며 그 빈 객체에 프로퍼티·메소드가 채워진다
4
완성된 객체를 반환함수가 따로 return을 안 해도, new가 채워진 객체를 자동으로 돌려준다 → account에 저장
new Account(...)
빈 객체 {}
this = 빈 객체
프로퍼티·메소드 채움
account에 반환

6 new를 빠뜨리면 생기는 문제
그냥 Account(...)로 호출하면 무슨 일이 생기나?

new 없이 Account("황기태", "111", 35000)처럼 일반 함수처럼 호출하면, 앞서 본 "빈 객체 생성 → this 바인딩" 단계가 통째로 생략된다. 이때 this는 새 객체가 아니라 브라우저의 전역 객체(window)를 가리키거나(비엄격 모드), strict 모드에서는 undefined가 되어 this.owner = owner;에서 즉시 에러가 난다.

new Account(...)
새 객체 생성 → this가 그 객체 → account에 정상적으로 owner·code·balance·메소드가 채워짐
Account(...) — new 없이
새 객체 없음 → this가 window(또는 undefined) → 전역 객체가 오염되거나 TypeError 발생
※ account 변수에는 undefined가 담긴다(함수가 return 문이 없으므로). 이후 account.owner를 읽으려 하면 "Cannot read properties of undefined" 에러가 난다.

7 return this.balance — 값을 돌려주는 메소드 vs 상태만 바꾸는 메소드
왜 inquiry는 return하고 deposit은 안 하는가?

inquiry는 잔액을 "확인만" 하는 메소드라서 바꿀 값이 없다. 그래서 return this.balance;로 현재 값을 바깥으로 돌려주는 것이 전부다. 반면 deposit은 잔액 자체를 변경하는 게 목적이라 return이 필요 없다. withdraw는 잔액을 줄이면서 동시에 "실제로 얼마를 인출했는지"도 알려주고 싶어서 return money;를 추가했다.

메소드 하는 일 반환값
inquiry() 현재 잔액을 조회만 함 this.balance (숫자)
deposit(money) balance를 money만큼 증가 없음 (undefined)
withdraw(money) balance를 money만큼 감소 money (인출한 금액)
※ 코드 주석에 적힌 "money가 balance보다 작다고 가정"이라는 말은 이 코드가 잔액 초과 인출을 검증하지 않는다는 뜻이다. 실무 코드라면 if (money > this.balance) return -1; 같은 방어 로직이 반드시 필요하다.

8 자주 하는 실수
실수 증상 해결
new를 빠뜨림 this가 window를 가리키거나 undefined 에러 객체를 만들 때는 반드시 new 생성자함수() 형태로 호출
생성자 함수 이름을 소문자로 시작 일반 함수인지 생성자인지 코드만 봐선 구분 불가 생성자 함수는 관례적으로 대문자로 시작 (Account, Person)
메소드를 생성자 안에서 매번 새로 만듦 인스턴스마다 같은 함수가 중복 생성되어 메모리 낭비 공통 동작은 Account.prototype.메소드 = function(){...}로 한 번만 정의
withdraw에서 잔액 검증 없이 차감 balance가 음수로 내려가도 막지 못함 인출 전 money <= this.balance 조건 확인
this와 지역 변수 이름이 같아 혼동 this.owner와 owner를 헷갈려 대입 순서를 반대로 씀 왼쪽은 항상 "객체의 프로퍼티(this.xxx)", 오른쪽은 "받은 값"으로 구분해서 읽기

핵심 한 줄 요약

생성자 함수같은 구조의 객체를 여러 개 찍어내는 틀 (대문자로 시작하는 관례)
this지금 만들어지고 있는(또는 호출한) 객체 자신을 가리키는 키워드
this.프로퍼티 = 값대입하는 순간 그 이름의 프로퍼티가 즉석에서 생성됨
this.메소드 = function(){}함수를 프로퍼티로 붙이면 곧 그 객체의 메소드가 됨
new빈 객체 생성 → this 바인딩 → 함수 실행 → 완성된 객체 반환, 4단계를 자동 처리
new 생략 시this가 전역 객체나 undefined가 되어 정상 동작하지 않음
인스턴스생성자 함수로 실제로 찍어낸 개별 객체 (account)

Tags

#JavaScript #프로토타입 #생성자함수 #this #new연산자 #객체지향 #메소드 #프로퍼티 #인스턴스 #자바스크립트기초 #JS #캡슐화 #웹개발 #티스토리
▼ 티스토리 태그 입력란 복사용
JavaScript, 프로토타입, 생성자함수, this, new연산자, 객체지향, 메소드, 프로퍼티, 인스턴스, 자바스크립트기초, JS, 캡슐화, 웹개발, 티스토리
반응형

댓글