코어 자바스크립트 3장: this

송나은·2021년 6월 7일
1

JavaScript

목록 보기
19/23

this는 함수를 호출할 때 결정된다.

상황에 따라 달라지는 this

1. 전역 공간에서 this = 전역 객체.

window / global

자바스크립트의 모든 변수는 특정객체의 프로퍼티로 동작한다.
실행 컨텍스트의 LexicalEnvironment

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

2. method로 호출할 때 method 내부에서의 this

어떤 함수를 method로 호출하는 경우 호출 주체는 함수명(프로퍼티명) 앞의 객체이다.

함수는 그 자체로 독립적인 기능을 수행하는 반면,
method는 자신을 호출한 대상 객체에 관한 동작을 수행한다.

3. 함수로서 호출할 때 그 함수 내부에서의 this =전역객체

var obj1 = {
  outer: function () {
    console.log(this); // 1) obj1
    var innerFunc = function () {
      console.log(this); // 2) 함수로 호출할 때: window, 3) method로 호출할 때: obj2
    }
    innerFunc(); // 함수로 호출
    
    var obj2 = {
      innerMethod: innerFunc
	};
    obj2.innerMethod(); // method로 호출
}
};
obj1.outer();

스코프 내부에서 변수에 this를 저장한 상태에서 호출한 함수의 경우 this를 우회해서 사용할 수 있다.

4. This를 바인딩 하지 않는 함수 (= 화살표 함수 (ES6))

실행 컨텍스트를 생성할 때 this 바인딩 과정 자체가 빠져 상위 스코프의 this를 그대로 활용한다.

var obj = {
  outer: fucntion (){
  console.log(this); // { outer : f } (= obj)
  var innerFunc = () => {
  console.log(this); // { outer : f } 전역객체가 아닌 상위 스코프의 this인 obj객체
  };
innerFunc();
}
};
obj.outer();

화살표 함수는 this, prototype, arguments 정보를 생성하지 않는다.

  • new로 함께 호출하더라도 인스턴스 객체가 만들어질 수 없다. (=생성자 함수 역할x)
  • arguments가 참조된다면 ReferenceError가 발생하거나, 상위 스코프상의 arguments 객체를 참조한다.

✍ 화살표 함수로 가변 인자 함수를 구현해야 할 때는 반드시 rest 파라미터를 사용해야 한다.

var normalFunc = function () {};
console.log(normalFunc.hasOwnProperty('arguments')); // true

const arrowFunc = () => {};
console.log(arrowFunc.hasOwnProperty('arguments')); // false

5. 콜백함수 호출 시

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

  • 콜백함수: 함수 A의 제어권을 다른 함수(또는 메서드) B에게 넘겨주는 경우 함수 A
  • addEventListener는 콜백 함수를 호출할 때 자신의 this를 상속한다. 메서드명의 점 앞부분이 this

6. 생성자 함수 내부에서의 this

생성자 함수로 호출된 경우 내부에서의 this는 곧 새로 만들 구체적인 인스턴스 자신.

생성자 호출(new 함수) → 생성자의 prototpe 프로퍼티를 참조하는 proto라는 프로퍼티가 있는 객체(인스턴스) 생성 → 미리 준비된 공통 속성 및 개성을 해당 객체(this)에 부여.

var Cat = function (name, age) {
	this.bark = "우에웅";
	this.name = name;
	this.age = age;
};
var choco = new Cat('토미', 10);
console.log(choco); // Cat { bark: '우에웅', name: '토미', age: 10 }
  • 생성자 함수: 어떤 공통된 성질을 지니는 객체들을 생성하는 데 사용하는 함수. ex) 클래스
  • 생성자(= Constructor): 구체적인 인스턴스를 만들기 위한 일종의 틀.

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

1. call

메서드의 호출 주체인 함수를 즉시 실행하도록 하는 명령.
첫 번째 인자를 this로 바인딩 한다. 이후의 인자들을 호출할 함수의 매개변수로 한다.

2. apply

메서드의 호출 주체인 함수를 즉시 실행하도록 하는 명령.
첫 번째 인자를 this로 바인딩 한다. 두 번째 인자를 배열로 받아 배열의 요소들을 호출할 함수를 매개변수로 지정한다.

var obj = {
  a: 1,
  method: function (a, b, c) {
    console.log(this, a, b, c);
  };
obj.method(2,3,4); // 1 2 3 4
obj.method.call({ a : 4}, 5, 6, 7); // 4 5 6 7
obj.method.apply({ a : 4}, [5, 6, 7]); // 4 5 6 7

활용 1) 유사배열객체

키가 0 또는 양의 정수인 프로퍼티가 존재하고 length 프로퍼티 값이 0 또는 양의 정수인 객체(= 배열의 구조와 비슷한 객체)

call 또는 apply메서드를 이용해 배열 메서드를 사용할 수 있다.

  • slice 시작 인덱스값과 마지막 인덱스값을 받아 시작값부터 마지막값의 앞부분까지의 배열 요소를 추출하는 method. 매개변수를 아무것도 넘기지 않을 경우 원본 배열의 얕은 복사본을 반환한다.
  • arguments 객체. querySelectorAll, getElementByClassName 등의 노드 선택자.
  • 문자열의 경우 length 프로퍼티가 읽기 전용이기 때문에 원본을 변경하는 method(push, pop, shift, unshift, splice등)는 에러를 던진다. concat은 대상이 반드시 배열이어야 하므로 제대로 된 결과를 얻을 수 없다.
  • Array.from 유사배열객체 또는 순회 가능한 모든 종류의 데이터 타입을 배열로 전환한다. (ES6)

활용 2) 생성자 내부에서 다른 생성자 호출

생성자 내부에 다른 생성자와 공통된 내용이 있을 경우 call / apply를 이용해 다른 생성자를 호출하면 간단하게 반복을 줄일 수 있다.

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

// 원본

var numbers = [10,20,3,16,45];
var max = min = numbers[0];
numbers.forEach(function(number){
  if (number > max){
    max = number;
  }
  if (number < min){
    min = number;
  }
});
console.log(max, min); // 45 3
// apply
var numbers = [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
// spread 연산자 (ES6)
var numbers = [10,20,3,16,45];
var max = Math.max(...numbers); 
var min = Math.min(...numbers);
console.log(max, min); // 45 3

3. Bind

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

  1. 함수에 this를 미리 적용한다.
  2. 부분 적용 함수를 구현한다.
var func = function (a, b, c, d){
	console.log(this,a, b, c, d);
};
func.call({ x : 1}, 5, 6, 7, 8) // 즉시 호출, { x : 1 } 5 6 7 8
func.bind({ x : 1})(5, 6, 7, 8) // 호출 해야 실행, { x : 1 } 5 6 7 8
  • name 프로퍼티: 어떤 함수의 name 프로퍼티가 'bound 함수명' 이라면, 원본 함수에 bind 메서드를 적용한 새로운 함수라는 의미. → 코드 추적이 수월하다.
  • 상위 컨텍스트의 this를 내부함수나 콜백함수에 전달할 수 있다. .bind(this)

4. 콜백함수 내에서의 this

요소를 순회하면서 콜백함수를 반복 호출하는 내용의 메서드는 별도의 인자로 this를 받는다.

thisArg를 인자로 받는 메서드

  • Array.prototype.(forEach, map, filter, some, every, find, findIndex, from)
  • (Set, Map).prototype.forEach

Reference

profile
그때그때 공부한 내용과 생각을 기록하는 블로그입니다.

0개의 댓글