📢 어렵고 정석적인 개념 설명보다는 저같은 초보자도 이해하기 쉽게 정리하는 것을 원칙으로 포스팅하고 있습니다. 😄
개념
프로퍼티 디스크립터란, ES5부터 지원하는 기능으로 프로퍼티의 속성 이름과 값을 정의한다.
일반적으로 객체를 만들 때, 혹은 객체를 수정할 때 쓰는 기능이라고 생각하면 된다.
그런데 객체를 만들 때 간단하고 쉬운 방법이 많은데, 디스크립터도 꼭 알아야 할까?
디스크립터는 객체의 속성을 추가, 삭제, 금지 할 수 있지만 역으로 하지 못하게 할 수도 있다.
즉, 디스크립터는 보안에 강점을 가지고 있으며 이 뿐만 아니라 알아두면 여러모로 쓸 일이 많은 기능이니까 알아두는 게 좋다.
프로퍼티 디스크립터에는 3가지 분류가 있다.
1) 데이터 프로퍼티 디스크립터 : value, writable
2) 액세스 프로퍼티 디스크립터 : get, set
3) 공용 프로퍼티 디스크립터 : enumerable, configurable
데이터와 액세스 프로퍼티 디스크립터는 서로 같이 쓸 수 없으며, 공용 프로퍼티 디스크립터는 누구든 같이 쓸 수 있다.
프로퍼티 추가하기
프로퍼티 디스크립터를 사용할 때 먼저, 프로퍼티에 대한 정의를 내려야 한다.
이 때 사용하는 메소드가 defineProperty()이며, 가장 많이 쓰이는 기본적인 메소드라고 생각하면 된다.
var obj = {};
Object.defineProperty(obj, "name", {
value: "Kim",
writable: true,
enumerable: true
})
console.log(obj); // {name: Kim}
작성은 이런 식으로 하면 된다. 파라미터의 첫 번째에는 대상 오브젝트 이름을 넣고 두 번째에는 추가/변경할 프로퍼티 이름, 세 번째에는 디스크립터 속성(상태)를 넣으면 된다.
var obj = {};
Object.defineProperties(obj, {
name: {
value: "Kim",
enumerable: true
},
age: {
value: 29,
enumerable: true
}
})
만약에 복수의 프로퍼티를 추가/변경하고 싶다면 defineProperties()를 통해 할 수 있다.
첫 번째 파라미터에는 똑같이 대상 오브젝트 이름을 넣고, 두 번째 파라미터에는 추가/변경할 프로퍼티 이름과 속성(상태)를 한꺼번에 넣으면 된다.
데이터 프로퍼티 디스크립터
let obj = {};
Object.defineProperty(obj, "name", {
value : "Kim",
writable : true
})
obj.name = "Park";
console.log(obj.name); // Park
데이터 프로퍼티 디스크립터에는 value와 writable이 있다. 이 둘의 개념은 간단하다.
value는 말그대로 오브젝트의 속성 값을 나타내고 writable은 변경이 가능한지 여부를 나타낸다.
위와 같이 작성하면, 'obj라는 오브젝트에 "name"이라는 속성을 만들고, "Kim"이라는 속성 값을 넣겠다. 또한 속성 값은 변경이 가능하다.' 라고 해석할 수 있다.
실제로 obj.name = "Park"을 하게 되면 변경이 가능하므로 "Kim"이 "Park"으로 변경이 된다.
만약, writable의 값을 false로 설정한다면 변경이 불가능하므로 "Park"이 아닌 "Kim"으로 반환될 것이다.
writable의 디폴트 값은 false이므로 추후 변경이 가능하게 하고 싶다면 꼭 넣어줘야 한다.
액세스 프로퍼티 디스크립터
let obj = {};
Object.defineProperty(obj, "name" {
set : function (param){
data.title = param;
},
get : function (param){
return data.title;
}
});
obj.name = "Kim"
console.log(obj.name); // Kim
액세스 프로퍼티 디스크립터는 get과 set으로 둘 다 함수를 이용한다.
함수가 호출되면 먼저 set 함수를 거친 후 get 함수를 호출하며 get에는 return 값을 넣어줘야 한다.
말 그대로 set 함수를 통해 먼저 셋팅(set)을 거친 후 get 함수를 통해 그 셋팅을 가져온다(get)는 개념이다.
let obj = {};
Object.defineProperty(obj, "name" {
get : function (){
return "Kim";
}
});
let result = obj.name;
console.log(result); // Kim
set 없이 get만 단독으로 사용하기도 한다. 이 경우 파라미터없이 바로 return 값을 반환한다.
공용 프로퍼티 디스크립터
let obj = {};
Object.defineProperty(obj, "name", {
value : "Kim",
enumerable : true,
configurable : true
});
for (item in obj){
console.log(item + " = " + obj[item]) // name = Kim
}
delete obj.name;
console.log(obj.name); // undefined
공용 프로퍼티 디스크립터에는 속성 값에 접근한다는 개념보다는 이 프로퍼티를 열거 가능하냐, 삭제 가능하냐의 프로퍼티 상태를 설정해주는 기능으로 데이터와 액세스 디스크립터 누구든 같이 사용할 수 있다.
먼저, enumerable은 열거의 가능 여부로 true를 하면 열거 가능, false를 하면 열거 불가능을 의미한다.
여기서 열거란, for~in문을 통해 프로퍼티의 속성과 속성 값을 반환하는 걸 말한다.
configurable은 삭제가 가능하냐 불가능하냐를 의미하는 속성으로 true면 삭제 가능, false면 삭제 불가능을 의미한다.
delete를 통해 삭제가 가능하며, 삭제할 경우 해당 프로퍼티의 속성과 속성 값 모두 삭제되어 undefined를 반환한다.
enumerable과 configurable 둘 다 디폴트 값은 false이기 때문에 열거와 삭제가 가능하게 하려면 true로 작성해야 한다. 만약 작성하지 않거나 false로 설정하면, 열거나 삭제를 하려고 해도 정상 작동되지 않는다.
프로퍼티 디스크립터 함수
let obj = {};
Object.defineProperty(obj, "name", {
vlaue : "Kim",
writable : true,
enumerable : true
})
let desc = Object.getOwnPropertyDescriptor(obj, "name");
for (key in desc){
console.log(key + " = " + desc[key]);
}
/*
vlaue = Kim
writable = true
enumerable = true
configurable = false
*/
getOwnPropertyDescriptor()는 프로퍼티 디스크립터의 속성 이름(상태)과 값을 반환해주는 함수로 defineProperty() 등으로 정의된 해당 프로퍼티의 속성 값과 상태 모두 출력해주는 기능을 갖고 있다.
configurable은 false로 설정하지 않았지만, 디폴트 값이 false이기 때문에 설정하지 않더라도 함께 반환된다.
let obj = {};
Object.preventExtension(obj); // 이 순간부터 추가 금지!
try {
Object.defineProperty(obj, "name", {
value : "Kim"
})
} catch (e){
console.log("추가 불가")
}
preventExtensions()는 말그대로 확대를 방지한다, 즉 프로퍼티에 추가를 금지한다는 함수이다.
isExtensible() 함수를 통해 preventExtensions() 함수로 프로퍼티 추가가 금지됐는지의 여부를 확인할 수도 있다.
let obj = {};
Object.defineProperty(obj, "name", {
value : "Kim",
writable : true
});
Object.seal(obj); // 이 순간부터 추가, 삭제 금지!
try {
Object.defineProperty(obj, "age", {
value : 29
})
} catch (e){
console.log("추가 불가")
}
seal()은 프로퍼티 추가 및 삭제 금지를 설정하는 함수로, 위에 preventExtensions()에 configurable이 추가된 함수이다.
isSeales() 함수를 통해 seal()의 여부를 물어볼 수 있다.
let obj = {};
Object.defineProperty(obj, "name", {
value : "Kim",
writable : true
})
Object.freeze(obj); // 이 순간부터 추가, 삭제, 변경 금지!
try {
Object.defineProperty(obj, "name", {
value : "Park"
})
} catch (e){
console.log("변경 불가")
}
freeze()는 추가, 삭제, 변경 모두 금지하는 함수로 말그대로 얼려버려서 아무것도 못하게 만들어버리는 함수이다.
isFrozen()을 통해 freeze()의 여부를 확인할 수 있다.
preventExtensions() | seal() | freeze() | |
추가 | 불가 | 불가 | 불가 |
삭제 | 가능 | 불가 | 불가 |
변경 | 가능 | 가능 | 불가 |
프로퍼티 디스크립터 함수들의 기능을 정리하자면, 위의 표와 같다. 또한 위 함수들 모두 함수의 여부를 물어보는 is~() 함수들이 존재한다. 이 함수들을 통해 프로퍼티의 열거, 삭제 뿐만 아니라 추가와 변경 또한 통제 가능하다.
프로퍼티 디스크립터가 필요한 이유는 바로 통제가 가능하기 때문인 것 같다.
변경 또는 삭제가 불가능한 객체를 만들면, 보안을 위해서도 좋고 협업을 할 때도 오류를 방지할 수 있어서 좋다.
'JavaScript' 카테고리의 다른 글
[JavaScript] 자바스크립트 함수 실행 과정과 호이스팅 (0) | 2022.01.18 |
---|---|
[JavaScript] 중복 체크에 활용하면 좋은 indexOf() (0) | 2022.01.17 |
[JavaScript] DOM 이벤트 핸들러 onclick과 onsubmit (0) | 2022.01.12 |
[JavaScript] this란 무엇일까? (0) | 2022.01.10 |
[JavaScript] Math.random()으로 랜덤 값 구하기 (0) | 2021.12.28 |