This

taehyung·2023년 8월 25일
0

JavaScript Core

목록 보기
4/9

읽기전 This 바인딩의 경우 여러가지 함수의 종류를 알아야하니 아래 내용을 보고 함수의 형태를 보시면 됩니다

일반함수
// 선언문
function add(a, b) {
	return a + b; 
}
// 표현식
const add = function(a, b) {
	return a + b;
}
메서드
const obj = {
	method : function(){}
}
콜백함수
function x(callback){
	console.log(callback);
}
x(function(){console.log(this)})
생성자함수
function constructor(x,y){
	this.var1 = x;
	this.var2 = y;
}
const ins = new constructor('1','2');
console.log(ins);

This 바인딩은 언제 누가 하는 것일까요?

bind ( 묶다 ) 라는 의미를 가지고있는데요, 해석해보면 '이것' '묶다' 입니다.. 이상하네요 ㅎ.. 자바스크립트에서의 This 는 어떠한 객체를 지칭하는 용도로 사용되는데요.

보통 객체지향 언어에서 클래스로 만들어낸 인스턴스 객체에서 객체 자신을 지칭하기위해 사용하는걸로 알고있습니다.

그렇다면 디스바인딩은 언제 누가 하는 것일까요?
호출된 함수의 실행컨텍스트가 생성될 때 렉시컬환경에 Thisbinding 이라는 녀석이 해줍니다.
함수를 호출하는 방식에따라 This가 지칭하는객체는 달라집니다.( 동적바인딩 )
그래서 This에 작동매커니즘에대해 잘 알지못하면 안쓰느니만 못한결과를 낳을 수 있는데요.. ㅠㅠ 앞으로 알아보도록 하겠습니다.

호출하는 방식의 종류

  • 전역공간 호출
    • 브라우저: window / node.js: global
  • 함수 호출
    • 브라우저: window / node.js: global
      ES5 는 무조건 전역객체를 가리킨다
      ES6 Arrow Function 은 부모 컨텍스트의 This 를 가져다쓴다.
  • 메서드 호출
    • 객체의 메서드를 호출
  • CallBack 호출
    • 함수의 인자로 함수를 호출
  • 생성자함수 호출
    • 생성자함수로 생성된 인스턴스 객체 함수

위 다섯개의 상황만 알고있다면 This는 거의 다 알고있다고 할 수 있습니다.


TIP.
This가 바인딩되는 시점은 "실행컨텍스트가 생성될 때"라고 하였는데요. 그렇다면 실행컨텍스트는 어떻게해야 생성이 될까요?
네, 맞습니다. 바로 함수를 호출하는 시점이죠. 그렇다면 함수가 호출되는 시점에 그 함수에대한 주도권을 어떤 "객체"가 가지고있는지가 가장 중요하다는 이야기입니다.
This 바인딩은 함수가 실행되어 컨텍스트가 생성되는 시점에 그 함수에 주도권을 가진 객체와 연결되게 됩니다.


전역공간에서의 This

전역컨텍스트에서 This는 무조건 브라우저: window / node.js: global 입니다.
전역객체는 host 객체라고도 하며, 전역 컨텍스트를 실행해주는 녀석이 전역 객체이기 때문에, 자바스크립트가 실행되는 환경 ( 런타임 ) 에 따라서 전역객체가 달라집니다.


숨겨진 Window

윈도우도 객체다!
우리가 사용하는 전역 객체라는 녀석이 브라우저에서는 window 입니다. 이 window 라는 녀석은 브라우저에 대한 정보와 브라우저에서 사용가능한 메서드들을 가지고있는데요, 우리가 사용하는 함수, 변수도 window 객체안에 저장이 됩니다. 자, 이제 window 도 객체라는것을 알았으니 어떤식으로 접근이 가능할까요? 맞습니다. window.함수() 와 같은 방식으로 접근이 가능하다는것이죠!

var myName = 'Taehyung';
	function getMyName(){
    	return myName;
	}
console.log(window.myName); // Taehyung
console.log(window.getMyName()); // Taehyung

위에 윈도우도 객체라는 개념을 아셨다면 함수 호출 시 This에 대한 이해해 도움이 조금 되실거라 생각합니다.


함수 호출시 This

일반적으로 알고계시는 함수 호출 방법 함수명(); 로 호출하시면 호출위치가 어디던간에 무조건 Window 객체를 바인딩합니다.

function x(){
	console.log(this);
}
x(); //Window

위에서 보셨듯이 x() 는 window 객체에 소속되게 되는데요. 아래와 같은 경우는 어떨까요?

function x(){
	console.log(this);
      function y(){
        console.log(this);
      }
    y(); //window
}
x(); //Window

이건 어떻게 된거죠..? 함수 내부 함수인데.. -ㅅ- 그래서 이건 자바스크립트를 개발한 사람의 실수라고도 이야기하기도 한다네요..


메서드 호출시 This

메서드 호출시 . 을 기준으로 . 바로 앞에 있는 식별자에 바인딩 됩니다.

const methodTest = {
	func: function(){
    	console.log(this);
      	function innerFunc(){
        	console.log(this);
        }
      	innerFunc(); // 일반적인 함수 호출 이기에 window
    }
}
methodTest.func(); // func: f

대괄호 표기법
객체["메서드"] == 객체.메서드();

위와 같이 func 함수를 메서드 내부에서 선언했어도 this는 window 객체에 바인딩 됩니다. 일반 함수는 호출시 무조건 window 객체와 바인딩 된다고 하였는데요 간단한 트릭으로 피해갈 수 있습니다.

const methodTest = {
  	a : "TEST",
	func: function(){
      	const self = this // 변수에 this 를 담고
    	console.log(this);
      	function innerFunc(){
        	console.log(self.a); // 스코프체인을 이용합니다.
        }
      	innerFunc(); // func: f
    }
}
methodTest.func(); // func: f

callBack 호출시 This

callBack 형태로 함수를 호출하게되면, 함수를 호출한 주체에게 바인딩됩니다.
모든 콜백함수가 호출한 주체에게 되는것은 아닙니다. 제어권을 넘겨받는 주체들만 바인딩 됩니다.

시작하기에 앞서 일반함수를 명시적으로 바인딩하는 세가지 방법을 알아보겠습니다.
함수야~ 이친구가 너의 주인이야~ 하고 알려주는 겁니다.

명시적인 This 바인딩
call

function method (x,y){   //일반함수, 매개변수도 받을 수 있습니다.
  console.log(this,x,y); //
}
const callMethod = { test : 'test' } //객체
method.call(callMethod,"pram1","pram2");

바인딩할함수명.call(바인딩할 객체,매개변수,매개변수...)

apply

function method (x,y){   //일반함수, 매개변수도 받을 수 있습니다.
  console.log(this,x,y); //
}
const callMethod = { test : 'test' } //객체
method.apply(callMethod,["pram1","pram2"]);

바인딩할함수명.call(바인딩할 객체, 배열[요소1,요소2])

bind

function method (x,y){   //일반함수, 매개변수도 받을 수 있습니다.
  console.log(this,x,y); //
}
const callMethod = { test : 'test' } //객체
const vari = method.bind(callMethod);
vari("pram1","pram2");

변수 = 바인딩할함수명.bind(바인딩할 객체)
변수(매개변수,매개변수...);


위의 세 방법의 결과는 모두 같습니다.

자, 이제 본격적으로 CallBack 함수 호출시 This 바인딩을 살펴보겠습니다. 그전에 콜백 함수란 뭘까요?
어떠한 함수에 매개변수로 전달되는 함수를 콜백함수라고 합니다.

콜백함수의 기본적인 형태

function printCallBack(callback){ //제어권을 가진 함수
	callback();
}
function callback(){ 
	console.log('콜백함수 입니다.');
}
printCallBack(callback); // 콜백함수

다른 함수에 콜백함수로서 동작하는 함수

function mixedName(last,first,callback){ //제어권을 가진 함수
  	const fullName = last+first;
	callback(fullName);
}
function callback(pram){ //콜백함수
console.log(pram);
}
mixedName("콜백함수","입니다.",callback);
함수 선언문으로 선언한 callback 와 mixedName 의 인자로 적혀있는 callback은 서로 다른 녀석입니다.

콜백함수에서의 This 는 따로 지정되어있는 특별한 경우가 아니라면 window와 바인딩 됩니다.
이벤트리스너 같은경우는 기본적으로 함수가 속해있는 HTML 엘리먼트와 바인딩 되게 되어있습니다.

document.body.innerHTML += '<div id="a">클릭</div>'; //HTML 태그
documant.getElementById('a').addEventListener('click',printThis); //클릭 이벤트리스너
function printThis(){ console.log(this) } //div#a

그럼 This 를 변경하고싶으면 어떻게하나요? 위에 배웠던 바인드 메서드를 사용하면 됩니다

const obj = { el:"element" }
document.body.innerHTML += '<div id="a">클릭</div>'; //HTML 태그
documant.getElementById('a').addEventListener('click',printThis); //클릭 이벤트리스너
function printThis(){ console.log(this) }.bind(obj) //obj

callback 요약

  • 기본적으로는 함수의 this 처럼 window와 바인딩 됩니다.
  • 제어권을 가져가는 함수는 콜백의 This를 지정해둔 경우도 있습니다
  • 제어권을 가져가는 함수에게 콜백을 넘기기 전 This 바인딩을 변경하여 넘기면 그에 따릅니다.

생성자함수 호출시 This

생성자 함수는 함수를 new 연산자를 사용해서 인스턴스 객체를 만들어내는것 입니다.
생성자 함수로 생성된 인스턴스 객체의 This는 생성된 인스턴스 객체와 This 바인딩이 됩니다.

function constructor(x,y){
	this.text1 = x;
  	this.text2 = y
}
const printConstructor = new constructor ('생성자함수','출력하기');
console.log(printConstructor); // constructor {text1: '생성자함수', text2: '출력하기'}

다음 포스팅에서는 콜백함수에대해 깊게 알아보도록 하겠습니다.

profile
Front End

0개의 댓글