๐Ÿงฌ 04. ํ”„๋กœํ† ํƒ€์ž… & ์ƒ์† โ€” JS๊ฐ€ ํด๋ž˜์Šค๋ฅผ ํ‰๋‚ด ๋‚ด๋Š” ์ง„์งœ ๋ฐฉ๋ฒ•

2026๋…„ 3์›” 8์ผ ์ˆ˜์ •๋จ

๐Ÿ“‹ ๊ฐœ์š”

JS์˜ ๋ณธ์งˆ์ธ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ, Object.create, ํด๋ž˜์Šค ๋ฌธ๋ฒ•์˜ ๋‚ด๋ถ€ ๋™์ž‘, ์‹ค๋ฌด์—์„œ์˜ ์ƒ์† ํŒจํ„ด์„ ์™„์ „ ์ •๋ณตํ•ฉ๋‹ˆ๋‹ค.

๐ŸŽฏ ์ด ์„น์…˜์„ ์ฝ๊ณ  ๋‚˜๋ฉด:

  • ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์ด ์†์„ฑ ํƒ์ƒ‰์„ ์–ด๋–ป๊ฒŒ ํ•˜๋Š”์ง€ ๋จธ๋ฆฟ์†์— ๊ทธ๋ฆด ์ˆ˜ ์žˆ๋‹ค.
  • class ๋ฌธ๋ฒ•์ด ํ”„๋กœํ† ํƒ€์ž…์˜ ๋ฌธ๋ฒ•์  ์„คํƒ•(syntactic sugar)์ž„์„ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Object.create, Object.getPrototypeOf ๋“ฑ ์‹ค๋ฌด API๋ฅผ ํ™œ์šฉํ•œ๋‹ค.

๐Ÿ“‹ ๋ชฉ์ฐจ


๐Ÿ“Œ ์ด ๋ฌธ์„œ๋ฅผ ์ฝ๊ธฐ ์ „์—

โฑ๏ธ ์˜ˆ์ƒ ์ฝ๊ธฐ ์‹œ๊ฐ„: 20๋ถ„(์ „์ฒด) / ํ•ต์‹ฌ ํŒŒํŠธ๋งŒ: 12๋ถ„

๐Ÿ—บ๏ธ ์ด ๋ฌธ์„œ์˜ ํ๋ฆ„
[ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ ์ดํ•ด] โ†’ [์ƒ์† ๊ตฌํ˜„ 3๊ฐ€์ง€ ๋ฐฉ๋ฒ•] โ†’ [์‹ค๋ฌด API] โ†’ [์•ˆํ‹ฐํŒจํ„ด ์ฃผ์˜]

๐ŸŽฏ ์ด ๋ฌธ์„œ๋ฅผ ๋‹ค ์ฝ์œผ๋ฉด ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ

  • "arr.map์€ ์–ด๋””์„œ ์˜ค๋Š”๊ฐ€?"๋ฅผ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์œผ๋กœ ์„ค๋ช…ํ•œ๋‹ค.
  • ES6 class๊ฐ€ ๋‚ด๋ถ€์ ์œผ๋กœ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š”์ง€ ์•Œ๊ณ  ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.
  • instanceof, hasOwnProperty๋ฅผ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์‚ฌ์šฉํ•œ๋‹ค.

๐Ÿ—บ๏ธ ์ด ๋ฌธ์„œ์˜ ๋ฐฐ๊ฒฝ ์„ธ๊ณ„๊ด€: '์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ'

๐Ÿฃ ์˜์ฒ : "์˜ํ˜ธ ๋‹˜! ์˜ค๋Š˜ class๋กœ User, AdminUser๋ฅผ ๋งŒ๋“ค์—ˆ๋Š”๋ฐ์š”. ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ ์—๋Ÿฌ๋„ ์—†๊ณ  ์ž˜ ๋˜๋Š” ๊ฒƒ ๊ฐ™์•„์„œ ์‹ ๋‚ฌ๋Š”๋ฐ, ์ฝ”๋“œ ๋ฆฌ๋ทฐ์—์„œ 'ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์„ ์ดํ•ดํ•˜๊ณ  class๋ฅผ ์“ฐ๋Š” ๊ฑด์ง€ ํ™•์ธ ํ•„์š”'๋ผ๋Š” ์ฝ”๋ฉ˜ํŠธ๊ฐ€ ๋‹ฌ๋ ธ์–ด์š”. class ์“ฐ๋ฉด ๋˜๋Š” ๊ฑฐ ์•„๋‹Œ๊ฐ€์š”? ์™œ ํ”„๋กœํ† ํƒ€์ž…์„ ์•Œ์•„์•ผ ํ•ด์š”?"

๐Ÿฆ ์˜ํ˜ธ: "class๋Š” JS๊ฐ€ ์›๋ž˜ ๊ฐ€์ง„ ํ”„๋กœํ† ํƒ€์ž… ๊ธฐ๋ฐ˜ ์ƒ์†์— ์˜ˆ์œ ์˜ท์„ ์ž…ํžŒ ๊ฑฐ์•ผ. ๋‚ด๋ถ€๋Š” ๋˜‘๊ฐ™์ด ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์œผ๋กœ ๋™์ž‘ํ•ด. ๊ทธ ๋‚ด๋ถ€๋ฅผ ๋ชจ๋ฅด๋ฉด, ๋ฉ”๋ชจ๋ฆฌ ์ตœ์ ํ™” ์•ˆ ๋˜๊ณ , ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์†์„ฑ ๊ณต์œ  ๋ฒ„๊ทธ ๋งŒ๋‚˜๊ณ , ๋””๋ฒ„๊น…ํ•  ๋•Œ chrome devtools์˜ [[Prototype]] ๋ณด๋ฉด์„œ ๋ฉ˜๋ถ•ํ•˜๊ฒŒ ๋ผ. ํ•œ ๋ฒˆ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜๋ฉด class๊ฐ€ ๋” ์ž˜ ๋ณด์—ฌ."


๐Ÿค” 1. ์™œ ์•Œ์•„์•ผ ํ•˜๋Š”๊ฐ€?

์˜ํ˜ธ ๋ฆฌ๋“œ ๋‹˜์ด ์ฝ”๋“œ ๋ฆฌ๋ทฐ์—์„œ ์˜์ฒ ์ด์—๊ฒŒ ๋ฌผ์—ˆ์Šต๋‹ˆ๋‹ค. "arr.map()์ด ๋„๋Œ€์ฒด ์–ด๋””์„œ ํŠ€์–ด๋‚˜์˜จ ๊ฑด์ง€ ์„ค๋ช…ํ•  ์ˆ˜ ์žˆ๋‚˜์š”?" ์˜์ฒ ์ด๋Š” ์„ ๋œป ๋Œ€๋‹ตํ•˜์ง€ ๋ชปํ–ˆ์ฃ . ์šฐ๋ฆฌ๊ฐ€ ๋งค์ผ ๊ณต๊ธฐ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฐ์—ด ๋ฉ”์„œ๋“œ๋“ค์˜ ๊ณ ํ–ฅ์„ ์ฐพ์•„๊ฐ€๋Š” ์—ฌ์ •์ด ๋ฐ”๋กœ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์„ ์ดํ•ดํ•˜๋Š” ๊ณผ์ •์ž…๋‹ˆ๋‹ค.

const arr = [1, 2, 3];
arr.map(x => x * 2);    // [2, 4, 6] โ€” map์€ ์–ด๋””์„œ ์™”๋Š”๊ฐ€?
arr.filter(x => x > 1); // [2, 3] โ€” filter๋Š” ์–ด๋””์„œ ์™”๋Š”๊ฐ€?

arr๋ฅผ ์ง์ ‘ ์„ ์–ธํ–ˆ์„ ๋•Œ map์ด๋‚˜ filter๋ฅผ ์ •์˜ํ•œ ์ ์ด ์—†๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์™œ ์“ธ ์ˆ˜ ์žˆ์„๊นŒ?

๋‹ต: ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ. arr์˜ [[Prototype]]์ด Array.prototype์„ ๊ฐ€๋ฆฌํ‚ค๊ณ , ๊ฑฐ๊ธฐ์— map, filter, reduce๊ฐ€ ์ •์˜๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ด ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด JS์˜ ์ƒ์† ์ด๋‹ค.


๐Ÿ”— 2. ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์˜ ๋ณธ์งˆ

[[Prototype]] ๋‚ด๋ถ€ ์Šฌ๋กฏ

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋ชจ๋“  ๊ฐ์ฒด๋Š” ์€๋ฐ€ํ•œ ํ†ต๋กœ๋ฅผ ํ•˜๋‚˜์”ฉ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฐ”๋กœ [[Prototype]]์ด๋ผ ๋ถˆ๋ฆฌ๋Š” ๋‚ด๋ถ€ ์Šฌ๋กฏ์ด์ฃ . ์ด ํ†ต๋กœ๊ฐ€ ์–ด๋–ป๊ฒŒ ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š”์ง€ ์ง์ ‘ ํ™•์ธํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

const user = { name: "์˜์ฒ ", role: "junior" };
 
// user์˜ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ:
// user โ†’ Object.prototype โ†’ null
 
console.log(Object.getPrototypeOf(user) === Object.prototype); // true
console.log(Object.getPrototypeOf(Object.prototype));           // null (์ฒด์ธ์˜ ๋)
 
// user๋Š” ์ง์ ‘ ์„ ์–ธํ•˜์ง€ ์•Š์•˜์ง€๋งŒ Object.prototype์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์“ธ ์ˆ˜ ์žˆ๋‹ค
user.toString();        // "[object Object]" โ€” Object.prototype.toString
user.hasOwnProperty("name"); // true โ€” Object.prototype.hasOwnProperty

์†์„ฑ ํƒ์ƒ‰ ์ˆœ์„œ

๊ฐ์ฒด์—์„œ ์–ด๋–ค ๊ฐ’์„ ์ฐพ์„ ๋•Œ, ์—”์ง„์€ ๋ฐฉ๊ธˆ ๋ณธ '์€๋ฐ€ํ•œ ํ†ต๋กœ'๋ฅผ ํƒ€๊ณ  ๋ถ€๋ชจ๋“ค์„ ์ฐพ์•„ ์˜ฌ๋ผ๊ฐ‘๋‹ˆ๋‹ค. ์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ์˜ ์œ ์ € ๊ถŒํ•œ ์ฒดํฌ ๋กœ์ง์„ ์˜ˆ๋กœ ๋“ค์–ด ํƒ์ƒ‰ ๊ณผ์ •์„ ๊ทธ๋ ค๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

// ์˜์ˆ˜๋„ค ์ปค๋ฎค๋‹ˆํ‹ฐ โ€” ์œ ์ € ์—ญํ•  ๊ถŒํ•œ ์ฒดํฌ
 
function User(name) {
  this.name = name; // ์ธ์Šคํ„ด์Šค ์ง์† ์†์„ฑ
}
 
User.prototype.role = "member"; // ํ”„๋กœํ† ํƒ€์ž… ์†์„ฑ
User.prototype.canPost = function () {
  return true; // ํ”„๋กœํ† ํƒ€์ž… ๋ฉ”์„œ๋“œ (๋ชจ๋“  ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ณต์œ )
};
 
const yc = new User("์˜์ฒ ");
const yh = new User("์˜ํ˜ธ");
 
// ์†์„ฑ ํƒ์ƒ‰ ์ˆœ์„œ:
// 1. ์ธ์Šคํ„ด์Šค ์ง์† ์†์„ฑ ํƒ์ƒ‰
// 2. ์—†์œผ๋ฉด [[Prototype]] (User.prototype) ํƒ์ƒ‰
// 3. ์—†์œผ๋ฉด Object.prototype ํƒ์ƒ‰
// 4. ์—†์œผ๋ฉด undefined
 
console.log(yc.name);   // "์˜์ฒ " โ€” ์ธ์Šคํ„ด์Šค ์ง์† โœ…
console.log(yc.role);   // "member" โ€” User.prototype์—์„œ ๋ฐœ๊ฒฌ
console.log(yc.canPost()); // true โ€” User.prototype์—์„œ ๋ฐœ๊ฒฌ
 
// ์ธ์Šคํ„ด์Šค์— ์ง์ ‘ ์„ค์ •ํ•˜๋ฉด ํ”„๋กœํ† ํƒ€์ž…์„ ๊ฐ€๋ฆฐ๋‹ค (Shadowing)
yc.role = "admin"; // yc ์ธ์Šคํ„ด์Šค์— ์ง์ ‘ ์ถ”๊ฐ€
console.log(yc.role); // "admin" โ€” ์ธ์Šคํ„ด์Šค ์ง์† ์†์„ฑ์ด ์šฐ์„ 
console.log(yh.role); // "member" โ€” yh๋Š” ๊ทธ๋Œ€๋กœ ํ”„๋กœํ† ํƒ€์ž… ์ฐธ์กฐ
 
// ํ”„๋กœํ† ํƒ€์ž… ๋ฉ”์„œ๋“œ๋Š” ๋ชจ๋“  ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ณต์œ  (๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ)
console.log(yc.canPost === yh.canPost); // true โ€” ๋™์ผํ•œ ํ•จ์ˆ˜ ์ฐธ์กฐ!

๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์˜ ํ•ต์‹ฌ: ๋ฉ”์„œ๋“œ๋ฅผ prototype์— ์ •์˜ํ•˜๋ฉด ๋ชจ๋“  ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•˜๋‚˜์˜ ํ•จ์ˆ˜ ๋ฅผ ๊ณต์œ ํ•œ๋‹ค. ์ƒ์„ฑ์ž ์•ˆ์— ์ •์˜ํ•˜๋ฉด ์ธ์Šคํ„ด์Šค๋งˆ๋‹ค ์ƒˆ ํ•จ์ˆ˜๊ฐ€ ์ƒ์„ฑ๋œ๋‹ค.


๐Ÿญ 3. ์ƒ์† ๊ตฌํ˜„ ๋ฐฉ๋ฒ• 3๊ฐ€์ง€

์ƒ์„ฑ์ž ํ•จ์ˆ˜ + prototype

๋ณธ๊ฒฉ์ ์ธ ํด๋ž˜์Šค ๋ฌธ๋ฒ•์ด ๋“ฑ์žฅํ•˜๊ธฐ ์ „, ์„ ๋ฐฐ ๊ฐœ๋ฐœ์ž๋“ค์ด ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์„ ์ง์ ‘ ์—ฐ๊ฒฐํ•˜๋ฉฐ ์ƒ์†์„ ๊ตฌํ˜„ํ•˜๋˜ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

// ๊ธฐ๋ฐ˜ ์ƒ์„ฑ์ž
function User(name, email) {
  this.name = name;
  this.email = email;
}
User.prototype.login = function () {
  console.log(`${this.name} ๋กœ๊ทธ์ธ`);
};
 
// AdminUser๊ฐ€ User๋ฅผ ์ƒ์†
function AdminUser(name, email, permissions) {
  User.call(this, name, email); // ๋ถ€๋ชจ ์ƒ์„ฑ์ž ํ˜ธ์ถœ (this ๋ฐ”์ธ๋”ฉ ์ด์ „)
  this.permissions = permissions;
}
 
// ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ ์—ฐ๊ฒฐ
AdminUser.prototype = Object.create(User.prototype);
AdminUser.prototype.constructor = AdminUser; // constructor ๋ณต๊ตฌ
 
AdminUser.prototype.manage = function () {
  console.log(`${this.name}์ด ๊ด€๋ฆฌ์ž ๊ถŒํ•œ์œผ๋กœ ๊ด€๋ฆฌ ์ค‘`);
};
 
const admin = new AdminUser("์˜ํ˜ธ", "yh@example.com", ["delete", "ban"]);
admin.login();  // "์˜ํ˜ธ ๋กœ๊ทธ์ธ" โ€” User.prototype ๋ฉ”์„œ๋“œ
admin.manage(); // "์˜ํ˜ธ์ด ๊ด€๋ฆฌ์ž ๊ถŒํ•œ์œผ๋กœ ๊ด€๋ฆฌ ์ค‘" โ€” AdminUser.prototype ๋ฉ”์„œ๋“œ
 
// ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ:
// admin โ†’ AdminUser.prototype โ†’ User.prototype โ†’ Object.prototype โ†’ null

Object.create

๊ฐ€์žฅ ์ˆœ์ˆ˜ํ•˜๊ฒŒ "์ด ๊ฐ์ฒด๋ฅผ ๋ถ€๋ชจ๋กœ ์‚ผ์•„์ค˜"๋ผ๊ณ  ๋ช…์‹œํ•˜๋ฉฐ ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.

const userMethods = {
  login() {
    console.log(`${this.name} ๋กœ๊ทธ์ธ`);
  },
  logout() {
    console.log(`${this.name} ๋กœ๊ทธ์•„์›ƒ`);
  },
};
 
// userMethods๋ฅผ ํ”„๋กœํ† ํƒ€์ž…์œผ๋กœ ๊ฐ€์ง€๋Š” ์ƒˆ ๊ฐ์ฒด ์ƒ์„ฑ
const yc = Object.create(userMethods);
yc.name = "์˜์ฒ ";
yc.email = "yc@example.com";
 
yc.login();  // "์˜์ฒ  ๋กœ๊ทธ์ธ" โ€” ํ”„๋กœํ† ํƒ€์ž… ๋ฉ”์„œ๋“œ
 
// ๊ด€๋ฆฌ์ž โ€” userMethods๋ฅผ ์ƒ์†ํ•˜๋ฉด์„œ ์ถ”๊ฐ€ ๋ฉ”์„œ๋“œ ๋ณด์œ 
const adminMethods = Object.create(userMethods);
adminMethods.manage = function () {
  console.log(`${this.name}์ด ๊ด€๋ฆฌ ์ค‘`);
};
 
const yh = Object.create(adminMethods);
yh.name = "์˜ํ˜ธ";
yh.login();  // "์˜ํ˜ธ ๋กœ๊ทธ์ธ" โ€” userMethods ์ฒด์ธ์„ ํ†ตํ•ด
yh.manage(); // "์˜ํ˜ธ์ด ๊ด€๋ฆฌ ์ค‘"
 
// ์ฒด์ธ: yh โ†’ adminMethods โ†’ userMethods โ†’ Object.prototype โ†’ null

class (ES6+)

"๋‚ด๋ถ€ ๋™์ž‘์€ ํ”„๋กœํ† ํƒ€์ž…์ด๋ž‘ ์™„์ „ํžˆ ๊ฐ™์•„์š”. ๋‹จ์ง€ ๋ฌธ๋ฒ•์ด ๋” ์ฝ๊ธฐ ์ข‹์„ ๋ฟ์ด์—์š”." ์˜ํ˜ธ ๋ฆฌ๋“œ ๋‹˜์˜ ์กฐ์–ธ์„ ๋ฐ˜์˜ํ•ด ์˜์ฒ ์ด๊ฐ€ ํ˜„๋Œ€์ ์ธ ํด๋ž˜์Šค ๋ฌธ๋ฒ•์œผ๋กœ ๋ฆฌํŒฉํ† ๋งํ•œ ๊ฒฐ๊ณผ๋ฌผ์ž…๋‹ˆ๋‹ค.

// โœ… ํ˜„๋Œ€์ ์ด๊ณ  ๊ถŒ์žฅ๋˜๋Š” ๋ฐฉ๋ฒ•
 
class User {
  // constructor ๋‚ด๋ถ€ = ์ธ์Šคํ„ด์Šค ์ง์† ์†์„ฑ
  constructor(name, email) {
    this.name = name;
    this.email = email;
  }
 
  // ํด๋ž˜์Šค ๋ณธ๋ฌธ์˜ ๋ฉ”์„œ๋“œ = User.prototype์— ์ •์˜๋จ
  login() {
    console.log(`${this.name} ๋กœ๊ทธ์ธ`);
  }
 
  // static = User ์ž์ฒด์˜ ๋ฉ”์„œ๋“œ (์ธ์Šคํ„ด์Šค์—์„œ ํ˜ธ์ถœ ๋ถˆ๊ฐ€)
  static createGuest() {
    return new User("๊ฒŒ์ŠคํŠธ", "guest@example.com");
  }
}
 
class AdminUser extends User {
  constructor(name, email, permissions) {
    super(name, email); // ๋ถ€๋ชจ constructor ํ˜ธ์ถœ (ํ•„์ˆ˜!)
    this.permissions = permissions;
  }
 
  manage() {
    console.log(`${this.name}์ด ๊ด€๋ฆฌ ์ค‘`);
  }
 
  // ๋ถ€๋ชจ ๋ฉ”์„œ๋“œ ์˜ค๋ฒ„๋ผ์ด๋“œ
  login() {
    super.login(); // ๋ถ€๋ชจ login ํ˜ธ์ถœ
    console.log("(๊ด€๋ฆฌ์ž ๊ถŒํ•œ์œผ๋กœ ์ ‘์†)");
  }
}
 
const admin = new AdminUser("์˜ํ˜ธ", "yh@example.com", ["delete"]);
admin.login();
// "์˜ํ˜ธ ๋กœ๊ทธ์ธ"
// "(๊ด€๋ฆฌ์ž ๊ถŒํ•œ์œผ๋กœ ์ ‘์†)"
 
// ๋‚ด๋ถ€์ ์œผ๋กœ ์—ฌ์ „ํžˆ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ!
console.log(Object.getPrototypeOf(AdminUser.prototype) === User.prototype); // true
console.log(admin instanceof User);      // true
console.log(admin instanceof AdminUser); // true

๐Ÿ” 4. ์‹ค๋ฌด์—์„œ ์•Œ์•„์•ผ ํ•  ํ”„๋กœํ† ํƒ€์ž… API

// hasOwnProperty โ€” ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ ์ œ์™ธ, ์ง์ ‘ ์†์„ฑ๋งŒ ํ™•์ธ
const user = { name: "์˜์ฒ " };
user.hasOwnProperty("name");     // true โ€” ์ง์ ‘ ์†์„ฑ
user.hasOwnProperty("toString"); // false โ€” Object.prototype์— ์žˆ์Œ
 
// ๊ถŒ์žฅ: Object.hasOwn (ES2022, hasOwnProperty๋ณด๋‹ค ์•ˆ์ „)
Object.hasOwn(user, "name");     // true
 
// instanceof โ€” ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์— ํŠน์ • prototype์ด ์žˆ๋Š”์ง€ ํ™•์ธ
const admin = new AdminUser("์˜ํ˜ธ", "yh@example.com", []);
admin instanceof AdminUser; // true
admin instanceof User;      // true โ€” ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์— User.prototype ์žˆ์Œ
admin instanceof Array;     // false
 
// Object.getPrototypeOf โ€” ํ”„๋กœํ† ํƒ€์ž… ์ ‘๊ทผ (๊ถŒ์žฅ)
Object.getPrototypeOf(admin) === AdminUser.prototype; // true
 
// Object.keys vs for...in
const post = Object.create({ type: "post" }); // type์€ ํ”„๋กœํ† ํƒ€์ž…
post.title = "ํด๋กœ์ €";
post.author = "์˜์ฒ ";
 
Object.keys(post);   // ["title", "author"] โ€” ์ง์ ‘ ์†์„ฑ๋งŒ
for (const key in post) console.log(key); // title, author, type โ€” ์ฒด์ธ ํฌํ•จ!
// โ†’ for...in ๋ฃจํ”„์—์„œ hasOwnProperty ์ฒดํฌ๊ฐ€ ํ•„์š”ํ•œ ์ด์œ 

โš ๏ธ 5. ํ”„๋กœํ† ํƒ€์ž… ์•ˆํ‹ฐํŒจํ„ด

์˜ํ˜ธ ๋ฆฌ๋“œ ๋‹˜์ด ์˜คํ”ˆ์†Œ์Šค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ถ„์„ํ•˜๋ฉฐ ํŒ€์›๋“ค์—๊ฒŒ ์ ˆ๋Œ€๋กœ ๋”ฐ๋ผ ํ•˜์ง€ ๋ง๋ผ๊ณ  ๊ฐ•์กฐํ•œ ์‚ฌ๋ก€๋“ค์ž…๋‹ˆ๋‹ค. "ํŽธ๋ฆฌํ•จ ๋’ค์— ์ˆจ์€ ์œ„ํ—˜์„ ๋ณผ ์ค„ ์•Œ์•„์•ผ ํ•œ๋‹ค"๋Š” ์˜ํ˜ธ ๋‹˜์˜ ๋ง์„ ๊ธฐ์–ตํ•˜๋ฉฐ ์‚ดํŽด๋ณด์„ธ์š”.

// โŒ ์ ˆ๋Œ€ ํ•˜๋ฉด ์•ˆ ๋˜๋Š” ๊ฒƒ: ๋‚ด์žฅ ํ”„๋กœํ† ํƒ€์ž… ์ˆ˜์ • (Monkey Patching)
Array.prototype.sum = function () {
  return this.reduce((acc, val) => acc + val, 0);
};
[1, 2, 3].sum(); // 3 โ€” ๋™์ž‘ํ•˜์ง€๋งŒ...
 
// ์ด ์ฝ”๋“œ๊ฐ€ ์™œ ์œ„ํ—˜ํ•œ๊ฐ€?
// 1. ๋‹ค๋ฅธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ๋˜‘๊ฐ™์€ ์ด๋ฆ„์œผ๋กœ sum์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค๋ฉด โ†’ ์˜ˆ๊ธฐ์น˜ ๋ชปํ•œ ์ถฉ๋Œ
// 2. ๋ฏธ๋ž˜์˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ‘œ์ค€์— Array.prototype.sum์ด ์ƒ๊ธด๋‹ค๋ฉด โ†’ ํ‘œ์ค€ ๋™์ž‘์„ ๋ฐฉํ•ดํ•จ
// 3. ํŒ€์›๋“ค์ด sum์„ ํ‘œ์ค€ ๋ฉ”์„œ๋“œ๋กœ ์˜คํ•ดํ•˜์—ฌ ํ˜ผ๋ž€์„ ์คŒ
 
// โœ… ๋Œ€์‹  ์œ ํ‹ธ ํ•จ์ˆ˜๋กœ ๋ถ„๋ฆฌ
const arrayUtils = {
  sum(arr) {
    return arr.reduce((acc, val) => acc + val, 0);
  },
};
arrayUtils.sum([1, 2, 3]); // 3 โœ…
 
// โŒ __proto__ ์ง์ ‘ ์ˆ˜์ • โ€” ์„ฑ๋Šฅ ์ €ํ•˜ ๋ฐ ์˜ˆ์ธก ๋ถˆ๊ฐ€
const obj = {};
obj.__proto__ = { greeting: "hello" }; // JS ์—”์ง„์ด ๊ฐ์ฒด ํ˜•ํƒœ๋ฅผ ์žฌ๊ตฌ์„ฑ
 
// โœ… Object.create ๋˜๋Š” Object.setPrototypeOf ์‚ฌ์šฉ (๊ทธ๋‚˜๋งˆ ๋‚ซ์ง€๋งŒ ์‹ ์ค‘ํ•˜๊ฒŒ)
const proto = { greeting: "hello" };
const obj2 = Object.create(proto);

๐Ÿ“ ๋งˆ๋ฌด๋ฆฌ ํ€ด์ฆˆ

Q1. ์•„๋ž˜ ์ฝ”๋“œ์—์„œ yc.canPost()๊ฐ€ ์ •์ƒ ๋™์ž‘ํ•˜๋Š” ์ด์œ ๋ฅผ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์œผ๋กœ ์„ค๋ช…ํ•˜๋ผ.

function User(name) {
  this.name = name;
}
User.prototype.canPost = function () { return true; };
 
const yc = new User("์˜์ฒ ");
console.log(yc.canPost()); // true

โœ… ์ •๋‹ต: yc ์ธ์Šคํ„ด์Šค์—๋Š” canPost๊ฐ€ ์—†์ง€๋งŒ, [[Prototype]]์ธ User.prototype์—์„œ ๋ฐœ๊ฒฌ๋˜์–ด ์‹คํ–‰๋œ๋‹ค.

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค:

  • new User("์˜์ฒ ") ์‹คํ–‰ ์‹œ, yc.[[Prototype]] = User.prototype์œผ๋กœ ์—ฐ๊ฒฐ๋œ๋‹ค.
  • yc.canPost ์ ‘๊ทผ ์‹œ: โ‘  yc ์ง์† โ†’ ์—†์Œ โ‘ก User.prototype โ†’ canPost ๋ฐœ๊ฒฌ โœ…
  • ์ด ๊ณผ์ •์ด ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ ํƒ์ƒ‰ ์ด๋‹ค. ๋ฐœ๊ฒฌ๋  ๋•Œ๊นŒ์ง€ ์ฒด์ธ์„ ํƒ€๊ณ  ์˜ฌ๋ผ๊ฐ€๋ฉฐ, null์— ๋„๋‹ฌํ•˜๋ฉด undefined๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ๐Ÿ“Œ ํ•ต์‹ฌ ๊ธฐ์–ต๋ฒ•: "๋‚ด ์ฃผ๋จธ๋‹ˆ์— ์—†์œผ๋ฉด ๋ถ€๋ชจ๋‹˜์˜ ์ฃผ๋จธ๋‹ˆ๋ฅผ ์ฐพ์•„๋ณด์„ธ์š”. ๋ถ€๋ชจ๋‹˜๋„ ์—†์œผ๋ฉด ํ• ์•„๋ฒ„์ง€๊ป˜ ๋ฌผ์–ด๋ณด๋Š” ์‹์ด์ฃ . ์ด ์—ฌ์ •์ด ๋๋‚˜๋Š” ์ง€์ (null)๊นŒ์ง€ ๋ฐœ๊ฒฌ๋˜์ง€ ์•Š๋Š”๋‹ค๋ฉด, ๊ทธ๋•Œ์„œ์•ผ undefined๋ฅผ ๋ฐ›๊ฒŒ ๋ฉ๋‹ˆ๋‹ค."

Q2. ๋ฉ”์„œ๋“œ๋ฅผ prototype์— ์ •์˜ํ•˜๋Š” ๊ฒƒ๊ณผ ์ƒ์„ฑ์ž ํ•จ์ˆ˜ ๋‚ด๋ถ€์— ์ •์˜ํ•˜๋Š” ๊ฒƒ์˜ ์ฐจ์ด๋Š”?

โœ… ์ •๋‹ต: prototype์— ์ •์˜ํ•˜๋ฉด ๋ชจ๋“  ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•˜๋‚˜์˜ ํ•จ์ˆ˜๋ฅผ ๊ณต์œ  (๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ), ์ƒ์„ฑ์ž ๋‚ด๋ถ€์— ์ •์˜ํ•˜๋ฉด ์ธ์Šคํ„ด์Šค๋งˆ๋‹ค ์ƒˆ๋กœ์šด ํ•จ์ˆ˜ ์ƒ์„ฑ (๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„).

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค:

// โŒ ์ƒ์„ฑ์ž ๋‚ด๋ถ€ โ€” ์ธ์Šคํ„ด์Šค๋งˆ๋‹ค ์ƒˆ ํ•จ์ˆ˜ ์ƒ์„ฑ (100๊ฐœ ์ธ์Šคํ„ด์Šค = ํ•จ์ˆ˜ 100๊ฐœ)
function User(name) {
  this.name = name;
  this.greet = function() { console.log(this.name); }; // ๋งค๋ฒˆ ์ƒˆ ํ•จ์ˆ˜
}
 
// โœ… prototype โ€” ๋ชจ๋“  ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ณต์œ  (100๊ฐœ ์ธ์Šคํ„ด์Šค = ํ•จ์ˆ˜ 1๊ฐœ)
function User(name) {
  this.name = name;
}
User.prototype.greet = function() { console.log(this.name); };
  • ์ธ์Šคํ„ด์Šค๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก prototype ๋ฐฉ์‹์˜ ๋ฉ”๋ชจ๋ฆฌ ํšจ์œจ์ด ์••๋„์ ์ด๋‹ค.
  • class ๋ฌธ๋ฒ•์˜ ๋ฉ”์„œ๋“œ๋Š” ์ž๋™์œผ๋กœ prototype์— ์ •์˜๋œ๋‹ค.
  • ๐Ÿ“Œ ํ•ต์‹ฌ ๊ธฐ์–ต๋ฒ•: "์ธ์Šคํ„ด์Šค๋งˆ๋‹ค ๋‹ฌ๋ผ์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์ƒ์„ฑ์ž์—, ๊ณตํ†ต์œผ๋กœ ์“ฐ์ด๋Š” ๊ฒƒ์€ prototype์—."

Q3. ์˜์ฒ ์ด์˜ ํ…Œ์ŠคํŠธ ํƒ€์ž„ โ€” ์•„ํ‚คํ…์ฒ˜ ์„ค๊ณ„

์˜์ˆ˜ PM์ด ์š”๊ตฌ์‚ฌํ•ญ์„ ์ „๋‹ฌํ–ˆ๋‹ค: "User, AdminUser, GuestUser ์„ธ ์ข…๋ฅ˜์˜ ์œ ์ €๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•ด์š”. ๊ณตํ†ต ๊ธฐ๋Šฅ(login, logout)์€ ์ค‘๋ณต ์—†์ด ์จ์•ผ ํ•˜๊ณ , AdminUser๋Š” manage ๊ธฐ๋Šฅ, GuestUser๋Š” ์ œํ•œ์  ๊ธฐ๋Šฅ๋งŒ ๊ฐ–๋„๋ก ์„ค๊ณ„ํ•ด์ฃผ์„ธ์š”."
์˜์ฒ ์ด๊ฐ€ ES6 class๋ฅผ ์‚ฌ์šฉํ•ด ์„ค๊ณ„ํ–ˆ๋Š”๋ฐ, ์–ด๋–ค ๊ตฌ์กฐ๊ฐ€ ์˜ฌ๋ฐ”๋ฅธ๊ฐ€?

โœ… ์ •๋‹ต: User ํด๋ž˜์Šค์— ๊ณตํ†ต ๋ฉ”์„œ๋“œ๋ฅผ ๋‘๊ณ , AdminUser extends User, GuestUser extends User๋กœ ์ƒ์† ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ ๋‹ค.

๐Ÿ’ก ์ƒ์„ธ ํ•ด์„ค:

class User {
  constructor(name, email) {
    this.name = name;
    this.email = email;
  }
  login() { console.log(`${this.name} ๋กœ๊ทธ์ธ`); }
  logout() { console.log(`${this.name} ๋กœ๊ทธ์•„์›ƒ`); }
}
 
class AdminUser extends User {
  constructor(name, email, permissions) {
    super(name, email);
    this.permissions = permissions;
  }
  manage() { console.log(`${this.name} ๊ด€๋ฆฌ ์ค‘`); }
}
 
class GuestUser extends User {
  constructor() {
    super("๊ฒŒ์ŠคํŠธ", "guest@example.com");
  }
  login() { // ์˜ค๋ฒ„๋ผ์ด๋“œ โ€” ์ œํ•œ๋œ ๊ถŒํ•œ ๋ฉ”์‹œ์ง€
    console.log("๊ฒŒ์ŠคํŠธ๋กœ ์ œํ•œ์  ์ ‘๊ทผํ•ฉ๋‹ˆ๋‹ค.");
  }
}
  • login/logout์€ User.prototype์— ํ•œ ๋ฒˆ๋งŒ ์ •์˜ โ†’ ์ฝ”๋“œ ์ค‘๋ณต ์ œ๊ฑฐ
  • AdminUser, GuestUser๋Š” ํ•„์š”ํ•œ ๊ฒƒ๋งŒ ์ถ”๊ฐ€/์˜ค๋ฒ„๋ผ์ด๋“œ
  • ๐Ÿ“Œ ํ•ต์‹ฌ ๊ธฐ์–ต๋ฒ•: "๊ณตํ†ต์€ ์œ„๋กœ(๋ถ€๋ชจ), ํŠน์ˆ˜๋Š” ์•„๋ž˜๋กœ(์ž์‹). ์ค‘๋ณต ์ฝ”๋“œ๊ฐ€ ๋ณด์ด๋ฉด ๋ถ€๋ชจ ํด๋ž˜์Šค๋กœ ๋Œ์–ด์˜ฌ๋ ค๋ผ."

๐Ÿฃ ์˜์ฒ ์ด์˜ ํ‡ด๊ทผ ์ผ๊ธฐ

์˜ค๋Š˜์€ ์ง„์งœ ๋‘๋‡Œ๊ฐ€ ๊ณผ์—ด๋œ ๊ฒƒ ๊ฐ™๋‹ค. ํ”„๋กœํ† ํƒ€์ž…์ด ๊ทธ๋ƒฅ "๋ญ”๊ฐ€ ๋ถ€๋ชจ ๊ฐœ๋…" ์ •๋„๋กœ ์•Œ์•˜๋Š”๋ฐ, ์‹ค์ œ๋กœ [[Prototype]] ์Šฌ๋กฏ์ด ๊ฐ์ฒด๋ผ๋ฆฌ ์—ฐ๊ฒฐ๋˜๋Š” ๊ตฌ์กฐ๋ผ๋Š” ๊ฒŒ ์‹ ๊ธฐํ–ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‚ด๊ฐ€ ๋งค์ผ ์“ฐ๋˜ arr.map()์ด ์‚ฌ์‹ค Array.prototype.map์„ ์ฒด์ธ์œผ๋กœ ์ฐพ์•„๊ฐ€๋Š” ๊ฑฐ์˜€๋‹ค๋‹ˆ...

์˜ํ˜ธ ๋‹˜์ด "class๋Š” ์˜ท๋งŒ ๋ฐ”๊ฟ”์ž…์€ ํ”„๋กœํ† ํƒ€์ž…"์ด๋ผ๊ณ  ํ–ˆ๋Š”๋ฐ, ์ฒ˜์Œ์—” ๋ฌด์Šจ ๋ง์ธ์ง€ ๋ชฐ๋ž๋‹ค. ์ง€๊ธˆ์€ ์™„์ „ํžˆ ์ดํ•ด๊ฐ€ ๋œ๋‹ค. ์†์ด ๋ณด์ด๋‹ˆ๊นŒ class๊ฐ€ ๋” ๋ฏฟ์Œ์ง์Šค๋Ÿฝ๊ฒŒ ๋А๊ปด์ง„๋‹ค.

๐Ÿ’ก ์˜ค๋Š˜์˜ ๊ตํ›ˆ: "์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ์ƒ์†์€ ๋ฐ์ดํ„ฐ๋ฅผ ํ†ต์งธ๋กœ ๋ณต์‚ฌํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ 'ํ†ต๋กœ๋กœ ์—ฐ๊ฒฐ'ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ์ธ์Šคํ„ด์Šค๋Š” ๋ชจ๋“  ๋ฌด๊ธฐ๋ฅผ ์ง์ ‘ ๋“ค๊ณ  ๋‹ค๋‹ˆ๋Š” ๋Œ€์‹ , ํ•„์š”ํ•  ๋•Œ๋งˆ๋‹ค ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ์ด๋ผ๋Š” ์ฐฝ๊ณ ์—์„œ ๋นŒ๋ ค ์”๋‹ˆ๋‹ค."

์˜ค๋Š˜ ๊ณต๋ถ€ ์–‘์ด ๋งŽ์•„์„œ ์ข€ ์ง€์ณค๋‹ค. ํ‡ด๊ทผํ•˜๊ณ  ์น˜ํ‚จ ์‹œ์ผœ์„œ ์‰ฌ์–ด์•ผ์ง€. ๋‚ด์ผ์€ ๋น„๋™๊ธฐ Promise ํŽธ์ธ๋ฐ, ์ด๊ฒƒ๋„ ๋งŒ๋งŒ์น˜ ์•Š์„ ๊ฒƒ ๊ฐ™๋‹ค. ๊ทธ๋ž˜๋„ ์˜ค๋Š˜์ฒ˜๋Ÿผ ํ•˜๋ฉด ์–ด๋–ป๊ฒŒ๋“  ๋˜๊ฒ ์ง€. ๋‚ด์ผ์˜ ๋‚˜, ํŒŒ์ดํŒ….


๐Ÿ”— ๋” ์•Œ์•„๋ณด๊ธฐ