Notice
Recent Posts
Recent Comments
Link
반응형
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- 우분투 시간 변경
- findIndex()
- indexOf()
- js 문자열을 문자배열로
- Robo3T 글씨키우기
- 시퀄 문법
- ubuntu타임존
- sql like연산자
- 레디스 확인
- Robo3T 폰트 키우기
- 코딩 어?
- 5.3.8 Modifying Queries
- search()
- @Moditying @Query
- 스프링 데이타 JPA
- lastIndexOf()
- Robo3T 폰트변경
- 객체의키값만 찾기
- 깃 토큰 만료
- 객체를 배열로
- ${변수}
- sql 문자열 패턴 검색
- 배열을 객체로
- 가상컴퓨터마법사
- 리엑트블로거
- 객체의 밸류값만 찾기
- Robo3T 글씨체 변경
- ...점점점문법
- 문자열 인터폴레이션
- 프론트엔드 스쿨
Archives
- Today
- Total
코딩기록
JS)모던 자바스크립트 Deep Dive 16장 프로퍼티 어트리뷰트 본문
728x90
16장 프로퍼티 어트리뷰트
16-1. 내부 슬롯과 내부 메서드
- 내부 슬롯과 내부 메서드란, 자바스크립트 엔진의 구현 알고리즘을 설명하기 위해 ECMAScript 사양에서 사용하는 의사 프로퍼티(pseudo property)와 의사 메서드(psuedo method). [덧, 의사 - 프로그램 모듈의 작동원리를 프로그램언어가 아닌 일반적인 언어로 사람이 알기 쉽게 작성한 것. 즉, 사양 명세서.]
- 내부 슬롯과 내부 메서드는 ECMAScript 사양에 정의된 대로 구현되어 자바스크립트 엔진에서 실제로 동작하지만 개발자가 직접 접근할 수 있도록 외부로 공개된 객체의 프로퍼티는 아님. 단, 일부 내부 슬롯과 내부 메서드에 한하여 간접적으로 제공.
- 모든 객체는 [[Prototype]]이라는 내부 슬롯을 갖는데 내부 슬롯은 자바스크립트 엔진의 내부 로직이므로 원칙적으로 직접 접근할 수 없지만 [[Prototype]] 내부 슬롯의 경우, _ _proto_ _를 통해 간접적으로 접근 가능.
-
const o = {};// 내부 슬롯은 자바스크립트 엔진의 내부 로직이므로 직접 접근불가.o.[[Prototype]] // -> Uncaught SyntaxError: Unexpected token '['// 단, 일부 내부 슬롯과 내부 메서드에 한하여 간접적으로 접근할 수 있는 수단을 제공.o.__proto__ // -> Object.prototype
- [예제 16-01]
덧),
es6 도입 이전에 browser들이 맘대로 __proto__ 만들어서 사용했음. 그래서 es6 버전에 만들어서 도입함.
__proto__ 가 현재 표준이긴 한데 없앨 예정. 언젠가 없앨 예정이라 Object.getPrototypeOf를 권장.
프로퍼티 확인(검색) - console.dir(프로퍼티이름적기);
16-2. 프로퍼티 어트리뷰트와 프로퍼티 디스크립터 객체
- 자바스크립트 엔진은 프로퍼티를 생성할 때 프로퍼티의 상태를 나타내는 프로퍼티 어트리뷰트를 기본값으로 자동 정의.
- 프로퍼티 상태란 프로퍼티 값(value), 값의 갱신 가능 여부(writable), 열거 가능 여부(enumerable), 재정의 가능 여부(configurable)를 말함.
- 프로퍼티 어트리뷰트란 자바스크립트 엔진이 관리하는 내부 상태 값(meta-property)인 내부 슬롯 [[Value]], [[Writable]], [[Enumerable]], [[Configurable]]
- ✨✨이 대괄호대괄호[[~~]] 이름들은 가상의 이름, ECMAScript에서 붙인 이름이고 이름보다는 이 내부 슬롯이 하는 역할이 더 중요하다. (이름은 다를수 있다는 뜻)
- 객체 리터럴로 객체 하나생성함.
- 펄슨이라는 식별자가 그 객체를 가리킴
- name: 'Lee'프로퍼티가 하나 존재함
- 객체리터럴은 할당문( = )이 동작하는 시점에 객체 리터럴{ ~~ }이 해석되어서 객체를 만듬. 그때 객체를 만듬과 동시에 프로퍼티들을 직접적으로 생성함 그때 프로퍼티 어트리뷰트들을 자동적으로 정의함.
-
- 따라서 프로퍼티 어트리뷰트에 직접 접근할 수 없지만 Object.getOwnPropertyDescriptor 메서드를 사용하여 간접적으로 확인할 수 있음.
-
[예제 16-02]const person = {name: 'Lee',};// 프로퍼티 어트리뷰트 정보를 제공하는 프로퍼티 디스크립터 객체를 반환한다.console.log(Object.getOwnPropertyDescriptor(person, "name"));// { value: 'Lee', writable: true, enumerable: true, configurable: true }
- getOwnPropertyDescriptor 메서드를 호출할 때
- 첫 번째 매개변수에는 객체의 참조를 전달하고, 두 번째 매개변수에는 프로퍼티 키를 문자열로 전달.
- 이때 Object.getOwnPropertyDescriptor 메서드는 프로퍼티 어트리뷰트 정보를 제공하는 프로퍼티 디스크립터(PropertyDescriptor)객체를 반환.
- 존재하지 않거나 상속받은 프로퍼티에 대한 프로퍼티 디스크립터를 요구하면 undefined가 반환.
- Object.getOwnPropertyDescriptor 메서드는 하나의 프로퍼티에 대해 프로퍼티 디스크립터 객체를 반환하지만, ES8에서 도입된 Object.getOwnPropertyDescriptors 메서드는 모든 프로퍼티의 프로퍼티 어트리뷰트 정보를 제공하는 프로퍼티 디스크립터 객체들을 반환.
-
[예제 16-03]const person = {name: 'Lee',};// 프로퍼티 동적 생성person.age = 20;// 프로퍼티 어트리뷰트 정보를 제공하는 프로퍼티 디스크립터 객체를 반환한다.console.log(Object.getOwnPropertyDescriptors(person));/*{name: {value: 'Lee', writable: true, enumerable: true, configurable: true},age: {value: 20, writable: true, enumerable: true, configurable: true}}*/
- 첫 번째 매개변수에는 객체의 참조를 전달하고, 두 번째 매개변수에는 프로퍼티 키를 문자열로 전달.
16-3. 데이터 프로퍼티와 접근자 프로퍼티
프로퍼티는 데이터 프로퍼티와 접근자 프로퍼티로 구분.
1). 데이터 프로퍼티 (Data property)
- 키와 값으로 구성된 일반적인 프로퍼티.
- 자바스크립트 엔진은 프로퍼티를 생성할 때 프로퍼티의 상태를 나타내는 프로퍼티 어트리뷰트를 기본값으로 자동 정의.
-
프로퍼티
어트리뷰트프로퍼티 디스크립터
객체의 프로퍼티설명 [[Value]] value - 프로퍼티 키를 통해 프로퍼티 값에 접근하면 반환되는 값.
- 프로퍼티 키를 통해 프로퍼티 값을 저장하면 [[Value]]에 값을 재할.
이때 프로퍼티가 없으면 생성하고 생성된 프로퍼티의 [[value]]에 값을 저장.[[Writable]] writable - 프로퍼티 값의 변경 가능 여부를 나타내며 boolean 값을 가짐.
- [[Writable]]의 값이 false인 경우,
해당 프로퍼티의 [[Value]]의 값을 변경할 수 없는 읽기 전용 프로퍼티가 됨.[[Enumerable]] enumerable - 프로퍼티의 열거 가능 여부를 나타내며 boolean 값을 가짐.
- [[Enumerable]]의 값이 false인 경우,
해당 프로퍼티는 for...in 문, Object.keys 메서드 등으로 열거 불가.[[Configurable]] configurable - 프로퍼티의 재정의 가능 여부를 나타내며 boolean 값을 가짐.
- [[Configurable]]의 값이 false인 경우,
해당 프로퍼티의 삭제, 프로퍼티 어트리뷰트 값의 변경 금지.
- [[Writable]]이 true인 경우,
[[value]]와 [[Writable]]을 false로 변경하는 것은 허용.-
[예제 16-05]const person = {name: "Lee",}// 프로퍼티 동적 생성person.age = 20;console.log(Object.getOwnPropertyDescriptors(person))/*{name: {value: 'Lee', writable: true, enumerable: true, configurable: true},age: {value: 20, writable: true, enumerable: true, configurable: true}}*/
-
- 메서드가 반환된 프로퍼티 디스크립터 객체를 살펴보면 value 프로퍼티의 값은 'Lee'.
- 프로퍼티 어트리뷰트 [[Value]]의 값이 'Lee'인 것을 의미.
- writable, enumerable, configurable 프로퍼티의 값이 모두 true.
- [[writable]], [[enumerable]], [[configurable]]의 값이 모두 true인 것을 의미.
- 이처럼 프로퍼티가 생성될 때 [[Value]]의 값은 프로퍼티 값으로 초기화되며 [[writable]], [[enumerable]], [[configurable]]의 값은 true로 초기화됨. 프로퍼티를 동적으로 추가해도 마찬가지.
- [[writable]], [[enumerable]], [[configurable]]의 값이 모두 true인 것을 의미.
덧) 스터디에서 나온 이런저런 내용 240722월-
*데이터 프로퍼티는 꼭 알아야함.
데이터 프로퍼티는 프로퍼티 어트리뷰트 중 벨류가 있음.
접근자 프로퍼티 -> 밸류라는 프로퍼티가 없음. 즉, 다른 프로퍼티를 참조하거나 조작하는 역할을 하고 set, get이라는 함수 두개를 갖고 있음.
2). 접근자 프로퍼티 (accessor property)
- 자체적으로는 값을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 호출되는 접근자 함수(accessor function)로 구성된 프로퍼티.
프로퍼티
어트리뷰트프로퍼티 디스크립터
객체의 프로퍼티설명 [[Get]] get - 접근자 프로퍼티를 통해 데이터 프로퍼티의 값을 읽을 때 호출되는 접근자 함수. 즉, 접근자 프로퍼티 키로 프로퍼티 값에 접근하면 프로퍼티 어트리뷰트 [[Get]]의 값인 getter 함수가 호출되고 그 결과가 프로퍼티 값으로 반환됨. [[Set]] set - 접근자 프로퍼티를 통해 데이터 프로퍼티의 값을 저장할 때 호출되는 접근자 함수. 즉, 접근자 프로퍼티 키로 프로퍼티 값을 저장하면 어트리뷰트 [[Set]]의 값인 setter 함수가 호출되고 그 결과가 프로퍼티 값으로 저장됨. [[Enumerable]] enumerable - 프로퍼티의 열거 가능 여부를 나타내며 boolean 값을 가짐.
- [[Enumerable]]의 값이 false인 경우,
해당 프로퍼티는 for...in 문, Object.keys 메서드 등으로 열거 불가.[[Configurable]] configurable - 프로퍼티의 재정의 가능 여부를 나타내며 boolean 값을 가짐.
- [[Configurable]]의 값이 false인 경우,
해당 프로퍼티의 삭제, 프로퍼티 어트리뷰트 값의 변경 금지.
- [[Writable]]이 true인 경우,
[[value]]와 [[Writable]]을 false로 변경하는 것은 허용.
- 접근자 함수는 getter/setter 함수라고도 부르며 접근자 프로퍼티는 getter와 setter 함수를 모두 정의할 수도 있고 하나만 정의할 수도 있음.
- getter, setter 함수
- 메서드 앞에 get, set이 붙은 메서드
-
get fullName() {return`${this.firstName}${this.lastName}`; }
- 위 getter함수의 { } 안이 Get 프로퍼티 어트리뷰트의 값.
-
set fullName(name) { [this.firstName, this.lastName] = name.split(' '); }
- 위 setter함수의 { } 안이 Set 프로퍼티 어트리뷰트의 값.
-
[예제 16-06]const person = {// 데이터 프로퍼티firstName: 'Ungmo',lastName: 'Lee',// fullName은 접근자 함수로 구성된 접근자 프로퍼티.// getter 함수get fullName() {return `${this.firstName} ${this.lastName}`;},// setter 함수set fullName(name) {// 배열 디스트럭처링 할당: "31.1 배열 디스트럭처링 할당" 참고[this.firstName, this.lastName] = name.split(' ');}};// 데이터 프로퍼티를 통한 프로퍼티 값의 참조.console.log(person.firstName + ' ' + person.lastName); // Ungmo Lee// 접근자 프로퍼티를 통한 프로퍼티 값의 저장// 접근자 프로퍼티 fullName에 값을 저장하면 setter 함수가 호출.person.fullName = 'Heegun Lee';console.log(person); // {firstName: "Heegun", lastName: "Lee"}// 접근자 프로퍼티를 통한 프로퍼티 값의 참조// 접근자 프로퍼티 fullName에 접근하면 getter 함수가 호출.console.log(person.fullName); // Heegun Lee// firstName은 데이터 프로퍼티.// 데이터 프로퍼티는 [[Value]], [[Writable]], [[Enumerable]], [[Configurable]]// 프로퍼티 어트리뷰트를 가짐.let descriptor = Object.getOwnPropertyDescriptor(person, 'firstName');console.log(descriptor);// {value: "Heegun", writable: true, enumerable: true, configurable: true}// fullName은 접근자 프로퍼티.// 접근자 프로퍼티는 [[Get]], [[Set]], [[Enumerable]], [[Configurable]] 프로퍼티 어트리뷰트를 가짐.descriptor = Object.getOwnPropertyDescriptor(person, 'fullName');console.log(descriptor);// {get: ƒ, set: ƒ, enumerable: true, configurable: true}
- [예제 16-06] 코드 설명
- // getter 함수
- get fullName() getter는 참조할 때 호출됨.
- console.log(person.fullName); fullName에 접근하면 getter함수 호출됨.
- return 옆에 씌여진 `~~` 내부 로직이 자바스크립트에 의해 호출되고 그 결과 값이 반환됨.
- getter인 경우엔 반드시 return 이 있어야 함. 프로퍼티를 참조하게 되면 무엇인가 값으로 평가되어야 하기 때문.
- const person = { this는 person 객체를 가리킴.
- 두 개의 문자열을 조합해서 반환.
- // setter 함수
- set fullName(name) setter는 값을 할당할 때 호출됨.
- person.fullName = 'Heegun Lee'; 접근자 프로퍼티(fullName)에 값을 할당할때 setter 호출됨.
- set fullName(name) { 할당한 값이 매개변수(name)에 인수로 넘어가고 { ~~~ } 내부 로직을 실행함. (자체적으로 값을 갖고 있지 않으므로 다른 프로퍼티 값을 저장하는 행위를 함)
- [this.firstName, this.lastName] = name.split(' '); 스페이스바를 기준으로 문자를 나눠 배열로 리턴함. 첫 번째 요소('Heegun)가 firstName에 두 번째 요소(Lee')가 lastName에 할당됨.
- [[Get]], [[Set]] - 다른 데이터 프로퍼티 값을 조작하여 가지고 오거나 저장할 때 조작할 수 있는 getter, setter 함수를 프로퍼티 어트리뷰트에 값으로 갖고 있음. (클래스, 생성자함수에서 다시 살펴볼 예정)
- 접근자 프로퍼티는 자체적으로 값(프로퍼티 어트리뷰트 [[Value]])을 가지지 않으며 다만 데이터 프로퍼티의 값을 읽거나 저장할 때만 관여함.
덧) 스터디 질문 Q :
[[Get]], [[Set]] 접근자 프로퍼티 외에 함수로도 동작이 가능한데 왜이걸 사용하는지 궁금.
다른 학생답 => 인수가 하나일때 사용할 수 있다는 특징이 있음. 그럼 자바스크립트 엔진이 의도한대로 사용할 수 있다.
====강사님 답 A====
위 [예제16-06] 함수를 내부에 감추겠다는 의도. 사용자를 더 배려한 행위.
const person = { // 데이터 프로퍼티 firstName: 'Ungmo', lastName: 'Lee', // getter 함수 get fullName() { // fullName은 접근자 함수로 구성된 접근자 프로퍼티. return `${this.firstName} ${this.lastName}`; }, // setter 함수 set fullName(name) { [this.firstName, this.lastName] = name.split(' '); } }; console.log(person.fullName); // Ungmo Lee person.fullName = 'Heegun Lee'; console.log(person); // {firstName: "Heegun", lastName: "Lee"} console.log(person.fullName); // Heegun Lee
fullName() 이라는 접근자 프로퍼티는 getter라는 함수로 구현이 되어있지만 사용할 때는 프로퍼티로 써야된다.
person.fullName을 참조했을 때 뭔가 값이 나와야 함. 즉, get함수는 반드시 리턴해야함.
set은 프로퍼티 처럼 사용.
person.fullName = 'Heegun Lee';
'Heegun Lee' 이라는 문자열이 fullName 이라는 프로퍼티를 갱신하기위해준 것처럼 쓰지만
실제로 'Heegun Lee' 이 값이 setter의 (name)이라는 인수로 넘어간다.
따라서 setter함수는 인수를 단 1개만 받을 수 있고 뮤테이션(값 변경)을 해야함.
[함수로 씀] 개발자를 배려한 행위.
const person = { // 데이터 프로퍼티 firstName: 'Ungmo', lastName: 'Lee', // getter 함수 getFullName() { return `${this.firstName} ${this.lastName}`; }, // setter 함수 setFullName(name) { [this.firstName, this.lastName] = name.split(' '); } }; console.log(person.getFullName()); // Ungmo Lee console.log(person.setFullName('Heegun Lee')); console.log(person.getFullName()); // Heegun Lee
둘다 된다라는 측면에서는 똑같으나 (~~~ 기억안남~~~~)
현업에서 접근자 프로퍼티를 많이 안쓰는데 접근자 프로퍼티의 선기능을 몰라서 많이 안쓴다는 생각이 듬.
JS에서 제공하는 빌트인 프로퍼티 메서드를 많이, 잘 알고 있는 것이 구현능력의 상승과 밀접한 연관이 있음.
Dom에도 굉장히 다양한 프로퍼티들이 제공됨. 접근자 프로퍼티로 해결가능하면 함수보단 접근자 프로퍼티로 해결하려는 흔적이 많음.
✅스터디 내용을 기억에 의존해서 쓴 글이라 틀린 부분이 있다면 댓글 부탁드립니다.- 뽀짝코딩 주인장-
16-4. 프로퍼티 정의
- 프로퍼티 정의란 새로운 프로퍼티를 추가하면서 프로퍼티 어트리뷰트를 명시적으로 정의하거나, 기존 프로퍼티의 프로퍼티 어트리뷰트를 재정의하는 것.
- Object.defineProperty 메서드
- 프로퍼티의 어트리뷰트를 정의 가능.
- 인수로는 객체의 참조와 데이터 프로퍼티의 키인 문자열, 프로퍼티 디스크립터 객체를 전달함.
- Object.defineProperty 메서드로 프로퍼티를 정의할 때 프로퍼티 디스크립터 객체의 프로퍼티를 일부 생략 가능.
- Object.defineProperty 메서드는 한번에 하나의 프로퍼티만 정의 가능.
- Object.defineProperties 메서드는 여러 개의 프로퍼티를 한 번에 정의 가능.
- Object.defineProperty 메서드
- [ Object.defineProperty 메서드 ]
-
const person = {};// 데이터 프로퍼티 정의Object.defineProperty(person, 'firstName', {value: 'Ungmo',writable: true,enumerable: true,configurable: true});Object.defineProperty(person, 'lastName', {value: 'Lee'});let descriptor = Object.getOwnPropertyDescriptor(person, 'firstName');console.log('firstName', descriptor);// firstName {value: "Ungmo", writable: true, enumerable: true, configurable: true}// 디스크립터 객체의 프로퍼티를 누락시키면 undefined, false가 기본값.descriptor = Object.getOwnPropertyDescriptor(person, 'lastName');console.log('lastName', descriptor);// lastName {value: "Lee", writable: false, enumerable: false, configurable: false}// [[Enumerable]]의 값이 false인 경우// 해당 프로퍼티는 for...in 문이나 Object.keys 등으로 열거할 수 없음.// lastName 프로퍼티는 [[Enumerable]]의 값이 false이므로 열거되지 않음.console.log(Object.keys(person)); // ["firstName"]// [[Writable]]의 값이 false인 경우 해당 프로퍼티의 [[Value]]의 값을 변경할 수 없음.// lastName 프로퍼티는 [[Writable]]의 값이 false이므로 값을 변경할 수 없음.// 이때 값을 변경하면 에러는 발생하지 않고 무시됨.person.lastName = 'Kim';// [[Configurable]]의 값이 false인 경우 해당 프로퍼티를 삭제할 수 없음.// lastName 프로퍼티는 [[Configurable]]의 값이 false이므로 삭제할 수 없음.// 이때 프로퍼티를 삭제하면 에러는 발생하지 않고 무시됨.delete person.lastName;// [[Configurable]]의 값이 false인 경우 해당 프로퍼티를 재정의할 수 없음.// Object.defineProperty(person, 'lastName', { enumerable: true });// Uncaught TypeError: Cannot redefine property: lastNamedescriptor = Object.getOwnPropertyDescriptor(person, 'lastName');console.log('lastName', descriptor);// lastName {value: "Lee", writable: false, enumerable: false, configurable: false}// 접근자 프로퍼티 정의Object.defineProperty(person, 'fullName', {// getter 함수get() {return `${this.firstName} ${this.lastName}`;},// setter 함수set(name) {[this.firstName, this.lastName] = name.split(' ');},enumerable: true,configurable: true});descriptor = Object.getOwnPropertyDescriptor(person, 'fullName');console.log('fullName', descriptor);// fullName {get: ƒ, set: ƒ, enumerable: true, configurable: true}person.fullName = 'Heegun Lee';console.log(person); // {firstName: "Heegun", lastName: "Lee"}
- [예제 16-08]
프로퍼티 디스크립터 객체의 프로퍼티 | 대응하는 프로퍼티 어트리뷰트 | 생략했을 때의 기본값 |
value | [[Value]] | undefined |
get | [[Get]] | undefined |
set | [[Set]] | undefined |
writable | [[writable]] | false |
enumerable | [[Enumerable]] | false |
configurable | [[Configurable]] | false |
- [ Object.defineProperties 메서드 ]
- [예제 16-09]
const person = {};Object.defineProperties(person, {// 데이터 프로퍼티 정의firstName: {value: 'Ungmo',writable: true,enumerable: true,configurable: true},lastName: {value: 'Lee',writable: true,enumerable: true,configurable: true},// 접근자 프로퍼티 정의fullName: {// getter 함수get() {return `${this.firstName} ${this.lastName}`;},// setter 함수set(name) {[this.firstName, this.lastName] = name.split(' ');},enumerable: true,configurable: true}});person.fullName = 'Heegun Lee';console.log(person); // {firstName: "Heegun", lastName: "Lee"}
16-5. 객체 변경 방지
- 객체는 변경이 가능한 값이므로 재할당 없이 직접 변경 가능.
- 프로퍼티를 추가하거나 삭제 가능.
- 프로퍼티 값을 갱신 가능.
- Object.defineProperty 또는 Object.defineProperties 메서드를 사용하여 프로퍼티 어트리뷰트를 재정의 가능.
- 자바스크립트는 객체의 변경을 방지하기 위해 다양한 메서드를 제공.
- 객체 변경 방지 메서드들은 객체의 변경을 금지하는 강도가 다름.
구분 | 메서드 | 상태 확인 메서드 |
프로퍼티 추가 |
프로퍼티 삭제 |
프로터피 값 읽기 |
프로퍼티 값 쓰기 |
프로퍼티 어트리뷰트 재정의 |
객체 금지 | Object.preventExtensions | Object.isExtensible | X | O | O | O | O |
객체 밀봉 | Object.seal | isSealed | X | X | O | O | X |
객체 동결 | Object.freeze | isFrozen | X | X | O | X | X |
1). 객체 확장 금지
- Object.preventExtensions 메서드는 객체의 확장을 금지.
- 확장이 금지된 객체는 프로퍼티 추가가 금지.
- 프로퍼티를 추가할 수 있는 2가지 방법 모두 추가 금지.
- ①프로퍼티 동적 추가와 ②Object.defineProperty 메서드.
- 확장 가능 객체 여부 확인 메서드- Object.isExtensible
-
[예제 16-10]const person = { name: 'Lee' };// person 객체는 확장이 금지된 객체가 아님.console.log(Object.isExtensible(person)); // true// person 객체의 확장을 금지하여 프로퍼티 추가를 금지.Object.preventExtensions(person);// person 객체는 확장이 금지된 객체.console.log(Object.isExtensible(person)); // false// 프로퍼티 추가가 금지.person.age = 20; // 무시. strict mode에서는 에러console.log(person); // {name: "Lee"}// 프로퍼티 추가는 금지되지만 삭제는 가능.delete person.name;console.log(person); // {}// 프로퍼티 정의에 의한 프로퍼티 추가도 금지.Object.defineProperty(person, 'age', { value: 20 });// TypeError: Cannot define property age, object is not extensible
2). 객체 밀봉
- Object.seal 메서드는객체를 밀봉.
- 프로퍼티 추가 및 삭제와 프로퍼티 어트리뷰트 재정의 금지 의미.
- 즉, 밀봉된 객체는 읽기와 쓰기만 가능.
- 밀봉된 객체 여부 확인 메서드- Object.isSealed
-
[예제 16-11]const person = { name: 'Lee' };// person 객체는 밀봉(seal)된 객체가 아님.console.log(Object.isSealed(person)); // false// person 객체를 밀봉(seal)하여 프로퍼티 추가, 삭제, 재정의를 금지.Object.seal(person);// person 객체는 밀봉(seal)된 객체.console.log(Object.isSealed(person)); // true// 밀봉(seal)된 객체는 configurable이 false.console.log(Object.getOwnPropertyDescriptors(person));/*{name: {value: "Lee", writable: true, enumerable: true, configurable: false},}*/// 프로퍼티 추가가 금지.person.age = 20; // 무시. strict mode에서는 에러console.log(person); // {name: "Lee"}// 프로퍼티 삭제가 금지.delete person.name; // 무시. strict mode에서는 에러console.log(person); // {name: "Lee"}// 프로퍼티 값 갱신은 가능.person.name = 'Kim';console.log(person); // {name: "Kim"}// 프로퍼티 어트리뷰트 재정의가 금지.Object.defineProperty(person, 'name', { configurable: true });// TypeError: Cannot redefine property: name
3). 객체 동결
- Object.freeze 메서드는 객체를 동결.
- 프로퍼티 추가 및 삭제와 프로퍼티 어트리뷰트 재정의 금지, 프로퍼티 값 갱신 금지 의미.
- 즉, 동결된 객체는 읽기만 가능.
- 동결된 객체 여부 확인 메서드- Object.isFrozen
-
[예제 16-12]const person = { name: 'Lee' };// person 객체는 동결(freeze)된 객체가 아님.console.log(Object.isFrozen(person)); // false// person 객체를 동결(freeze)하여 프로퍼티 추가, 삭제, 재정의, 쓰기를 금지.Object.freeze(person);// person 객체는 동결(freeze)된 객체.console.log(Object.isFrozen(person)); // true// 동결(freeze)된 객체는 writable과 configurable이 false.console.log(Object.getOwnPropertyDescriptors(person));/*{name: {value: "Lee", writable: false, enumerable: true, configurable: false},}*/// 프로퍼티 추가가 금지.person.age = 20; // 무시. strict mode에서는 에러console.log(person); // {name: "Lee"}// 프로퍼티 삭제가 금지.delete person.name; // 무시. strict mode에서는 에러console.log(person); // {name: "Lee"}// 프로퍼티 값 갱신이 금지.person.name = 'Kim'; // 무시. strict mode에서는 에러console.log(person); // {name: "Lee"}// 프로퍼티 어트리뷰트 재정의가 금지.Object.defineProperty(person, 'name', { configurable: true });// TypeError: Cannot redefine property: name
덧) 스터디에서 나온 이런저런 내용 240722월-
*객체 동결- 프로퍼티를 추가,삭제,갱신,쓰기,재정의 못하고 읽기만함.
쓰는이유는 객체내부가 중첩되고 중첩이될 가능성이 있어서임.
안까지 싹 얼리려면 재귀적행위를 해야하는데 객체가 크면 굉장히 부담스러움.
메모리를 많이 사용하는 퍼포먼스 때문에 많이 사용하진 않음.
4). 불변 객체
- 지금까지 살펴본 변경 방지 메서드들은 얕은 변경 방지(shallow only)로 직속 프로퍼티만 변경이 방지되고 중첩 객체까지는 영향을 주지는 못함.
- 따라서 Object.freeze 메서드로 객체를 동결하여도 중첩 객체까지 동결할 수 없음.
-
[예제 16-13]const person = {name: 'Lee',address: { city: 'Seoul' }};// 얕은 객체 동결Object.freeze(person);// 직속 프로퍼티만 동결.console.log(Object.isFrozen(person)); // true// 중첩 객체까지 동결하지 못함.console.log(Object.isFrozen(person.address)); // falseperson.address.city = 'Busan';console.log(person); // {name: "Lee", address: {city: "Busan"}}
- 객체의 중첩 객체까지 동결하여 변경이 불가능한 읽기 전용의 불변 객체를 구현하려면 객체를 값으로 갖는 모든 프로퍼티에 대해 재귀적으로 Object.freeze 메서드 호출해야함.
-
[예제 16-14]function deepFreeze(target) {// 객체가 아니거나 동결된 객체는 무시하고 객체이고 동결되지 않은 객체만 동결.if (target && typeof target === 'object' && !Object.isFrozen(target)) {Object.freeze(target);/*모든 프로퍼티를 순회하며 재귀적으로 동결.Object.keys 메서드는 객체 자신의 열거 가능한 프로퍼티 키를 배열로 반환.("19.15.2. Object.keys/values/entries 메서드" 참고)forEach 메서드는 배열을 순회하며 배열의 각 요소에 대하여 콜백 함수를 실행.("27.9.2. Array.prototype.forEach" 참고)*/Object.keys(target).forEach(key => deepFreeze(target[key]));}return target;}const person = {name: 'Lee',address: { city: 'Seoul' }};// 깊은 객체 동결deepFreeze(person);console.log(Object.isFrozen(person)); // true// 중첩 객체까지 동결.console.log(Object.isFrozen(person.address)); // trueperson.address.city = 'Busan';console.log(person); // {name: "Lee", address: {city: "Seoul"}}
참고
도서 - 모던 자바스크립트 Deep Dive -이웅모
이웅모 강사님 홈피 - https://poiemaweb.com/js-prototype
이웅모 강사님 유튜브 - https://www.youtube.com/watch?v=0AjTZG6bGq8
블로그 - https://codeno-te.tistory.com/152
✅ 덧, 부분은 스터디 내용을 기억에 의존해서 쓴 글이라 틀린 부분이 있다면 댓글 부탁드립니다.- 뽀짝코딩 주인장-
반응형
'프론트 > 모던 자바스크립트 Deep Dive 책 스터디' 카테고리의 다른 글
JS)모던 자바스크립트 Deep Dive 18장 함수와 일급 객체 (0) | 2024.07.21 |
---|---|
JS)모던 자바스크립트 Deep Dive 17장 생성자 함수에 의한 객체 생성 (0) | 2024.07.21 |
JS)모던 자바스크립트 Deep Dive 15장 let, const 키워드와 블록 레벨 스코프 (0) | 2024.07.19 |
JS)모던 자바스크립트 Deep Dive 14장 전역 변수의 문제점 (0) | 2024.07.18 |
JS)모던 자바스크립트 Deep Dive 13장 스코프 (0) | 2024.07.18 |
Comments