코어자바스크립트 : 프로퍼티 getter와 setter
객체의 프로퍼티는 데이터 프로퍼티와 접근자 프로퍼티로 나뉜다.
접근자 프로퍼티는 'getter'와 'setter' 메서드로 표현된다. 객체 리터럴 안에서 getter와 setter 메서드는 get과 set으로 나타낼 수 있다.
let obj = {
get propName() {
// getter, obj.propName을 실행할 때 실행되는 코드
},
set propName(value) {
// setter, obj.propName = value를 실행할 때 실행되는 코드
}
};
즉 getter 메서드는 프로퍼티를 읽으려고 할 때 실행되고, setter 메서드는 프로퍼티에 값을 할당하려 할 때 실행된다.
let user = {
name: "John",
surname: "Smith",
get fullName() {
return `${this.name} ${this.surname}`;
}
};
alert(user.fullName); // John Smith
기존 값을 복사-붙여넣기 하지 않고도 getter 메서드로 구현한 코드이다. 바깥 코드에서는 접근자 프로퍼티를 일반 프로퍼티처럼 사용할 수 있다. 마치 일반 프로퍼티 값에 접근하는 것 처럼 user.fullName
을 사용해서 값을 얻을 수 있다. 하지만 위 코드는 getter 메서드만 가지고 있기 때문에 user.fullName=
형식으로 값을 할당하려하면 에러가 난다.
let user = {
name: "John",
surname: "Smith",
get fullName() {
return `${this.name} ${this.surname}`;
},
set fullName(value) {
[this.name, this.surname] = value.split(" ");
}
};
// 주어진 값을 사용해 set fullName이 실행됩니다.
user.fullName = "Alice Cooper";
alert(user.name); // Alice
alert(user.surname); // Cooper
setter 메서드를 추가해서 값을 할당할 수 있도록 만들었다.
접근자 프로퍼티는 데이터 프로퍼티와는 다른 설명자를 가지고 있다. 접근자 프로퍼티에는 value
와 writable
이 없는 대신 get
과 set
이라는 함수가 있다.
접근자 프로퍼티의 설명자
get
: 인수가 없는 함수로, 프로퍼티를 읽을 때 동작한다.set
: 인수가 하나인 함수로, 프로퍼티에 값을 쓸때 호출된다.enumerable
, configurable
: 데이터 프로퍼티와 동일하다.defineProperty
에 설명자 get
과 set
을 전달하여 fullName
을 위한 접근자를 생성한 코드.
let user = {
name: "John",
surname: "Smith"
};
Object.defineProperty(user, 'fullName', {
get() {
return `${this.name} ${this.surname}`;
},
set(value) {
[this.name, this.surname] = value.split(" ");
}
});
alert(user.fullName); // John Smith
for(let key in user) alert(key); // name, surname
프로퍼티는 접근자 프로퍼티(get/set
메서드)나 데이터 프로퍼티(value
) 중 한 종류에만 속할 수 있다. 둘 다 속하는 것 불가능하다!
// Error: Invalid property descriptor.
Object.defineProperty({}, 'prop', {
get() {
return 1
},
value: 2
});
let user = {
get name() {
return this._name;
},
set name(value) {
if (value.length < 4) {
alert("입력하신 값이 너무 짧습니다. 네 글자 이상으로 구성된 이름을 입력하세요.");
return;
}
this._name = value;
}
};
user.name = "Pete";
alert(user.name); // Pete
user.name = ""; // 너무 짧은 이름을 할당하려 함
접근자 프로퍼티를 실제 프로퍼티 값을 감싸는 래퍼로 사용하면 위와 같이 프로퍼티 값을 원하는 대로 통제할 수 있다.
접근자 프로퍼티는 getter와 setter를 사용해서 데이터 프로퍼티의 행동과 값을 원하는 대로 조정할 수 있게 해준다는 점에서 유용하다.
function User(name, age) {
this.name = name;
this.age = age;
}
let john = new User("John", 25);
alert( john.age ); // 25
위 코드에서 age
대신에 birthday
를 저장해야 한다면?
function User(name, birthday) {
this.name = name;
this.birthday = birthday;
}
let john = new User("John", new Date(1992, 6, 1));
이렇게 하면 기존 코드 중 age
프로퍼티를 사용하는 코드도 수정해줘야 한다. (으악!)
기존 코드는 그대로 두고 age
를 위한 getter
를 추가해서 문제를 해결해보자.
function User(name, birthday) {
this.name = name;
this.birthday = birthday;
// age는 현재 날짜와 생일을 기준으로 계산됩니다.
Object.defineProperty(this, "age", {
get() {
let todayYear = new Date().getFullYear();
return todayYear - this.birthday.getFullYear();
}
});
}
let john = new User("John", new Date(1992, 6, 1));
alert( john.birthday ); // birthday를 사용할 수 있습니다.
alert( john.age ); // age 역시 사용할 수 있습니다.
우..와 대박이다......