제대로 파는 자바스크립트(JavaScript) - by 얄코
(https://www.inflearn.com/course/제대로-파는-자바스크립트/dashboard)
목차
8-1. Object
8-2. 프로퍼티 어트리뷰트
8-3. JSON
8-4. 중간점검 퀴즈
지금까지 학습한 자바스크립트 객체들의 원형
각각 출력해서 [[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는 얕게만 적용됨!!
객체의 프로퍼티가 생성될 때 엔진에 의해 자동 정의되는 상태
프로퍼티에는 두 종류가 있음
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 |
1. getOwnPropertyDescriptor, getOwnPropertyDescriptors
객체 프로퍼티 어트리뷰트들의 설명자 descriptor를 반환
2. defineProperty, defineProperties
객체의 프로퍼티를 정의
defineProperty: 한 프로퍼티씩 각각 설정. 누락한 어트리뷰트는 기본값으로 자동 설정
(getOwnPropertyDescriptors로 확인해보기)
defineProperties: 여러 프로퍼티들을 객체 형식으로 한꺼번에 설정
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 예시와 다르게, 주어진 인자 자체를 변형하지 않도록 설계
XML과 JSON
- 복잡한 구조를 가질 수 있는 데이터를 한 줄의 문자열로 표현 (직렬화)
- 서버와 클라이언트 등 데이터들을 주고받는 주체들 사이에 널리 사용
- XML/JSON minifier와 formatter를 통해 전송 효율을 높이거나 데이터를 직관적으로 확인할 수 있음
JSON의 장점: 가벼움
- XML에 비해 문법이 간단하고 가독성이 좋음
- 자바스크립트의 객체 표기법을 기반으로 사용
- 보다 간결한 형태로 구조화된 정보를 표시
XML의 장점: 안정성
- XML은 일부 태그에 오타가 생겨도 유연하게 처리 가능함(모든 경우에 허용되는 것은 아님)
*JSON은 문법 오류에 취약함(" 하나만 빠져도 문서 전체에 영향)
- 주석 사용 가능
- XSD(XML Schema Definition) 등을 통해 구조와 타입을 정형화하고 검증할 수 있음
+YAML
- 줄바꿈과 들여쓰기가 필수 요소(minifier로 한 줄로 만들지 않음)
*데이터를 한 줄로 실어보내는 것이 아닌 사람이 읽기 쉬운 표현에 중점을 둠(사용자 친화적)
- 주석 사용 가능
- 상속을 사용하여 여러 데이터를 효율적으로 작성할 수 있음
- 스프링, Docker Compose 등의 설정 파일에 많이 사용됨
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 함수
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은 여전히 불가)
아직은 일부 브라우저 및 환경에서만 지원
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.
[자바스크립트] 섹션 10. 이터러블과 제너레이터 (0) | 2025.04.13 |
---|---|
[자바스크립트] 섹션 9. 추가 자료형들 (0) | 2025.04.08 |
[자바스크립트] 섹션 7. 배열 (0) | 2025.04.02 |
[자바스크립트] 섹션 6. 주요 빌트인 객체 (1) | 2025.01.26 |
[자바스크립트] 섹션 5. 객체와 클래스 (0) | 2025.01.18 |
댓글 영역