javascript의 this는 실행컨텍스트가 생성될 때 함께 결정된다.
실행 컨텍스트는 함수를 호출할 때 생성된다. 요컨대, this는 함수가 호출될 때 결정된다.
전역 공간의 this는 전역 객체다. 전역 컨텍스트를 생성하는 주체가 전역 객체이기 때문이다.
브라우저의 전역 객체는 window이고, node.js 환경의 전역 객체는 global이다.
전역 변수를 선언하면 자바스크립트 엔진은 이를 전역 객체의 프로퍼티로 할당한다.
전역 변수를 선언하나 전역 객체(window, global)로 프로퍼리를 할당하나 똑같지만,
삭제 할 때의 동작은 다르다.
var a = 1;
delete window.a;
console.log(a, window.a, this.a); // 1, 1, 1 - 삭제 안됨
var b = 2;
delete b;
console.log(b, window.b, this.b); // 2, 2, 2 - 삭제 안됨
window.c = 3;
delete window.c;
console.log(c, window.c, this.c); // c is not defined - 삭제 됨
window.d = 4;
delete d;
console.log(d, window.d, this.d) // d is not defined - 삭제 됨
결과 정리
var
로 선언해서 해당 변수를 삭제하는 경우window
전역 객체로 해당 프로퍼티를 삭제하는 경우JS에서의 함수와 메소드의 개념부터 알아보자
독립성이라는 차이가 있다.
함수는 그 자체로 독립적인 기능을 수행하는 반면, 메소드는 자신을 호출한 대상 객체에 관한 동작을 수행한다.
어떤 함수를 객체의 프로퍼티에 할당했을 때, 그 자체로 메소드가 되는 것이 아니다.
객체의 메소드로서 호출할 때만 메소드가 된다. 그렇지 않은 상황이면 함수이다.
var func = function (x) {
console.log(this, x);
};
func(1); // Window { ... } 1
var obj = {
method: func,
}
obj.method(2); // { method: func } 2
메소드 내부의 this는 호출한 주체에 대한 정보가 담긴다.
var func = function (x) {
console.log(this, x);
};
var obj = {
method: func,
inner: {
methodB: func
}
}
obj.method(2); // { method: func } 2
obj.inner.methodB(3); // { methodB: func } 3
var obj1 = {
outer: function () {
console.log(this);
var innerFunc = function () {
console.log(this);
}
innerFunc(); // this: Window
var obj2 = {
innerMethod: innerFunc
};
obj2.innerMethod(); // this: { innerMethod: innerFunc } => obj2 객체
}
}
obj1.outer(); // this: { outer: f, ... } => obj1 객체
this 바인딩은 함수를 실행하는 주변 환경이 중요하지 않음
오직 함수 호출인지, 메소드 호출인지가 중요한 거임
var obj = {
outer: function () {
console.log(this); // { outer: f } => obj 객체
var innerFunc1 = function () {
console.log(this);
};
innerFunc1(); // Window => 전역 객체
var self = this;
var innerFunc2 = function () {
console.log(self); // { outer: f } => obj 객체
};
innerFunc2();
}
};
obj.outer();
ES6에서는 함수 내부의 this가 전역 객체를 바라보는 문제가 생겨, this를 바인딩하지 않는 화살표 함수를 도입함
화살표 함수는 실행 컨텍스트를 생성할 때, this 바인딩 과정이 빠져서 상위 스코프의 this를 활용할 수 있다.
var obj = {
outer: function () {
console.log(this); // { outer : f } => obj 객체
var innerFunc = () => {
console.log(this); // { outer : f } => obj 객체
}
innerFunc();
}
};
obj.outer();
자기 맘대로다.
forEach에 넣는 함수의 this는 전역 객체를 바라본다.
addEventListener의 this는 해당 셀렉터를 바라본다.
var Cat = function (name, age) {
this.bark = "야옹";
this.name = name;
this.age = age;
};
var choco = new Cat('초코', 7);
var nabi = new Cat('나비', 5);
console.log(choco, nabi); // 초코 객체, 나비 객체
var func = function (a, b, c) {
console.log(this, a, b, c);
};
func(1, 2, 3); // Window, 1, 2, 3
func.call({ x: 1 }, 4, 5, 6); // { x: 1 }, 4, 5, 6
임의의 객체를 this로 지정할 수 있다.
var func = function (a, b, c) {
console.log(this, a, b, c);
};
func.apply({ x : 1 }, [4, 5, 6]); // { x: 1 }, 4, 5, 6
call 과 같지만, apply 메소드는 실행시킬 함수의 인자를 배열로 전달한다는 점이 다르다.
var func = function (a, b, c, d) {
console.log(this, a, b, c, d);
}
var bindFunc = func.bind({ x : 1});
bindFunc(5, 6, 7, 8); // { x : 1}, 5, 6, 7, 8
var func = function (a, b, c, d) {
console.log(this, a, b, c, d);
}
var bindFunc = func.bind({ x : 1}, 4, 5);
bindFunc(7, 8); // { x : 1}, 4, 5, 7, 8
console.log(bindFunc.name); // bound func
넘겨받은 this와 인수를 적용한 새로운 함수를 반환해주는 메소드
bind된 함수의 name을 살펴보면 bound 접두어가 붙는다.
콜백함수에 this 인자를 명시적으로 줄 수 있는 함수들이 있다.
Array.prototype.forEach(callback[, thisArg])
이 대표적이다.
Refer - Core Javascript