bind는 this 값을 특정한 값으로 고정시킨 함수를 만들 수 있는 메소드이다.
bind는 ES5에 추가되었기 때문에 ES5 이전에는 call, apply를 통해서만 this를 변경할 수 있었다. bind처럼 this를 변경 한 함수로 만들기 위해서는 직접 구현을 했어야했다.
그러면 call, apply와 클로저를 활용해서 bind와 똑같이 구현하게 만들어볼 것이다.
Function.prototype.bind = function(target, ...args) {
if(typeof this !== 'function') throw new Error('함수가 아닙니다.');
const that = this;
return function(...rest){
return that.call(target, ...args, ...rest);
}
}
이렇게 작성하면 기존의 bind와 똑같이 작동하는 것을 확인할 수 있을 것이다.
that
은 return으로 일반 함수를 반환할 경우 this값이 바뀔 수 있으므로 클로저로 저장해놓은 것이다. 또는 화살표 함수를 사용하면 된다.
Function.prototype.bind = function(target, ...args) {
if(typeof this !== 'function') throw new Error('함수가 아닙니다.');
return (...rest) => this.call(target, ...args, ...rest)
}
하지만 첫번째 function은 화살표 함수로 변경하면 안 된다! 화살표함수의 this는 lexical this
로 선언시의 this로 고정되어 버리기 때문에 일반 모드일 경우 winodw or global, use strict
인 엄격모드일 경우에는 undefined가 되어 에러가 날 것이다.
rest 문법과 화살표 함수는 ES6문법이다. ES5 이전 문법으로 하려면 어떡해야할까? arguments를 사용해볼 수 있을 것 같다.
Function.prototype.bind = function(target) {
if(typeof this !== 'function') throw new Error('함수가 아닙니다.');
var args = Array.prototype.slice.call(arguments, 1);
var that = this;
return function(){
var rest = Array.prototype.slice.call(arguments);
return that.apply(target, args.concat(rest))
}
}
call은 , 를 기준으로 들어가야하는데 spread 문법을 못 쓰니 펼칠 방법이 생각나지 않더라. 그래서 apply를 사용하고 concat을 이용해서 배열 형식으로 넣어주는 방식을 택했다. call, apply가 나눠진게 이 이유가 아닐까 생각해본다.
해당 bind는 제가 생각해서 짠 것이므로 모든 상황에 돌아가지 않을 수도 있습니다. 정확한 참고는 https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/bind
에 polyfill 부분을 참고하면 좋을 것 같습니다!