ES6 객체 확장 (ES6 Object Extensions)

ES6 객체 확장 (ES6 Object Extensions)

자바스크립트(JavaScript)의 ES6(ECMAScript 2015)에서 객체를 다루는 기능이 크게 확장되었다. ES6 객체 확장은 객체 리터럴 문법 개선, 새로운 메서드 추가 등을 포함한다. ES6에서 도입된 객체 관련 기능과 그 사용법을 예제로 확인해보자.


기존 방식보다 간결하고 효율적인 객체 작업이 가능해졌다.


ES6 객체 확장이란 무엇인가?

ES6 객체 확장은 객체 정의와 조작을 더 편리하게 만드는 문법과 메서드를 제공한다. 대표적인 기능을 예제로 보자:

const name = "철수";
const obj = { name }; // 속성 축약
console.log(obj."name"); // "철수"

ES6 객체 확장 기능

ES6에서 추가된 주요 객체 기능을 예제로 확인해보자.


1. 속성 이름 축약

변수 이름과 속성 이름이 같을 때 축약 가능하다:

const age = 25;
const user = { age, "name": "영희" };
console.log(user); // { age: 25, name: "영희" }

2. 메서드 정의 축약

객체 내 함수 정의에서 function 키워드를 생략한다:

const obj2 = {
    sayHello() {
        return "안녕!";
    }
};
console.log(obj2.sayHello()); // "안녕!"

3. 계산된 속성 이름

속성 이름을 동적으로 정의한다:

const key = "id";
const obj3 = { [key]: 1 };
console.log(obj3."id"); // 1

4. Object.assign

여러 객체를 하나로 병합한다:

const obj4 = { "a": 1 };
const obj5 = { "b": 2 };
const merged = Object.assign({}, obj4, obj5);
console.log(merged); // { a: 1, b: 2 }

5. Object.is

두 값의 엄격한 비교를 수행한다:

console.log(Object.is(0, -0)); // false
console.log(Object.is(NaN, NaN)); // true

사용 사례

ES6 객체 확장을 활용한 예제를 확인해보자.


1. 동적 속성 생성

const prefix = "user";
const data = {
    [prefix + "Name"]: "철수",
    [prefix + "Age"]: 25
};
console.log(data); // { userName: "철수", userAge: 25 }

2. 객체 병합

const defaults = { "theme": "light" };
const settings = { "font": "Arial" };
const config = Object.assign({}, defaults, settings);
console.log(config); // { theme: "light", font: "Arial" }

3. 메서드 정의 간소화

const calculator = {
    value: 0,
    add(x) { this.value += x; },
    getValue() { return this.value; }
};
calculator.add(5);
console.log(calculator.getValue()); // 5

성능과 한계

장점

- 간결함: 코드가 더 짧고 읽기 쉽다.

- 유연성: 동적 속성 이름과 메서드 정의가 편리하다.


한계

- 호환성: ES6 미지원 환경에서는 변환(Babel 등)이 필요하다.

- 얕은 복사: Object.assign은 깊은 복사를 지원하지 않는다.

깊은 복사가 필요한 경우 JSON 방식이나 커스텀 함수를 고려할 수 있다.


마무리

ES6 객체 확장은 자바스크립트에서 객체를 다루는 방식을 개선한다. 새로운 문법과 메서드를 예제로 다뤘다.


객체 복사 (Object Cloning)

객체 복사 (Object Cloning)

자바스크립트(JavaScript)에서 객체를 다룰 때, 원본 객체를 유지하면서 동일한 데이터를 가진 새 객체를 만들고 싶을 때가 있다. 이런 경우에 객체 복사(Object Cloning)를 사용한다. 객체 복사의 개념, 얕은 복사와 깊은 복사의 차이, 구현 방법을 예제로 확인한다.


객체 복사는 원본 데이터를 안전하게 보존하거나 수정 가능한 복제본을 생성하는 데 사용된다. 다양한 방법이 존재한다.


객체 복사(Object Cloning)란 무엇인가?

객체 복사는 기존 객체의 속성을 새 객체로 옮기는 과정이다. 기본적으로 객체는 참조 타입이므로 단순 할당은 복사가 아닌 참조를 공유한다:

const obj = { "name": "철수" };
const ref = obj;
ref."name" = "영희";
console.log(obj."name"); // "영희" (원본 변경됨)

진정한 복사는 원본과 독립적인 새 객체를 만든다:

const obj2 = { "name": "철수" };
const copy = Object.assign({}, obj2);
copy."name" = "영희";
console.log(obj2."name"); // "철수" (원본 유지)

얕은 복사와 깊은 복사의 차이

객체 복사는 얕은 복사(Shallow Copy)와 깊은 복사(Deep Copy)로 나뉜다.


1. 얕은 복사

최상위 속성만 복사하며, 중첩 객체는 참조를 공유한다:

const original = { "info": { "age": 25 } };
const shallow = Object.assign({}, original);
shallow."info"."age" = 30;
console.log(original."info"."age"); // 30 (원본 변경됨)

2. 깊은 복사

모든 수준의 속성을 복사해 완전히 독립적인 객체를 만든다:

const original2 = { "info": { "age": 25 } };
const deep = JSON.parse(JSON.stringify(original2));
deep."info"."age" = 30;
console.log(original2."info"."age"); // 25 (원본 유지)

객체 복사 방법

객체 복사를 구현하는 여러 방법을 예제로 확인한다.


1. Object.assign

얕은 복사를 수행한다:

const obj3 = { "x": 1, "y": 2 };
const copy1 = Object.assign({}, obj3);
copy1."x" = 10;
console.log(obj3."x"); // 1

2. 스프레드 연산자(...)

ES6에서 도입된 문법으로 얕은 복사를 한다:

const obj4 = { "a": 1, "b": { "c": 2 } };
const copy2 = { ...obj4 };
copy2."b"."c" = 3;
console.log(obj4."b"."c"); // 3 (중첩 객체 참조 공유)

3. JSON 방식

깊은 복사를 위해 JSON 변환을 사용한다:

const obj5 = { "data": { "value": 100 } };
const copy3 = JSON.parse(JSON.stringify(obj5));
copy3."data"."value" = 200;
console.log(obj5."data"."value"); // 100

4. 커스텀 깊은 복사 함수

재귀적으로 깊은 복사를 구현한다:

function deepClone(obj) {
    if (obj === null || typeof obj !== "object") return obj;
    const copy = Array.isArray(obj) ? [] : {};
    for (let key in obj) {
        copy[key] = deepClone(obj[key]);
    }
    return copy;
}
const obj6 = { "nested": { "x": 1 } };
const copy4 = deepClone(obj6);
copy4."nested"."x" = 2;
console.log(obj6."nested"."x"); // 1

사용 사례

객체 복사를 활용한 예제를 확인한다.


1. 원본 데이터 보존

const config = { "setting": 1 };
const workingCopy = { ...config };
workingCopy."setting" = 2;
console.log(config."setting"); // 1

2. 중첩 객체 수정

const data = { "user": { "name": "철수" } };
const deepCopy = JSON.parse(JSON.stringify(data));
deepCopy."user"."name" = "영희";
console.log(data."user"."name"); // "철수"

성능과 한계

장점

- 독립성: 원본과 분리된 객체를 생성한다.

- 간편함: 얕은 복사는 간단한 코드로 가능하다.


한계

- JSON 방식: 함수나 undefined는 복사되지 않는다.

- 성능: 깊은 복사는 큰 객체에서 느릴 수 있다.

복사 대상에 따라 적절한 방법을 선택하는 것이 중요하다.


마무리

객체 복사(Object Cloning)는 자바스크립트에서 데이터를 다루는 방법 중 하나다. 얕은 복사와 깊은 복사의 차이, 구현 방법을 예제로 다뤘다.


getter와 setter (Getters and Setters)

getter와 setter (Getters and Setters)

자바스크립트(JavaScript)에서 객체의 속성을 다룰 때, 속성 값을 읽거나 설정하는 동작을 제어하고 싶을 때가 있다. 이런 경우에 gettersetter를 사용한다. getter와 setter의 개념, 정의 방법, 활용 사례를 예제로 확인한다.


getter는 속성 값을 가져오는 함수이고, setter는 속성 값을 설정하는 함수다. 이들은 Object.defineProperty나 객체 리터럴 문법으로 정의된다.


getter와 setter란 무엇인가?

getter와 setter는 객체 속성에 접근하거나 수정할 때 호출되는 특수 메서드다. 속성처럼 보이지만 내부적으로 함수로 동작한다. 기본적인 예제를 보자:

const obj = {
    _name: "철수",
    get name() {
        return this._name;
    },
    set name(value) {
        this._name = value;
    }
};
console.log(obj.name); // "철수"
obj.name = "영희";
console.log(obj.name); // "영희"

위 코드에서 get name은 속성 값을 반환하고, set name은 값을 설정한다.


getter와 setter의 정의 방법

getter와 setter는 두 가지 주요 방식으로 정의된다.


1. 객체 리터럴 문법

객체를 정의할 때 직접 getter와 setter를 추가한다:

const user = {
    _age: 25,
    get age() {
        return this._age;
    },
    set age(value) {
        if (value >= 0) this._age = value;
    }
};
user.age = 30;
console.log(user.age); // 30
user.age = -5; // 무시됨
console.log(user.age); // 30

2. Object.defineProperty

속성을 동적으로 정의한다:

const obj2 = { _data: 10 };
Object.defineProperty(obj2, "data", {
    get: function() {
        return this._data;
    },
    set: function(value) {
        this._data = value * 2;
    }
});
console.log(obj2.data); // 10
obj2.data = 5;
console.log(obj2.data); // 10

getter와 setter의 동작 방식

getter는 속성에 접근할 때 호출되고, setter는 속성에 값을 할당할 때 호출된다. 속성처럼 사용되지만 내부 로직을 포함할 수 있다.


예제를 통해 동작을 확인한다:

const person = {
    _firstName: "철수",
    _lastName: "김",
    get fullName() {
        return `${this._firstName} ${this._lastName}`;
    },
    set fullName(value) {
        const [first, last] = value.split(" ");
        this._firstName = first;
        this._lastName = last;
    }
};
console.log(person.fullName); // "철수 김"
person.fullName = "영희 박";
console.log(person.fullName); // "영희 박"

사용 사례

getter와 setter를 활용한 몇 가지 예제를 확인한다.


1. 데이터 유효성 검사

값을 설정할 때 조건을 확인한다:

const product = {
    _price: 1000,
    get price() {
        return this._price;
    },
    set price(value) {
        if (typeof value === "number" && value > 0) {
            this._price = value;
        }
    }
};
product.price = 2000;
console.log(product.price); // 2000
product.price = -500; // 무시됨
console.log(product.price); // 2000

2. 계산된 속성

동적으로 값을 계산한다:

const rectangle = {
    width: 5,
    height: 10,
    get area() {
        return this.width * this.height;
    }
};
console.log(rectangle.area); // 50
rectangle.width = 6;
console.log(rectangle.area); // 60

3. 속성 보호

내부 데이터를 간접적으로 관리한다:

const account = {
    _balance: 10000,
    get balance() {
        return this._balance;
    },
    set balance(value) {
        if (value >= 0) this._balance = value;
    }
};
console.log(account.balance); // 10000
account.balance = -1000; // 무시됨
console.log(account.balance); // 10000

4. 클래스에서의 사용

클래스에서도 getter와 setter를 정의할 수 있다:

class Person {
    _name;
    constructor(name) {
        this._name = name;
    }
    get name() {
        return this._name;
    }
    set name(value) {
        this._name = value;
    }
}
const p = new Person("철수");
console.log(p.name); // "철수"
p.name = "영희";
console.log(p.name); // "영희"

성능과 한계

장점

- 제어 가능: 속성 접근과 수정을 세밀하게 관리한다.

- 가독성: 속성처럼 보이는 문법으로 코드가 깔끔하다.


한계

- 오버헤드: 단순 속성보다 실행 속도가 느릴 수 있다.

- 재귀 호출 위험: getter와 setter 내부에서 동일한 속성을 호출하면 무한 루프가 발생한다.

재귀 호출 방지를 위해 내부 변수(예: _name)를 사용하는 습관을 들이는 것이 좋다.


마무리

getter와 setter는 자바스크립트에서 속성을 제어하는 도구다. 정의 방법과 활용 사례를 예제로 다뤘다.


속성 열거 (Property Enumeration)

속성 열거 (Property Enumeration)

자바스크립트(JavaScript)에서 객체의 속성을 다룰 때, 속성을 하나씩 확인하거나 목록으로 가져와야 할 상황이 있다. 이런 경우에 속성 열거(Property Enumeration)를 사용한다. 속성 열거의 개념, 사용 가능한 메서드, 활용 사례를 예제로 확인한다.


속성 열거는 for...in 루프, Object.keys, Object.values, Object.entries 등의 방법으로 구현된다. 각 방법의 특징과 사용법을 다룬다.


속성 열거(Property Enumeration)란 무엇인가?

속성 열거는 객체의 속성(Property)을 순회하거나 나열하는 과정을 의미한다. 객체의 키(Key), 값(Value), 또는 키-값 쌍을 가져와 작업할 수 있다. 기본적인 예제를 보자:

const obj = { "name": "철수", "age": 25 };
console.log(Object.keys(obj)); // ["name", "age"]

Object.keys는 객체의 열거 가능한 속성 키를 배열로 반환한다. 다른 방식도 있다:

for (let key in obj) {
    console.log(key); // "name", "age"
}

속성 열거 메서드와 동작 방식

속성 열거를 위한 여러 도구가 있다. 각 도구의 동작 방식을 예제로 확인한다.


1. for...in 루프

객체의 열거 가능한 속성을 순회한다. 프로토타입 체인의 속성까지 포함된다:

const parent = { "inherited": true };
const child = Object.create(parent);
child."own" = 1;
for (let key in child) {
    console.log(key); // "own", "inherited"
}

2. Object.keys

객체 자체의 열거 가능한 속성 키만 배열로 반환한다:

const obj2 = { "x": 10, "y": 20 };
const keys = Object.keys(obj2);
console.log(keys); // ["x", "y"]

3. Object.values

속성 값만 배열로 반환한다:

console.log(Object.values(obj2)); // [10, 20]

4. Object.entries

키-값 쌍을 배열로 반환한다:

console.log(Object.entries(obj2)); // [["x", 10], ["y", 20]]

for...in과 Object 메서드의 차이점

두 접근법의 차이를 정리한다.


1. 프로토타입 포함 여부

- for...in: 프로토타입 속성 포함.

- Object.keys/values/entries: 객체 자체의 속성만.

const proto = { "protoKey": true };
const obj3 = Object.create(proto);
obj3."ownKey" = false;
console.log(Object.keys(obj3)); // ["ownKey"]

2. 반환 형태

- for...in: 순회하며 직접 접근.

- Object 메서드: 배열로 반환.


사용 사례

속성 열거를 활용한 몇 가지 예제를 확인한다.


1. 객체 속성 출력

const user = { "name": "영희", "age": 22 };
Object.entries(user).forEach(([key, value]) => {
    console.log(`${key}: ${value}`);
}); // "name: 영희", "age: 22"

2. 필터링

특정 조건을 만족하는 속성만 추출한다:

const scores = { "math": 90, "english": 85, "science": 95 };
const highScores = Object.keys(scores).filter(key => scores[key] > 90);
console.log(highScores); // ["science"]

3. 객체 복사

const original = { "a": 1, "b": 2 };
const copy = {};
Object.keys(original).forEach(key => copy[key] = original[key]);
console.log(copy); // { a: 1, b: 2 }

4. 열거 불가능 속성 확인

Object.defineProperty로 열거 불가능한 속성을 설정한 경우:

const obj4 = {};
Object.defineProperty(obj4, "hidden", {
    value: 42,
    enumerable: false
});
obj4."visible" = 10;
console.log(Object.keys(obj4)); // ["visible"]

성능과 한계

장점

- 유연성: 다양한 방식으로 속성을 다룰 수 있다.

- 편리함: 배열 메서드와 조합 가능.


한계

- 프로토타입 주의: for...in 사용 시 필터링 필요.

- 열거 불가능 속성: 기본 메서드로는 접근 불가.

hasOwnProperty로 프로토타입 속성을 걸러내는 방법을 고려할 수 있다.


마무리

속성 열거(Property Enumeration)는 자바스크립트에서 객체를 다루는 방법 중 하나다. for...inObject 메서드의 차이와 활용 사례를 예제로 다뤘다.


객체 동결과 봉인 (Object Freeze and Seal)

객체 동결과 봉인 (Object Freeze and Seal)

자바스크립트(JavaScript)에서 객체를 다룰 때, 데이터를 보호하거나 의도치 않은 수정을 방지하고 싶을 때가 있다. 이때 객체 동결(Object Freeze)객체 봉인(Object Seal)이 유용하다. 이번 포스팅에서는 이 두 메서드의 정의, 동작 방식, 차이점, 그리고 실제 사용 사례를 예제를 통해 자세히 알아본다.


객체 동결과 봉인(Object Freeze and Seal)이란 무엇인가?

자바스크립트에서 객체는 기본적으로 수정이 가능하다. 속성을 추가하거나 삭제하고, 값을 변경할 수 있다. 하지만 때로는 객체를 '잠가서' 변경을 막고 싶을 때가 있다. Object.freezeObject.seal은 이런 상황에서 사용하는 객체 메서드다.


- Object.freeze: 객체를 완전히 동결시켜 속성 추가, 삭제, 값 변경을 모두 막는다.

- Object.seal: 객체를 봉인해 속성 추가와 삭제는 막지만, 기존 속성의 값은 변경할 수 있다.


간단한 예제를 보자:

const obj = { name: "철수" };
Object.freeze(obj);
obj.name = "영희"; // 변경 시도
console.log(obj.name); // "철수" (변경되지 않음)

위 코드에서 Object.freeze를 사용해 obj를 동결시켰기 때문에 name 속성 값이 바뀌지 않는다.


const obj2 = { age: 25 };
Object.seal(obj2);
obj2.age = 30; // 값 변경 가능
obj2.gender = "남"; // 속성 추가 시도
console.log(obj2); // { age: 30 } (속성 추가는 안 됨)

Object.seal은 값 변경은 허용하지만 새로운 속성 추가는 막는다.


Object.freeze와 Object.seal의 동작 방식

이 두 메서드는 객체의 속성 설명자(Property Descriptor)를 조작해 동작한다. 속성 설명자는 객체 속성의 특성을 정의하는 메타데이터인데, 이를 통해 속성이 쓰기 가능(writable)인지, 열거 가능(enumerable)인지 등을 제어할 수 있다.


Object.freeze는 모든 속성을 writable: false, configurable: false로 설정하고, 객체 자체도 확장 불가능하게 만든다. 반면 Object.sealconfigurable: false만 설정해 속성 추가/삭제를 막지만 값 변경은 허용한다.


예제로 확인해보자:

const obj3 = { x: 10 };
Object.freeze(obj3);
obj3.x = 20; // 값 변경 시도
delete obj3.x; // 삭제 시도
obj3.y = 30; // 추가 시도
console.log(obj3); // { x: 10 }

Object.freeze는 모든 변경을 차단한다.


const obj4 = { y: 15 };
Object.seal(obj4);
obj4.y = 25; // 값 변경
delete obj4.y; // 삭제 시도
obj4.z = 35; // 추가 시도
console.log(obj4); // { y: 25 }

Object.seal은 값 변경만 가능하다.


Object.freeze와 Object.seal의 차이점

이제 두 메서드의 차이를 명확히 정리해보자.


1. 값 변경 가능 여부

- Object.freeze: 값 변경 불가.

const frozen = { a: 1 };
Object.freeze(frozen);
frozen.a = 2;
console.log(frozen.a); // 1

- Object.seal: 값 변경 가능.

const sealed = { b: 2 };
Object.seal(sealed);
sealed.b = 3;
console.log(sealed.b); // 3

2. 속성 추가/삭제 가능 여부

- Object.freeze: 추가, 삭제 모두 불가.

- Object.seal: 추가, 삭제 모두 불가.


3. 동결/봉인 확인 방법

객체가 동결되었는지, 봉인되었는지 확인하려면 Object.isFrozenObject.isSealed를 사용한다:

const obj5 = { c: 5 };
Object.freeze(obj5);
console.log(Object.isFrozen(obj5)); // true
console.log(Object.isSealed(obj5)); // true (동결은 봉인을 포함)

const obj6 = { d: 6 };
Object.seal(obj6);
console.log(Object.isFrozen(obj6)); // false (값 변경 가능하므로)
console.log(Object.isSealed(obj6)); // true

사용 사례

이제 실무에서 어떻게 활용할 수 있는지 예제를 통해 알아보자.


1. 상수 객체 보호

설정값처럼 절대 바뀌지 않아야 하는 객체를 보호할 때 유용하다:

const config = {
    apiKey: "xyz123",
    endpoint: "https://api.example.com"
};
Object.freeze(config);
config.apiKey = "abc456"; // 시도
console.log(config.apiKey); // "xyz123"

2. 데이터 무결성 유지

함수에 전달된 객체가 수정되지 않도록 보장한다:

function processData(data) {
    const frozenData = Object.freeze(data);
    // frozenData 수정 시도 불가
    console.log(frozenData);
}
processData({ id: 1, value: "test" });

3. 일부 수정 허용

값은 변경하되 구조는 유지하고 싶을 때:

const user = { name: "철수", age: 20 };
Object.seal(user);
user.age = 21; // 나이 변경
user.gender = "남"; // 추가 시도
console.log(user); // { name: "철수", age: 21 }

4. 중첩 객체 다루기

freezeseal은 얕은(shallow) 동작만 한다. 중첩 객체는 별도로 처리해야 한다:

const nested = {
    info: { name: "영희" }
};
Object.freeze(nested);
nested.info.name = "민수"; // 가능!
console.log(nested.info.name); // "민수"

이를 해결하려면 깊은 동결(deep freeze)을 구현해야 한다:

function deepFreeze(obj) {
    Object.keys(obj).forEach(key => {
        if (typeof obj[key] === "object" && obj[key] !== null) {
            deepFreeze(obj[key]);
        }
    });
    return Object.freeze(obj);
}
const deepNested = {
    info: { name: "영희" }
};
deepFreeze(deepNested);
deepNested.info.name = "민수"; // 불가
console.log(deepNested.info.name); // "영희"

5. 객체 복사 후 동결

원본을 보호하면서 작업하려면 복사 후 동결한다:

const original = { key: "값" };
const copy = Object.assign({}, original);
Object.freeze(copy);
copy.key = "변경"; // 불가
console.log(copy.key); // "값"

성능과 한계

장점

- 데이터 보호: 실수로 인한 변경을 방지한다.

- 간단함: 한 줄로 객체를 잠글 수 있다.


한계

- 얕은 동작: 중첩 객체는 별도 처리 필요.

- 성능: 큰 객체에서 호출 시 약간의 오버헤드 발생 가능.

중첩 객체를 다룰 때는 깊은 동결을 고려하자.


마무리

객체 동결과 봉인(Object Freeze and Seal)은 자바스크립트에서 객체를 안전하게 관리하는 도구다. Object.freeze는 완전한 불변성을, Object.seal은 제한된 유연성을 제공한다.


객체 메서드 (Object Methods)

객체 메서드 (Object Methods)

자바스크립트(JavaScript)에서 객체 메서드(Object Methods)는 객체(Object)를 조작하고 관리하는 기능을 제공한다. 속성 관리와 객체 상태 변화를 처리한다. 객체 메서드(Object Methods)의 정의, 동작 방식, 일반 객체와의 차이점, 그리고 사용 사례를 예제로 확인한다.


객체 메서드(Object Methods)는 Object 객체에 정의된 정적 메서드와 인스턴스 메서드를 포함한다. ES5와 ES6에서 확장된 기능들이 있다.


객체 메서드(Object Methods)란 무엇인가?

객체 메서드(Object Methods)는 객체(Object)에 대한 작업을 수행하는 내장 함수다. 기본적인 예제를 살펴보자:

const obj = { name: "철수" };
console.log(Object.keys(obj)); // ["name"]

Object.keys는 객체의 속성 키를 배열로 반환한다. 다른 예제는 다음과 같다:

const frozen = Object.freeze({ age: 25 });
frozen.age = 30;
console.log(frozen.age); // 25

객체 메서드(Object Methods)의 동작 방식

객체 메서드(Object Methods)는 객체의 속성, 프로토타입(Prototype), 상태를 다룬다. 정적 메서드는 Object를 직접 호출하며, 인스턴스 메서드는 객체에서 상속된다.


예제를 통해 동작 방식을 확인한다:

const target = { x: 1 };
const source = { y: 2 };
const merged = Object.assign(target, source);
console.log(merged); // { x: 1, y: 2 }

Object.assign은 소스 객체의 속성을 대상 객체로 복사한다.


객체 메서드(Object Methods)와 일반 객체의 차이점

1. 조작 가능성

- 일반 객체: 직접 접근만 가능.

const plain = { a: 1 };
console.log(plain.a); // 1

- 객체 메서드: 구조화된 조작.

console.log(Object.values(plain)); // [1]

2. 기능성

- 일반 객체: 기본 동작.

- 객체 메서드: 추가 기능 제공.


사용 사례

객체 메서드(Object Methods)의 활용 사례를 예제로 확인한다.


1. 속성 목록

const data = { id: 1, name: "영희" };
console.log(Object.keys(data)); // ["id", "name"]

2. 값 추출

console.log(Object.values(data)); // [1, "영희"]

3. 객체 병합

const obj1 = { a: 1 };
const obj2 = { b: 2 };
console.log(Object.assign({}, obj1, obj2)); // { a: 1, b: 2 }

4. 객체 동결

const locked = Object.freeze({ key: "값" });
locked.key = "변경";
console.log(locked.key); // 값

5. 프로토타입 확인

const proto = { test: true };
const obj3 = Object.create(proto);
console.log(Object.getPrototypeOf(obj3).test); // true

6. 속성 정의

const defined = {};
Object.defineProperty(defined, "secret", {
    value: 42,
    writable: false
});
console.log(defined.secret); // 42

7. 속성 설명자

console.log(Object.getOwnPropertyDescriptor(defined, "secret"));
// { value: 42, writable: false, enumerable: false, configurable: false }

8. 객체 생성

const created = Object.create(null, {
    x: { value: 1, writable: true }
});
console.log(created.x); // 1

성능과 한계

장점

- 편리함: 객체 관리가 간단해진다.

- 제어: 속성 접근을 세밀히 조정한다.


한계

- 오버헤드: 복잡한 작업은 성능에 영향을 줄 수 있다.

- 호환성: 일부 메서드는 최신 환경에서만 동작한다.

필요한 메서드만 사용하여 불필요한 호출을 줄인다.


마무리

객체 메서드(Object Methods)는 자바스크립트(JavaScript)에서 객체를 다루는 유용한 방법이다. 사용 사례를 통해 그 활용 방식을 살펴봤다.


프록시 (Proxy)

프록시 (Proxy)

자바스크립트(JavaScript)에서 프록시(Proxy)는 객체(Object)의 동작을 가로채고 커스터마이징하는 기능을 제공한다. 속성 접근과 수정에 대한 제어를 가능하게 한다. 프록시(Proxy)의 정의, 동작 방식, 일반 객체와의 차이점, 그리고 사용 사례를 예제로 확인한다.


프록시(Proxy)는 ES6에서 도입된 기능으로, 핸들러(Handler)를 통해 객체의 기본 동작을 변경한다. 메타프로그래밍(Metaprogramming)에 유용하다.


프록시(Proxy)란 무엇인가?

프록시(Proxy)는 대상 객체(Target Object)에 대한 중간 계층을 생성하여 동작을 가로챈다. 기본적인 예제를 살펴보자:

const target = { name: "철수" };
const handler = {
    get: (obj, prop) => obj[prop] || "없음"
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // 철수
console.log(proxy.age); // 없음

handler.get은 속성 접근을 가로채며, 존재하지 않는 속성에 대해 기본값을 반환한다.


프록시(Proxy)의 동작 방식

프록시(Proxy)는 핸들러(Handler) 객체에 정의된 트랩(Trap)을 통해 대상 객체(Target Object)의 동작을 제어한다. 속성 읽기, 쓰기, 삭제 등을 커스터마이징할 수 있다.


예제를 통해 동작 방식을 확인한다:

const obj = { count: 0 };
const handler2 = {
    set: (obj, prop, value) => {
        obj[prop] = value;
        return true;
    }
};
const proxy2 = new Proxy(obj, handler2);
proxy2.count = 5;
console.log(obj.count); // 5

handler.set은 속성 설정을 가로채며, 대상 객체(Target Object)에 반영한다.


프록시(Proxy)와 일반 객체의 차이점

1. 동작 제어

- 일반 객체: 기본 동작만 가능.

const plain = { x: 1 };
console.log(plain.y); // undefined

- 프록시: 동작을 재정의.

const proxy3 = new Proxy({}, { get: () => 0 });
console.log(proxy3.y); // 0

2. 유연성

- 일반 객체: 고정된 동작.

- 프록시: 상황별 처리 가능.


사용 사례

프록시(Proxy)의 활용 사례를 예제로 확인한다.


1. 속성 검증

const validator = {
    set: (obj, prop, value) => {
        if (typeof value !== "number") throw new Error("숫자만 가능");
        obj[prop] = value;
        return true;
    }
};
const proxyNum = new Proxy({}, validator);
proxyNum.age = 25; // 성공
// proxyNum.age = "문자"; // 오류

2. 기본값 제공

const withDefault = new Proxy({}, {
    get: (obj, prop) => obj[prop] ?? "기본"
});
console.log(withDefault.name); // 기본

3. 속성 삭제 로깅

const logDelete = new Proxy({ x: 1 }, {
    deleteProperty: (obj, prop) => {
        console.log(`${prop} 삭제`);
        return delete obj[prop];
    }
});
delete logDelete.x; // x 삭제

4. 읽기 전용

const readOnly = new Proxy({ data: "중요" }, {
    set: () => { throw new Error("수정 불가"); }
});
readOnly.data = "변경"; // 오류

5. 메서드 호출 감지

const targetFn = { fn: () => "실행" };
const monitor = new Proxy(targetFn, {
    apply: (target, thisArg, args) => {
        console.log("호출됨");
        return target.fn(...args);
    }
});
console.log(monitor.fn()); // 호출됨, 실행

6. 속성 존재 확인

const checker = new Proxy({}, {
    has: (obj, prop) => prop in obj
});
console.log("key" in checker); // false

7. 동적 속성 생성

const dynamic = new Proxy({}, {
    get: (obj, prop) => {
        if (!(prop in obj)) obj[prop] = 0;
        return obj[prop];
    }
});
console.log(dynamic.count++); // 0
console.log(dynamic.count); // 1

8. 객체 래핑

const wrapped = new Proxy({ secret: 42 }, {
    get: (obj, prop) => prop === "secret" ? "숨김" : obj[prop]
});
console.log(wrapped.secret); // 숨김

성능과 한계

장점

- 제어: 세밀한 동작 조정이 가능하다.

- 유연성: 다양한 상황에 적용된다.


한계

- 오버헤드: 프록시 사용은 성능에 영향을 줄 수 있다.

- 복잡성: 트랩(Trap) 관리가 어려울 수 있다.

필요한 경우에만 프록시를 적용하여 성능 저하를 방지한다.


마무리

프록시(Proxy)는 자바스크립트(JavaScript)에서 객체 동작을 제어하는 유용한 방법이다. 사용 사례를 통해 그 활용 방식을 살펴봤다.


상속 구현 (Implementing Inheritance)

상속 구현 (Implementing Inheritance)

자바스크립트(JavaScript)에서 상속 구현(Implementing Inheritance)은 객체(Object)가 다른 객체의 속성과 메서드를 물려받는 과정을 말한다. 프로토타입 체인(Prototype Chain)을 통해 상속 관계를 형성한다. 상속 구현(Implementing Inheritance)의 정의, 동작 방식, 일반 객체와의 차이점, 그리고 사용 사례를 예제로 확인해보자.


상속 구현(Implementing Inheritance)은 ES6 클래스(Class)와 프로토타입(Prototype)을 활용하며, 코드 재사용성과 계층 구조를 제공한다. 자바스크립트(JavaScript)의 객체 지향 프로그래밍(Object-Oriented Programming)을 가능하게 한다.


상속 구현(Implementing Inheritance)이란 무엇인가?

상속 구현(Implementing Inheritance)은 부모 객체의 기능을 자식 객체가 물려받아 사용하는 메 커니즘이다. 기본적인 예제를 살펴보자:

function Animal(name) {
 this.name = name;
}
Animal.prototype.speak = function() {
 return `${this.name}가 소리를 낸다`;
};
function Dog(name) {
 Animal.call(this, name);
}
Dog.prototype = Object.create(Animal.prototype);
const dog = new Dog("멍멍이");
console.log(dog.speak()); // 멍멍이가 소리를 낸다

Animal.call로 속성을 상속받고, Object.create로 프로토타입(Prototype)을 연결한다.


상속 구현(Implementing Inheritance)의 동작 방식

상속 구현(Implementing Inheritance)은 프로토타입 체인(Prototype Chain)을 통해 부모 객체의 속성과 메서드를 참조한다. ES6에서는 classextends로 간소화된다.


예제를 통해 동작 방식을 확인한다:

class Vehicle {
 constructor(speed) { this.speed = speed; }
 move() { return `속도: ${this.speed}`; }
}
class Car extends Vehicle {
 constructor(speed) { super(speed); }
}
const car = new Car(100);
console.log(car.move()); // 속도: 100

super는 부모 생성자를 호출하며, 메서드는 프로토타입 체인(Prototype Chain)에서 상속된다.


상속 구현(Implementing Inheritance)과 일반 객체의 차이점

1. 속성 공유

- 일반 객체: 독립적인 속성만 가짐.

const obj = { name: "객체" };
console.log(obj.speak); // undefined

- 상속: 부모 속성을 물려받음.

function Parent() {}
Parent.prototype.say = function() { return "말한다"; };
const child = Object.create(Parent.prototype);
console.log(child.say()); // 말한다

2. 구조

- 일반 객체: 단일 구조.

- 상속: 계층 구조 형성.


사용 사례

상속 구현(Implementing Inheritance)의 활용 사례를 예제로 확인한다.


1. 기본 상속

function Shape() { this.type = "도형"; }
Shape.prototype.draw = function() { return "그린다"; };
function Circle() { Shape.call(this); }
Circle.prototype = Object.create(Shape.prototype);
const circle = new Circle();
console.log(circle.draw()); // 그린다

2. 클래스 상속

class Animal {
 constructor(name) { this.name = name; }
 eat() { return "먹는다"; }
}
class Bird extends Animal {
 fly() { return "난다"; }
}
const bird = new Bird("참새");
console.log(bird.eat()); // 먹는다

3. 메서드 오버라이드

class Base {
 speak() { return "기본"; }
}
class Derived extends Base {
 speak() { return "파생"; }
}
const d = new Derived();
console.log(d.speak()); // 파생

4. 다중 계층

class A { a() { return "A"; } }
class B extends A { b() { return "B"; } }
class C extends B { c() { return "C"; } }
const c = new C();
console.log(c.a()); // A

5. 프로토타입 확장

function Machine() {}
Machine.prototype.power = "켜짐";
function Robot() { Machine.call(this); }
Robot.prototype = Object.create(Machine.prototype);
Robot.prototype.task = function() { return "작업"; };
const robot = new Robot();
console.log(robot.power); // 켜짐

6. 믹스인

const mixin = {
 log() { return "로그"; }
};
function Device() {}
Object.assign(Device.prototype, mixin);
const dev = new Device();
console.log(dev.log()); // 로그

7. 생성자 연결

function Parent(name) { this.name = name; }
function Child(name, age) {
 Parent.call(this, name);
 this.age = age;
}
Child.prototype = Object.create(Parent.prototype);
const child = new Child("철수", 10);
console.log(child.name); // 철수

8. 클래스 속성 추가

class User {
 constructor(id) { this.id = id; }
}
class Admin extends User {
 constructor(id) { super(id); this.role = "관리자"; }
}
const admin = new Admin(1);
console.log(admin.role); // 관리자

성능과 한계

장점

- 재사용성: 공통 코드를 공유한다.

- 계층화: 복잡한 구조를 표현한다.


한계

- 복잡성: 깊은 상속은 관리가 어렵다.

- 성능: 체인 탐색에 시간이 걸릴 수 있다.

상속 깊이를 제한하여 복잡성을 줄인다.


마무리

상속 구현(Implementing Inheritance)은 자바스크립트(JavaScript)에서 객체 간 관계를 형성하는 유용한 방법이다. 사용 사례를 통해 그 활용 방식을 살펴봤다.


+ Recent posts