\(@^0^@)/

[BOOK] 코어 자바스크립트, this(2) 본문

BOOKS/코어 자바스크립트

[BOOK] 코어 자바스크립트, this(2)

minjuuu 2022. 3. 14. 11:36
728x90

오늘 읽은 범위 : (this) p.80 ~ p.93


< 책에서 기억하고 싶은 내용 >

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

1️⃣ call 메서드

Function.prototype.call(thisArg[, arg1[, arg2[, ...]]])
  • 메서드의 호출 주체인 함수를 즉시 실행하도록 하는 명령
  • 첫 번째 인자를 this로 바인딩하고, 이후의 인자들을 호출할 함수의 매개변수로.
  • 함수를 그냥 실행하면 this는 전역 객체를 참조하지만 call 메서드를 이용하면 임의의 객체를 this로 지정할 수 있다.
  • 객체의 메서드를 그냥 호출하면 this는 객체를 참조하지만 call 메서드를 이용하면 임의의 객체를 this로 지정할 수 있다.
// 함수
var func = function (a, b, c) {
	console.log(this, a, b, c);
};

func(1, 2, 3);                  // Window{ ... } 1 2 3
func.call({ x:1 }, 4, 5, 6);    // { x:1 } 4 5 6


// 메서드
var obj = {
	a: 1,
    method: function (x, y) {
    	console.log(this.a, x, y);
    }
};

obj.method(2, 3);                 // 1 2 3
obj.method.call({ a:4 }, 5, 6);   // 4 5 6

2️⃣ apply 메서드

Function.prototype.apply(thisArg[, argsArray])
  • call 메서드와 기능적으로 완전 동일
  • 두 번째 인자를 배열로 받아 그 배열의 요소들을 호출할 함수의 매개 변수로 지정한다.
// 함수
var func = function (a, b, c) {
	console.log(this, a, b, c);
};

func.apply({ x:1 }, 4, 5, 6);    // { x:1 } 4 5 6


// 메서드
var obj = {
	a: 1,
    method: function (x, y) {
    	console.log(this.a, x, y);
    }
};

obj.method.apply({ a:4 }, 5, 6);   // 4 5 6

call / apply 메서드의 활용

  • 유사배열객체 (array-like object)에 배열 메서드를 적용
    1. 유사배열객체에 배열 메서드를 적용
    2. arguments.NodeList에 배열 메서드를 적용
    3. 문자열에 배열 메서드를 적용
    4. ES6의 Array.from 메서드 적용
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);
console.log(arr);                           // ['a', 'b', 'c', 'd']


// ES6의 Array.from
var arr = Array.from(obj);
console.log(arr);                           // ['a','b','c']
  • 생성자 내부에서 다른 생성자를 호출
    생성자 내부에 다른 생성자와 공통된 내용이 있을 경우 call 또는 apply를 이용해 다른 생성자를 호출하면 간단하게 반복을 줄일 수 있다.
// Student, Employee 생성자 함수 내부에서 Person 생성자 함수를 호출해서 인스턴스의 속성을 정의하도록 구현

function Person(name, gender) {
	this.name = name;
    this.gender = gender;
}

function Student(name, gender, school) {
	Person.call(this, name, gender);
    this.school = school;
}

function Employee(name, gender, company) {
	Person.apply(this, [name, gender]);
    this.company = company;
};

var by = new Student('보영', 'female', '단국대');
var jn = new Employee('재난', 'male', '구골');
  • 여러 인수를 묶어 하나의 배열로 전달하고 싶을 때 - apply 활용
// 최대, 최솟값을 구하는 코드

// 여러 인수를 받는 메서드(Math.max/Math.min)에 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

// ES6의 스프레드 연산자 활용
const numbers = [10, 20, 3, 16, 45];
const max = Math.max(...numbers);
const min = Math.min(...numbers);
conosle.log(max, min);                   // 45 3

call / apply 메서드는 명시적으로 별도의 this를 바인딩하면서 함수 또는 메서드를 실행하는 훌륭한 방법이지만
오히려 이로 인해 this를 예측하기 어렵게 만들어 코드 해석을 방해한다는 단점이 있음에도 불구하고
ES5 이하의 환경에서는 마땅한 대안이 없기 때문에 실무에서 매우 광범위하게 활용되고 있음.

3️⃣ bind 메서드

Function.prototype.bind(thisArg[, arg1[, arg2[, ...]]])

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

var func = function(a, b, c, d) {
	console.log(this, a, b, c, d);
};
func(1, 2, 3, 4);                          // Window{ ... } 1 2 3 4

var bindFunc1 = func.bind({ x:1 });
bindFunc1(5, 6, 7, 8);                     // { x:1 } 5 6 7 8

var bindFunc2 = func.bind({ x:1 }, 4, 5);
bindFunc2(6, 7);                           // { x:1 } 4 5 6 7
bindFunc2(8, 9);                           // { x:1 } 4 5 8 9
  • bind메서드를 적용해서 새로 만든 함수는 name 프로퍼티에 동사 bind의 수동태인 'bound'라는 접두어가 붙는다.
    어떤 함수의 name 프로퍼티가 'bound xxx' 라면 이는 곧 함수명이 xxx인 원본 함수에 bind 메서드를 적용한 새로운 함수라는 의미로 기존의 call이나 apply 보다 코드를 추적하기에 더 수월하다.
  • 콜백 함수 내에서의 this에 관여하는 함수 또는 메서드에 대해서 bind 메서드를 이용하면 this 값 커스텀이 가능.

4️⃣ 화살표 함수의 예외사항

ES6에 새롭게 도입된 화살표 함수는 실행 컨텍스트 생성 시 this를 바인딩하는 과정이 제외됐다.
즉 이 함수 내부에는 this가 아예 없으며, 접근하고자 하면 스코프 체인상 가장 가까운 this에 접근하게 된다.
화살표 함수를 사용하면 별도의 변수로 this를 우회하거나 call/apply/bind를 적용할 필요가 없어 더욱 간결하고 편리함.

5️⃣ 별도의 인자로 this를 받는 경우(콜백 함수 내에서의 this)

콜백 함수를 인자로 받는 메서드 중 일부는 추가로 this로 지정할 객체(thisArg)를 인자로 지정할 수 있는 경우가 있다.
이러한 메서드의 thisArg 값을 지정하면 콜백 함수 내부에서 this 값을 원하는 대로 변경할 수 있다.
이런 형태는 여러 내부 요소에 대해 같은 동작을 반복 수행해야 하는 배열 메서드와 Set, Map 등의 메서드에도 일부 존재.

// 콜백 함수와 함께 thisArg를 인자로 받는 메서드

Array.prototype.forEach(callback[, thisArg])
Array.prototype.map(callback[, thisArg])
Array.prototype.filter(callback[, thisArg])
Array.prototype.some(callback[, thisArg])
Array.prototype.every(callback[, thisArg])
Array.prototype.find(callback[, thisArg])
Array.prototype.findIndex(callback[, thisArg])
Array.prototype.flatMap(callback[, thisArg])
Array.prototype.from(arrayLike[, callback[, thisArg])
Set.prototype.forEach(callback[, thisArg])
Map.prototype.forEach(callback[, thisArg])

< 오늘 읽은 소감? 떠오르는 생각을 가볍게 적어보기 >

내가 개발 공부를 시작했을 때 부터 ES6가 도입된 상태여서 ES5를 제대로 생각해본 적이 없었는데,
이렇게 ES6가 없을 경우에 사용하는 this 바인딩 방법들을 훑고 나니까 ES6가 엄청난 혁신이었다는 것을 다시 한번 깨닫는 계기가 되었다~ 나는 정말 쉽게 개발 공부를 하고 있는 거구나...
아직도 무슨 말인지 정확히 모르겠고.... ES6가 없었다면 나는 진작 공부를 포기했었을 거 같은 느낌적인 느낌을 받았다^^.... ES6 문법 감사해~


< 3줄 요약 >

  • call, apply 메서드는 this를 명시적으로 지정하면서 함수 또는 메서드를 호출한다.
  • bind 메서드는 this 및 함수에 넘길 인수를 일부 지정해서 새로운 함수를 만든다.
  • 요소를 순회하면서 콜백 함수를 반복 호출하는 내용의 일부 메서드는 별도의 인자를 this로 받는다.

[ 출처 : 코어 자바스크립트 ]

728x90