그렇다.
내가 쓰는 this는 대부분 내가 생각하는 그것이 아니었다.
js의 this는 함수 호출방식에 따라 결정된다.
js의 함수는 호출될 때, 매개변수로 전달되는 인자값 외에 arguments 객체와 this를 암묵적으로 전달받는다.
실행중에는 할당으로 설정할 수 없고, 함수를 호출할 때마다 다를 수 있다.
아래 링크를 참고하여 글을 쓴다.
그래서 ES5는 함수가 어떻게 호출되었는지에 상관없이 this값을 설정할 수 있는 bind메서드를 도입했고, this바인딩을 제공하지 않는 애로우 펑션을 추가했다.
함수 호출 방식
1. 함수 호출
const f=function(){
console.log(this);
}
f();
이러면 여기서의 this는 전역객체를 가리킨다.
전역객체는 브라우저에서는 window를, node.js에서는 global객체를 의미한다.
이는 내부함수에서도 마찬가지이다.
function f(){
console.log("f this",this);
function c(){
console.log("c this",this);
}
c();
}
f();
메소드의 내부함수도 마찬가지다
const obj={
value:10,
f:function(){
console.log("f this: ",this);
console.log("f this.valie:",this.value);
function c(){
console.log("c this:",this);
console.log("c this.value:",this);
}
c();
}
}
obj.f();
2. 메소드 호출
함수가 객체의 프로퍼티 값이면, 메소드로써 호출된다.
여기서 this는 해당 메소드를 가진 객체에 바인딩된다.
var obj1 = {
name: 'Lee',
sayName: function() {
console.log(this.name);
}
}
var obj2 = {
name: 'Kim'
}
obj2.sayName = obj1.sayName;
obj1.sayName();
obj2.sayName();
명시적 바인딩(apply, call)
this를 특정 객체에 명시적으로 바인딩 하는 방법이 있으니 그것이 바로 Function.prototype.apply와 FUnction.prototype.call메소드이다.
apply
아래와 같은 형식으로 사용한다.
func.apply(this에바인딩할객체, [함수에, 전달할, 인자들의, 배열, 형태]);
const Person=function(name){
this.name=name;
}
const foo={};
Person.apply(foo,['이름입니다']);
console.log(foo);
이렇게 사용할 수도 있다.
call
call은 apply와 모두 같으나 this에 바인딩할 객체 이후에 배열 대신 하나씩 받는다.
object.apply(foo,[1,2,3]);
object.call(foo,1,2,3);
bind
function Person(name) {
this.name = name;
}
Person.prototype.doSomething = function(callback) {
if(typeof callback == 'function') {
// --------- 1
callback();
}
};
function foo() {
console.log(this.name); // --------- 2
}
var p = new Person('Lee');
p.doSomething(foo); // undefined
1의 관점에서 this는 Person이다. 그러나 2는 Person 외부에 있으므로 this가 window를 가리키게되고, 이 둘의 this가 다르기때문에 문제가 발생한다. 따라서 콜백함수의 this를 호출하는 함수의 this와 일치시켜주어야 하는 번거로움이 발생한다.
call로 해결하기
function Person(name) {
this.name = name;
}
Person.prototype.doSomething = function (callback) {
if (typeof callback == 'function') {
callback.call(this);
}
};
function foo() {
console.log(this.name);
}
var p = new Person('Lee');
p.doSomething(foo); // 'Lee'
callback.call(this)를 통해 this를 바인딩해주었다.
bind를 사용하기
function Person(name) {
this.name = name;
}
Person.prototype.doSomething = function (callback) {
if (typeof callback == 'function') {
// callback.call(this);
// this가 바인딩된 새로운 함수를 호출
callback.bind(this)();
}
};
function foo() {
console.log('#', this.name);
}
var p = new Person('Lee');
p.doSomething(foo); // 'Lee'
함수명.bind(this)와 같이 사용하여 this를 바인딩한다.