JS-柯里化

824 阅读2分钟

应用场景:一个函数拥有多个参数,且频繁调用,且前几个参数相对固定,使用柯里化固定函数前面的参数

为什么会有多个参数,且前几个参数又是相对固定的?

个人猜测:可能是某一个库比较灵活,很多功能都可以用到它,而前面几个参数可能就是划分类的,做到适配

实现

function kelihua(fn, ...args) {
    return function (...subArgs) {
        let newArgs = [...args, ...subArgs];
        if (newArgs.length == fn.length) {
            return fn(...newArgs);
        } else {
            console.log(newArgs)
            return kelihua(fn, ...newArgs)
        }
    }
}
function calc(a, b, c, d) {
    console.log("calc")
    return a + b * c - d
}
console.log(calc.length)
var fn1 = kelihua(calc, 1, 2)
var fn2 = fn1(3)
console.log(fn2(4))

笔记

  1. function.length是参数的长度
  2. 柯里化函数的参数在return function后形成闭包,不需要另外保存
  3. 函数的执行需要满参数
  4. 对第二次柯里化操作,两次参数在递归调用一次后再次形成闭包保存

bind直接柯里化

var cate = {}
var ds1 = calc.bind(cate, 2, 3).bind(cate,4).bind(cate,5)
ds1()

上面链式写法是可以的,也可以逐级拆分

bind是Function.prototype的函数,所以由Function生成的function都能用bind这个方法

bind改变this指向的优先级小于new

bind生成的构造函数,用于new对象,对象保持原有的特性,bind不起作用

function original(x) {
	this.a = 1;
	this.b = function () { return this.a + x }
}
var obj1 = {
	a: 10
}
var newObj = new (original.bind(obj1, 2)); //传入了一个实参2
console.log(newObj.a);  //输出1, 说明返回的函数用作构造函数时obj(this的值)被忽略了
console.log(newObj.b()); //输出3 ,说明传入的实参2传入了原函数original

Function.prototype.myBind

细微差别,两种写法都能满足一定的功能

Function.prototype.myBind1 = function () {
    var args = Array.prototype.slice.call(arguments, 1)
    var obj = arguments[0]
    var that = this
    return function () {
        var subArgs = Array.prototype.slice.call(arguments)
        var newArgs = args.concat(subArgs)//concat不改变原数组
        console.log(newArgs)
        return that.apply(obj, newArgs)
    }
}
Function.prototype.myBind2 = function (obj, ...args) {
    const that = this
    return function (...subArgs) {
        let newArgs = [...args, ...subArgs]
        console.log(newArgs)
        if (that.length <= newArgs.length) {
            return that.apply(obj, newArgs)
        } else {
            return callee(obj, newArgs)
        }
    }
}
var objs = {}
// var newfn = calc.myBind1(null, 1, 2).myBind1(null, 3).myBind1(null, 4)
var newfn = calc.myBind2(null, 1, 2).myBind2(null, 3).myBind2(null, 4)
newfn()

补充

fun.bind(obj)可以将一个函数剥夺给obj使用

fun.bind(obj)不会改变原来的函数,而是返回一个新的函数

在下例中,function先是运行了bind后,再赋给了fun

var objshadow = {value:14}
var obj = {
    value:13,
    fun:function(){
        console.log(this.value);
    }.bind(objshadow)
};
obj.fun()//14