const ellie = { name: "ellie", age: 4 };
https://www.youtube.com/watch?v=fFs2pkpWwQU
자바스크립트 엔진은 프로퍼티를 생성할 때, 프로퍼티의 상태를 나타내는 프로퍼티 어트리뷰트를 기본값으로 자동 정의한다. 프로퍼티의 상태란 프로퍼티의 값(value), 값의 갱신 가능 여부(writable), 열거 가능 여부(enumerable), 재정의 가능 여부(configurable)를 말한다.
프로퍼티 어트리뷰트는 자바스크립트 엔진이 관리하는 내부 상태 값인 내부 슬롯이므로 직접 접근할 수 없지만, Object.getOwnPropertyDescriptor
메소드를 사용하여 간접적으로 확인할 수 있다.
const person = {
name: "Lee",
};
console.log(Object.getOwnPropertyDescriptor(person, "name"));
// {value: 'Lee', writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(person, "age"));
// undefined
Object.getOwnPropertyDescriptors
Object.getOwnPropertyDescriptor
메소드는 단 한개의 프로퍼티에 대해 프로퍼티 디스크립터 객체를 반환하지만, Object.getOwnPropertyDescriptors
메소드는 ES8에서 도입된 것으로 모든 프로퍼티의 프로퍼티 어트리뷰트 정보를 제공하는 프로퍼티 디스크립터 객체들을 반환한다.
const person = {
name: "Lee",
age: "20",
};
console.log(Object.getOwnPropertyDescriptors(person));
/*
{
age: {value: '20', writable: true, enumerable: true, configurable: true}
name: {value: 'Lee', writable: true, enumerable: true, configurable: true}
}
*/
프로퍼티는 데이터 프로퍼티와 접근자 프로퍼티로 구분할 수 있다.
https://www.youtube.com/watch?v=0AjTZG6bGq8
데이터 프로퍼티(data property)는 키(key)와 값(value)으로 구성된 일반적인 프로퍼티로, 지금까지 살펴본 모든 프로퍼티가 데이터 프로퍼티 이다.
프로퍼티 | 설명 |
---|---|
value | 프로퍼티 키로 프로퍼티 값에 접근하면 반환되는 값 |
writable | 프로퍼티 값의 변경 가능 여부를 나타내는 불리언 값 |
enumerable | 프로퍼티의 열거 가능 여부를 나타내는 불리언 값 |
configurable | 프로퍼티의 재정의 가능 여부를 나타내는 불리언 값 |
https://www.youtube.com/watch?v=JIMUy2RmclI
접근자 프로퍼티(accessor property)는 자체적으로 값을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 호출되는 접근자 함수(accessor function)로 구성된 프로퍼티 이다.
프로퍼티 | 설명 |
---|---|
get | 프로퍼티 를 읽을 때 동작되는 함수 |
set | 프로퍼티 값을 쓸 때 동작되는 함수 |
enumerable | 데이터 프로퍼티 enumerable와 같다 |
configurable | 데이터 프로퍼티 configurable와 같다. |
접근자 함수는 getter/setter 함수라고도 부른다. 접근자 프로퍼티는 getter와 setter 함수를 모두 정의할 수도 있고 하나만 정의할 수도 있다.
※ getter 함수는 return
존재하도록 작성해야됨.
const person = {
// 데이터 프로퍼티
firstName: "Ungmo",
lastName: "Lee",
// getter 함수
get fullName() {
return `${this.firstName} ${this.lastName}`;
},
// setter 함수
set fullName(name) {
[this.firstName, this.lastName] = name.split(" ");
},
};
console.log(`${person.firstName} ${person.lastName}`); // Ungmo Lee
console.log(person.fullName); // Ungmo Lee
// fullName 값을 저장하면 setter가 호출된다.
person.fullName = "Heegun Lee";
console.log(person); // {firstName: 'Heegun', lastName: 'Lee'}
// fullName에 접근하면 getter가 호출된다.
console.log(person.fullName); // Heegun Lee
let descriptorData = Object.getOwnPropertyDescriptor(person, "firstName");
console.log(descriptorData);
// {value: 'Ungmo', writable: true, enumerable: true, configurable: true}
let descriptorAccessor = Object.getOwnPropertyDescriptor(person, "fullName");
console.log(descriptorAccessor);
// {get: ƒ, set: ƒ, enumerable: true, configurable: true}
https://www.youtube.com/watch?v=CPTq48Bl6Co
Object.defineProperty
Object.defineProperty
메소드를 사용하면 프로퍼티의 어트리뷰트를 정의할 수 있다. 인수는 객체의 참조와 프로퍼티의 키인 문자열 그리고 프로퍼티 디스크립터 객체를 전달한다.
const person = {};
Object.defineProperty(person, "firstName", {
value: "Ungmo",
writable: true,
enumerable: true,
configurable: true,
});
console.log(Object.getOwnPropertyDescriptor(person, "firstName"));
// {value: 'Ungmo', writable: true, enumerable: true, configurable: true}
Object.defineProperty(person, "lastName", {
value: "Lee",
});
console.log(Object.getOwnPropertyDescriptor(person, "lastName"));
// {value: 'Lee', writable: false, enumerable: false, configurable: false}
writable: false
이므로 [[value]]
값을 변경할 수 없다.person.lastName = "kim";
console.log(person.lastName); // Lee
enumerable: false
이므로 for...in
, Object.keys
등 열거되지 않는다.console.log(Object.keys(person)); // ['firstName']
configurable: false
이므로 프로퍼티 삭제시 무시된다.delete person.lastName;
console.log(Boolean(person.lastName)); // true
Object.defineProperty(person, "fullName", {
get() {
return `${this.firstName} ${this.lastName}`;
},
set(name) {
[this.firstName, this.lastName] = name.split(" ");
},
enumerable: true,
configurable: true,
});
console.log(Object.getOwnPropertyDescriptor(person, "fullName"));
// {enumerable: true, configurable: true, get: ƒ, set: ƒ}
Object.definePropertys
Object.defineProperty
메소드는 한번에 하나의 프로퍼티만 정의할 수 있다. Object.defineProperties
메소드를 사용하면 여러 개의 프로퍼티를 한번에 정의할 수 있다.
const person = {};
Object.defineProperties(person, {
firstName: {
value: "Ungmo",
writable: true,
enmerable: true,
configurable: true,
},
lastName: {
value: "Lee",
writable: true,
enmerable: true,
configurable: true,
},
fullName: {
get() {
return `${this.firstName} ${this.lastName}`;
},
set(name) {
[this.firstName, this.lastName] = name.split(" ");
},
enmerable: true,
configurable: true,
},
});
console.log(person.fullName); // Ungmo Lee
person.fullName = "Heegun Lee";
console.log(person.fullName); // Heegun Lee
https://www.youtube.com/watch?v=llM1uf8kLMs
객체는 변경 가능한 값이므로 재활당없이 직접 변경이 가능하다. 즉, 프로퍼티를 추가하거나 삭제할 수 있고, 프로퍼티의 값을 갱신할 수 있으며 Object.defineProperty
또는 Object.definePropertys
메소드를 사용하여 프로퍼티 어트리뷰트를 재정의할 수도 있다.
자바스크립트는 객체의 변경을 방지할 수 있는 다양한 메소드를 제공한다. 객체 변경 방지 메소드 들은 객체의 변경을 금지하는 강도가 다르다.
구분 | 메소드 | 프로퍼티 추가 | 프로퍼티 삭제 | 프로퍼티 값 읽기 | 프로퍼티 값 쓰기 | 프로퍼티 어트리뷰트 재정의 |
---|---|---|---|---|---|---|
객체 확장 금지 | Object.preventExtensions | X | O | O | O | O |
객체 밀봉 | Object.seal | X | X | O | O | X |
객체 동결 | Object.freeze | X | X | O | X | X |
Object.preventExtensions
메소드는 객체의 확장을 금지한다.Object.defineProperty
사용한 방법 모두 금지된다.Object.isExtensible
메소드로 확인가능함.const person = { name: "Lee" };
console.log(Object.isExtensible(person)); // true
// person 객체의 확장 금지(프로퍼티 추가 금지) 적용
Object.preventExtensions(person);
console.log(Object.isExtensible(person)); // false
person.age = 20; // 'use strict' 모드에서는 에러 발생됨
console.log(person); // {name: 'Lee'}
delete person.name;
console.log(person); // {}
Object.seal
메소드는 객체를 밀봉한다.Object.isSealed
메소드로 확인 할 수 있다.person
객체의 밀봉(seal) 전/후const person = { name: "Lee" };
console.log(Object.isSealed(person)); // false
// 객체 밀봉으로 프로퍼티 추가, 삭제, 재정의가 금지된다.
Object.seal(person);
console.log(Object.isSealed(person)); // true
// 밀봉된 객체는 configurable 디스크립터가 false로 된다.
console.log(Object.getOwnPropertyDescriptors(person));
/*
{
name: {value: 'Lee', writable: true, enumerable: true, configurable: false},
}
*/
person.age = 20; // 'use strict' 모드에서는 에러 발생됨
console.log(person); // {name: 'Lee'}
delete person.name; // 'use strict' 모드에서는 에러 발생됨
console.log(person); // {name: 'Lee'}
person.name = "kim";
console.log(person); // {name: 'kim'}
Object.definedProperty(person, "name", { configurable: true });
// TypeError: Object.definedProperty is not a function
Object.freeze
메소드는 객체를 동결한다.Object.isFrozen
메소드로 확인 할 수 있다.const person = { name: "Lee" };
console.log(Object.isFrozen(person)); // false
// 객체 동결로 프로퍼티 추가, 삭제, 재정의, 쓰기를 금지한다.
Object.freeze(person);
console.log(Object.isFrozen(person)); // true
// 동결된 객체는 writable 디스크립터가 false로 된다.
console.log(Object.getOwnPropertyDescriptors(person));
/*
{
name: {value: 'Lee', writable: false, enumerable: true, configurable: false},
}
*/
person.age = 20; // 'use strict' 모드에서는 에러 발생됨
console.log(person); // {name: 'Lee'}
delete person.name; // 'use strict' 모드에서는 에러 발생됨
console.log(person); // {name: 'Lee'}
person.name = "Kim"; // 'use strict' 모드에서는 에러 발생됨
console.log(person); // {name: 'Lee'}
Object.definedProperty(person, "name", { writable: true });
// TypeError: Object.definedProperty is not a function