티스토리 뷰

안녕하세요 좋아요요정입니다.

이번 게시글에서는 자바스크립트의 객체에 대해 더 깊게 이해해보겠습니다.

객체의 프로퍼티는 속성(Properties)로써 Key와 value값을 한 쌍의로 정의한 것을 뜻했습니다.

이 프로퍼티에 갱신이 가능한지, 열거가 가능한지, 재정의가 가능한지 등의 상태를 정의하고, 프로퍼티에 접근할 때 값을 읽거나 저장할 때의 상태를 관리할 수 있습니다.  

 

 

객체의 프로퍼티의 상태

자바스크립트 내부 슬롯과 내부 메서드

객체의 프로퍼티의 상태는 어떻게 정의될까요?

자바스크립트 내부 슬롯에 정의되어 있습니다. 내부 슬롯과 내부 메서드는 EcmaScript에서 자바스크립트 엔진의 구현 알고리즘을 설명하기 위해 사용하는 의사 프로퍼티와 의사 메서드입니다. 자바스크립트 엔진에서 실제로 동작을 하지만, 개발자가 직접 접근할 수 있도록 외부적으로 공개된 프로퍼티는 아닙니다. (단 일부 내부 슬롯과 내부 메서드에 한하여 간접적으로 접근할 수 있는 수단이 존재합니다.) 

 

 cat 객체를 살펴보겠습니다.

const cat = { 
    name: 'cookie',
    age: 2
}

자바스크립트의 모든 객체들은 [[prototype]]이라는 내부 슬롯을 갖고 있습니다. 하지만 key값을 접근하듯 접근할 수는 없습니다.

 

보통 자바스크립트 엔진 내부에 구현된 로직이므로 개발자가 사용할 수 없지만, 프로토타입 내부 슬롯은 __proto__를 통해 간접적으로 접근할 수 있습니다. MDN에서는 권장되는 접근방법이 아니라고 표기되어 있습니다. 아래서 정의하고 접근하는 방법에 대해 알아보겠습니다.

 

 

 

 


프로퍼티 상태를 나타내는 프로퍼티 어트리뷰트

자바스크립트 엔진은 객체의 프로퍼티가 생성될 때, 해당 프로퍼티의 상태를 나타내는 프로퍼티 어트리뷰트를 기본값을 자동으로 정의합니다. 프로퍼티가 생성될 때 {키:값} 만 저장되는 것이 아니라 값의 갱신 가능 여부, 열거 가능 여부, 재정의 가능 여부를 함께 정의합니다.

 

 

프로퍼티 디스크립터 객체

프로퍼티 어트리뷰트를 확인할 수 있는 방법으로는 프로퍼티 디스크립터 객체에 접근하는 메서드가 있습니다.

디스크립터 객체는 객체의 일부 어트리뷰트를 설명해놓은 객체입니다. 개발자가 쉽게 확인하고 접근, 재정의해 사용할 수 있습니다.

먼저 디스크립터 객체를 확인하는 방법입니다.

 

1. 해당 객체의 모든 프로퍼티의 디스크립터 객체 반환

Object.getOwnPropertyDescriptors(cat)

주어진 객체의 모든 속성들의 설명자 반환

해당 객체에 주어진 모든 속성들의 설명자(Descriptor)들을 반환합니다. 만약 객체에 프로퍼티가 없다면 빈 객체가 반환됩니다. 

반환된 객체의 값을 변경해도 원본 객체와 값이 변경되지 않는 것을 보면 동일한 메모리주소를 가지고 있지 않는 것으로 보여집니다.

 

2. 해당 객체의 특정 프로퍼의 디스크립터 객체 반환

Object.getOwnPropertyDescriptor(cat, 'age')

2번째 인자로 들어간 속성 key의 설명자들을 반환합니다. 만약 없는 속성자인 경우 undefined이 반환됩니다. 

 

 

 


프로퍼티 디스크렉터 객체의 프로퍼티 종류 

프로퍼티의 어트리뷰트를 설명하는 프로퍼티 디스크립터 객체의 프로퍼티의 종류로는 데이터 프로퍼티접근자 프로퍼티로 나뉘어져 있습니다. 

 

 

데이터 프로퍼티

먼저 데이터 프로퍼티는 키와 값으로 구성된 형태로 상단 이미지와 같이 configurable, enumerable, value, writable이 있습니다.

데이터 프로퍼티는 개발자가 정의하지 않아도 자바스크립트 엔진이 객체의 프로퍼티를 생성할 때 기본값으로 자동 정의됩니다.

프로퍼티 어트리뷰트 데이터 프로퍼티 기본값 설명
[[Value]] value value 프로퍼티 키를 통해 프로퍼티 값에 접근하면 반환되는 값 모든 데이터 타입
[[Writable]] witable true 프로퍼티 값의 변경 가능 여부를 표현.
false인 경우 value값을 변경할 수 없는 read-only 프로퍼티로 설정된다.
true/ false
[[Enumerable]] enumerable ture 프로퍼티 열거 가능 여부를 표현.
Object.assing()과 전개연산자가 속성을 볼 수 있는지 여부 결정.
(for..of/ for ..in 등)
true/ false
[[Configurable]] configurable ture 프로퍼티 재정의 가능 여부를 표현.
해당 프로퍼티 값 변경 또는 삭제 금지여부를 설정할 수 있다.
(value와 writable은 제외)
true/ false

 

 

접근자 프로퍼티

접근자 프로퍼티는 데이터 프로퍼티처럼 자체적인 값을 가지고 있지는 않습니다. 다만, 프로퍼티의 값을 읽거나 저장할 때 사용하는 접근자 함수로 구성된 프로퍼티입니다. 

프로퍼티 어트리뷰트 접근자 프로퍼티 설명
[[Get]] get 데이터 프로퍼티의 값을 읽을 때 호출되는 접근자 함수
프로퍼티의 키로 접근하면 [[Get]]의 값인 getter 함수가 호출되어 프로퍼티의 값을 반환
[[Set]] set 데이터 프로퍼티의 값을 저장할 때 호출되는 접근자 함수
프로퍼티의 키로 값을 저장하면 [[Set]]의 값인 setter 함수가 호출되어 프로퍼티의 값을 저장
[[Enumerable]] enumerable 프로퍼티 열거 가능 여부를 표현. 데이터 프로퍼티와 동일
[[Configurable]] configurable 프로퍼티 재정의 가능 여부를 표현. 테이터 프로퍼티와 동일

프로퍼티 디스크렉터 객체의 데이터 프로퍼티와 접근자 프로퍼티를 살펴보았습니다. 해당 디스크립터 객체의 프로퍼티로 접근해 프로퍼티 어트리뷰트 [[]]의 반환, 정의, 재정의등이 가능합니다. 

 

 


프로퍼티 디스크렉터 객체의 프로퍼티 정의

객체에 새로운 프로퍼티를 추가하면서 프로퍼티 어트리뷰트를 명시적으로 정의할 수 있습니다.

또한 기존에 존재하는 프로퍼티의 어트리뷰트를 재정의할 수도 있습니다.

그렇다면 어떻게 디스크립터 객체로 접근할 수 있을까요?

Object.defineProperty()  메소드를 이용해 생성 또는 수정할 수 있습니다.

Object.defineProperty(해당객체, '프로퍼티 키', {데이터 프로퍼티 or 접근자 프로퍼티})

1. 해당 객체에 프로퍼티 키가 존재하지 않으면 새로 생성하여 등록합니다.  키가 존재하면 수정합니다.

2. 데이터 프로퍼티와 접근자 프로퍼티는 혼용해서 사용할 수 없습니다.

3. 서술자의 일부 항목은 생략이 가능하며, 생략한 항목에는 기본 값을 사용합니다(자동 정의되는 기본값과 다릅니다)

 

 

데이터 프로퍼티 정의 및 확인

const avatar = {};

//데이터프로퍼티 생성하기(변경 가능, 열거 가능, 재정의 가능)
Object.defineProperty(avatar, "firstName", {
	value: "좋아요",
    writable: true, 
  	enumerable: true,
  	configurable: true,
});

//객체의 특정 프로퍼티 확인하기
const firstNameDescriptor = Object.getOwnPropertyDescriptor(avatar, "firstName");
console.log(firstNameDescriptor) 
//{ value: '좋아요', writable: true, enumerable: true, configurable: true }


//데이터프로퍼티 추가하기(변경 불가, 열거 불가, 재정의 불가)
Object.defineProperty(avatar, "lastName", {
	value: "요정",
    writable: false, 
  	enumerable: false,
  	configurable: false,
});

console.log(Object.keys(avatar)); // ['firstName']만 출력됨

1.빈 객체를 생성하고 Object.defineProperty()  메소드를 이용해 데이터프로퍼티를 생성했습니다.

2. lastName 프로퍼티의 경우 변경 불가, 열거 불가, 재정의 불가 속성을 가지고 있습니다. 열거되는 Object.keys(avatar)를 출력하면 lastName은 출력되지 않는 것을 볼 수 있습니다.

3. lastName에 값을 할당하면 출력되지 않는 것을 볼 수 있습니다.

 

 

 

접근자 프로퍼티 정의 및 확인

//접근자프로퍼티 생성하기
Object.defineProperty(avatar, "fullName", {
  get() {
    return `${this.firstName} ${this.lastName}`; 
  },
  set(name) {
    [this.firstName, this.lastName] = name.split(" ");
  },
  enumerable: true,
  configurable: true,
});

console.log(avatar.fullName) //"좋아요 요정"

avatar.fullName = "공부하는 요정"
console.log(avatar) //"공부하는 요정"

avater.fullName = "공부하는 학생"
console.log(avatar) //"공부하는 요정"

//객체의 모든 프로퍼티 확인하기
const avatarDescriptor = Object.getOwnPropertyDescriptors(avatar);

1. 접근자 프로퍼티도 동일한  Object.defineProperty()  메소드를 이용해 생성합니다. 이때 get(), set(), enumerable, configurable 정의를 작성합니다.

2. 해당 프로퍼티로 호출하면 get() 접근자 함수 내의 코드블럭이 실행됩니다. (avatar.fullName) 이때 함수가 아니기 때문에 객체의 키로 접근하는 것처럼 접근하면 됩니다.

3. set()으로 값을 저장할 수 있습니다. 이때 데이터 프로퍼티의 속성 정의에 따라 별다른 오류없이 진행됩니다.(lastName은 변경되지 않음)

4. 객체의 모든 프로퍼티를 호가인해보면  firstName, fullName, lastName을 확인해볼 수 있습니다.

 

 

 

 


와! 저 지금 이해한거 맞습니까

자바스크립트 처음 배울 때 간장공장공장장, 게터와 세터.. 하나도 이해하지 못했었는데 이번 스터디를 통해 이해하게 되었습니다 예!!

객체를 그저 key:value의 집합으로 사용하고, 중첩 객체를 사용하며 충분하다 생각했었습니다..

이렇게 객체의 사용법을 더 자세히 알게되니 객체가 새롭게 보입니다. 꽃이네요 꽃.

 

다른 교재를 통해 이 부분을 3번 읽었던 기억이 납니다. 이해가 되지 않았습니다..

글로 작성되어있는데 속성이 객체의 속성, 속성 기술자에 정의된 속성, 단어가 같기 때문에 머릿속에 전혀 그려지지 않았었습니다.

스터디를 하며 이걸 어떻게 풀어낼 수 있을지 예시를 작성하며 데이터 프로퍼티와 접근자 프로퍼티의 종류와 정의방법, get, set의 사용법에 대해 파악하게 되었습니다. 

꼭! 써봐야겠습니다. :)  팀러버덕 감사합니다 훈님 감사합니다!!! 

행복한 코딩라이프되세요~~

 

JavaScript 스터디 팀 러버덕과 함께 합니다.

 
 

 

혹시 잘못 이해한 곳이 있다면 자비로운 댓글 부탁드립니다. 감사합니다.

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/06   »
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
글 보관함