16장
프로퍼티 어트리뷰트와 프로퍼티 디스크립터 객체
자바스크립트 엔진은 프로퍼티를 생성할 때 프로퍼티의 상태를 나타내는 프로퍼티 어트리뷰트를
기본값으로 자동 정의한다.
프로퍼티 상태란 프로퍼티의 값, 값의 갱신 가능 여부, 열거 기능 여부, 재정의 가능 여부를 말한다.
object.getOwnPropertyDescriptor 메서드를 사용하면 간접적으로 확인할 수 있다.
const person = {
name : 'ah'
};
//첫번째 매개변수는 객체를 두번째는 프로퍼티 키를
console.log(Object.getOwnPropertyDescriptor(person,'name'));
데이터 프로퍼티와 접근자 프로퍼티
데이터 프로퍼티 : 키와 값으로 구성된 일반적인 프로퍼티
접근자 프로퍼티 : 자체적으로 값을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나
저장할 때 호출되는 접근자 함수로 구성
데이터 프로퍼티
- [[Value]] - value : 프로퍼티 키를 통해 프로퍼티 값을 변경하면 [[Value]]에 값을 재할당, 이때 프로퍼티가 없으면 프로퍼티를 동적으로 생성하고 생성된 프로퍼티의 [[Value]]에 값을 저장
- [[Writable]] - writable : 값의 변경 여부 , 불리언 값, false인 경우 변경불가
- [[Enumerable]] - enumerable : 열거 가능 여부, 불리언 값, false인 경우 해당 프로퍼티는 for ... in문이나 object.keys 메서드 등으로 열거할 수 없다.
- [[Configurable]] - configurable : 재정의 가능 여부, 불리언 값, false인 경우 해당 프로퍼티 삭제,값의 변경 금지단 [[Writable]] 이 true인 경우 [[Value]]의 변경과 [[Writable]] 을 false로 변경하는 것은 허용
프로퍼티가 생성될 때 [[Value]] 의 값은 초기화 되며 나머지의 값들도 true로 초기화 된다.
const person = {
name : 'ah'
};
person.age = 20;
//첫번째 매개변수는 객체를 두번째는 프로퍼티 키를
console.log(Object.getOwnPropertyDescriptor(person));
//name : {value:"ah", writable: true, enumerable: true, configurable: true}
//age : {value:"20", writable: true, enumerable: true, configurable: true}
접근자 프로퍼티
자체적으로 값을 갖지 않고 다른 데이터 프로퍼티의 값을 읽거나 저장할 때 사용하는 접근자 함수로 구성
- [[Get]] - get : 값을 읽을떄 호출
- [[Set]] - set : 값을 저장할 때 호출
- [[Enumerable]] - enumerable : 데이터 프로퍼티 [[Enumerable]] 와 같다
- [[Configurable]] - configurable : 데이터 프로퍼티 [[Configurable]] 와 같다
const person = {
firstName: 'alice',
lastName : 'Han',
get fullName() {
return `${this.firstName} ${this.lastName}`;
},
set fullName(name) {
[this.firstName, this.lastName] = name.split(' ');
}
};
//데이터 프로퍼티를 통한 값 참조
console.log(person.firstName + ' ' + person.lastName);
//접근자 프로퍼티를 통한 값 저장
//접근자 프로퍼티 fullName에 값을 저장하면 setter 함수가 호출
person.fullName = 'Heegun Lee';
console.log(person); //person 안에 있던 값이 바뀜
console.log(person.fullName);
//firstName은 데이터 프로퍼티
let descriptor = object.getOwnPropertyDescriptor(person, 'firstName');
console.log(descriptor);
//{value: "alice", writable : true, enumerable : true, configurable : true}
descriptor = object.getOwnPropertyDescriptor(person, 'fulltName');
console.log(descriptor);
//{get: f,set: f, enumerable : true, configurable : true}
person 객체의 firstName과 lastName 프로퍼티는 일반적인 데이터 프로퍼티이다.
getter/setter 함수를 쓰는 fullName이 접근자 프로퍼티다
접근자 프로퍼티는 값을 가지지 않고 값을 저장할 때만 관여
//구별하는 법
//일반 객체의 __proto__는 접근자 프로퍼티다
Object.getOwnPropertyDescriptor(Object.prototype, '__proto__');
//함수 객체의 prototype은 데이터 프로퍼티다
Object.getOwnPropertyDescriptor(function() {}, 'prototype');
프로퍼티 정의
새로운 프로퍼티를 추가하면서 프로퍼티 어트리뷰트를 명시적으로 정의하거나
기존 프로퍼티의 프로퍼티 어트리뷰트를 재정의하는 것
Object.defineProperty메서드를 사용하면 프로퍼티의 어트리뷰트를 정의 할 수 있다
객체 변경 방지
객체 확장 금지
프로퍼티 추가 금지를 의미
Object.preventExtensions 메서드는 객체의 확장을 금지한다.
객체 밀봉
프로퍼티 추가 및 삭제와 프로퍼티 어트리뷰트 재정의 금지를 의미
즉 밀봉된 객체는 읽기와 쓰기만 가능
Object.isSealed 메서드로 확인
객체 동결
객체 동결이랑 프로퍼티 추가 및 삭제와 프로퍼티 어트리뷰트 재정의 금지, 프로퍼티 값 갱신 금지
즉 읽기만 가능
Object.isFrozen 메서드로 확인가능
불변 객체
객체 확장 금지, 객체 밀봉, 객체 동결은 얕은 변경 방지이며
중첩 객체까지는 영향을 주지 못한다.
변동이 불가능한 읽기 전용의 불변 객체를 구현하려면 모든 프로퍼티에 대해 재귀적으로
Object.freeze 메서드를 호출
17장
Object 생성자 함수
const person = new object();
생성자 함수란 new 연산자와 함께 호출하여 객체(인스턴스)를 생성하는 함수
생성자 함수에 의해 생성된 객체를 인스턴스라 한다
생성자 함수
객체 리터럴에 의한 객체 생성 방식이 문제점
동일한 프로퍼티를 갖는 객체를 여러 개 생성해야 하는 경우 매번 같은 프로퍼티를 기술해야 하기 때문이
비효율적이다
생성자 함수에 의한 객체 생성 방식의 장점
템플릿(클래스)처럼 생성자 함수를 사용하여 프로퍼티 구조가 동일한 객체 여러 개를 간편하게 생성할 수 있다
new 연산자와 함께 호출하면 해당 함수는 생성자 함수로 동작
생성자 함수의 인스턴스 생성 과정
function Circle(radius) {
//1.암묵적으로 인스턴스가 생성되고 this에 바인딩
//2.this에 바인딩되어 있는 인스턴스를 초기화
this.radius = radius;
this.getDiamer = function() {
return 2* this.radius;
};
//3. 완성된 인스턴스가 바인딩된 this를 암묵적으로 반환
return {}; //this가 있으므로 무시된다
}
//this에 프로퍼티를 추가하고 필요에 따라 전달된 인수를 프로퍼티의 초기값으로 할당하여
//인스턴스를 초기화한다
내부 메서드 [[Call]]과 [[Construct]]
함수는 호출할 수 있는 객체라서 내부 메서드 [[Call]]과 [[Construct]]를 가지고 있다
function foo() {}
//일반적인 함수로서 호출: [[call]]이 호출
foo();
//생성자 함수로서 호출: [[construct]]가 호출
new foo();
[[Call]] : 호출할 수 있는 함수 callable
[[Construct]] : 내부 메서드를 가지고 있는 함수(없을수도 있음) constructor
constructor와 non-constructor 구분
constructor : 함수 선언문, 함수 표현식, 클래스(클래스도 함수다)
non-constructor :메서드(축약표현), 화살표
function foo() {}
const bar = function() {};
const baz = {
x : function () {}
};
//non-constructor
const arrow = () => {};
const obj = {
x() {}
};
new 연산자
생성자 함수, constructor 함수가 호출되어야 한다
new.target
this와 유사하게 constructor인 모든 함수 내부에서 암묵적인 지역 변수와 같이 사용되며
메타 프로퍼티라고 부른다
new 연산자와 함께 생성자 함수로서 호출되면 함수 내부의 new.target은 함수 자신을 가리킨다.
new 연산자 없이 일반 함수로서 호출된 함수 내부의 new.target은 undefined다
따라서 함수 내부에서 new.target을 사용하여 new 연산자와 생성자 함수로서 호출했는지 확인하여
그렇지 않은 경우 new 연산자와 함께 재귀 호출을 통해 생성자 함수로서 호출할 수 있다
function Circle(radius) {
if(!new.target) {
return new Circle(radius);
}
this.radius = radius;
this.getDiameter = function() {
return 2 * this.radius;
};
}
const circle = Circle(5); //new 연산자 없이 생성자 함수를 호출하여도 생성자 함수로서 호출된다.
console.log(circle.getDiameter();
instanceof 메소드를 통해서도 확인 가능
대부분의 빌트인 생성자 함수 new 연산자와 함께 호출되었는지를 확인한 후 적절한 값을 반환하다.
'언어 > WEB' 카테고리의 다른 글
모던 자바스크립 19장 프로토타입(미완성) (0) | 2023.06.14 |
---|---|
18장 모던 자바스크립 함수와 일급 객체 (1) | 2023.06.13 |
언어/JAVAScript모던 자바스크립 12장 스코프 (0) | 2023.06.06 |
[제이쿼리] 배열 관련 메서드 (0) | 2023.06.02 |
[제이쿼리] 선택자 (1) | 2023.06.01 |