This pt.2

심현인·2021년 6월 20일
0
post-custom-banner

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

1. call 메소드

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

메소드일때도 객체의 매소드를 그냥 호출하면 this는 객체를 참조하지만, call을 사용하면 임의의 객체를 this로 지정할 수 있다.

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 메소드

위에서 봤던 call과 기능적으로 완전 동일하지만, apply메소드는 두 번째 인자를 배열로 받아 그 배열의 요소들을 호출할 함수의 매개변수로 지정한다는 차이만 있다.

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

3. 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"]

console.dir(arr)
/*
Array(4)
0: "a"
1: "b"
2: "c"
3: "d"
length: 4
*/

객체에는 배열 메소드를 사용할 수 없지만, 키가 0 혹은 양의 정수인 프로퍼티가 존재하고, length 프로퍼티의 값이 0 또는 양의 정수인 객체(유사배열객체)의 경우에는 call / apply 메소드를 사용할 수 있다.
ES6에서는 유사배열객체 또는 순회가능한 모든 종류의 데이터 타입을 배열로 전환하나는 Array.from 메소드를 도입했다.

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

생성자 내부에서 다른 생성자를 호출

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

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 jm = new Student('절미', 'female', '사과대')
var cg =  new Employee('홍창기','male','LG Twins')

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

은 ES6에서 나온 spread 연산자를 사용하자구!

const numbers = [9, 6, 33, 41, 17]
const max = Math.max(...numbers)
const min = Math.min(...numbers)
console.log(min, max) //6 41

call/apply는 명시적으로 별도의 this를 바인딩 하면서 함수 혹은 메소드를 실행하는 훌륭한 방법이지만, 이로인해 this를 예측하기 어렵게 만들어서 코드해석을 방해 할 수도 있다. 레거시한 환경에서는 어쩔 수 없는 선택으로 활용되고 있다..

4. bind메소드

bind메소드는 ES5에서 추가된 기능이다. call과 비슷하지만 바로 호출하는 것이 아니라 넘겨받은 this 및 인수들을 바탕으로 새로운 함수를 반환하기만 한다. 다시 새로운 함수를 호출할 때 인수를 넘기면 그 인수들은 기존 bind메소드를 호출할 때 전달했던 인수들의 뒤에 이어서 등록이 된다. 즉 함수에 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

name프로퍼티

bind 메소드를 적용해서 새로만든 함수에 한 가지 독특한 성질이 있는데, 바로 name프로퍼티에 동사 bind의 수동태인 bound라는 접두어가 붙는다는 점이다. bound + 원본

var func = function(a,b,c,d){
    console.log(this, a,b,c,d)}
var bindFunc1 = func.bind({x:1},4,5) 
console.log(func.name) //func
undefined
console.log(bindFunc1.name) //bound func

상위 컨텍스트의 this를 내부함수나 콜백 함수에 전달하기

메소드의 내부함수에서 메소드의 this를 그대로 바라보기 위해선 self등의 변수를 활용해 우회하였지만, call, apply, bind를 사용해 좀 더 깔끔하게 처리할 수 있다.

var obj = {
  outer: function () {
    console.log(this);
    var innerFunc = function () {
      console.log(this);
    };
    innerFunc.call(this);
  },
};
obj.outer();

var obj = {
  outer: function () {
    console.log(this);
    var innerFunc = function () {
      console.log(this);
    }.bind(this);
    innerFunc();
  },
};
obj.outer();

또한 콜백함수를 인자로 받는 함수나 메소드 중에서 기본적으로 콜백 함수 내에서의 this에 관여하는 함수 또슷 메소드에 대해서도 bind를 활용해서 유저의 입맛에 맞게 this를 바꿀 수 있다.

var obj = {
  logThis: function () {
    console.log(this);
  },
  logThisLater1: function () {
    setTimeout(this.logThis, 500);
  },
  logThisLater2: function () {
    setTimeout(this.logThis.bind(this, 1000));
  },
};
obj.logThisLater1(); //Window{...}  
obj.logThisLater2(); // {logThis: ƒ, logThisLater1: ƒ, logThisLater2: ƒ}

5. 화살표 함수의 예외사항

화살표 함수는 this를 바인딩하는 과정이 제외되어서 해당 함수 내부에는 this가 아예 없으며, 접근하고자하면 스코프체인상 가장 가까운 this에 접근하게 된다

var obj = {
  outer: function () {
    console.log(this); // {outer: ƒ}
    var innerFunc = () => {
      console.log(this); // {outer: ƒ}
    };
    innerFunc();
  },
};
obj.outer();

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

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

var report = {
  sum: 0,
  count: 0,
  add: function () {
    var args = Array.prototype.slice.call(arguments);
    args.forEach(function (entry) {
      this.sum += entry;
      ++this.count;
    }, this);
  },
  average: function () {
    return this.sum / this.count;
  },
};

report.add(60, 85, 95);
console.log(report.sum, report.count, report.average());
//240 3 80
profile
가로
post-custom-banner

0개의 댓글