읽기전 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);
bind ( 묶다 ) 라는 의미를 가지고있는데요, 해석해보면 '이것' '묶다' 입니다.. 이상하네요 ㅎ.. 자바스크립트에서의 This 는 어떠한 객체를 지칭하는 용도로 사용되는데요.
보통 객체지향 언어에서 클래스로 만들어낸 인스턴스 객체에서 객체 자신을 지칭하기위해 사용하는걸로 알고있습니다.
그렇다면 디스바인딩은 언제 누가 하는 것일까요?
호출된 함수의 실행컨텍스트가 생성될 때 렉시컬환경에 Thisbinding 이라는 녀석이 해줍니다.
함수를 호출하는 방식에따라 This가 지칭하는객체는 달라집니다.( 동적바인딩 )
그래서 This에 작동매커니즘에대해 잘 알지못하면 안쓰느니만 못한결과를 낳을 수 있는데요.. ㅠㅠ 앞으로 알아보도록 하겠습니다.
호출하는 방식의 종류
위 다섯개의 상황만 알고있다면 This는 거의 다 알고있다고 할 수 있습니다.
TIP.
This가 바인딩되는 시점은 "실행컨텍스트가 생성될 때"라고 하였는데요. 그렇다면 실행컨텍스트는 어떻게해야 생성이 될까요?
네, 맞습니다. 바로 함수를 호출하는 시점이죠. 그렇다면 함수가 호출되는 시점에 그 함수에대한 주도권을 어떤 "객체"가 가지고있는지가 가장 중요하다는 이야기입니다.
This 바인딩은 함수가 실행되어 컨텍스트가 생성되는 시점에 그 함수에 주도권을 가진 객체와 연결되게 됩니다.
전역컨텍스트에서 This는 무조건 브라우저: window / node.js: global 입니다.
전역객체는 host 객체라고도 하며, 전역 컨텍스트를 실행해주는 녀석이 전역 객체이기 때문에, 자바스크립트가 실행되는 환경 ( 런타임 ) 에 따라서 전역객체가 달라집니다.
윈도우도 객체다!
우리가 사용하는 전역 객체라는 녀석이 브라우저에서는 window 입니다. 이 window 라는 녀석은 브라우저에 대한 정보와 브라우저에서 사용가능한 메서드들을 가지고있는데요, 우리가 사용하는 함수, 변수도 window 객체안에 저장이 됩니다. 자, 이제 window 도 객체라는것을 알았으니 어떤식으로 접근이 가능할까요? 맞습니다. window.함수() 와 같은 방식으로 접근이 가능하다는것이죠!var myName = 'Taehyung'; function getMyName(){ return myName; } console.log(window.myName); // Taehyung console.log(window.getMyName()); // Taehyung
위에 윈도우도 객체라는 개념을 아셨다면 함수 호출 시 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
이건 어떻게 된거죠..? 함수 내부 함수인데.. -ㅅ- 그래서 이건 자바스크립트를 개발한 사람의 실수라고도 이야기하기도 한다네요..
메서드 호출시 . 을 기준으로 . 바로 앞에 있는 식별자에 바인딩 됩니다.
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 바인딩
callfunction 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 요약
생성자 함수는 함수를 new 연산자를 사용해서 인스턴스 객체를 만들어내는것 입니다.
생성자 함수로 생성된 인스턴스 객체의 This는 생성된 인스턴스 객체와 This 바인딩이 됩니다.
function constructor(x,y){ this.text1 = x; this.text2 = y } const printConstructor = new constructor ('생성자함수','출력하기'); console.log(printConstructor); // constructor {text1: '생성자함수', text2: '출력하기'}
다음 포스팅에서는 콜백함수에대해 깊게 알아보도록 하겠습니다.