自己封装一个bind方法,需要考虑以下几点:
- 参数的获取(方法里面的参数和bind返回的函数的参数)
- this的设置(会转换基础数据类型为对象,null和undedined转换为windos对象)
- apply或者call的使用
- 返回待执行函数而不是执行函数
Function.prototype.myBind = function(...arg) {
// 拿到bind方法的参数
let obj = arg[0]
// 拿到执行的函数
let fn = this
// 获取去除this指向的参数
let params = arg.slice(1)
// 根据obj的类型对象obj进行封装,因为原生bind会将基础数据类型装换为对象
// null于undefined转换为window
if(obj === null || obj === undefined) {
obj = window
}else if(typeof obj === 'number') {
obj = Number(obj)
}else if(typeof obj === 'string') {
obj = String(obj)
}else if(typeof obj === 'boolean') {
obj = Boolean(obj)
}
// 返回一个待执行函数
return function(...arg2) {
params = params.concat(arg2)
return fn.call(obj, ...params)
}
}
var test = function (a, b, c) {
console.log("x=" + this.x, "a=" + a, "b=" + b, "c=" + c);
};
var o = {
x: 1,
};
test.bind(o, 1)(2, 3); //x=1 a=1 b=2 c=3
值得一提的是,在使用bind方法的函数里面打印this(也就是函数的第一个参数),会将基础数据类型转换为对象进行打印。null和undefined会会转换为window对象。
test.bind([])(); //[]
test.bind(1)(); //Number {1}
test.bind('1')(); //String {"1"}
test.bind(true)(); //Boolean {true}
test.bind(null)(); //window
test.bind(undefined)(); //window
test.bind(function(){})(); //ƒ (){}
test.bind(Symbol())() //Symbol {Symbol()}
所以我们封装的方法也要跟原生保持一致。