this
this
1. this
this
는 실행 컨텍스트가 생성 될 때 함께 결정됌.- 따라서
this
는 함수를 호출할 때 결정되는것이다.
(1) 전역 공간에서의 this
- 전역 공간에서
this
는 전역 객체를 가르킨다. - 따라서 브라우저 환경의
this
는window
를 가르킴 - 따라서 Node.js 환경의
this
는global
을 가르킴
var a = 1;
console.log(a); // 1
console.log(window); // 1
console.log(this.a); // 1
- 이 코드에서는 전역 공간에서 선언한 변수에 1을 할당했는데
window
,this
가 모두1
이 출력됌 ⇒this
는 전역객체이므로window
객체가 나와야한다 근데1
이 출력됌 - 여기서 중요한 것은 전역변수를 선언하면 JavaScript 엔진은 전역 객체의 프로퍼티로 할당된다
- 이유는 변수
a
에 전역객체에서 전역 스코프 L.E , 선언한 프로퍼티a
를 발견해서 그 값을 반환했기 때문에 1이 출력된것이다
따라서 window 프로퍼티에 할당해도 var로 선언한 결과가 똑같다
var a = 1;
window b = 2;
console.log(a,window a, this.a);// 1 1 1
console.log(b,window b, this.b);// 2 2 2
(2) 메서드로서 호출할 때 메서드 내부에서의 this
- 함수 호출: 독립 적인 기능 수행
- 메서드 호출: 자신을 호출한 대상 객체에 관한 동작 수행
var func = function (x) {
console.log(this, x);
};
// (1) 함수 호출
func(1);
//Window {0: Window, window: Window, self: Window, document: document, name: '', location: Location, …}
var obj = {
method: func,
};
// (2) 메서드 호출 (점 표기법)
obj.method(2);
// {method: ƒ}method: ƒ (x)[[Prototype]]: Object 2
// (3) 메서드 호출 (대괄호 표기법)
var obj2 = {
method: function (x) {
console.log(this, x);
},
};
obj2["method"](2);
- 쉽게 구분 하는 방법은 함수 앞에 점(.)이 있냐 없냐 대괄호가 있냐 없냐의 판단으로 쉽게 구분 가능하다
따라서 점 표기법에선 마지막 점 앞에 명시된 객체가 this
라는 것이다
(3) 함수 호출로서 호출할 때 함수 내부의 this
var obj1 = {
outer: function () {
console.log(this); // (1) obj1
var innerFunc = function () {
console.log(this); // (2) window // (3) obj2
};
innerFunc();
var obj2 = {
innerMethod: innerFunc,
};
obj2.innerMethod();
},
};
obj1.outer();
this
를 이해 하기 위한 코드 실행 과정
- 객체를 생성하고
outer()
프로퍼티를 obj1에 할당 obj.outer()
호출obj.outer()
의 실행 컨텍스트 생성 및innerFunc
와obj2
를 Hoistingconsole.log(this)
에서 해당this
를 바인딩한다- 점 표기법으로 메서드를 호출했으니 (1)은 점 앞의 객체
obj1
를 바인딩 innerFunc
에 익명함수를 할당하고 호출innerFunc
의 실행 컨텍스트 생성 및 Hoistngconsole.log(this)
에서 해당this
를 바인딩한다- 이
this
호출엔 점 표기법으로 호출되지 않았으니 전역객체window
가 바인딩된다 obj2
는innerMethod
프로퍼티에innerFunc
를 할당하고 다시 호출- 여기선 또 호출 시
innerMethod
앞에obj2
의 점표기로 호출 했으니obj2
가 바인딩된다
주변 환경은 중요하지 않고 해당 함수 호출 부분에 따라서 this는 점 표기 인지 대괄호 표기를 확인해야 this가 어떤 걸 바인딩하는지 알 수 있다
(1) 메서드 내부에서 this 우회 방법
this
에 변수를 활용하는 방법이 있다
(2) this 바인딩을 하지 않는 함수
- ES6에서 화살표 함수는
this
바인딩 과정 자체가 빠져서 상위 스코프의this
를 활용 할 수 있다. 따라서 ES6부턴 우회법이 불필요하다
(4) 콜백 함수 호출에서의 this
- 콜백 함수도 함수라 기본적으로
this
가 전역객체를 참조하지만, 제어권을 받은 함수에서 콜백함수에 별도로 this가 될 대상을 지정한 경우는 그 대상을 참조하게 된다.
setTimeout(function () {
console.log(this), 300;
}); // (1) : window
[1, 2, 3, 4, 5].forEach(function (x) {
console.log(this, x); // (2) : window
});
document.body.innerHTML += '<button id ="a">클릭</button>';
document.body.querySelector("#a").addEventListener("click", function (e) {
console.log(this, e); // (3) : document.body.querySelector('#a')
});
- 다만 콜백 함수에선
this
가 무조건적이진 않다
(5) 생성자 함수 내부에서의 this
- 생성자 함수에서 호출된 경우의
this
는 새로 만들 구체적인 인스턴스 자신이다
var Cat = function (name, age) {
this.bark = "야옹";
this.name = name;
this.age = age;
};
var choco = new Cat("초코", 7); // (1): Cat { bark: '야옹', name: '초코', age: 7 }
var nabi = new Cat("나비", 5); // (2): Cat { bark: '야옹', name: '나비', age: 5 }
console.log(choco, nabi);
2. 명시적 this 바인딩
(1) call
- 메서드 호출 주체인 함수를 즉시 실행하는 명령
call
메서드의 첫번째 인자를this
바인딩하고 나머지 인자들을 호출할 함수의 매개변수로 할당call
메서드는 임의의 객체를this
로 지정 가능함
var obj = {
a:1,
method:function(x,y){
console.log(this.a,x,y);
}
};
obj.method(2,3);
obj.method.call({a:4},5,6);
// 1 2 3
// 4 5 6
[Done] exited with code=0 in 0.051 seconds
call
메서드 활용
- 유사배열객체에 배열 메서드 적용할때
argument
,NodeList
에 배열 메서드 적용할때- 문자열에 배열 메서드 적용할때
var obj1 = {
0: "a",
1: "b",
2: "c",
length: 3,
};
Array.prototype.push.call(obj1, "d");
console.log(obj1);
var arr1 = Array.prototype.slice.call(obj1);
console.log(arr1);
(2) apply
- 기능적으론
call
과 동일함 - 차이점은
call
메서드는 첫번째 인자를 제외한 모든 인자들을 매개 변수로 지정하지만apply
메서드는 두번째 인자를 배열로 받아서 처리
var func = function(a,b,c){
console.log(this,a,b,c);
}
func.apply({x:1},[4,5,6]);
var obj = {
a:1,
method:function(x,y){
console.log(this.a,x,y);
}
};
obj.method.call({a:4},5,6);
// { x: 1 } 4 5 6
// 4 5 6
[Done] exited with code=0 in 0.052 seconds
ES6
대안
Array.from
var obj = {
0:'a',
1:'b',
2:'c',
length:3,
}
var arr =Array.from(obj);
console.log(arr);
// [ 'a', 'b', 'c' ]
[Done] exited with code=0 in 0.045 seconds
apply
메서드 활용
- 최대/최소값 구하는 코드
var numbers = [10, 20, 3, 16, 45];
var max = Math.max.apply(null, numbers);
var min = Math.min.apply(null, numbers);
console.log(max, min);
ES6 대안
Spread Operator
var numbers = [10, 20, 3, 16, 45];
var max = Math.max(...numbers);
var min = Math.min(...numbers);
console.log(max, min);
(3) bind
call
과 비슷하지만 즉시 호출하지 않고 넘겨 받은this
및 인수들을 바탕으로 새로운 함수를 반환하기만 함bind
의 핵심은this
를 미리 적용 , 부분 적용 함수를 구현
var func = function(a,b,c,d){
console.log(this,a,b,c,d);
}
func(1,2,3,4);
var bindFunc1 = func.bind({x:1});
bindFunc1(5,6,7,8);
// Window{...} 1 2 3 4
// { x: 1 } 5 6 7 8
[Done] exited with code=0 in 0.061 seconds
ES6 대안 : 화살표 함수
- 화살표 함수는
this
를 바인딩하는 과정이 제외됐음 - 내부의
this
는 없고 접근하면 가장 가까운 스코프체인의this
에 접근 - 따로
this
우회할 필요도 없고call/apply/bind
를 적용 할 필요 없음
(4) 정리
- 전역 공간에서의
this
: 전역객체(window
,global
..) - 함수 메서드에서의
this
: 메서드 호출 주체 참조 - 함수 호출에서의
this
: 함수 호출 주체 참조 (기본적으론 전역 객체 참조) - 콜백 함수에서의
this
: 콜백 함수의 제어권을 넘겨받은 함수 주체 참조 (기본적으론 전역 객체 참조) - 생성자 함수에서의
this
: 인스턴스 대상 참조
화살표 함수를 쓰면 this 명시적 바인딩을 적용 할 필요가 없다