在前面的文章中介绍过了,apply 和bind 的作用就是显示改变函数执行的this的绑定。
apply 和 call 是执行函数并该改变this,二者的参数有所区别
而bind则是 返回一个待执行的新函数, 当新函数执行的时候改变了this的指向。
所以,bind的情况会与apply和call不同。
Function.prototype.myapply = function(context){
context = context ? Object(context) : window; // 确定对象
var fn = Symbol();
context[fn] = this; // 绑定到当前对象上
let result;
let arr = [...arguments].slice(1); // 获取参数
// 执行函数
if (!arr.length) {
result = context[fn]();
} else {
result = context[fn](arr);
}
delete context[fn]; // 删除绑定
return result;
}
Function.prototype.mycall = function(context){
context = context ? Object(context) : window;
let fn = Symbol();
// 绑定到当前对象上
context[fn] = this;
// 获取参数
let args = [...arguments].slice(1);
// 执行函数
let result = context[fn](...args);
// 删除绑定
delete context[fn]
return result;
}
如果参照 apply 和 call 的想法,实现方式如下:
Function.prototype.mybind = function(context, ...perAgrs){
context = context ? Object(context) : window;
let fn = this; // 记录函数
let fnBound = function(...args){
fn.apply(context, perAgrs.concat(args) )
}
return fnBound;
}
此时我们正常的绑定函数是没有问题的。
但是在 new 绑定后的函数时候就会出现问题
function fn(a){
this.a = a;
}
let t1 = {a:2};
let t2 = {a:2};
let mybindFn = fn.mybind(t1);
let bindFn = fn.bind(t2);
let objmybindFn = new mybindFn(1);
let objbindFn = new bindFn(1);
let objn = new fn(1);
console.log(objmybindFn); // fn {a: 1}
console.log(objbindFn); // fnBound {}
我们会发现这两结果是不一样的,
objmybindFn是 fnBound 实例化后的对象。
objbindFn则是 fn实例化后的对象。
其实对于objmybindFn的结果,我们也很容易理解,构造函数就是fnBound。而在fnBound的函数体内执行语句是fn.apply(context, perAgrs.concat(args) )
所以new值设置在t2上了。
可是我们发现原生bind的实现并不是这样的。他使用的构造函数是fn, 而且他也不会改变t1。你可以认为是直接new fn(2).
到此,我们需要解决两个问题。
fn.apply(context, perAgrs.concat(args) )
的context是谁。instanceof
可以做原型链的检查, 判断当前对象是都 new 出来的。 用于确定 context是谁。fnBound.prototype = fn.prototype
, 这样在改写 fnBound.prototype
时候会影响 fn.prototype
fnBound.prototype = new fn()
,fnBound.prototype = Object.create(fn.prototype)
fnBound.prototype
的时候只会改写创建出来的对象,但是访问的时候却可以通过原型链访问到 fn.prototype
。fn.prototype
上的属性和方法。Function.prototype.mybind = function(context, ...perAgrs){
context = context ? Object(context) : window;
let fn = this; // 记录函数
let fnBound = function(...args){
fn.apply( this instanceof fnBound ? this : context, perAgrs.concat(args) )
}
fnBound.prototype = Object.create(fn.prototype);
return fnBound;
}
function fn(a){
this.a = a;
}
let mybindFn = fn.mybind({a:2});
let bindFn = fn.bind({a:2});
let objmybindFn = new mybindFn(1);
let objbindFn = new bindFn(1);
let objn = new fn(1);
console.log(mybindFn.prototype) // {}
console.log(bindFn.prototype) // undefined
这里你就会发现,其实我们实现的结果和bind还是有所差异。
原文:https://www.cnblogs.com/cyrus-br/p/14031185.html