javascript에서는 this의 동작에 대해 이해를 하려면 Execution ContextLexical Environment를 이해해야한다.

Execution Context

  • 자바스크립트 엔진은 실행이 가능한 코드를 만나면 Execution Context를 생성한다.
  • 매번 함수의 호출마다 새로운 Execution Context가 생성된다
  • EC는 Lexical Environment, Variable Environment, ThisBinding에 대한 정보를 가지고 있다.

Lexical Environment Object

  • 자원을 어디에서 찾을 것인가?
  • 해당 Context에서 선언된 변수/함수들의 Reference 값을 저장하는 객체
  • EC 생성 초기 시점에는 Variable Environment와 동일한 값을 가지나, 바인딩된 값들에 따라 변경된다.

Variable Environment Object

  • Lexical Environment에 포함되는 개념
  • 내부에 선언된 변수, 함수 선언, 함수 매개 변수 들을 저장한다.
  • 값이 절대로 변하지 않는다.

ThisBinding

  • ThisBinding은 함수의 호출 시점에 정해지며, this 키워드를 말한다.
  • this는 함수가 현재 어느 EC에서 구동하고 있는 지를 알려준다.
  • ThisBinding이 null, undefined이면 기본으로 global(window)를 대입한다.
  • 단, ‘use strict’ 모드인 경우에는 null로 대입한다.

자바스크립트에서의 this 예시

this는 함수의 현재 실행 문맥을 말한다. 즉, 함수가 호출된 시점에서 포함된 객체를 찾아서 this에 바인딩한다.

var item = 'global item!';
var obj = {
  item: 'item from obj',
  mtd: function() {
  	console.log('this === window : ', this === window);
  	console.log('this === obj : ', this === obj);
    console.log(this.item);
  }
}

var mtd = obj.mtd;
mtd();	
obj.mtd();
/**
this === window :  true
this === obj :  false
global item!

this === window :  false
this === obj :  true
item from obj
**/

함수 실행에서의 this

일반적인 함수 실행에서의 this는 전역 객체이다.

function func() {
    console.log('in func, this === window : ', this === window);
    console.log('in func, this === undefined : ', this === undefined);
}
func();
console.log('out func, this === window : ', this === window);
/*
in func, this === window :  true
in func, this === undefined :  false
out func, this === window :  true
*/

하지만 strict mode를 선언하는 경우에는 함수 내부에서 this 는 전역 객체가 아니다.

'use strict'
function func() {
    console.log('in func, this === window : ', this === window);
    console.log('in func, this === undefined : ', this === undefined);
}
func();
console.log('out func, this === window : ', this === window);
/*
in func, this === window :  false
in func, this === undefined :  true
out func, this === window :  true
*/

strict mode 선언을 함수 스코프 내에서만 적용되도록 사용할 수 있다.

function strictFunc() {
    'use strict'
    console.log('in strictFunc, this === window : ', this === window);
    console.log('in strictFunc, this === undefined : ', this === undefined);
}

function func() {
    console.log('in func, this === window : ', this === window);
    console.log('in func, this === undefined : ', this === undefined);
}

func();
strictFunc();
console.log('out func, this === window : ', this === window);
/*
in func, this === window :  true
in func, this === undefined :  false
in strictFunc, this === window :  false
in strictFunc, this === undefined :  true
out func, this === window :  true
*/

bind & apply & call

bind, apply, call 메서드는 this에 강제로 해당 메서드를 호출한 함수를 바인딩 시킨다. bind 메서드는 바인딩 후 새로운 함수를 반환하는 반면, apply 메서드는 해당 함수를 호출한다. call 메서드는 apply 메서드와 동일하나 여러 개의 파라미터를 전달받을 수 있다.

bind 메서드 예시

function speakNation() {
  console.log(this.nation);
}

var person = {
  name: 'Hong Kil Dong',
  nation: '한국'
}

var hongSpeakNation = speakNation.bind(person);
hongSpeakNation();

apply 메서드 예시

function speakNation() {
  console.log(this.nation);
}

var person = {
  name: 'Hong Kil Dong',
  nation: '한국'
}

speakNation.apply(person);

ES6 - Arrow Function

Arrow Function을 사용하면 현재 실행 시점의 this를 가르키는 것이 아니라, 상위 스코프의 this를 가르킨다.

const job = {
    items: ['teacher', 'baker', 'student'],
    find() {
       	this.items.findIndex(function(item) {
    		console.log('this === window : ', this === window); // true
    	}); 
    	this.items.findIndex((item) => {
        	console.log('this === window : ', this === window); // false
    	});
    }
}
job.find();

Reference