Today I Learned 2023.02.22. [코어 자바스크립트 2]

Dongchan Alex Kim·2023년 2월 22일
0

Today I Learned

목록 보기
18/31
post-thumbnail

this

this는 함수를 호출할 때 결정된다.

전역공간에서의 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

어떤 함수를 프로퍼티에 할당한다고 해서 무조건 메서드가 되는건 아니다.
객체의 메서드로서 호출한 경우에만 메서드로 동작하고, 그렇지 않으면 함수로 동작한다.

  • 점 표기법이든, 대괄호 표기법이든, 함수 호출시에 앞에 객체가 명시되어 있는 경우 메서드로 호출한 것이다.
  • this 바인딩에 관해서는 함수를 실행하는 당시의 주변환경은 중요하지 않고, 오직 해당 함수호출구문 앞에 구문 앞에 점 또는 대괄호 표긱가 있는지 없는지가 중요하다.

??? 호출주체가 없을 때 자동으로 전역객체를 바인딩하지 않고, 호출 당시 주변 환경의 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

콜백함수의 제어권을 가지는 함수(메서드)가 콜백함수에서의 this를 무엇으로 할지를 결정하며, 특별히 정의하지 않은 경우에는 기본적으로 함수와 마찬가지로 전역객체를 바라본다.

  • Bind 매서드
    call과 비슷하지만, 즉시 호출하지는 않고, 넘겨 받은 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();

명시적 this 바인딩

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가 가리키는 함수만 전달한 것이다.

그럼 콜백함수 내부의 this에 다른 값 바인딩하기

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가 되도록 지정해 이를 콜백으로 사용했다.

  • 기명함수로 변환 (콜백지옥에서 탈출)
  • promise (비동기 작업의 동기적 표현)
    promise의 인자로 넘겨주는 콜백 함수는 호출할 때 바로 실행되지만, 그 내부에 resolve또는 reject함수를 호출하는 구문이 있을 경우 둘 중 하나가 실행되기 전까지 then이나 catch로 넘어가지 않는다.

-> 비동기 작업이 완료될 때까지 비로소 resolve 또는 reject를 호출하는 방법으로 비동기 작업의 동기적 표현이 가능하다.

profile
Disciplined, Be systemic

0개의 댓글