모던 JavaScript 튜토리얼을 따라가면서 정리합니다.
4.4. 메서드와 this
- 객체는 사용자, 주문 등 실제 존재하는 개체(entity)를 표현하고자 할 때 생성된다.
- 사용자는 현실에서 장바구니에서 물건 선택하기, 로그인하기 등 행동을 한다. 마찬가지로 사용자를 나타내는 객체 user도 특정한 행동을 할 수 있다.
- 자바스크립트에서는 객체의 프로퍼티에 함수를 할당해 객체에게 행동할 수 있는 능력을 부여한다.
메서드 만들기
객체 user
에게 인사할 수 있는 능력을 부여한다.
1
2
3
4
5
6
7
8
9
10
let user = {
name: "John",
age: 30
};
user.sayHi = function() {
alert("안녕하세요!");
};
user.sayHi(); // 안녕하세요!
객체 프로퍼티에 할당된 함수를 메서드(method)라고 부른다.
메서드는 이미 정의된 함수를 이용해서 만들 수도 있다.
1 2 3 4 5 6 7
function sayHi() { alert("안녕하세요!"); }; user.sayHi = sayHi; user.sayHi(); // 안녕하세요!
메서드 단축 구문을 사용하면 객체 리터럴 안에 메서드를 선언할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12
user = { sayHi: function() { alert("Hello"); } }; // 단축 구문 user = { sayHi() { // "sayHi: function()"과 동일 alert("Hell"); } }
메서드와 this
메서드 내부에서
this
키워드를 사용하면 객체에 접근할 수 있다.이때 점 앞의
this
는 메서드를 호출할 때 사용된 객체를 나타낸다. (user.sayHi()
가 실행되는 동안에this
는user
를 나타냅니다.)1 2 3 4 5 6 7 8 9 10 11 12
let user = { name: "John", age: 30, sayHi() { // 'this'는 '현재 객체'를 나타낸다. alert(this.name); } }; user.sayHi(); // John
this
를 사용하지 않고 외부 변수를 참조해 객체에 접근하는 것도 가능하다.그러나 외부 변수를 사용해 객체를 참조하면 예상치 못한 에러가 발생할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
let user = { name: "John", age: 30, sayHi() { alert( user.name ); // Error: Cannot read property 'name' of null } }; let admin = user; user = null; // user를 null로 덮어 쓴다. admin.sayHi(); // sayHi()가 엉뚱한 객체를 참고하면서 에러가 발생했다.
자유로운 this
자바스크립트에서는 모든 함수에
this
를 사용할 수 있다.this
값은 런타임에 결정된다. 컨텍스트에 따라 달라진다.동일한 함수라도 다른 객체에서 호출했다면
this
가 참조하는 값이 달라진다.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
let user = { name: "John" }; let admin = { name: "Admin" }; function sayHi() { alert( this.name ); } // 별개의 객체에서 동일한 함수를 사용함 user.f = sayHi; admin.f = sayHi; // 'this'는 '점(.) 앞의' 객체를 참조하기 때문에 // this 값이 달라짐 user.f(); // John (this == user); admin.f(); // Admin (this == admin); admin['f'](); // Admin (점과 대괄호는 동일하게 동작함)
객체 없이 호출하면
this == undefined
1
sayHi(); // undefined
엄격 모드에서 실행하면
this
에는undefined
가 할당된다.엄격 모드가 아닐 때는
this
가 전역 객체(브라우저에서는window
)를 참조한다.
자유로운 this
가 만드는 결과
- bound this: 다른 언어에서
this
는 항상 메서드가 정의된 객체를 참조한다. - 자바스크립트에서
this
는 런타임 결정되고, 메서드가 어디서 정의되었는지 상관 없이this
는 점 앞의 객체가 무엇인가에 따라 자유롭게 결정된다. - 함수를 하나만 만들어 여러 객체에서 재사용할 수 있다는 것은 장점이지만, 이런 유연함이 실수로 이어질 수 있다는 단점이 있다.
‘this’가 없는 화살표 함수
화살표 함수는 일반 함수와 달리 ‘고유한’
this
를 가지지 않는다.화살표 함수에서
this
를 참조하면 화살표 함수가 아닌 평범한 외부 함수에서this
값을 가져온다.1 2 3 4 5 6 7 8 9
let user = { firstName: "보라", sayHi() { let arrow = () => alert(this.firstName); arrow(); } }; user.sayHi(); // 보라
별개의
this
가 만들어지는 것은 원치 않고, 외부 컨텍스트에 있는this
를 이용하고 싶은 경우 화살표함수가 유용하다.
과제
객체 리터럴에서 ‘this’ 사용하기
1
2
3
4
5
6
7
8
9
10
function makeUser() {
return {
name: "John",
ref: this
};
};
let user = makeUser(); // { name: "John", ref: undefined }
alert( user.ref.name ); // Error: Cannot read property 'name' of undefined
this
값은 호출 시점에 결정된다. makeUser()
가 메서드로써 호출된 게 아니라 함수로써 호출되었기 때문에 this
는 undefined가 된다.
에러가 발생하지 않게 하려면 코드를 다음과 같이 수정한다.
1
2
3
4
5
6
7
8
9
10
11
12
function makeUser() {
return {
name: "John",
ref() {
return this;
}
};
};
let user = makeUser();
alert( user.ref().name ); // John
계산기 만들기
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let calculator = {
read() {
this.firstParam = +prompt("첫 번째 피연산자", "");
this.secondParam = +prompt("두 번째 피연산자", "");
},
sum() {
return this.firstParam + this.secondParam;
},
mul() {
return this.firstParam * this.secondParam;
}
};
calculator.read();
alert( calculator.sum() );
alert( calculator.mul() );
체이닝
1
2
3
4
5
6
7
8
9
10
11
12
let ladder = {
step: 0,
up() {
this.step++;
},
down() {
this.step--;
},
showStep: function() { // 사다리에서 몇 번째 단에 올라와 있는지 보여줌
alert( this.step );
}
};
메서드를 연이어 호출하려면 다음과 같이 해야 한다.
1
2
3
4
ladder.up();
ladder.up();
ladder.down();
ladder.showStep(); // 1
up
, down
, showStep
을 수정해 메서드 호출 체이닝이 가능하게 해보자.
1
ladder.up().up().down().showStep(); // 1
해답
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
let ladder = {
step: 0,
up() {
this.step++;
return this;
},
down() {
this.step--;
return this;
},
showStep: function() { // 사다리에서 몇 번째 단에 올라와 있는지 보여줌
alert( this.step );
return this;
}
};