this
자바 스크립트에서 this 는 기본적으로 전역 객체를 가리킨다. (node.js : global, browser : window)
함수 내에서 this 를 참조하더라도 마찬가지로 전역 객체가 찍히게 된다. this는 기본적으로 전역 객체를 가리키도록 되어있기 때문이다.
1
2
3
4
function a() {
console.log(this); //Object [global] {...} or window {...}
}
a();
그러나, 예외적으로 this에 바인딩되는 객체가 변하는 순간들이 있다.
1) 객체의 함수 호출
객체의 함수를 호출하게 되면 this가 가리키는 객체가 해당 객체로 바뀌게 된다.
1
2
3
4
5
6
let obj = {
a: function () {
console.log(this); //{ a: [Function: a] }
},
};
obj.a();
그런데 obj 객체의 함수 a 내부에 inner 함수를 생성하고 inner 함수 내부에서 this를 찍어보면 전역 객체가 찍히게 된다.
그 이유는 객체의 함수를 호출하는 것과 일반 함수를 호출하는 것의 차이인데 inner 함수는 객체 내부에서 호출될 뿐 객체의 함수가 아닌 일반 함수이기 때문에 default로 전역 객체를 가리키기 때문이다.
1
2
3
4
5
6
7
8
9
10
11
let object = {
a: function () {
console.log(this); //{ a: [Function: a] }
function inner() {
console.log(this); //Object [global] {...} or window {...}
}
inner();
},
};
object.a();
2) 이벤트 리스너
이벤트 리스너에서 콜백 함수가 호출될때 this는 이벤트가 발생한 DOM Element를 가리키게 된다.
1
2
3
4
5
6
7
8
9
<button class="btn-test">click!</button>
<script>
let buttonEl = document.querySelector('.btn-test');
buttonEl.addEventListener('click', function () {
console.log(this); //<button class=".btn-test">...
});
</script>
하지만 이 경우에도 1) 의 경우처럼 내부에 새로운 inner 함수를 생성하면 해당 함수에서는 다시 this가 전역 객체를 가리키는 것을 볼 수 있다. 이 역시 inner 함수의 호출은 일반 함수의 호출이므로 default로 전역 객체를 가리키기 때문이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<button class="btn-test">click!</button>
<script>
let buttonEl = document.querySelector('.btn-test');
buttonEl.addEventListener('click', function () {
console.log(this); //<button class=".btn-test">...
function inner() {
console.log(this); // window {...}
}
inner();
});
</script>
3) 생성자 함수
생성자 함수를 new 로 실행하면 생성자 함수 내의 this 는 생성된 인스턴스를 가리키게 된다.
만약, new 를 붙이지 않으면 생성자 함수 내의 this 가 전역 객체를 가리키게 된다고 한다. (크롬에서는 new를 붙이지 않으면 아예 오류로 처리한다.)
1
2
3
4
5
6
7
8
9
10
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function () {
console.log('Hi, ' + this.name);
};
const me = new Person('Changhee');
me.sayHello(); // Hi, Changhee
또한, 1)에서 처럼 객체의 함수를 호출할 때 this가 해당 객체를 가리키게 되므로 me 객체의 name 값을 출력하게 된다.
1
2
const me = new Person('Changhee');
me.sayHello(); // Hi, Changhee
4) 명시적 변환
bind, call, apply 함수들은 this를 명시적으로 바꾸는 함수들이다.
해당 함수들을 사용하게 되면 this가 인자로 받은 객체를 가리키게 된다.
1
2
3
4
5
6
7
8
9
let obj = {};
function a() {
console.log(this);
}
a(); // Object [global] {...} or window {...}
a.bind(obj).call(); // {}
a.call(obj); // {}
a.apply(obj); // {}
Arrow Function
Arrow Function(화살표 함수)을 사용하게 되면 상위 스코프의 this를 상속받게 된다.
따라서, 아래의 코드에서 inner 함수의 this 는 함수 a 의 this 를 상속받게 되어 object 객체를 가리키게 된다.
1
2
3
4
5
6
7
8
9
10
11
let object = {
a: function () {
console.log(this); // { a: [Function: a] }
const inner = () => {
console.log(this);
};
inner(); // { a: [Function: a] }
},
};
object.a();
만약 이벤트 리스너의 콜백함수를 arrow 함수로 선언한다면?
이벤트 리스너 콜백함수의 this는 상위 스코프의 this인 window를 가리키게 되고 inner 함수 또한 window를 가리키게 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<button class="btn-test">click!</button>
<script>
let buttonEl = document.querySelector('.btn-test');
buttonEl.addEventListener('click', () => {
console.log(this); // window{...}
const inner = () => {
console.log(this); // window{...}
};
inner();
});
</script>