Javascript - Function & This
Function & This
객체는 사용자(user), 주문(order) 등과 같이 실제 존재하는 개체(entity)를 표현하고자 할 때 생성됩니다.
let user = {
name: "Kim",
age: 30
};
사용자는 현실에서 장바구니에서 물건 선택하기, 로그인하기, 로그아웃하기 등의 행동을 합니다. 이와 마찬가지로 사용자를 나타내는 객체 user도 특정한 _행동_을 할 수 있습니다.
자바스크립트에선 객체의 프로퍼티에 함수를 할당해 객체에게 행동할 수 있는 능력을 부여해줍니다.
함수 생성
객체 user
에게 인사할 수 있는 능력을 부여해 줍시다.
let user = {
name: "Kim",
age: 30
};
user.sayHi = function() {
alert("안녕하세요");
};
user.sayHi();
함수 표현식으로 함수를 만들고, 객체 프로퍼티 user.sayHi
에 함수를 할당해 주었습니다.
이제 객체에 할당된 함수를 호출하면 user가 인사를 해줍니다.
이렇게 객체 프로퍼티에 할당된 함수를 메서드(method) 라고 부릅니다.
위 예시에선 user
에 할당된 sayHi
가 메서드이죠.
함수는 아래와 같이 이미 정의된 함수를 이용해서 만들 수도 있습니다.
let user = {...};
function sayHi() {
alert(안녕하세요);
};
// 만들어진 함수를 user의 프로퍼티로 할당
user.sayHi = sayHi;
user.sayHi();
함수 단축 구문
객체 리터럴 안에 함수를 선언할 때 사용할 수 이는 단축 문법입니다.
function을 생략해도 함수를 정의할 수 있습니다.
// 단축 X
user = {
sayHi: function() {
alert("Hello");
}
};
// 단축
user = {
sayHi() {
alert("Hello");
}
};
Function과 this
메서드는 객체에 저장된 정보에 접근할 수 있어야 제 역할을 할 수 있습니다. 모든 메서드가 그런 건 아니지만, 대부분의 메서드가 객체 프로퍼티의 값을 활용합니다.
user.sayHi()
의 내부 코드에서 객체 user
에 저장된 이름(name)을 이용해 인사말을 만드는 경우가 이런 경우에 속합니다.
메서드 내부에서 this
키워드를 사용하면 객체에 접근할 수 있습니다.
이때 '점 앞’의 this
는 객체를 나타냅니다. 정확히는 메서드를 호출할 때 사용된 객체를 나타내죠.
이미 자바,코틀린 등을 배울때 알고 있는 내용이기 때문에 기본적인 사용법은 생략합니다.
다만 자바스크립트의 this는 다른 프로그래밍 언어들과는 동작방식이 조금 다릅니다.
자바스크립트에선 모든 함수에 this를 사용할 수 있습니다.
아래와 같이 코드를 작성해도 Syntax Error가 발생하지 않습니다.
function sayHi() {
alert(this.name);
}
왜냐하면 자바스크립트에서 this
의 값은 런타임 시 결정됩니다. 컨텍스트에 따라 달라지죠.
동일한 함수라도 다른 객체에서 호출했다면 this
가 참조하는 값이 달라집니다.
let user = { name: "Kim" };
let admin = { name: "Admin" };
function sayHi() {
alert(this.name);
}
// 각각의 객체에서 동일한 함수 사용
user.f = sayHi();
admin.f = sayHi();
// this는 '.' 앞의 객체를 참조하기 때문에 this의 값이 각각 달라짐
user.f(); // Kim, this == user
admin.f(); // Admin, this == admin
admin['f'](); // Admin, 점과 대괄호는 동일하게 동작함
규칙은 간단합니다.
obj.f()
를 호출했다면 this는 f를 호출하는동안의 obj
입니다.
객체 없이 호출하기 this == undefined
객체가 없어도 함수를 호출할 수 있습니다.
function sayHi() {
alert(this);
}
sayHi(); // undefined
위와 같은 코드를 엄격 모드에서 실행하면, this
엔 undefined
가 할당됩니다. this.name
으로 name에 접근하려고 하면 에러가 발생하죠.
그런데 엄격 모드가 아닐 때는 this
가 _전역 객체_를 참조합니다.
브라우저 환경에선 window
라는 전역 객체를 참조하죠. 이런 동작 차이는 "use strict"
가 도입된 배경이기도 합니다.
이런 식의 코드는 대개 실수로 작성된 경우가 많습니다. 함수 본문에 this
가 사용되었다면, 객체 컨텍스트 내에서 함수를 호출할 것이라고 예상하시면 됩니다.
자유로운 this가 만드는 결과
다른 언어를 사용하다 자바스크립트로 넘어온 개발자는 this
를 혼동하기 쉽습니다.
this
는 항상 메서드가 정의된 객체를 참조할 것이라고 착각하죠. 이런 개념을 'bound this
'라고 합니다.
자바스크립트에서 this
는 런타임에 결정됩니다.
메서드가 어디서 정의되었는지에 상관없이 this
는 ‘점 앞의’ 객체가 무엇인가에 따라 ‘자유롭게’ 결정됩니다.
이렇게 this
가 런타임에 결정되면 좋은 점도 있고 나쁜 점도 있습니다.
함수(메서드)를 하나만 만들어 여러 객체에서 재사용할 수 있다는 것은 장점이지만, 이런 유연함이 실수로 이어질 수 있다는 것은 단점입니다.
자바스크립트가 this
를 다루는 방식이 좋은지, 나쁜지는 우리가 판단할 문제가 아닙니다.
개발자는 this
의 동작 방식을 충분히 이해하고 장점을 취하면서 실수를 피하는 데만 집중하면 됩니다.
this가 없는 화살표 함수
화살표 함수는 일반 함수와는 달리 ‘고유한’ this
를 가지지 않습니다.
화살표 함수에서 this
를 참조하면, 화살표 함수가 아닌 ‘평범한’ 외부 함수에서 this
값을 가져옵니다.
아래 예시에서 함수 arrow()
의 this
는 외부 함수 user.sayHi()
의 this
가 됩니다.
let user = {
firstName = "구름";
sayHi() {
let arrow = () => alert(this.firstName);
arrow();
}
};
user.sayHi(); // 구름
별개의 this
가 만들어지는 건 원하지 않고, 외부 컨텍스트에 있는 this
를 이용하고 싶은 경우 화살표 함수가 유용합니다.