const o = {};
o.[Prototype]; //SyntaxError: Unexpected token '['
console.log(o.__proto__); // 콘솔에서 prototype과 프로퍼티, 메서드 확인 가능
/**
Object {}
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
__proto__: null
get __proto__: ƒ get __proto__()
set __proto__: ƒ set __proto__()
*/
const str = 'Hello';
console.log(str.__proto__);
/**
String ""
anchor: ƒ anchor()
at: ƒ at()
charAt: ƒ charAt()
charCodeAt: ƒ charCodeAt()
codePointAt: ƒ codePointAt()
concat: ƒ concat()
length: 0
... 생략...
toUpperCase: ƒ toUpperCase()
Symbol(Symbol.iterator): undefined
__proto__: Object
*/
책의 설명은 Object 기준이다
원시 타입도 프로퍼티(.length 등), 메서드(.toUpperCase() 등)가 준비되어 있다
참고 : https://ko.javascript.info/primitives-methods
프로퍼티의 상태
프로퍼티의 값(value)
값의 갱신 가능 여부(wriable)
열거 가능 여부(enumerable)
재정의 가능 여부(configurable)
내부 슬롯의 종류 : [[Value]], [[Writable]], [[Enumerable]], [[Confinugrable]]
Object.getOwnPropertyDescriptor() 메서드로 접근 가능
const person = {
name: 'Lee'
};
console.log(Object.getOwnPropertyDescriptors(person));
/**
Object {
name: Object
configurable: true
enumerable: true
value: "Lee"
writable: true
}
*/
| 프로퍼티 어트리뷰트 | 프로퍼티 디스크립터 객체의 프로퍼티 | 설명 |
|---|---|---|
| [[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로 변경하는 것은 허용된다. |
const person = {
name: 'Lee'
};
console.log(Object.getOwnPropertyDescriptors(person, 'name'));
/**
Object {name: {…}}
name: Object
configurable: true
enumerable: true
value: "Lee"
writable: true
*/
| 프로퍼티 어트리뷰트 | 프로퍼티 디스크립터 객체의 프로퍼티 | 설명 |
|---|---|---|
| [[Get]] | get | - 접근자 프로퍼티를 통해 데이터 프로퍼티의 값을 읽을 때 호출되는 접근자 함수 - 접근자 프로퍼티 키로 프로퍼티 값에 접근하면 프로퍼티 어트리뷰트 [[Get]]의 값, 즉 getter 함수가 호출된다. |
| [[Set]] | set | - 접근자 프로퍼티를 통해 데이터 프로퍼티의 값을 저장할 때 호출되는 접근자 함수 - 접근자 프로퍼티 키로 프로퍼티 값을 저장하면, 프로퍼티 어트리뷰터 [[Set]]의 값, 즉 setter 함수가 호출된다. |
| [[Enumerable]] | enumerable | - 데이터 프로퍼티의 [[Enumerable]]과 같다. |
| [[Configurable]] | configurable | - 데이터 프로퍼티의 [[Configurable]]과 같다. |
const person = {
// 데이터 프로퍼티들
firstName: 'Ed',
lastName: 'Lee',
// 접근자 프로퍼티 fullName
get fullName() {
return this.firstName + ' ' + this.lastName;
},
set fullName(name) {
[this.firstName, this.lastName] = name.split(' ');
}
};
// 데이터 프로퍼티 value의 사용
console.log(person.firstName); //Ed, Value의 호출
person.firstName = 'Jason'; // Value에 할당
console.log(person.firstName); // Jason
// 데이터 프로퍼티 어트리뷰트
// Object {value: "Jason", writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(person, 'firstName'));
// 접근자 프로퍼티의 사용
console.log(person.fullName); // Jason Lee, getter가 호출됐다
person.fullName = 'Ed Lee' // setter가 호출됐다
console.log(person.fullName); // Ed Lee
// 접근자 프로퍼티 어트리뷰트
//Object {get: ƒ, set: ƒ, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(person, 'fullName'));
// 함수 객체의 prototype은 데이터 프로퍼티
console.log(Object.getOwnPropertyDescriptor(function() { }, 'prototype'));
// Object {value: {…}, writable: true, enumerable: false, configurable: false}
// 일반 객체의 __proto__는 접근자 프로퍼티
console.log(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__'));
// Object {get: ƒ, set: ƒ, enumerable: false, configurable: true}
const person = {
firstName: '',
lastName: 'Lee',
};
person.firstName = 'Ed';
console.log(Object.getOwnPropertyDescriptor(person, 'firstName'));
// Object {value: "Ed", writable: true, enumerable: true, configurable: true}
Object.defineProperty(person, 'firstName', {
writable: false,
});
person.firstName = 'Jason';
console.log(Object.getOwnPropertyDescriptor(person, 'firstName'));
// Object {value: "Ed", writable: false, enumerable: true, configurable: true}
// 다수의 프로퍼티를 한 번에 정의
Object.defineProperties(person, {
firstName: {
writable: true,
},
lastName: {
configurable: false,
}
})
console.log(Object.getOwnPropertyDescriptor(person, 'firstName'));
// Object {value: "Ed", writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(person, 'lastName'));
// Object {value: "Lee", writable: true, enumerable: true, configurable: false}
const person = {};
person.firstName = 'Ed'; // 생성자에 의해 프로퍼티가 생성됨
console.log(Object.getOwnPropertyDescriptor(person, 'firstName'));
// Object {value: "Ed", writable: true, enumerable: true, configurable: true}
Object.defineProperty(person, 'lastName', {});
console.log(Object.getOwnPropertyDescriptor(person, 'lastName'));
// Object {value: undefined, writable: false, enumerable: false, configurable: false}
| 프로퍼티 어트리뷰트 | 프로퍼티 디스크립터 객체의 프로퍼티 | defineProperty의 기본값 | 생성자의 기본값 |
|---|---|---|---|
| [[Value]] | value | undefined | Value가 없으면 데이터 프로퍼티 생성 불가 |
| [[Get]] | get | undefined | undefined, 접근자 프로퍼티로 만드려면 get, set 둘 중 하나는 있어야 함 |
| [[Set]] | set | undefined | undefined, 접근자 프로퍼티로 만드려면 get, set 둘 중 하나는 있어야 함 |
| [[Writable]] | writable | false | true |
| [[Enumerable]] | enumerable | false | true |
| [[Configurable]] | configurable | false | true |
const person = {
set setter(name){}
};
console.log(Object.getOwnPropertyDescriptor(person, 'setter'));
// Object {get: undefined, set: ƒ, enumerable: true, configurable: true}
const person = {};
Object.defineProperty(person, 'name', {
value: 'Jason',
get() {
return "";
}
});
// TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute
참고 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object
| 구분 | 메서드 | 프로퍼티 추가 | 프로퍼티 삭제 | 프로퍼티 값 읽기 | 프로퍼티 값 쓰기 | 프로퍼티 어트리뷰트 재정의 | 관련 프로퍼티 어트리뷰트 |
|---|---|---|---|---|---|---|---|
| 객체 확장 금지 | Object.preventExtensions() Object.isExtensible() | X | O | O | O | O | - |
| 객체 밀봉 | Object.seal() Object.isSealed() | X | X | O | O | X | configurable: false |
| 객체 동결 | Object.freeze() Object.isFrozen() | X | X | O | X | X | writable: false configurable: false |
function deepFreeze(target) {
if (target && typeof target === 'object' && !Object.isFrozen(target)) {
Object.freeze(target);
Object.keys(target).forEach(key => deepFreeze(target[key]));
}
return target;
}
const person1 = {
name: 'EdLee',
address: { city: 'Seoul' }
};
Object.freeze(person1);
console.log(Object.isFrozen(person1.address)); // false
const person2 = {
name: 'EdLee',
address: { city: 'Seoul' }
};
deepFreeze(person2);
console.log(Object.isFrozen(person2.address)); // true