// 求和
let add = function (a, b, c) {
return a + b + c
}
{
/* 简单版curry函数示例 */
// 对求和函数做curry化
let f1 = curry(add, 1, 2, 3)
console.log('简单版', f1())// 6
// 对求和函数做curry化
let f2 = curry(add, 1, 2)
console.log('简单版', f2(3))// 6
// 对求和函数做curry化
let f3 = curry(add)
console.log('简单版', f3(1, 2, 3))// 6
// 但是简单版curry函数多次调用会报错,如下:
// console.log('简单版',f3(1)(2)(3))// Uncaught TypeError: f3(...) is not a function
// 简单版(只能调用1次)
function curry(fn) {
// 缓存除函数fn之外的所有参数
let args = Array.prototype.slice.call(arguments, 1)
// 闭包
return function () {
// 连接已缓存的老的参数和新传入的参数(即把每次传入的参数全部先保存下来,但是并不执行)
let newArgs = args.concat(Array.from(arguments))
// 调用,这里的apply只是为了方便传参数,可以不用
return fn.apply(null, newArgs)
}
}
}
{
/* 复杂版curry函数示例 */
// 对求和函数做curry化
let f1 = curry(add, 1, 2, 3)
console.log('复杂版', f1())// 6
// 对求和函数做curry化
let f2 = curry(add, 1, 2)
console.log('复杂版', f2(3))// 6
// 对求和函数做curry化
let f3 = curry(add)
console.log('复杂版', f3(1, 2, 3))// 6
// 复杂版curry函数可以多次调用,如下:
console.log('复杂版', f3(1)(2)(3))// 6
console.log('复杂版', f3(1, 2)(3))// 6
console.log('复杂版', f3(1)(2, 3))// 6
// 复杂版(每次可传入不定数量的参数,当所传参数总数不少于函数的形参总数时,才会执行)
function curry(fn) {
// 闭包
// 缓存除函数fn之外的所有参数
let args = Array.prototype.slice.call(arguments, 1)
return function () {
// 连接已缓存的老的参数和新传入的参数(即把每次传入的参数全部先保存下来,但是并不执行)
let newArgs = args.concat(Array.from(arguments))
if (newArgs.length < fn.length) {// 累积的参数总数少于fn形参总数
// 递归传入fn和已累积的参数,这里的call只是为了方便传参数,可以不用
return curry.call(null, fn, ...newArgs)
} else {
// 调用,这里的apply只是为了方便传参数,可以不用
return fn.apply(null, newArgs)
}
}
}
}
参数解构版本:
function curry(fn, ...args) {
return function(...newArgs) {
let allArgs = args.concat(newArgs)
if(allArgs.length
前端开发者进阶之函数柯里化Currying
JavaScript专题之函数柯里化
// 全局变量
a = 1
// 求和
let add = function (b, c) {
return this.a + b + c
}
{
/* 作为普通函数直接调用 */
// 此时this指向window,window.a是1
console.log(add(2, 3))// 6
}
{
/* 简单版bind实现,不具备curry化效果(不支持在传入对象的同时传入其他参数) */
Function.prototype.bind = function (obj) {
// 缓存Function构造函数的this(表达式函数声明时相当于new Function...)
const self = this
// 闭包
return function () {
// 调用
return self.apply(obj, arguments)
}
}
let f1 = add.bind({ a: 0 })
console.log(f1(2, 3))// 5
// 但是简单版bind实现不支持对象和其他参数同时传入,如下:
let f2 = add.bind({ a: 0 }, 2, 3)
// 因为上一行代码传入的2、3并没有接收到,所以求和后返回NaN
console.log(f2())// NaN
}
{
/* 复杂版bind实现,具备部分curry化效果(之所以说部分,是因为它支持在传入对象的同时可以其他参数,但是不支持多次调用) */
Function.prototype.bind = function (obj) {
// 缓存Function构造函数的this(表达式函数声明时相当于new Function...)
const self = this
// 缓存除函数fn之外的所有参数
let args = Array.prototype.slice.call(arguments, 1)
// 闭包
return function () {
// 连接已缓存的老的参数和新传入的参数(即把每次传入的参数全部先保存下来,但是并不执行)
let newArgs = args.concat(Array.from(arguments))
// 调用
return self.apply(obj, newArgs)
}
}
let f1 = add.bind({ a: 0 })
console.log(f1(2, 3))// 5
// 复杂版bind实现支持对象和其他参数同时传入,如下:
let f2 = add.bind({ a: 0 }, 2, 3)
console.log(f2())// 5
// 但是复杂版bind实现多次调用会报错,如下:
let f3 = add.bind({ a: 0 })
// console.log(f3(2)(3))// Uncaught TypeError: f3(...) is not a function
}
JS bind() 方法之人和狗的故事
JS中的bind的实现以及使用
大家看以下代码,是不是思路都是想通的,详细的大家就自行拓展吧
// 在之前执行
Function.prototype.before = function (fn) {
let self = this
return function () {
fn.apply(this, arguments)
return self.apply(this, arguments)
}
}
// 在之后执行
Function.prototype.after = function (fn) {
let self = this
return function () {
let res = self.apply(this, arguments)
fn.apply(this, arguments)
return res
}
}
function foo(params) {
console.log(params, 1)
return 22
}
// 钩子可以共享参数和返回值
console.log(foo.before((params) => {
console.log(params, 2)
}).after((params) => {
console.log(params, 3)
})({ a: 1 }))