언어/자바스크립트

[Javascript] bind 메서드

youngble 2022. 6. 19. 18:18

ES5에서 추가된 기능으로 call과 비슷하지만 즉시 호출하지않고 넘겨받은 this 및 인수들을 바탕으로 새로운 함수를 반환하기만 하는 메서드이다. 다시 새로운 함수를 호출할 때 인수를 넘기면 그 인수들은 기존 bind 메서드를 호출할 때 전달했던 인수들의 뒤에 이어서 등록된다.

bind 메서드는 두가지 목적을 지닌다.

1. 함수에 this를 미리 적용하는 것

2. 부분 적용 함수를 구현

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

위와 같이 bindFunc1은 this만 미리 지정한 것이고 bindFunc2는 this 지정과 부분 적용 함수를 구현한 것이다.

 

name 프로퍼티

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

bind 메서드를 적용시 새로 만드는 함수의 독특한 성질이 있는데 name 프로퍼티에 'bound'라는 접두어가 붙는다. 따라서 어떤 함수의 name 프로퍼티가 'bound xxx'라면 함수명이 xxx인 원본 함수bind메서드를 적용한 새로운 함수라는 의미이고 기존의 call/apply 보다 코드를 추적하기에 더 수월한 면이 있다.

 

내부함수에 this 전달- call vs bind

기존

var obj = {
	outer: function(){
    	console.log(this); // { outer: f}
        var innerFunc = function(){
        	console.log(this); // Window { ...}
        }; 
        innerFunc();
    }
};
obj.outer();

call

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

bind

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

 

bind(2)

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

위의 코드를 보면 obj.logThisLater1() 로 실행하면 점(.)앞의 객체를 this로 바인딩한다는건 그전에 설명했다.

따라서 logThisLater1 프로퍼티 함수내에서 this를 console로 찍어보면 obj {logThis: f, logThisLater1: f, logThisLater2: f} 가 나오는데 setTimout함수내부에서 쓰는 this.logThis경우 this는 Window {...}로 출력된다. 

logThisLater2의 경우는 .bind(this)를 통해 obj {logThis: f, logThisLater1: f, logThisLater2: f}를 this에 미리 적용하였기때문에 obj.logThisLater2()는 obj {logThis: f, logThisLater1: f, logThisLater2: f}출력되는 것이다.

 

forEach문 this

var report = {
	sum: 0,
    count: 0,
    add: function(){
    	var args = Array.prototype.slice.call(arguments);
        args.forEach(function(entry){
        	console.log(this)
            this.sum+= entry;
            ++this.count;
        }, this) // forEach메서드의 두번째 인자는 callback을 실행할 때 this로 사용할 값.
    },
    average: function(){
    	return this.sum / this.count;
    }
};
report.add(60, 85, 95);
console.log(report.sum, report.count, report.average());

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach

콜백함수를 인자로 받는 메서드 중 일부는 추가로 this로 지정할 객체(thisArg)를 인자로 받는 경우가 있다. 그 예로 위의 forEach메서드를 보면 forEach메서드의 두번째 인자에 this를 넣어주었는데 이건 callback함수를 실행할 때 this로 사용할 값을 결정한다.

따라서 report.add(60, 85, 95) 를 호출할때 점(.)앞의 report객체를 this로 참조하기때문에 {sum: 0, count:0, add: f, average:f} 가 this값으로 사용된다. 

 

forEach문의 콘솔 출력 결과


9줄 {sum: 0, count: 0, add: ƒ, average: ƒ}
9줄 {sum: 60, count: 1, add: ƒ, average: ƒ}
9줄 {sum: 145, count: 2, add: ƒ, average: ƒ}
17줄 240 3 80

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

Array.prototype.forEach(callback[, thisArg])
Set.prototype.forEach(callback[, thisArg])
Map.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]])