4. this

gugyeoj1n·2022년 4월 23일
0

자바스크립트

목록 보기
4/9

오늘 근무 힘들었다. 밤엔 추운데 낮엔 덥다. 겁나 더웠다. 그래도 후임들 프라페도 사 주고 버거킹 포장해 와서 지우랑 오붓하게 아이즈원 보면서 조졌다. 통새우와퍼 맛있더라. 이게 낭만이다. 전역하고 싶다

비동기에 대한 궁금증이 솟구치고 있지만 강의 순서가 이래서 this 부터 하겠다. 생각해 보니 실행 컨텍스트 안에 ThisBinding 도 있었는데 물 흐르듯 넘어가 버려서 어쩔 수 없다

ThisBinding ?.?

ThisBinding 은 실행 컨텍스트가 열릴 때 힘을 쓴다. 실행 컨텍스트가 열린다 == 함수가 호출된다 이므로 함수가 호출될 때 this 를 binding 한다는 뜻이다. 우리가 함수에서 쓰던 this 이다. 우리가 코드만 딱 봤을 때 아 여기서 this 가 뭐다 라고 공식처럼 정해져 있는 것이 아니라, 그 함수의 호출 방식에 따라 this 는 달라진다. 전역 공간의 실행 컨텍스트는 무조건 처음부터 호출되니 this 가 정해져 있다. 하지만 함수는 method, callback, constructor 등 다양한 용도로 쓰이고 그마다 this 가 다르다.

1. 전역 공간에서의 this

전역 공간에서 this 는 전역 객체를 뜻한다. 예를 들어 Node.js 에서는 global, 브라우저에서는 window 가 해당된다. 실제로 각 환경에서 console.log(this); 를 실행해 보면 해당하는 객체가 출력된다.

2. 함수가 호출될 때 this

이상하게 함수가 호출될 때도 this 는 무조건 전역 객체를 가리킨다. 당황스럽지만 함수를 호출하는 주체는 당연히도 전역 공간의 전역 객체이니 맞는 말이다.

function first() {
	function second() {
    	console.log(this);
    }
}

함수를 호출하는 주체에 this 가 맞춰지면 이 코드에서는 second() 를 호출하는 주체가 first() 가 되겠다. 하고 실행해 보니 또 전역 객체가 나온다. 실화냐?

버그라는 말이 많아서 그냥 넘기려고 했다. 좋은 습관은 아님 근데 세상에 똑똑한 사람이 얼마나 많으면 해결책이 항상 나오는지, ES6에 나온 화살표 함수가 바로 위 컨텍스트의 this 를 가져와 사용하면서 무조건 this 가 전역 객체가 되지 않도록 되었다.

3. 함수를 메서드로 사용할 때 this

const a = {
	hungry: function () {
    	console.log(this);
    }
}

a.hungry();

hungry 메서드가 들어있는 객체 a를 선언하고 hungry 를 실행했다.
메서드가 실행될 때의 this 는 그 메서드를 실행한 주체가 된다. hungry() 의 주인님이신 a 가 this 가 되는 셈이다.

지금 vscode를 쓸 수 없는 관계로 repl.it 에 이 코드를 넣고 돌려 봤더니

{ hungry: [Function] }

가 나왔다. 잘 보면 a = { ... } 와 같은 내용이라는 걸 확인할 수 있다.

그리고 강의에서 야매로 this 를 찾는 방법을 알려 주셨다. 점 앞에 있는 게 this 이다. ㅋ ㅡ ㅋ
a.hungry() 에서 점 앞에 있는 게 a 이니 this는 a 이다. 로 응용할 수 있다.
그럼 a.hungry() 대신 a['hungry']() 를 쓰면? ['hungry'] 앞에 붙어있는 a 가 this 이다. 무슨 수학 공식 마냥 써도 this 를 찾을 수 있다

ES6에는 화살표 함수가 있지만 ES5에는 없기에 함수 안의 함수에서 this 를 찾으면 무조건 전역 객체가 나온다. 그래서 바깥 함수에 this 를 담은 변수를 만들고 안쪽 함수에 스코프 체인을 활용해 그 변수를 찾게 만드는 방법으로 this 를 바꾸는 방법을 쓴다.

4. 콜백 함수가 호출될 때 this

일단 this 를 지정해 주는 여러 방법을 알아보자.

// ES5 기준으로 작성함. var 잘 지냈니..?
function a(x, y, z) {
	console.log(this, x, y, z);
}

var b = {
	bb: 'bbb'
};

a.call(b, 1, 2, 3); // 1번
a.apply(b, [1, 2, 3]); // 2번

var c = a.bind(b);
c(1, 2, 3); // 3번

var d = a.bind(b, 1, 2);
d(3); // 4번

call, apply, bind 라는 메서드가 등장했다. 난 처음 봤다.
마찬가지로 repl.it 에서 실행해 봤다.

{ bb: 'bbb' } 1 2 3
{ bb: 'bbb' } 1 2 3
{ bb: 'bbb' } 1 2 3
{ bb: 'bbb' } 1 2 3

1번부터 확인해 보겠다. a.call(b, 1, 2, 3) 의 결과는 객체 b 와 1 2 3 이 출력되었다.
함수 a의 내용은 console.log(this, x, y, z) 인데, this 의 결과가 객체 b 이니 call 의 첫번째 인자가 this 로 넘어가고 그 뒤부터 매개변수로 넘어간다는 걸 알 수 있다.

2번 apply 도 마찬가지이다. 단지 배열을 넘긴다는 차이밖에 없다.

3번은 c = a.bind(b) 후에 c(1, 2, 3) 이 실행됐는데, this에 b를 넣기만 하고 다음 코드에서 나머지를 넘긴 셈이 된다. 같은 논리로 4번을 보면 this에 b, x에 1, y에 2까지 넣은 후 d(3) 을 실행함으로 마지막 z에 3이 들어가고 console.log(...) 가 실행되었다.

공식 문서를 보면 세 메서드 모두 첫번째 인자에 thisArg 가 들어가 있는데, 이는 사용자가 this 를 명시적으로 걸어줄 수 있도록 하는 기능이 있다는 것이다.


이 정보를 바탕으로 callback 호출 시의 this 를 찾아 보겠다.

var callback = function () {
	console.log(this);
};

var obj = {
	a: 1,
    b: function (cb) {
    	cb();
    }
};

obj.b(callback);

마지막 줄에서 obj 객체의 b 메서드가 callback을 받아 호출되었다.
callback 의 console.log(this) 가 실행되는데, cb() 는 메서드가 아니라 함수로 호출됐기 때문에 this 가 전역 객체로 고정되고 결과 또한 전역 객체가 출력될 것이다.

var callback = function () {
	console.log(this);
};

var obj = {
	a: 1,
    b: function (cb) {
    	cb.call(this);
    }
};

obj.b(callback);

이러면 어떨까? cb.call(this) 에서 this 는 obj 이고, call 로 this 를 직접 지정해 주었으니 콘솔 창에 전역 객체가 아닌 obj 가 출력된다. 즉 콜백 함수의 this 는 지정하지 않으면 기본적으로 전역 객체, 지정해 주면 지정한 어떤 값이 된다.

var callback = function () {
  console.log(this);
};

var obj = {
  a: 1
};

setTimeout(callback, 1000);

예시로 setTimeout 을 가져왔다. callback 에 this 를 지정하지 않았으니 실행하면 1초 뒤에 전역 객체가 출력된다.

setTimeout(callback.call(obj), 1000);

하지만 call, bind 등으로 this 를 지정해 주면 결과가 바뀐다. 여기서는 obj 가 출력된다.


정리하면 콜백은 일반 함수가 호출될 때처럼 기본적으로 전역 객체가 this 가 된다. 하지만 얼마든지 this 를 지정해 줄 수 있다. 뭐 처음부터 지정돼 있는 함수도 있다.

5. 생성자 함수가 호출될 때 this

생성자 함수가 호출됐다는 것은 new 연산자를 사용했다는 뜻이다. 생성자 함수의 내용으로 새로운 객체가 태어나는데, 이 때 태어난 객체 자체가 this 가 된다.

function Human (name, age) {
	this.name = name;
    this.age = age;
}

var me = new Human("구겨진", 22);
console.log(me);

new 연산자로 me 라는 이름의 새로운 Human 객체를 만들었다. me 자체가 this 가 되므로 me 객체 안에 name, age 프로퍼티가 생겨나고 거기에 인자로 받은 "구겨진" 과 22가 문제 없이 들어간다.




이렇게 여러 조건에서 this 는 무엇인가에 대해 알아보았다. 내용이 많지만 강의를 듣고 정리하면서 다시 보니 절대 어렵진 않다. 어이없는 점은 내가 콜백 함수의 정의, 인자와 매개변수의 차이를 검색했다는 것이다. 기본적인 내용도 제대로 모른 채 공부하고 있었던 것이다. 물론 헷갈릴 수도 있지만 내 자신이 좀 한심했다. CS 지식 없이 언어 문법만 익혀왔던 내 문제점을 지금이라도 발견해서 참 다행이긴 하다. 아직 공부한 게 많지는 않지만 개념을 더 더 확실하게 익히면서 가야겠다. 나름 성장하는 거 아닐까 ?.?

이렇게 하나하나 쌓아가다 보면 이 벨로그도 하나의 포트폴리오가 되고 개발 실력도 좋아져 있을 상상하니 기부니가 좋다. 난 프로그래밍이 참 좋은데, 내가 좋아하고 적성에 맞는 활동이 내 직업이 되면 얼마나 행복할까 싶다 ~ 그러기 위해선




자야 됨 john k 노래 하나 듣고 꿀잠 자러 가겠다

0개의 댓글