객체 속성에는 두 가지 종류가 있습니다.
첫 번째 종류는 데이터 속성 입니다. 우리는 이미 그들과 협력하는 방법을 알고 있습니다. 지금까지 사용했던 모든 속성은 데이터 속성이었습니다.
두 번째 유형의 속성은 새로운 것입니다. 접근자 속성 입니다. 본질적으로 값을 가져오고 설정할 때 실행되는 함수이지만 외부 코드에서는 일반 속성처럼 보입니다.
접근자 속성은 "getter" 및 "setter" 메서드로 표현됩니다. 객체 리터럴에서는 get
및 set
으로 표시됩니다.
obj = {라고 놔두세요 propName() 가져오기 { // getter, obj.propName을 가져올 때 실행되는 코드 }, propName(값) 설정 { // setter, obj.propName = value 설정 시 실행되는 코드 } };
getter는 obj.propName
읽을 때 작동하고, setter는 할당될 때 작동합니다.
예를 들어 name
과 surname
있는 user
개체가 있습니다.
사용자 = { 이름: "존", 성 : "스미스" };
이제 "John Smith"
여야 하는 fullName
속성을 추가하려고 합니다. 물론 기존 정보를 복사하여 붙여넣는 것을 원하지 않으므로 이를 접근자로 구현할 수 있습니다.
사용자 = { 이름: "존", 성: "스미스", 전체 이름() 가져오기 { return `${this.name} ${this.surname}`; } }; 경고(사용자.전체 이름); // 존 스미스
외부에서 접근자 속성은 일반 속성처럼 보입니다. 이것이 접근자 속성의 아이디어입니다. user.fullName
함수로 호출 하지 않고 정상적으로 읽습니다 . getter는 뒤에서 실행됩니다.
현재 fullName
getter만 있습니다. user.fullName=
할당하려고 하면 오류가 발생합니다.
사용자 = { 전체 이름() 가져오기 { `...`를 반환; } }; user.fullName = "테스트"; // 오류(속성은 getter만 가짐)
user.fullName
에 대한 setter를 추가하여 문제를 해결해 보겠습니다.
사용자 = { 이름: "존", 성: "스미스", 전체 이름() 가져오기 { return `${this.name} ${this.surname}`; }, 전체 이름(값) 설정 { [this.name, this.surname] = value.split(" "); } }; // set fullName은 주어진 값으로 실행됩니다. user.fullName = "앨리스 쿠퍼"; 경고(사용자.이름); // 앨리스 경고(사용자.성); // 쿠퍼
결과적으로 "가상" 속성 fullName
있습니다. 읽고 쓸 수 있습니다.
접근자 속성에 대한 설명자는 데이터 속성에 대한 설명과 다릅니다.
접근자 속성에는 value
나 writable
없지만 대신 get
및 set
함수가 있습니다.
즉, 접근자 설명자는 다음을 가질 수 있습니다:
get
– 속성을 읽을 때 작동하는 인수 없는 함수,
set
- 속성이 설정될 때 호출되는 인수가 하나인 함수입니다.
enumerable
– 데이터 속성과 동일
configurable
- 데이터 속성과 동일합니다.
예를 들어, defineProperty
사용하여 fullName
접근자를 생성하려면 get
및 set
사용하여 설명자를 전달할 수 있습니다.
사용자 = { 이름: "존", 성 : "스미스" }; Object.defineProperty(사용자, 'fullName', { 얻다() { return `${this.name} ${this.surname}`; }, 설정(값) { [this.name, this.surname] = value.split(" "); } }); 경고(사용자.전체 이름); // 존 스미스 for(사용자의 키를 입력하세요) Alert(key); // 이름, 성
속성은 접근자( get/set
메서드 포함) 또는 데이터 속성( value
포함)일 수 있으며 둘 다일 수는 없습니다.
동일한 설명자에 get
과 value
모두 제공하려고 하면 오류가 발생합니다.
// 오류: 잘못된 속성 설명자입니다. Object.defineProperty({}, 'prop', { 얻다() { 1을 반환 }, 값: 2 });
Getter/Setter는 "실제" 속성 값에 대한 래퍼로 사용되어 해당 작업을 더 효과적으로 제어할 수 있습니다.
예를 들어 user
에 대해 너무 짧은 이름을 금지하려는 경우 setter name
갖고 해당 값을 별도의 속성인 _name
에 보관할 수 있습니다.
사용자 = { 이름 가져오기() { this._name을 반환합니다. }, 이름(값) 설정 { if (value.length < 4) { Alert("이름이 너무 짧습니다. 4자 이상이어야 합니다."); 반품; } this._name = 값; } }; user.name = "피트"; 경고(사용자.이름); // 피트 사용자.이름 = ""; // 이름이 너무 짧습니다...
따라서 이름은 _name
속성에 저장되고 getter 및 setter를 통해 액세스가 수행됩니다.
기술적으로 외부 코드는 user._name
사용하여 이름에 직접 액세스할 수 있습니다. 그러나 밑줄 "_"
로 시작하는 속성은 내부 속성이므로 객체 외부에서 건드리면 안 된다는 널리 알려진 규칙이 있습니다.
접근자의 가장 큰 용도 중 하나는 "일반" 데이터 속성을 getter 및 setter로 대체하고 해당 동작을 조정하여 언제든지 "일반" 데이터 속성을 제어할 수 있다는 것입니다.
name
및 age
데이터 속성을 사용하여 사용자 개체를 구현하기 시작했다고 가정해 보겠습니다.
함수 사용자(이름, 나이) { this.name = 이름; this.나이 = 나이; } let john = new User("John", 25); 경고(존.나이); // 25
…그러나 조만간 상황이 바뀔 수도 있습니다. age
대신 birthday
저장하기로 결정할 수도 있습니다. 더 정확하고 편리하기 때문입니다.
함수 사용자(이름, 생일) { this.name = 이름; this.birthday = 생일; } let john = new User("John", new Date(1992, 6, 1));
이제 여전히 age
속성을 사용하는 이전 코드를 어떻게 해야 할까요?
우리는 그런 곳을 모두 찾아 고치려고 노력할 수 있지만, 시간이 걸리고 다른 많은 사람들이 해당 코드를 사용하는 경우에는 어려울 수 있습니다. 게다가 age
user
에 있어서 좋은 것입니다. 그렇죠?
그것을 지키자.
age
에 대한 getter를 추가하면 문제가 해결됩니다.
function 사용자(이름, 생일) { this.name = 이름; this.birthday = 생일; // 나이는 현재 날짜와 생일로 계산됩니다. Object.defineProperty(this, "나이", { 얻다() { todayYear = new Date().getFullYear(); todayYear 반환 - this.birthday.getFullYear(); } }); } let john = new User("John", new Date(1992, 6, 1)); 경고( john.birthday ); // 생일이 가능합니다 경고(존.나이); // ...그리고 나이도 마찬가지
이제 이전 코드도 작동하며 멋진 추가 속성을 갖게 되었습니다.