자바스크립트에서 this는 자바와 달리 this에 바인딩되는 객체의 종류가 한 가지가 아니며, 해당 객체는 함수 호출 방식에 따라 달라지는 특성(동적
)을 가지고 있다.
✅ 여기서 바인딩이란, 식별자와 값을 연결하는 과정을 의미한다.
예를 들면, 변수 선언은 변수 이름(식별자)과 확보된 메모리 공간의 주소를 바인딩하는 것이다.
때문에 this 바인딩은 this(키워드로 분류되지만, 식별자의 역할을 수행)와 this가 가리킬 객체를 바인딩하는 것을 말한다.
this에 대해 자세하게 알아보자.
this는
자신이 속한 객체 또는 자신이 생성할 인스턴스를 가리키는 자기 참조 변수
이다
따라서 this를 통해 자신이 속한 객체 또는 자신이 생성할 인스턴스의 프로퍼티
나 메서드
를 참조할 수 있다.
this 바인딩은 함수 호출 방식에 따라 동적으로 결정되는 특성을 가지고 있다.
함수 호출 방식은 아래와 같다.
기본적으로 this에는
전역 객체
가 바인딩된다.
브라우저 콘솔을 켜고, this를 콘솔로 출력해보면
function a(){
console.log(this);
};
a( ); // Window{ }
window가 반환되는 것을 알 수 있다.
객체 메서드 안으로 this를 넣어보면,
let obj = {
a : function(){
console.log(this);
},
};
obj.a(); // a가 반환
obj.a( )로 호출할 때의 this는 a를 가리키므로 window가 반환되지 않는다.
만약, window를 this로 받고 싶다면, 객체 메서드를 window에서 호출하면 된다.
let b = obj.a;
b( ); // window{ }
b에 객체 메소드 할당하면 더 이상 obj의 메소드 아니다.
따라서 이에 대한 호출을 실행하면 window에 this가 바인딩 된다.
일반 함수에서 this === window
이기에 this.name, this,age는 각각 window.name, window.age로 나타낼 수 있다.
var name = "seohee";
console.log(name);
console.log(window.name);
function foo(){
console.log(this.name);
};
foo();
모두 다 똑같은 값을 출력하는 것을 확인할 수 있다.
내부함수는 일반 함수, 메소드, 콜백함수 어디에서 선언되었든 관계없이 this는 전역객체를 바인딩한다.
var value = 1;
var obj = {
value: 100,
foo: function() {
console.log("foo's this: ", this); // obj
console.log("foo's this.value: ", this.value); // 100
function bar() {
console.log("bar's this: ", this); // window
console.log("bar's this.value: ", this.value); // 1
}
bar();
}
};
obj.foo();
window에서 obj.foo( )를 호출하였기에 foo의 this에는 obj가 바인딩되지만,
bar는 foo의 내부 함수이므로 전역 객체가 바인딩되는 결과를 보였다.
var value = 1;
var obj = {
value: 100,
foo: function() {
setTimeout(function() {
console.log("callback's this: ", this); // window
console.log("callback's this.value: ", this.value); // 1
}, 100);
}
};
obj.foo();
window 객체가 바인딩됨을 알 수 있다.
이를 회피하기 위한 방식으로 that이나 apply, call, bind 메소드를 사용하기도 한다.
foo: function() {
console.log("foo's this: ", this); // obj
console.log("foo's this.value: ", this.value); // 100
function bar(a, b) {
console.log("bar's this: ", this); // obj
console.log("bar's this.value: ", this.value); // 100
console.log("bar's arguments: ", arguments);
}
bar.apply(obj, [1, 2]);
bar.call(obj, 1, 2);
bar.bind(obj)(1, 2);
}
함수가 객체의 프로퍼티 값이면 메소드로서 호출된다.
이때, 메소드 내부의 this는 해당 메소드를 소유한 객체
즉, 해당 메소드를 호출한 객체에 바인딩된다.
var obj1 = {
name: 'Lee',
sayName: function() {
console.log(this.name);
}
}
var obj2 = {
name: 'Kim'
}
obj2.sayName = obj1.sayName;
obj1.sayName();
obj2.sayName();
obj1.sayName( )의 this는 obj1이므로 Lee가 출력되고,
obj2.sayName( )의 this는 obj2이므로 Kim이 출력된다.
자바스크립트의 생성자 함수는 말 그대로 객체를 생성하는 역할을 한다.
자바와 달리, 기존 함수에 new 연산자를 붙여 호출하면, 해당 함수는 생성자 함수처럼 동작할 수 있다.
function Person(name) {
this.name = name;
}
var me = new Person('Lee');
console.log(me);
var you = Person('Kim');
console.log(you);
me는 생성자 함수를 사용하였지만, you는 생성자 함수로 호출하지 않았으므로 동작하지 않는다.
계속해서 말해왔듯이 this에 바인딩될 객체는 함수 호출 패턴에 의해 결정된다. 이는 자바스크립트 엔진이 수행하는 것이며, 암묵적 this 바인딩 외에
특정 객체에 명시적으로 바인딩
하는 방법인Function.prototype.apply,call, bind
메소드가 제공된다.
이들을 호출하는 주체는 함수이기에 각 메소드들이 this를 특정 객체에 바인딩할 뿐, 본질적인 기능은 함수 호출
이라는 점을 기억해야 한다.
예제 코드를 보자
var Person = function (name) {
this.name = name;
};
var foo = {};
// apply 메소드는 생성자함수 Person을 호출한다. 이때 this에 객체 foo를 바인딩한다.
Person.apply(foo, ['name']);
console.log(foo); // { name: 'name' }
📚 학습할 때, 참고한 자료 📚