- JavaScript 안에서 getter/setter 함수 -
let user = {
name: "Tom",
lastName: "Holland",
get fullName() {
return `${this.name} {this.lastName}`;
},
set name(data) {
this.name = data;
}
}
위와 같은 user 객체가 있다.
user 객체가 가지는 name 속성값을 'Hello'로 바꾸고 싶으면 어떻게 해야 할까?
간단하게 생각하자면 아래와 같은 명령어를 떠올릴 것이다.
user.name = 'Hello';
그러나 이 객체에 위와 같은 명령어를 실행하면 에러가 난다.
> Uncaught RangeError: Maximum call stack size exceeded
명령어를 실행하다가 call stack이 초과했다는 뜻이다.
이는 무한 루프가 돌아서 그렇다.
단순히 user 객체에 name 속성을 넣어주겠다는데 왜 무한 루프가 돌게 되는가?
그 이유를 이해하려면 먼저 JavaScript ES6 문법인 get/set 키워드를 이해해야 한다.
- Java에서 사용하던 getter/setter 함수와의 차이점 -
아래 user 라는 객체의 내부를 살펴보자.
let user = {
_firstName: "Tom",
_lastName: "Holland",
get fullName() {
return `{$this._firstName} ${this.lastName}`;
},
set name(data) {
this._firstName = data;
}
}
이 'user'라는 객체를 변수도 가지고 있고 함수도 가지고 있다.
변수는 '_firstName'과 '_lastName' 이고,
함수는 'fullName()' 과 'name()' 이다.
그런데 함수에 특이한 점이 있다.
함수를 선언할 때 함수 이름 앞에 'get/set' 같은 키워드들이 붙어 있다.
getter 함수와 setter 함수라는 뜻이다.
Java 에서도 익숙하게 쓰던 기능이다.
클래스의 내부 변수를 getter함수나 setter를 통해 접근할 수 있었다.
단, Java 에서는 getter/setter 함수는 다른 멤버 메소드와 사용법이 똑같다.
getter/setter 함수가 문법적으로 따로 있는 게 아니었기 때문이다.
그냥 다른 메소드와 똑같은 메소드이지만, 개발자들끼리 관습적으로 그 기능을 특정했을 뿐이었다.
> user.setName("Hello"); / user.getFullName();
그런데 JavaScript에서는 문법적으로 getter/setter 함수를 분리했다.
즉, get/set 키워드가 붙은 함수는 특별 취급한다.
그 객체가 가지는 다른 함수들과는 사용법이 다르다.
함수처럼 쓰지 않고 변수처럼 쓴다.
아래는 getter 함수다.
> user.name; // "Tom"
아래는 setter 함수다.
> user.name = "Hello";
함수처럼 선언하고 변수처럼 사용하니까 헷갈릴 뿐이다.
원래 user.name("Hello"); 처럼 써야 하는데 user.name = "Hello"; 이라고 쓴다.
name 이라는 함수 앞에 'set' 이라는 키워드가 붙어 있기 때문이다.
원래 user.fullName() 처럼 써야 하는데 user.fullName 이라고 쓴다.
fullName() 이라는 함수 앞에 'get' 이라는 키워드가 붙어 있기 때문이다.
- user.name = 'hello'에서 무한 루프 에러가 나는 과정 -
자 여기까지 이해했다면 아래 명령어가 왜 무한 루프를 일으켰는지 이해할 수 있다.
다시 한 번 user 객체 내부를 살펴보자.
let user = {
_firstName: "Tom",
_lastName: "Holland",
get fullName() {
return `{$this._firstName} ${this.lastName}`;
},
set name(data) {
this._firstName = data;
}
}let user = {
name: "Tom",
lastName: "Holland",
get fullName() {
return `${this.name} {this.lastName}`;
},
set name(data) {
this.name = data;
}
}
user.name = "Hello";
위 명령어를 실행하면 user 라는 객체 안에서
함수 이름이 'name'이면서 앞에 'set' 키워드가 붙은 함수를 찾는다.
그러면 아래 함수를 찾아서 실행한다.
set name(data) {
this.name = data;
}
그 함수 안에 있는 명령어는 아래이다.
this.name = data;
그런데 이 명령어는 어디서 많이 봤던 구조다.
this.name = data;
user.name = "Hello";
user 객체 안에서 name이라는 setter 함수를 찾듯이,
this 안에서 name 이라는 setter 함수를 찾아서 실행한다.
다시 아래 함수를 불러서 실행한다.
set name(data) {
this.name = data;
}
그리고 그 안에는 또 다시 setter 함수를 실행하라는 명령어가 있다.
this.name = data;
이 과정이 무한 방복되면서 call stack 이 넘치게 된 것이다.
- 무한 루프 해결 방법 -
따라서 get/set 함수를 쓸 때는 변수 이름과 함수 이름이 같지 않도록 주의해야 한다.
아래처럼 밑줄을 넣어주는 방법을 흔히 쓴다.
let user = {
_firstName: "Tom",
_lastName: "Holland",
get fullName() {
return `{$this._firstName} ${this.lastName}`;
},
set name(data) {
this._firstName = data;
}
}
//221018
'JavaScript' 카테고리의 다른 글
[JavaScript] 배열에서 중복되는 요소 제거하여 합치기 (0) | 2022.12.19 |
---|---|
[JavaScript]두 배열 요소 합쳐서 return 하기 / concat 함수 null 체크 (0) | 2022.11.21 |
[JavaScript] 걸려 있는 클릭 이벤트 핸들러 제거하기 remove Event Listener (0) | 2022.09.28 |
[JavaScript] checkbox 체크박스 '전체' 버튼 선택/해제 클릭 이벤트 함수 (0) | 2022.09.21 |
HTML 요소의 'data-' 속성 ele.dataset.? 활용하기 (0) | 2022.08.24 |