코어 자바스크립트 : 03. this 정리

yojuyoon·2020년 9월 3일
2

TIL👌

목록 보기
23/23

대부분의 객체지향 언어에서 this는 클래스로 생성한 인스턴스 객체를 의미한다. 클래스에서만 사용할 수 있기 때문에 혼란의 여지가 많지 않지만, this는 자바스크립트의 어디서든 사용할 수 있다.

this는 상황에 따라 바라보는 대상이 달라지게 되는데, 어떤 이유로 그렇게 되는지 파악하기 위해서는 정확한 작동 방식을 이해해야 한다.

상황에 따라 달라지는 this

this는 함수를 호출할 때 결정된다. 즉 함수를 어떤 방식으로 호출하느냐에 따라 값이 달라지는 것.

전역 공간에서의 this

전역 공간에서 this는 전역 컨텍스트를 생성하는 주체가 전역 객체이기 때문에 전역 객체를 가리킨다.
브라우저 환경에서는 window, Node.js에서는 global이다.

전역변수를 선언하면 자바스크립트 엔진은 이를 전역객체의 프로퍼티로 할당한다.

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

그런데 '삭제'명령에서는 전역변수 선언과 전역객체의 프로퍼티 할당 사이가 전혀 다른데, 이는 사용자가 의도치 않게 삭제하는 것을 방지하는 차원에서 마련한 방어전략이라고 볼 수 있다. 즉 전역변수를 선언하면 자바스크립트 엔진이 이를 자동으로 전역객체의 프로퍼티로 할당하면서 추가적으로 해당 프로퍼티의 configurable 속성(변경 및 삭제 가능성)을 false로 정의하는 것이다.

메서드로서 호출할 때 그 메서드 내부에서의 this

함수 vs 메서드

함수와 메서드를 구분하는 유일한 차이는 독립성에 있다. 함수는 그 자체로 독립적인 기능을 수행하는 반면, 메서드는 자신을 호출한 대상 객체에 관한 동작을 수행한다. 둘을 구분할 때 가장 큰 차이점은 함수 앞에 점(.) 또는 대괄호([])가 있는지 여부만으로 간단하게 구분할 수 있다.

메서드 내부에서의 this

this에는 호출한 주체(함수명,프로퍼티명 앞에 객체)에 대한 정보가 담긴다.

함수로서 호출할 때 그 함수 내부에서의 this

함수 내부에서의 this

어떤 함수를 함수로서 호출할 경우 호출 주체를 명시하지 않고 개발자가 코드에 직접 관여해서 실행한 것이기 때문에 호출 주체를 알 수 없어서 this가 지정되지 않는다. 따라서 함수에서의 this는 전역객체를 가리킨다.

메서드의 내부함수에서의 this

this바인딩에 관해서는 함수를 실행하는 당시의 주변환경(메서드 내부인지, 함수 내부인지 등)은 중요하지 않고, 오직 해당 함수를 호출하는 구문 앞에 점 또는 대괄호 표기가 있는지 없는지가 관건이다.

메서드의 내부 함수에서의 this를 우회하는 방법

변수를 활용하여 우회할 수 있다. 예를들어서

var obj = {
  outer: function () {
    console.log(this); // (1) {outer: f }
    var innerFunc1 = function () {
      console.log(this); // (2) Window { ... }
    };
    innerFunc1();
    
    var self = this;
    var innerFunc2 = function () {
      console.log(self); // (3) {outer: f }
    };
    innerFunc2();
    
  }
};
obj.outer();

(3)의 경우를 살펴보면 객체 obj가 출력되는 것을 볼 수 있다. 변수명을 지정할 때 사람마다 this, that혹은 등 을 사용하지만 self가 가장 보편적으로 사용된다.

this를 바인딩하지 않는 함수

화살표 함수는 실행 컨텍스트를 생성할 때 this 바인딩 과정 자체가 빠지게 되어, 상위 스코프의 this를 그대로 활용할 수 있다.

리액트에서도 콜백 this가 작동하려면 바인딩을 해야하지만 화살표 함수를 사용하여 bind를 사용하지 않을 수 있다.

콜백 함수 호출 시 그 함수 내부에서의 this

콜백 함수도 함수이기 때문에 기본적으로 this가 전역객체를 참조하지만, 제어권을 받은 함수에서 콜백 함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조하게 된다.

생성자 함수 내부에서의 this

생성자 함수는 어떤 공통된 성질을 지니는 객체들을 생성하는데 사용하는 함수이다. 객체지향 언어에서는 생성자를 클래스, 클래스를 통해 만든 객체를 인스턴스라고 한다. 어떤 함수가 생성자 함수로서 호출된 경우 내부에서의 this는 곧 새로 만들 구체적인 인스턴스 자신이 된다.

var Cat = function (name, age) {
  this.bark = "야옹";
  this.name = name;
  this.age = age;
  
};
var choco = new Cat("초코", 7);
var nabi = new Cat("나비", 5);
console.log(choco, nabi);

//Cat ( bark: "야옹", name: "초코", age: 7 }
//Cat ( bark: "야옹", name: "나비", age: 5 }

명시적으로 this를 바인딩하는 방법

this에 별도의 대상을 바인딩하는 방법

call / aplly 메서드, 활용

call메서드와 apply 메서드는 임의의 객체를 this로 지정할 수 있다. 차이점은 call 메서드는 첫번째 인자를 제외한 나머지 모든 인자들을 호출할 함수의 매개변수로 지정하는 반면, apply 메서드는 두번째 인자를 배열로 받아 그 배열의 요소들을 호출할 함수의 매개변수로 지정한다는 차이점이 있다.

유사배열객체에 배열 메서드를 적용

배열의 구조와 유사한 객체의 경우 call, apply 메서드를 이용해 배열 메서드를 차용할 수 있다.

var obj = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
};
Array.prototype.push.call(obj, 'd');
console.log(obj); // {0:'a', 1: 'b', 2: 'c', 3: 'd', length: 4 }

var arr = Array.prototype.slice.call(obj); // slice메서드 매개변수에 아무것도 넘기지 않을 경우에는 원본 배열의 얕은 복사본을 반환한다.
console.log(arr); // {'a', 'b', 'c', 'd' }

Array.from

ES6에 도입된 문법으로, 유사배열객체 또는 순회 가능한 모든 종류의 데이터 타입을 배열로 전환하는 메서드.
MDN : https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/from

var obj = {
  0: 'a',
  1: 'b',
  2: 'c',
  length: 3
};
var arr = Array.from(obj);
console.log(arr); // ['a', 'b', 'c']

여러 인수를 묶어 하나의 배열로 전달하고 싶을 때 - apply활용

var Number = [10, 20, 3, 16, 45];
var max = Math.max.apply(null, numbers);
var min = Math.min.apply(null, numbers);
console.log(max, min); //45 3

bind메서드
call 과 비슷하지만 즉시 호출하지않고 넘겨받는 this 및 인수들을 바탕으로 새로운 함수를 반환하기만 하는 메서드

bind 메서드는 함수에 this를 미리 적용하는 것과 부분 적용 함수를 구현하는 두가지 목적을 모두 지닌다.
MDN: https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

name 프로퍼티
bind 메서드를 적용해서 새로 만든 함수는 name 프로퍼티에 동사 bound라는 접두어가 붙는다. 이 의미는 bind 메서드를 적용한 새로운 함수라는 의미가 되므로 call, apply보다 코드를 추적하기에 더 수월하다.

상위 컨텍스트의 this를 내부함수나 콜백 함수에 전달하기
앞서 언급했던 self등의 변수를 활용한 우회법보다 call, apply또는 bind메서드를 이용하면 더 깔끔하게 처리할 수 있다.

이 또한 화살표 함수를 사용하면 더욱 간결하게 처리가 가능하다.


감각적(?)으로 인지하고 있는 this와 책의 내용을 통해 개념적으로 인지하게 된 this의 간극에서 살짝 혼란스러움을 느끼고 있지만, 결국 this는 문자 그대로의 특징적인 부분을 고려하되 예외적인 부분을 잘 파악하고 있으면 될 듯 하다.

profile
하고싶은게 많은 사람. Front-end Developer

0개의 댓글