码迷,mamicode.com
首页 > 其他好文 > 详细

bind的那些事

时间:2018-03-28 01:29:12      阅读:119      评论:0      收藏:0      [点我收藏+]

标签:blog   操作符   相同   接受   重点   调用函数   bin   add   第一个   

最近面头条的时候,要求自己手动实现一个bind函数,然后又问了bind还能干嘛。这里就围绕这两个好好写一下。

首先bind的文档说明:

bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。
fun.bind(thisArg[, arg1[, arg2[, ...]]])
参数

  • thisArg
    当绑定函数被调用时,该参数会作为原函数运行时的 this 指向。当使用new 操作符调用绑定函数时,该参数无效。
  • arg1, arg2, ...
    当绑定函数被调用时,这些参数将置于实参之前传递给被绑定的方法。
  • 返回值
    返回由指定的this值和初始化参数改造的原函数拷贝

bind() 函数会创建(返回)一个新函数(称为绑定函数),新函数与被调函数(绑定函数的目标函数)具有相同的函数体(在 ECMAScript 5 规范中内置的call属性)。当新函数被调用时 this 值绑定到 bind() 的第一个参数,该参数不能被重写。绑定函数被调用时,bind() 也接受预设的参数提供给原函数。(注意这句话是重点,也就是说bind支持了这个功能)

一般新手分不清于call,apply的关系,call/apply一般会伴随这函数的调用的,而bind只是返回了带新this的函数,将在下次调用。一般用法是调用bind后赋给一个变量,支持调用的时候继续传参。

我们一般快速实现一个bind:

/*

函数体内的this,就是需要绑定this的实例函数,或者说是原函数。最后我们使用apply来进行参数(context)绑定,并返回。
同时,将第一个参数(context)以外的其他参数,作为提供给原函数的预设参数,这也是基本的柯里化基础。(应该是偏函数)

*/
Function.prototype.bind =  Function.prototype.bind || function(context) {
    var self = this;
    arg = Array.prototype.slice.call(arguments,1);
    return function() {
        return self.apply(context,arr);
    }
}

但是这个实现有个问题,我们将参数限定了arguments.slice(1),我们返回的绑定函数中,如果想实现预设传参,上个代码就不能满足了。
eg:

function sum(a, b) {
    console.log(a + b)
}

var sum2 = sum.bind(null,2);   // 固定参数a, 值为2
sum2(4)                        // 传入参数b, 值为4, 结果为6 重在我们在调用函数的时候可以预设传参

那么我们将上个bind的实现更完善一下:

Function.prototype.bind =  Function.prototype.bind || function(context) {
    var self = this;
    var args = Array.prototype.slice.call(arguments,1);
    return function() {
        var innerArgs = Array.prototype.slice.call(arguments);
        var FinalArgs = args.concat(innerArgs);
        return self.apply(context,FinalArgs);
    }
}

这样就是实现了偏函数功能,在一些资料里是说“柯里化”,我觉得还是有点区别的,共同特点是实现了参数复用。

但举个例子:
假设有一个Add(x,y,z)函数,接收x,y,z三个参数,返回x+y+z

  • 偏函数

AddBySeven =Otherbind(Add, 7);
AddBySeven(5, 10); // returns 22;
这是偏函数,固定了你函数的某一个或几个参数,返回一个新的函数,接收剩下的参数, 参数个数可能是1个,也可能是2个,甚至更多。

  • 柯里化:把一个有n个参数的函数变成n个只有1个参数的函数

curryAdd = Curry(Add);
AddBySeven = curryAdd(7);
AddBySeven(5)(10); // returns 22
// curryAdd(7)(5)(10)

Add = (x, y, z) => x + y + z
变成了CurryAdd = x => y => z => x + y + z

很多资料有的叫柯里化有的叫偏函数,这点我觉得还是读者自己判断把。

到这里可能大家觉得上面的实现已经完美了,但是JS的坑是补不完的,问题又来了!
看过文档的就知道,在文档上介绍bind时还说了这点:

一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。

那么如果bind返回的函数当做构造函数调用的时候,我们就需要在内部重新构造原型链了。所以更兼容的写法来了:

Function.prototype.bind =  Function.prototype.bind || function(context) {
    var self = this;
    var args = Array.prototype.slice.call(arguments,1);
    var Fun = {};
    Fun.prototype = this.prototype;//继承原来函数
    var Comb = function(){
        var innerArgs = Array.prototype.slice.call(arguments);
        var FinalArgs = args.concat(innerArgs);
        return self.apply(this instanceof Fun ? this : context || this ,FinalArgs);
    }
    Comb.prototype = new Fun();
    return Comb;
    }

现在,
这里我有个问题,我明天好好问下师傅,懂了那个之后在这里继续说明,23333。

bind的那些事

标签:blog   操作符   相同   接受   重点   调用函数   bin   add   第一个   

原文地址:https://www.cnblogs.com/zhangmingzhao/p/8660985.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!