상세 컨텐츠

본문 제목

[자바스크립트] 섹션 8. 객체 깊게 다루기

[SW]/JavaScript (2025)

by 시원00 2025. 4. 8. 11:46

본문


제대로 파는 자바스크립트(JavaScript) - by 얄코

(https://www.inflearn.com/course/제대로-파는-자바스크립트/dashboard)

섹션 8. 객체 깊게 다루기

더보기
목차
8-1. Object
8-2. 프로퍼티 어트리뷰트
8-3. JSON
8-4. 중간점검 퀴즈

8-1. Object

I. Object 클래스

지금까지 학습한 자바스크립트 객체들의 원형

각각 출력해서 [[Prototye]] 확인

 

(참고) globalThis: JavaScript에서 전역 객체(global object)를 참조하는 방법 중 하나

   *전역 객체(Global Object): JavaScript 실행 환경에서 모든 전역 변수와 전역 함수를 포함하는 객체

 

생성자 함수

빈 객체 생성

각 값에 적합한 래핑함수로 작용

 

II. 주요 정적 메서드

1. assign: 인자로 주어진 객체(들)의 프로퍼티들을 대상 객체에 붙여넣음

대상 객체를 변경!!

결과 객체를 반환

얕은 복사

 

인자들

- 대상 객체

- 원본 객체(들)

 

프로퍼티의 키가 같을 경우 뒤에 오는 인자의 것이 덮어씀

(obj2의 y를 obj3의 y가 덮어씀)

 

얕은 복사

 

(참고) 정적 메서드(Static Method)

   클래스 자체에 직접 연결된 메서드로, 인스턴스를 생성하지 않고 호출할 수 있는 메서드다.
   JavaScript에서는 static 키워드를 사용해 정적 메서드를 정의할 수 있다.

(참고) Object: JavaScript에서 기본 제공하는 내장 클래스(Built-in Class)

   Object.메서드() 형태로 Object 클래스의 정적 메서드를 사용할 수 있다.

(참고) 정적 메서드는 특정 클래스에 속해 있음

   정적 메서드는 각 클래스에 정의된 것이므로 해당 클래스에서만 호출할 수 있다.
   즉, Object 클래스의 정적 메서드는 Object.메서드() 형태로 사용할 수 있지만,
   Array, Math, String 등의 클래스에 정의된 정적 메서드는 Object 뒤에 붙여 사용할 수 없다.

 

2. keys, values, entries: 객체의 키, 값, [키, 값]을 배열로 반환

 

3. preventExtensions: 프로퍼티 추가 금지

isExtensible: 추가 가능 여부 확인 (추가가 가능하면 true)

 

수정과 삭제는 가능 (추가만 금지)

 

배열에 적용

 

4. seal: 프로퍼티 추가와 삭제 금지

isSealed: sealed 여부 확인 (추가와 삭제가 안되면 true)

 

수정은 가능 (추가와 삭제만 금지)

 

5. freeze: 객체만 동결 (읽기만 가능)

isFrozen: 동결 여부 확인 (수정, 삭제, 추가 모두 안 되면 true)

 

수정, 삭제, 추가 모두 금지

 

배열에 사용

 

freeze는 얕게만 적용됨!!


8-2. 프로퍼티 어트리뷰트

I. 프로퍼티 어트리뷰트 property attributes

객체의 프로퍼티가 생성될 때 엔진에 의해 자동 정의되는 상태

 

프로퍼티에는 두 종류가 있음

1. 데이터 프로퍼티

2. 접근자 프로퍼티

 

1. 데이터 프로퍼티의 어트리뷰트

프로퍼티 어트리뷰트 설명 설정중 생략 시 기본값
[[Value]] 프로퍼티의 값 undefined
[[Writable]] 값 갱신 가능 여부 (false일 경우 읽기 전용) false
[[Enumerable]] 열거(for ... in 문, Object.keys 사용) 가능 여부 false
[[Configurable]] 프로퍼티 제거, (Value와 Writable 제외) 어트리뷰트 수정 가능 여부 false

 

2. 접근자 프로퍼티의 어트리뷰트

프로퍼티 어트리뷰트 설명 설정중 생략 시 기본값
[[Get]] 객체로부터 값을 읽을 때 호출되는 getter 함수 undefined
[[Set]] 객체에 값을 저장할 때 호출되는 setter 함수 undefined
[[Enumerable]] 열거(for ... in 문, Object.keys 사용) 가능 여부 false
[[Configurable]] 프로퍼티의 제거, (Value와 Writable 제외) 어트리뷰트 수정 가능 여부 false

 

II. Object의 프로퍼티 어트리뷰트 관련 정적 메서드들

1. getOwnPropertyDescriptor, getOwnPropertyDescriptors

객체 프로퍼티 어트리뷰트들의 설명자 descriptor를 반환

 

2. defineProperty, defineProperties

객체의 프로퍼티를 정의

 

defineProperty: 한 프로퍼티씩 각각 설정. 누락한 어트리뷰트는 기본값으로 자동 설정

(getOwnPropertyDescriptors로 확인해보기)

 

defineProperties: 여러 프로퍼티들을 객체 형식으로 한꺼번에 설정

 

III. 적용 예

Value 변경

 

enumerable을 false로 바꿈

fullName의 enumerable을 false로 바꾸면 Object.keys로 fullName에 접근할 수 없음 (열거 불가)

 

getOwnPropertyNames

Object의 또 다른 정적 메서드

enumerable이 false인 프로퍼티도 반환함

 

seal: configurable을 false로 바꿈

getOwnPropertyDescriptors()로 어트리뷰트 확인

 

(참고) Object.seal(): 추가 삭제 금지 / 수정 가능

- 모든 프로퍼티의 [[Configurable]]을 false로 만든다. 

- 새로운 프로퍼티 추가 불가

- 기존 프로퍼티 삭제 불가

- 기존 value는 바꿀 수 있음 (단, writable: true인 경우)

=> Object.seal() 모든 프로퍼티의 configurable을 false로 만든다

 

freeze: configurable과 writable을 false로 바꿈

getOwnPropertyDescriptors()로 어트리뷰트 확인

 

깊은 동결 deep freeze

재귀적으로 객체를 가장 깊숙히까지 동결하는 방법

 

(참고) 얕은 동결 (https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze)

Object.freeze(object) 호출의 결과는 object 스스로의 직속 속성에만 적용되며, object에 대해서만 속성 추가, 제거, 재할당 연산을 방지합니다. 만약 그 속성의 값이 객체라면, 그 객체는 동결되지 않으며 속성 추가, 제거, 재할당의 대상이 될 수 있습니다.

 

MDN의 깊은 동결

 

MDN 문서의 deepFreeze 예시와 다르게, 주어진 인자 자체를 변형하지 않도록 설계


8-3. JSON

I. JSON JavaScript Object Notation

XML과 JSON

- 복잡한 구조를 가질 수 있는 데이터를 한 줄의 문자열로 표현 (직렬화)

- 서버와 클라이언트 등 데이터들을 주고받는 주체들 사이에 널리 사용

- XML/JSON minifier와 formatter를 통해 전송 효율을 높이거나 데이터를 직관적으로 확인할 수 있음

 

JSON의 장점: 가벼움

- XML에 비해 문법이 간단하고 가독성이 좋음

- 자바스크립트의 객체 표기법을 기반으로 사용

- 보다 간결한 형태로 구조화된 정보를 표시

 

XML의 장점: 안정성

- XML은 일부 태그에 오타가 생겨도 유연하게 처리 가능함(모든 경우에 허용되는 것은 아님)

   *JSON은 문법 오류에 취약함(" 하나만 빠져도 문서 전체에 영향)

- 주석 사용 가능

- XSD(XML Schema Definition) 등을 통해 구조와 타입을 정형화하고 검증할 수 있음

 

+YAML

- 줄바꿈과 들여쓰기가 필수 요소(minifier로 한 줄로 만들지 않음)

   *데이터를 한 줄로 실어보내는 것이 아닌 사람이 읽기 쉬운 표현에 중점을 둠(사용자 친화적)

- 주석 사용 가능

- 상속을 사용하여 여러 데이터를 효율적으로 작성할 수 있음

- 스프링, Docker Compose 등의 설정 파일에 많이 사용됨

 

II. JSON 객체의 정적 메서드

JSON: 표준 내장 객체 중 하나

 

1. stringify: 객체를 문자열로 직렬화 serialize

 

데이터 형태별 직렬화 결과

모든 데이터를 직렬화하지는 않음

 

값이 함수인 프로퍼티는 직렬화되지 않음

 

2번째 인자: replacer 함수

직렬화될 방식을 지정

a. key와 value 매개변수

 

(참고) 조건에 key && 을 붙이지 않으면 항상 undefined가 반환됨

replacer 함수의 동작 방식

   replacer (key, value)를 받는데, 첫 번째 호출에서 key는 빈 문자열 ''이고 value는 전체 객체다.

   (JSON.stringify가 객체 전체를 stringify하기 전에 먼저 최상위 value에 대해서 replacer를 호출하기 때문)

key와 value 로그 확인

따라서 key && 조건을 앞에 넣어줘야 첫 호출에서 의도치 않은 undefined 반환을 막을 수 있다.

 

b. 반환한 key의 배열 매개변수

 

3번째 인자: 인덴트

space: 들여쓰기 설정 (숫자(space) 또는 문자열)

 

(참고) 용어

indent (인덴트) 들여쓰기
dedent (디덴트) 들여쓰기 없애기
tab 보통 4칸 또는 2칸 띄우는 키 (들여쓰기에 자주 사용)
space 공백 (스페이스 키로 입력)

 

객체의 toJSON 프로퍼티

객체에 toJSON() 메서드가 정의되어 있으면, JSON.stringify()는 객체 전체를 그 메서드의 반환값으로 대체해서 직렬화함

아래 예제의 경우, 원래 {"x":1,"y":2}가 나와야 하지만 toJSON()이 정의되어 있기 때문에 return 문자열이 그대로 JSON 문자열이 됨

 

2. parse: 역직렬화

JSON 문자열의 구문을 분석하고, 그 결과에서 JavaScript의 값이나 객체를 생성하는 메서드

 

2번째 인자: receiver 함수

 

II. 깊은 복사 deep copy

JSON을 사용한 깊은 복사: 원본과 독립된 복사본 생성

   1. JSON.stringify(원본) → 객체를 문자열(JSON 형태)로 변환

   2. JSON.parse(...) → 그 문자열을 다시 새로운 객체로 파싱

 

 

 

함수, Date, Symbol, BigInt 프로퍼티는 JSON 방식으로는 깊은 복사 불가 (또는 제한적)

JSON.stringify가 이 값들을 제대로 처리하지 못하기 때문

 

(참고) JSON.stringify() 타입허용 여부

string ✅ 가능
number ✅ 가능 (단, Infinity, NaN은 null로 처리)
boolean ✅ 가능
null ✅ 가능
array ✅ 가능
object (plain) ✅ 가능
function ❌ 무시됨
undefined ❌ 무시됨
Symbol ❌ 무시됨
BigInt ❌ 에러 발생
Date ✅ 문자열로 변환됨 (제한적)
순환 참조 ❌ 에러 발생

 

(참고) structuredClone

깊은 복사(deep copy)를 위한 Web API

JSON 방식보다 빠르고 효율적인 깊은 복사

Date와 BigInt까지 제대로 복사 (함수와 Symbol은 여전히 불가)

아직은 일부 브라우저 및 환경에서만 지원


8-4. 중간점검 퀴즈

1. Object의 정적 메소드를 사용해서 person1에는 spec1의 프로퍼티를 person2에는 spec1, spec2, spec3 모두의 프로퍼티들을 더해보세요. person1에 프로퍼티를 추가하거나 삭제하지 못하게 만들어보세요. person2를 읽기만 가능한 객체로 만들어보세요.

const person1 = { name: 'Alice', age: 25 };
const person2 = { name: 'Bob', age: 27 };

const spec1 = { job: 'developer' };
const spec2 = { degree: 'doctor' };
const spec3 = { cert: 'photoshop' };

예상 답:

Object.assign(person1, spec1);
Object.assign(person2, spec1, spec2, spec3);

Object.seal(person1);
Object.freeze(person2);

 

정답:

Object.assign(person1, spec1);
Object.assign(person2, spec1, spec2, spec3);

Object.seal(person1); 
Object.freeze(person2);

 

2. 위의 person1 객체를 privates에 속한 프로퍼티를 제외하고 깊은 복사를 하는 코드를 작성해보세요.

const privates = ['height', 'weight']

const person1 = {
	name: '홍길동',
	sex: 'M',
	height: 175,
	weight: 70,
	family: ['부', '모', '누나'],
	profession: {
		job: 'developer',
		position: '사원',
		department: '프론트엔드'
	}
}

예상 답:

const person2 = JSON.parse(JSON.stringify(person1, (key, value) => {
    if (privates.includes(key)) return undefined; // includes: 인자로 주어진 요소 유무 확인
    return value;
}
));

 

정답:

const copied = JSON.parse(
  JSON.stringify(person1,
    (key, value) => {
      if (privates.includes(key)) return undefined;
      return value;
    }
  )
);

 

 

FIN.

728x90

관련글 더보기

댓글 영역