昨天看到一个面试题将的自己实现一个bind函数,自己思考了一下决定写写试试.
1 首先明确第一个功能实现this的显示绑定
bind函数最明显的功能就是实现this的显示绑定, bind返回的是一个新函数:
复制代码
Function.prototype.bind = function () {
var slice = Array.prototype.slice,
context = arguments[0],
_this = this,
outerArg = slice.call(arguments, 1);
return function () {
_this.apply(context, outerArg)
}
}
复制代码
这种写法实现了最基础的this显示绑定,然而bind还是一种函数的柯里化,能够先传参,下面对代码稍加进行更改.
复制代码
2 实现柯里化
Function.prototype.bind = function () {
var slice = Array.prototype.slice,
context = arguments[0],
_this = this,
outerArg = slice.call(arguments, 1);
return function () {
var innerArg = slice.call(argunments); // 新增
var arg = outerArg.contact(innerArg); // 新增
_this.apply(context, arg)
}
}
复制代码
这样就实现了柯里化和this的显示绑定, 但是这并没有结束. 大多数情况下我们现在写的bind都能满足我们的使用,但是官方文档上有这么一句话
A bound function may also be constructed using the new operator: doing
so acts as though the target function had instead been constructed.
The provided this value is ignored, while prepended arguments are
provided to the emulated function.
这句话叙述的是关于函数被bind后如果我们对他进行new 操作后的行为;
复制代码
3 this 的问题
我们来看这个截图,testBind是我们上面所写的bind的实现方式, 当我们对fn进行testBind绑定后传入context(这里是obj),
调retFn进行 new操作后 他返回的是一个空对象, 再看看 我们用原生的bind去绑定fn传入obj 对retBindFn进行new操作后会返回一个对象包含a属性.
这个差异说明了我们目前实现的testBind函数还是有功能欠缺的, 那欠缺的在哪里呢?
this! 没错就是this. 原生的bind虽然把使用bind显示绑定将函数内部this指向我们传入的context
但是new操作是将函数内部的this指向他new操作后反返回的实例, 两个操作都是改变this指向,那么谁更优先级更高一些呢?
复制代码
传入的obj中的a属性没变!!! new操作更厉害,优先级更高一些.
那说明在这两种情况同时存在的情况下函数内部的this要指向函数本身的this(因为new操作会将此this指向new操作返回的实例);
那这个操作应该如何实现呢, 这里可以借助一个中间函数;
复制代码
Function.prototype.bind = function () {
var slice = Array.prototype.slice,
context = arguments[0],
_this = this,
outerArg = slice.call(arguments, 1);
var retFn = function () {
var innerArg = slice.call(argunments);
var arg = outerArg.contact(innerArg);
var oThis = this instanceof F ? this : context
_this.apply(oThis, arg)
}
var F = function () {}
F.prototype = this.prototype;
retFn.prototype = new F()
return retFn
}
复制代码
借助F函数根据我的理解是让我们区分这里是是否使用了new
F.prototype = this.prototype;
retFn.prototype = new F()
如果没有这两句, 我们所有的new retFn(), 内部的this指向的是实例本身即为 Object 的实例。
不使用new 操作 retFn 内部this指向的是context(不传的话一般采用默认的this绑定,this指向的是window)也是 Object 的实例。
retFn.prototype = new F()
我们没法判断是否使用new操作, 而借助F函数 如果使用new RetFn()的话 首先内部this 就是F的实例也是Object的实例。
这样的话我们就能能够通过这种方法判断是否使用new 操作从而选择this的指向.
F.prototype = this.prototype; 是在纠正retFn的原型, 作者才疏学浅, 如有错误请多指教,请多包涵复制代码