this는 함수를 호출할 때 결정된다.
전역 컨텍스트에서 생성하는 주체가 전역 객체이다.
자바스크립트의 모든 변수는 실은 특정 객체의 프로퍼티로 작동한다.
-> 특정 객체란 바로 실행 컨텍스트의 Lexical Environment이다.
-> 이후 어떤 변수를 호출하면, Lexical Environment를 조회해서 일치하는 프로퍼티가 있을 경우 그 값을 반환한다.
전역변수를 선언하면 자바스크립트 엔진은 이를 전역객체의 프로퍼티로 할당한다.
var a = 1;
delete window.a; //false
console.log(a, window.a, this.a);
//1 1 1
var b = 2;
delete b; // false
console.log(b, window.b, this.b);
//2 2 2
window.c = 3;
delete window.c; // true
console.log(c, window.c, this.c);
//Uncaught ReferenceError: c is not defined
window.d =4;
delete d; // true
console.log(d, window.d, this.d);
//Uncaught RefereneceErro: d is not defined
처음부터 전역객체의 프로퍼티로 선언한 경우에는 삭제가 되는 반면,
전역변수로 선언한 경우에는 삭제가 되지 않는다.
-> 자바스크립트는 전역변수를 선언하면서 자동으로 전역객체의 프로퍼티로 할당은 하지만, 추가적으로 해당 프로퍼티의 configurable속성 (삭제 및 변경)을 false로 정의하는 것이다.
어떤 함수를 프로퍼티에 할당한다고 해서 무조건 메서드가 되는건 아니다.
객체의 메서드로서 호출한 경우에만 메서드로 동작하고, 그렇지 않으면 함수로 동작한다.
??? 호출주체가 없을 때 자동으로 전역객체를 바인딩하지 않고, 호출 당시 주변 환경의 this를 그대로 상속받아 사용하고 싶을 때 ???
① self 라는 변수에 this를 저장한 상태에서 호출한 innerFunc2의 경우 self에는 객체 obj가 출력된다.
var obj = {
outer : function(){
console.log(this); // (1)
var innerFunc1 = function(){
console.log(this); // (2)
};
innerFunc1();
var self = this;
var innerFunc2 = function(){
console.log(self); //(3)
}
innerFunc2();
}
};
obj.outer();
// (1) 에서는 outer 함수를 가리킨다
// (2) 에서는 함수로서 호출되었기 떄문에 this가 지정되지 않았다.
// 전역객체인 window를 가리킨다.
// (3) this를 self라는 변수에 저장한 상태에서 self를 호출하면,
// 객체 obj가 출력된다.
그저 상위 스코프의 this를 저장해서 내부함수에서 활용하려는 수단
② this를 바인딩하지 않는 화살표함수를 사용한다.
var obj = {
outer : function(){
console.log(this); // (1)
var innerFunc = () => {
console.log(this); // (2)
};
innerFunc();
}
};
obj.outer();
화살표 함수는 실행 컨텍스트를 생성할 때 this 바인딩 자체가 빠지게 되어, 상위 스코프의 this를 그대로 활용할 수 있다.
콜백함수의 제어권을 가지는 함수(메서드)가 콜백함수에서의 this를 무엇으로 할지를 결정하며, 특별히 정의하지 않은 경우에는 기본적으로 함수와 마찬가지로 전역객체를 바라본다.
var obj = {
outer : function(){
console.log(this); // (1)
var innerFunc = function(){
console.log(this); // (2)
};
innerFunc.call(this);
}
};
obj.outer();
var obj = {
outer : function(){
console.log(this); // (1)
var innerFunc = function(){
console.log(this); // (2)
}.bind(this);
innerFunc();
}
};
obj.outer();
call, apply 메서드는 this를 명시적으로 지정하면서 함수 또는 메서드를 호출한다.
bind 메서드는 this 및 함수에 넘길 인수를 일부 지정해서 새로운 함수를 만든다
요소를 순회하면서 콜백 함수를 반복 호출하는 내용의 일부 메서드는 별도의 인자로 this를 받기도 한다.
어떤 함수 x를 호출시 '특정 조건일 때 함수 y를 실행해라'
-> 콜백 함수도 함수이기 때문에 기본적으로 this가 전역객체를 참조하지만, 제어권을 넘겨받을 코드에서 콜백 함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조하게 된다.
setTimeout(function(){console.log(this),300});
[1,2,3,4,5].forEach(function(x){
console.log(this);
});
document.body.innerHTML += `<button id ="a">클릭<button>`;
document.body.querySelector(`#a`)
.addEventListener('click',function(e){
console.log(this, e);
})
(2) 별도의 인자로 this를 받는 경우가 아니라, 별도의 인자로 this를 넘겨주지 않았기 때문에 전역객체를 가리킨다.
Array.prototype.map = function (callback,thisArg){
var mappedArr = [];
for (var i = 0; i < this.length; i++){
var mappedValue = callback.call(thisArg||window, this[i], i, this);
mappedArr[i] = mappedValue;
}
return mappedArr;
}
thisArg가 있을 경우에는 this에는 그 값을 넣고, 없으면 전역객체를 지정한다.
첫 번째 인자에는 메서드의 this가 배열을 가리킬 것이므로 배열의 i번째 요소값을, 두 번째 인자에는 i값을, 세 번째 인자에는 배열 자체를 지정해 호출한다.
콜백함수로 어떤 객체의 메서드를 보내도, 그 메서드는 메서드가 아닌 함수로서 호출된다.
forEach 함수의 콜백 함수로서 전달했다. obj를 this로 하는 메서드를 그대로 전달한 것이 아니라, obj.logValues가 가리키는 함수만 전달한 것이다.
var obj2 = {
name : obj2,
func : obj.func
};
var callback2 = obj2.func();
setTimeout(callback2,1500)
var obj3 = {name : obj3}
var callback3 = obj1.func.call(obj3);
setTimeout(callback3,2000)
callback3의 경우 obj1의 func를 실행하면서 this를 obj3가 되도록 지정해 이를 콜백으로 사용했다.
-> 비동기 작업이 완료될 때까지 비로소 resolve 또는 reject를 호출하는 방법으로 비동기 작업의 동기적 표현이 가능하다.