bind的第一个参数为新绑定的上下文,而其余参数将作为新函数的参数,供调用时使用。
fn = fn.bind(this, args);
// 用法
const obj = {name: 'xiaoming'};
function sayName(...arg) {
console.log(arg[0] || '---------');
console.log(this.name);
}
const objSayName = sayName.bind(obj, '-----practice-bind-----');
objSayName();
// es6 实现bind
Function.prototype._bind1 = function(context, ...args) {
// return (...args2) => this.call(context, ...args, ...args2);
return (...args2) => this.apply(context, [...args, ...args2]);
}
const objSayName1 = sayName._bind1(obj, '--------es6-bind--------');
objSayName1();
// 该方法简单但es6兼容性有问题
// es5 基本实现bind
Function.prototype._bind2 = function() {
var args = Array.prototype.slice.call(arguments, 0);
var context = args.splice(0, 1)[0];
var fn = this;
return function () {
var args2 = Array.prototype.slice.call(arguments, 0);
var newArgs = args.concat(args2);
return fn.apply(context, newArgs);
};
}
const objSayName2 = sayName._bind2(obj, '--------es5-bind-base--------');
objSayName2();
如果使用了bind之后的fn指向了 指定的上下文,然后将返回的函数作为构造函数,那么这时候 bind指定的上下文 与 new创建的上下文(新对象) 到底 指向谁?
var testObj = {a: 0};
function setA (val) {
console.log('-----------------')
this.a = val;
}
// 先测试一段 原生bind 与new的结果
var testBind = setA.bind(testObj);
var testNewObj = new testBind(1);
console.log('testObj.a: ' + testObj.a); // testObj.a: 0
console.log('testNewObj.a: ' + testNewObj.a); // testNewObj.a: 1
// 执行new 改变this指向 要强过bind
如果用上面手写的bind来测试
var testHandBind = setA._bind2(testObj);
var testHandObj = new testHandBind(2);
console.log('testObj.a: ' + testObj.a); // testObj.a: 2
console.log('testHandObj.a: ' + testHandObj.a); // testNewObj.a: undefined
console.log(testHandObj) // {}
//如上结果与 原生bind出现不一致性 那么就需要兼容这种情况
Function.prototype._bind3 = function() {
var args = Array.prototype.slice.call(arguments, 0);
var context = args.splice(0, 1)[0];
var fn = this;
if (typeof fn !== "function") {
throw new Error("Must accept function");
}
var resFn = function() {
var args2 = Array.prototype.slice.call(arguments, 0);
var newArgs = args.concat(args2);
// resFn.prototype.isPrototypeOf(this)
// 这里的判断很多地方都可以看到,可以用来判断构造函数是不是通过new关键字实例化
// 从而写出对应的兼容代码
if (this instanceof resFn) {
fn.apply(this, newArgs);
} else {
return fn.apply(context, newArgs);
}
}
return resFn;
}
var testHandBind1 = setA._bind3(testObj);
var testHandObj1 = new testHandBind1(3);
console.log('testObj.a: ' + testObj.a); // testObj.a: 2
console.log('testHandObj1.a: ' + testHandObj1.a); // testNewObj.a: undefined
console.log(testHandObj1) // {}
testHandBind1(4);
console.log('testObj.a: ' + testObj.a);