[JS] this

이애진·2022년 12월 2일
0

JavaScript

목록 보기
13/16
post-thumbnail

1. this

전역 공간에서 this는 전역객체를 가르킨다.
전역객체는 자바스크립트 런타임 환경에 따라 다른 정보를 갖고 있는데, 브라우저 환경에서는 window, node.js 환경에서는 global 이다.


2. 전역변수와 전역객체

var a = 1;

console.log(a); // 1
console.log(window.a); // 1
console.log(this.a); // 1

위와 같은 결과는 자바스크립트의 모든 변수가 렉시컬 환경의 프로퍼티이기 때문에 가능하다.
변수를 선언하더라도 자바스크립트 엔진은 렉시컬 환경의 프로퍼티로 인식하며, 전역 객체의 프로퍼티로 선언한다.


3. 매서드 내부에서 this

우선 매서드가 무엇인지 살펴보면 아래와 같다.

매서드는 자신이 호출한 대상 객체에 관한 동작을 수행한다. => 객체의 프로퍼티가 함수인 경우
이 때 말하는 객체는 사용자가 정의한 객체를 의미한다.

const obj = {
	foo: () => console.log("매서드");
}

obj.foo();

어떤 함수를 객체의 프로퍼티에 무작정 할당됐다고 해서 그 자체가 매서드가 되는건 아니고, 객체의 매서드로서 호출할 경우에만 메서드로 동작하고 그게 아니라면 함수이다.

this에는 호출한 주체에 대한 정보가 담긴다
메서드가 호출되는 경우 호출 주체는 함수명(프로퍼티명) 앞의 객체이다

const foo = function() {
	console.log(this);
}

const obj = { foo }

obj.foo(); // {foo: f}

4. 함수 내부에서 this

함수는 독립적인 기능을 수행하며 자체적을 존재한다

const foo = function() {
	console.log(this);
}

foo(); // Window {...}

함수로서 호출할 경우에는 호출 주체를 알 수 없기 때문에 this가 지정되지 않는다


5. 화살표 함수

es6에서는 함수 내부에서 this가 전역객체를 바라보는 문제를 보완하고자 this를 바인딩하지 안흔 화살표 함수를 도입했다
화살표 함수는 실행 컨텍스트를 생성할 때 this 바인딩 과정 자체가 빠지게 되어(화살표 함수 내부에는 this가 아예 없음) 상위 스코프의 this를 그대로 사용할 수 있다

const obj = {
  foo: function() {
    console.log(this);
    
    const foo2 = () => console.log(this)
    foo2(); // {foo: f}
    
    const foo3 = function() {
      console.log(this);
    }
    foo3(); // Window {...}
  }
}

obj.foo(); // {foo: f}

6. 콜백 함수에서 this

setTimeout(function() { console.log(this); }, 300); // Window {...}

[1, 2, 3, 4, 5].forEach(function(x) {
  console.log(this, x); // Window {...} 1, ...
});

document.body.querySelector("#a").addEventListener("click", function(e) {
  console.log(this, e); // #a, 클릭 이벤트 정보
});

setTimeout 콜백과 forEach 콜백을 호출할 때 대상이 될 this를 지정하지 않아서 콜백 내부에서의 this는 전역객체를 참조한다
하지만 addEventListener 메서드는 콜백 함수를 호출할 때 자신의 this를 상속하도록 되어있다 (.) 앞부분이 this가 된다

그렇기 때문에 콜백함수에서 this는 무조건 한가지 유형으로 정의할 수 없다


7. call(), apply(), bind()

function menuGlobal(item){
  console.log(`오늘 저녁은 ${item} ${this.name}`);
}

function menuGlobal2(item1, item2){
  [item1, item2].forEach(function(item) {
    console.log(`오늘 저녁은 ${item} ${this.name}`);
  }, this); // forEach 안에 this를 받으려면 두 번째 인자로 this를 넣어주어야한다 그렇지 않으면 항상 window를 가르킴
}

var myDinner = {
  name: "김치찌개"
}

var yourDinner = {
  name: "된장찌개"
}

menuGlobal.call(myDinner, "묵은지"); // 오늘 저녁은 묵은지 김치찌개
menuGlobal.call(yourDinner, "차돌"); // 오늘 저녁은 차돌 된장찌개

menuGlobal2.apply(myDinner, ["묵은지", "삼겹살"]); // 오늘 저녁은 묵은지 김치찌개 \n 오늘 저녁은 삼겹살 김치찌개
menuGlobal2.apply(yourDinner, ["두부", "애호박"]); // 오늘 저녁은 두부 된장찌개 \n 오늘 저녁은 애호박 된장찌개

call은 함수를 실행할 때 사용할 인수를 전달할 수 있다
apply는 함수를 실행할 때 인수를 배열로 묶어 한 번에 전달한다
두 매서드 다 첫 번째 인자로 this로 주입 받을 객체를 넣고, 두 번째 인자는 전달할 인수를 넣는다

call과 apply 차이는 call은 함수를 실행할 때 인수 하나하나를 전달한다면, apply는 전달할 인수를 배열로 묶어 한 번에 전달한다
인수를 배열로 보낸다는 점 빼고 call과 apply는 동일한 기능을 한다

function menuGlobal(item){
  console.log(`오늘 저녁은 ${item} ${this.name}`);
}

var myDinner = {
  name: "김치찌개"
}

var yourDinner = {
  name: "된장찌개"
}

var menuGlobalForMe = menuGlobal.bind(myDinner);
var menuGlobalForYou = menuGlobal.bind(yourDinner);
menuGlobalForMe("묵은지"); // 오늘 저녁은 묵은지 김치찌개
menuGlobalForYou("차돌"); // 오늘 저녁은 차돌 된장찌개

myDinner.menuMine = menuGlobalForYou;
myDinner.menuMine("묵은지"); // 오늘 저녁은 묵은지 된장찌개

bind 매서드는 es5에서 추가된 개념으로 this에 할당되는 객체가 고정된 새로운 함수를 생성한다

ref

profile
Frontend Developer

0개의 댓글