1905 ๋‹จ์–ด
10 ๋ถ„
๐Ÿงฉ Javascript์˜ Object

๐Ÿงฉ Javascript์˜ Object#

์ตœ๊ทผ ๊นŠ์€ ๋ณต์‚ฌ๋ฅผ ์œ„ํ•œ ์œ ํ‹ธ๋ฆฌํ‹ฐ ํ•จ์ˆ˜๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋ผ๋Š” ๊ณผ์ œ๋ฅผ ๋ฐ›์•˜๋‹ค.

๋‹จ์ˆœํ•œ ๊ฐ์ฒด๋งŒ์ด ์•„๋‹ˆ๋ผ Array, Map, Set์€ ๋ฌผ๋ก  ์ปค์Šคํ…€ ๊ฐ์ฒด๊นŒ์ง€ ๋ชจ๋‘ ์ œ๋Œ€๋กœ ๋ณต์‚ฌํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ–ˆ๋‹ค. ์ฒ˜์Œ์—” ํ‚ค-๊ฐ’ ์Œ์„ ์žฌ๊ท€์ ์œผ๋กœ ์ƒˆ ๊ฐ์ฒด์— ๋ณต์‚ฌํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ํ•ด๊ฒฐํ•˜๋ ค ํ–ˆ์ง€๋งŒ, ๊ณง ๋‹ค์–‘ํ•œ ๊ฐ์ฒด ํƒ€์ž…์„ ์ •ํ™•ํžˆ ๋‹ค๋ฃจ๋ ค๋ฉด ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ Object, ์†์„ฑ ๊ตฌ์กฐ, ๊ทธ๋ฆฌ๊ณ  ํ”„๋กœํ† ํƒ€์ž… ์ฒด๊ณ„์— ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ํ•„์ˆ˜์ ์ด์—ˆ๋‹ค.

์ด ๊ณผ์ •์—์„œ ๋‚ด๊ฐ€ ๊ฐ์ฒด ์‹œ์Šคํ…œ์— ๋Œ€ํ•ด ์–ผ๋งˆ๋‚˜ ํ”ผ์ƒ์ ์œผ๋กœ ์•Œ๊ณ  ์žˆ์—ˆ๋Š”์ง€ ์‹ค๊ฐํ–ˆ๊ณ , ์ด๋ฅผ ๊ณ„๊ธฐ๋กœ ๊ด€๋ จ ๊ฐœ๋…์„ ๊นŠ์ด ์žˆ๊ฒŒ ํ•™์Šตํ•˜๊ณ  ์ •๋ฆฌํ•ด๋ณด๊ฒŒ ๋˜์—ˆ๋‹ค.


1) Object๋ž€?#

๊ฐ์ฒด๋Š” **๋ฐ์ดํ„ฐ์™€ ๊ธฐ๋Šฅ(๋ฉ”์„œ๋“œ)**๋ฅผ ํ‚คโ€“๊ฐ’ ์Œ์œผ๋กœ ์ €์žฅํ•˜๋Š” ๊ตฌ์กฐ.

const person = {
name: 'MyName',
age: 25,
greeting() {
console.log("Hello, my name is", this.name);
}
};
  • name, age๋Š” ์†์„ฑ(property), greeting์€ ๋ฉ”์„œ๋“œ(method).

2) ๊ฐ์ฒด ์ƒ์„ฑ ๋ฐฉ๋ฒ•#

โœ… ๋ฆฌํ„ฐ๋Ÿด#

const obj = { key: 'value', number: 12345 };

โœ… ์ƒ์„ฑ์ž & Object.create#

const obj = new Object();
obj.key = 'value';
obj.number = 12345;
// ์›๋ณธ์˜ ํ”„๋กœํ† ํƒ€์ž…/๋””์Šคํฌ๋ฆฝํ„ฐ๊นŒ์ง€ ์œ ์ง€ ๋ณต์‚ฌ
const clone = Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
);
  • Object.create(proto, descriptors): ์ง€์ •ํ•œ ํ”„๋กœํ† ํƒ€์ž…๊ณผ ๋””์Šคํฌ๋ฆฝํ„ฐ๋กœ ์ƒˆ ๊ฐ์ฒด ์ƒ์„ฑ.

โœ… ํด๋ž˜์Šค#

class Person {
constructor(name, age) { this.name = name; this.age = age; }
}
const personA = new Person("a", 27);

โœ… Getter/Setter#

const person = {
firstName: 'value',
lastName: '12345',
get fullName() { return `${this.firstName} ${this.lastName}`; },
set fullName(name) { [this.firstName, this.lastName] = name.split(" "); }
};

3) ์†์„ฑ ์ ‘๊ทผ#

const a = new Person("a", 27);
console.log(a.name); // ์  ํ‘œ๊ธฐ๋ฒ•
console.log(a['name']); // ๋Œ€๊ด„ํ˜ธ ํ‘œ๊ธฐ๋ฒ•

4) ์†์„ฑ ์ถ”๊ฐ€/์ˆ˜์ •/์‚ญ์ œ#

const p = new Person("a", 27);
p.job = 'Developer'; // ๋“ฑ๋ก
p.age = 26; // ๋ณ€๊ฒฝ
delete p.job; // ์‚ญ์ œ

Object.defineProperty / defineProperties#

const p2 = new Person("a", 27);
Object.defineProperties(p2, {
job: { value: 'Developer', writable: true, configurable: true, enumerable: true }
});
Object.defineProperty(p2, "favoriteFood", {
value: 'apple', writable: true, configurable: true, enumerable: true
});
  • ๋””์Šคํฌ๋ฆฝํ„ฐ๋กœ ์“ฐ๊ธฐ/์—ด๊ฑฐ/์žฌ์ •์˜ ๊ฐ€๋Šฅ ์—ฌ๋ถ€๋ฅผ ์ œ์–ด.
    • writable
    • configurable
    • enumerable

5) ๋ณ€๊ฒฝ ์ œ์•ฝ: freeze / seal (๏ผ‹preventExtensions)#

  • Object.freeze() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด๋ฅผ ๋™๊ฒฐํ•˜๊ฒŒ ๋˜๋ฉด ๋™๊ฒฐ๋œ ๊ฐ์ฒด๋Š” ๋” ์ด์ƒ ์ƒˆ๋กœ์šด ์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•œ๋‹ค.
    • ์กด์žฌํ•˜๋Š” ์†์„ฑ์˜ ๋ถˆ๋ณ€์„ฑ, ์„ค์ • ๊ฐ€๋Šฅ์„ฑ, ์ž‘์„ฑ ๊ฐ€๋Šฅ์„ฑ์ด ๋ณ€๊ฒฝ๋˜๋Š” ๊ฒƒ ์—ญ์‹œ ๋ฐฉ์ง€๋˜๋ฉฐ, ์กด์žฌ ์†์„ฑ์˜ ๊ฐ’์„ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ๋„ ๋ฐฉ์ง€ํ•œ๋‹ค.
  • Object.seal() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด๋ฅผ ๋ฐ€๋ด‰ํ•˜๊ฒŒ ๋˜๋ฉด ์ƒˆ๋กœ์šด ์†์„ฑ์˜ ์ถ”๊ฐ€๊ฐ€ ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฉฐ ํ˜„์žฌ ์กด์žฌํ•˜๋Š” ์†์„ฑ์„ ์„ค์ • ๋ถˆ๊ฐ€๋Šฅ ์ƒํƒœ๋กœ ๋งŒ๋“ค์–ด์ค€๋‹ค. ๋‹ค๋งŒ ์“ฐ๊ธฐ ๊ฐ€๋Šฅํ•œ ์†์„ฑ์— ๋Œ€ํ•œ ์†์„ฑ์˜ ๊ฐ’์€ ๋ฐ€๋ด‰ ํ›„์—๋„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์—์„œ Object.freeze() ๋ฉ”์„œ๋“œ์™€ ์ฐจ์ด๊ฐ€ ์žˆ๋‹ค.
  • ๋™๊ฒฐ/๋ฐ€๋ด‰ ์—ฌ๋ถ€๋Š” Object.isFrozen(), Object.isSealed() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
const f = Object.freeze(new Person("a", 25));
f.age = 27; // ๋ฌด์‹œ
console.log(Object.isFrozen(f), Object.isSealed(f)); // true, true
const s = Object.seal(new Person("a", 26));
s.age = 27; // ๊ฐ€๋Šฅ(์†์„ฑ writable์ด๋ฉด)
console.log(Object.isFrozen(s), Object.isSealed(s)); // false, true
๋ฉ”์„œ๋“œ์ƒˆ ์†์„ฑ ์ถ”๊ฐ€๊ธฐ์กด ์†์„ฑ ์‚ญ์ œ๊ฐ’ ๋ณ€๊ฒฝ(์“ฐ๊ธฐ)๋””์Šคํฌ๋ฆฝํ„ฐ ๋ณ€๊ฒฝ
Object.freezeโŒโŒโŒโŒ
Object.sealโŒโŒโœ… (writable์ผ ๋•Œ)์ผ๋ถ€ โŒ
Object.preventExtensionsโŒโœ…โœ…โœ…

6) ์†์„ฑ ๋ณด์œ  ํ™•์ธ: hasOwnProperty vs Object.hasOwn#

๊ฐ์ฒด๊ฐ€ ํŠน์ • ์†์„ฑ์„ ์ž์‹ ์˜ ์†์„ฑ์œผ๋กœ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”์ง€ ํ™•์ธํ•  ๋•Œ hasOwnproperty ๋ฉ”์„œ๋“œ๋‚˜ ES2022์— ์ƒˆ๋กœ ์ถ”๊ฐ€๋œ ์ •์  ๋ฉ”์„œ๋“œ์ธ Object.hasOwn()์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

class Person {
constructor(name, age) { this.name = name; this.age = age; }
greeting() { console.log("Hi", this.name); }
}
const p = new Person("person", 25);
p.sayHello = function() { console.log("Hello", this.name); };
console.log(p.hasOwnProperty("name")); // true
console.log(Object.hasOwn(p, "name")); // true
console.log(Object.hasOwn(p, "sayHello")); // true
console.log(Object.hasOwn(p, "greeting")); // false (ํ”„๋กœํ† ํƒ€์ž…์˜ ๋ฉ”์„œ๋“œ)
  • Object.hasOwn(obj, key)๋Š” ์•ˆ์ „ํ•œ ์ •์  ๋ฉ”์„œ๋“œ (์ธ์Šคํ„ด์Šค๊ฐ€ hasOwnProperty๋ฅผ ์˜ค๋ฒ„๋ผ์ด๋“œํ•ด๋„ ์•ˆ์ „).

๐Ÿงฌ ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ#

๐Ÿ”— ํ”„๋กœํ† ํƒ€์ž…

  • ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ ๋ชจ๋“  ๊ฐ์ฒด๋Š” ๋‚ด๋ถ€ [[Prototype]] ๋งํฌ๋ฅผ ๊ฐ€์ง„๋‹ค.
  • ์ด๋Ÿฌํ•œ ๊ตฌ์กฐ๋ฅผ ํ†ตํ•ด ๊ฐ์ฒด๋Š” ํด๋ž˜์Šค ๊ธฐ๋ฐ˜ ์–ธ์–ด์˜ ์ƒ์†์ฒ˜๋Ÿผ ๊ณตํ†ต ์†์„ฑ๊ณผ ๋ฉ”์„œ๋“œ๋ฅผ ์ƒ์†๋ฐ›๊ฑฐ๋‚˜ ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋ ‡๊ฒŒ ํ˜•์„ฑ๋œ ์ƒ์† ๊ตฌ์กฐ๋ฅผ **ํ”„๋กœํ† ํƒ€์ž… ์ฒด์ธ(Prototype Chain)**์ด๋ผ๊ณ  ํ•œ๋‹ค.
    • ์—†์œผ๋ฉด ์ž๊ธฐ ์ž์‹  โ†’ ํ”„๋กœํ† ํƒ€์ž… โ†’ โ€ฆ โ†’ Object.prototype โ†’ null๋กœ ํƒ์ƒ‰.
const arr = [1, 2, 3];
console.log(arr.toString()); // "1,2,3" (Array.prototype โ†’ Object.prototype)

๐Ÿ› ๏ธ ์ƒ์„ฑ์ž ํ•จ์ˆ˜์™€ ํ”„๋กœํ† ํƒ€์ž…

  • new ์—ฐ์‚ฐ์ž๋กœ ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๋ฉด ํ•ด๋‹น ๊ฐ์ฒด๋Š” ์ƒ์„ฑ์ž ํ•จ์ˆ˜์˜ prototype ์†์„ฑ์„ ์ž์‹ ์˜ [[Prototype]]์œผ๋กœ ์—ฐ๊ฒฐํ•œ๋‹ค.

    function Person(name) {
    this.name = name;
    }
    Person.prototype.sayHello = function () { console.log(`Hi, I'm ${this.name}`); };
    const p1 = new Person("Alice");
    console.log(p1.sayHello === Person.prototype.sayHello); // true

7) ์†์„ฑ ์„ค๋ช…์ž ์กฐํšŒ#

const p = new Person("a", 1);
Object.defineProperty(p, "job", {
value: 'Developer', writable: true, configurable: false, enumerable: true
});
console.log(Object.getOwnPropertyDescriptors(p));
  • getOwnPropertyDescriptors๋กœ ๋ชจ๋“  own ์†์„ฑ์˜ ๋””์Šคํฌ๋ฆฝํ„ฐ๋ฅผ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.

8) ๊ฐ์ฒด ์ˆœํšŒ#

forโ€ฆin

// for...in (์ž์‹  + ์ƒ์†๋œ enumerable ํฌํ•จ)
for (const k in p) console.log(k, p[k]);

Object.keys / values / entries

// own enumerable๋งŒ
Object.keys(p); // ํ‚ค ๋ฐฐ์—ด
Object.values(p); // ๊ฐ’ ๋ฐฐ์—ด
Object.entries(p); // [ํ‚ค,๊ฐ’] ๋ฐฐ์—ด (์ •์ˆ˜ ํ‚ค โ†’ ๋ฌธ์ž์—ด ํ‚ค ์‚ฝ์ž… ์ˆœ์„œ)

์—ด๊ฑฐ ๋ถˆ๊ฐ€๋Šฅ/์‹ฌ๋ณผ ํ‚ค#

const obj = { a: 1, b: 2 };
Object.defineProperty(obj, "c", { value: 3, enumerable: false });
console.log(Object.keys(obj)); // ['a','b']
console.log(Object.getOwnPropertyNames(obj));// ['a','b','c']
const sym = Symbol('id');
const o2 = { [sym]: 123, a: 1 };
console.log(Object.getOwnPropertySymbols(o2)); // [Symbol(id)]

9) Map โ†” Object ๋ณ€ํ™˜#

  • Object.entries()๋Š” forโ€ฆin๊ณผ ๊ฐ™์€ ์ˆœ์„œ๋กœ ์ฃผ์–ด์ง„ ๊ฐ์ฒด ์ž์ฒด์˜ enumerable ์†์„ฑ์„ ํ‚ค-๊ฐ’ ์Œ ํ˜•ํƒœ์˜ ๋ฐฐ์—ด๋กœ ๋ฐ˜ํ™˜ํ•œ๋‹ค. ์ด๋ฅผ ํ™œ์šฉํ•˜์—ฌ Map์œผ๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ฐ˜๋Œ€๋กœ Object.fromEntries๋Š” ํ‚ค-๊ฐ’ ์Œ ํ˜•ํƒœ์˜ ๋ฐฐ์—ด์„ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•ด์ฃผ๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค. ์ด๋ฅผ ํ†ตํ•ด Map์„ Object๋กœ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.
const object = { a: 1, b: 2, c: 3 };
const map = new Map(Object.entries(object)); // Object โ†’ Map
const fromMap = new Map([["a",1],["b",2]]);
const toObj = Object.fromEntries(fromMap); // Map โ†’ Object

10) ๊ฐ์ฒด ๋ณต์‚ฌ#

โœ… ์–•์€ ๋ณต์‚ฌ#

const copy1 = Object.assign({}, person);
const copy2 = { ...person };
// ํ”„๋กœํ† ํƒ€์ž…/๋น„์—ด๊ฑฐ ์†์„ฑ๊นŒ์ง€ ์‚ด๋ฆฌ๋Š” ์–•์€ ๋ณต์‚ฌ
const copyAll = Object.create(
Object.getPrototypeOf(person),
Object.getOwnPropertyDescriptors(person)
);
  • ์–•์€ ๋ณต์‚ฌ ์‹œ์—๋Š” ์ค‘์ฒฉ ๊ฐ์ฒด๋Š” ์ฐธ์กฐ ๊ณต์œ  โ†’ ๋‚ด๋ถ€ ๋ณ€๊ฒฝ์ด ์›๋ณธ์— ์ „ํŒŒํ•œ๋‹ค.
  • Object.assign()์„ ํ†ตํ•œ ๋ณต์‚ฌ๋Š” ๋ชฉํ‘œ ๊ฐ์ฒด๋กœ ์—ด๊ฑฐ ๊ฐ€๋Šฅํ•œ ์†์„ฑ๊ณผ ๊ฐ์ฒด์˜ ์†์„ฑ๋“ค๋งŒ ๋ณต์‚ฌํ•  ์ˆ˜ ์žˆ์ง€๋งŒ Object.getPrototypeOf, Object.getOwnPropertyDescriptors๋ฅผ ํ™œ์šฉํ•˜๋ฉด ์—ด๊ฑฐ ๋ถˆ๊ฐ€๋Šฅํ•œ ์†์„ฑ๋“ค๋„ ๋ณต์‚ฌํ•  ์ˆ˜ ์žˆ๋‹ค.

โœ… ๋ณ‘ํ•ฉ#

const m = Object.assign({}, obj1, obj2); // ๋’ค์— ์˜จ ํ‚ค๊ฐ€ ๋ฎ์–ด์”€
const m2 = { ...obj1, ...obj2 };
  • Spread ์—ฐ์‚ฐ์ž, Object.assign ๋ฉ”์„œ๋“œ๋ฅผ ํ™œ์šฉํ•ด ๋‹ค์ค‘ ๊ฐ์ฒด๋ฅผ ๋ณ‘ํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค๋งŒ ํ›„์ž์˜ ํ‚ค๊ฐ€ ๋ฎ์–ด์”Œ์›Œ์ง€๊ธฐ ๋•Œ๋ฌธ์— ๋ณ‘ํ•ฉ ์ˆœ์„œ์— ์œ ์˜ํ•ด์•ผ ํ•œ๋‹ค.

โœ… ๊นŠ์€ ๋ณต์‚ฌ (์ฃผ์˜: JSON ๊ธฐ๋ฐ˜ ํ•œ๊ณ„)#

const deepCopied = JSON.parse(JSON.stringify(person));
  • JSON.parse, JSON.stringify๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๊ฐ„๋‹จํ•˜๊ฒŒ ๊นŠ์€ ๋ณต์‚ฌ๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค๋งŒ JSON.parse, JSON.stringify๋ฅผ ์‚ฌ์šฉํ•œ ๊นŠ์€ ๋ณต์‚ฌ์—๋Š” ์—ฌ๋Ÿฌ๊ฐ€์ง€ ์ œ์•ฝ์‚ฌํ•ญ ๋ฐ ํ•œ๊ณ„๊ฐ€ ์กด์žฌํ•œ๋‹ค.
    • ๋ฌด์‹œ/๋ถˆ๊ฐ€: undefined, Function, Symbol, BigInt(์—๋Ÿฌ), Map/Set, Date/RegExp(์†์‹ค), ์ˆœํ™˜ ์ฐธ์กฐ(์—๋Ÿฌ).
    • ๋Œ€์•ˆ: ์ง์ ‘ ๊ตฌํ˜„ ๋˜๋Š” lodash.cloneDeep.

11) ๊ฐ์ฒด ๋น„๊ต#

๊ฐ์ฒด๋Š” ์ฐธ์กฐํ˜• ํƒ€์ž…์œผ๋กœ ๋‚ด๋ถ€ ์†์„ฑ์˜ ๊ฐ’์ด ๋™์ผํ•˜๋”๋ผ๋„ ์ฐธ์กฐ๊ฐ’์ด ๋‹ค๋ฅผ ๊ฒฝ์šฐ ์„œ๋กœ ๋‹ค๋ฅธ ๊ฐ์ฒด๋กœ ๊ฐ„์ฃผ๋œ๋‹ค.

const person = new Person("a", 26);
const copy = { ...person };
console.log(person === copy); // false (์ฐธ์กฐ ๋น„๊ต)

โ€œ๊ฐ’ ๋™๋“ฑโ€ ๊ฒ€์‚ฌ(๊ฐ„๋‹จ ์šฉ๋„)#

JSON.stringify(person) === JSON.stringify(copy);
  • ๊ฐ์ฒด ๋‚ด๋ถ€ ์†์„ฑ ๊ฐ’์ด ์‹ค์ œ๋กœ ๋™์ผํ•œ์ง€ ๋น„๊ตํ•  ๋•Œ, JSON.stringify๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹จ, JSON.stringify๋Š” ํ•จ์ˆ˜, undefined, Symbol ๋“ฑ์€ ๋ฌด์‹œํ•˜๊ณ , ์†์„ฑ ์ˆœ์„œ๊ฐ€ ๋‹ค๋ฅผ ๊ฒฝ์šฐ ๋‹ค๋ฅธ ๊ฒฝ์šฐ๊ฐ€ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋‹ค.
    • ํ•จ์ˆ˜/undefined/Symbol ๋ฌด์‹œ, ํ‚ค ์ˆœ์„œ ์˜ํ–ฅ ๊ฐ€๋Šฅ.
    • ์ •๊ตํ•œ ๋น„๊ต๋Š” lodash.isEqual ๋“ฑ ์‚ฌ์šฉ ๊ถŒ์žฅ.

๐Ÿ“š ์ฐธ๊ณ  ์ž๋ฃŒ#