es6에서 변화된 내용을 공부하고 있는데 arrow function 을 공부하다가 계속 미루고 미루던 this의 개념에 부딪혀 이건 정리 안하면 넘어가기 힘들겠다고 생각이 들어
드디어 정리를 하려고 한다.
자바스크립트에서 this 가 논란의 중심이 되는 이유는 한 가지 개념만 가지는 게 아니라 여러 상황에서 다르게 기능하기 때문이다.
java를 공부했던 사람은 this가 자기 자신인 객체를 가리키는 개념이라고만 알고 있다. 그 외 역할은 따로 없다. 그렇기 때문에 자바에 익숙해진 사람이 자바스크립트의 this 를 보면 예상 밖의 기능을 하는 것에 당황하는 것이다.
이 글에선 다양한 this 의 상황에 따른 기능을 정리하려고 한다.
- 함수 실행 : alert('Hello world!')
- 메소드(함수 내부의) 실행 : console.log('Hello world!')
- 생성자 실행 : new RegExp('\d')
- 간접(indirection) 실행 : alert.call(undefined, 'Hello world!');
출처: https://kim-solshar.tistory.com/42 [김솔샤르의 인사이트]
function myFunc() {
console.log(this);
}
myFunc();
해당 함수를 실행하면 콘솔 창에는 window 전역 객체가 찍혀나온다.
함수 부분에서 this 를 사용하면 this는 전역객체를 가르킨다.
var obj = {
count: 1,
helloFunc: function () {
console.log(this.count);
},
};
obj.helloFunc();
위 예제 처럼 함수 실행이 아닌, 객체 내부의 메소드 실행을 할 경우 자바에서의 사용과 같이 this는 해당 객체를 가리키게 된다.
function Country(name, traveled) {
this.name = name ? name : 'United Kingdom';
this.traveled = Boolean(traveled);
}
Country.prototype.travel = function() {
this.traveled = true;
console.log(this)
};
var france = new Country('France', false);
var unitedKingdom = new Country;
france.travel();
자바스크립트의 모든 함수는 생성자 함수가 될 수 있다. 생성자는 객체를 만들어내는 initiator 이다. 때문에 이 생성자 함수와 일반 함수를 구분짓는 것은 new 키워드를 통해 새로운 객체를 만들어내었는가 아닌가로 구분지을 수 있다.
새로운 객체를 만들게 된다면 해당 console.log(this) 는 Country 객체를 가르키게 된다.
결과는
Country { name: 'France', traveled: false }
Country { name: 'United Kingdom', traveled: false }
이렇게 나온다.
만약 new 키워드를 통해 객체를 만들어낸 것이 아닌, 위 예시에서
Country("hello" , true); 로 함수를 실행을 시켜버리면 결과는 일반 함수의 실행과 마찬가지로 window 전역 객체를 가리키게 된다. 때문에 이 생성자 함수와 일반 함수는 형태만으로는 구분이 불가능하지만, new 키워드로 객체화를 시키는지 아닌지를 잘 구분해야 한다. 또한 생성자 함수는 앞 글자를 대문자로 사용하는 것으로도 구분한다.
자바스크립트에는 자바스크립트 함수가 가지고 있는 공통적인 메소드와 속성이 있다. 함수에서 이 메소드를 호출해 함수를 실행하는 것이 간접실행이다.
function increment(number) {
return ++number;
console.log(this)
}
increment.call("hi", 10); // => 11
increment.apply("hello", [10]); // => 11
위의 increment 함수에서 call() 과 apply() 메소드를 통해 간접적으로 함수를 실행했다.
이 때 함수안에 this가 있으면 이 this 는 메소드의 첫번째 인자를 가리킨다.
즉 위의 예에서는 [String : "hi"], [String : "hello"] 가 출력된다.
후...... this를 공부하고 나니
es6 가 발표 되기 이전에 왜 사람들이 자바스크립트를 언어로 취급조차 안했는지 알 수 있었다.
function objFunction() {
console.log('Inside `objFunction`:', this.foo); // 13
return {
foo: 25,
bar: function() {
console.log('Inside `bar`:', this.foo); // 25
},
};
}
objFunction.call({foo: 13}).bar(); // objFunction의 `this`를 오버라이딩한다
위 예시를 보자.
내가 공부하면서 아주 기겁을 한 예시다. 한 함수에서 같은 this.foo를 출력하는데 결과 값이 다르다.
위의 콘솔에서의 this.foo 는 objFunction의 간접실행이기 때문에 this 가 call의 인자로 받아진 {foo:13} 을 가르키게 되고, 아래 콘솔의 this.foo 는 메소드의 this 이기 때문에 return 하는 객체의 foo를 가리키게 된다. 그래서 출력 결과가 13과 25로 다르다.
이 말은 즉슨 코드를 아주 꼼꼼하게 문맥을 따라 읽어야 버그를 잡아낼 수 있다는 얘기이다. 더해서 버그도 엄청나게 많이 생길 수 있다.
다음엔 arrow function을 하면서 arrow function에서의 this는 어떻게 작동하는지, 전반적인 arrow function은 기존의 function과 어떤 것이 다른지를 정리해야 될 것 같다.