Giter VIP home page Giter VIP logo

Comments (140)

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024 294

segmentfault 的@大笑平 补充的高颜值写法:

var curry = fn =>
    judge = (...args) =>
        args.length === fn.length
            ? fn(...args)
            : (arg) => judge(...args, arg)

from blog.

FrontToEnd avatar FrontToEnd commented on May 2, 2024 139

好难理解啊☹️

from blog.

hlmjack avatar hlmjack commented on May 2, 2024 136

深受启发,这样理解柯里化 :用闭包把参数保存起来,当参数的数量足够执行函数了,就开始执行函数,有没有毛病

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024 16

@fi3ework 之所以写成 this 是因为希望根据环境的不同而设置不同的 this 值,我写了一个示例:

function curry(fn, args) {
    var length = fn.length;

    args = args || [];

    return function() {

        var _args = args.slice(0),

            arg, i;

        for (i = 0; i < arguments.length; i++) {

            arg = arguments[i];

            _args.push(arg);

        }
        if (_args.length < length) {
            return curry.call(this, fn, _args);
        }
        else {
            return fn.apply(this, _args);
        }
    }
}


var fn = curry(function(a, b, c) {
    console.log(this)
});

var obj = {
    value: 1,
    fn: fn
}

obj.fn(1, 2, 3);

这个时候的 this 的值为 obj 对象,如果设置成 null ,就会变成打印 window 对象

from blog.

xiaobinwu avatar xiaobinwu commented on May 2, 2024 15

终于理解这句话了,“用闭包把参数保存起来,当参数的数量足够执行函数了,就开始执行函数”

from blog.

iiicon avatar iiicon commented on May 2, 2024 14

我现在才知道 function 的 length 竟然就是参数的长度,太水了 😄

很喜欢你的第二版,逻辑很清晰,很赞

from blog.

EmiyaYang avatar EmiyaYang commented on May 2, 2024 10

经历了这么多次面试这种定长 curry 问题我好像一次都没遇到过. 反倒是不定长 curry 的考察频频出现:

如实现这样一个 add: (头条一面, 腾讯一面考了同一题)

add(1); // 1
add(1)(2); // 3
add(1)(2)(3); // 5

这样的题目其实是有问题的, 因为确实没有办法预先获取这个调用链的长度. 面试官应该传达一点, 其实给的注释并不代表 return 值...

因此, 相应的实现有:

const add = sum => {
    const fn = n => add(n + sum);

    fn.valueOf = () => sum;

    return fn;
}

/** Test **/
add(1); // Function
+add(1); // 1
+add(1)(2); // 3
+add(1)(2)(3); // 5

按照犀牛书的定义, 这个可能不属于 curry , 就只是纯粹的链式调用罢了. 尽管有些混淆, 还是跟大家分享一下.

from blog.

yangchongduo avatar yangchongduo commented on May 2, 2024 9

没有说道 什么场景下使用 柯里化

from blog.

dreamerhammer avatar dreamerhammer commented on May 2, 2024 7

segmentfault 的@大笑平 补充的高颜值写法:

var curry = fn =>
   judge = (...args) =>
       args.length === fn.length
           ? fn(...args)
           : (arg) => judge(...args, arg)

参数不满足长度要求时,返回的函数仍需使用rest parameter:(...arg) => judge(...args, ...arg),否则除了第一次可以传递多个参数,后面只能一个一个传到足够为止了,不能直接处理fn(1,2)(3,4,5)的情况。

from blog.

xiaoyanhao avatar xiaoyanhao commented on May 2, 2024 6

函数的length属性获取形参的个数,但是形参的数量不包括剩余参数个数,仅包括第一个具有默认值之前的参数个数。

((a, b, c = 3) => {}).length; // 2
((a, b = 2, c) => {}).length; // 1
((a = 1, b, c) => {}).length; // 0
((...args) => {}).length; // 0

如果使用了ES6的函数参数默认值,可能不适用柯里化的场景。

const fn = curry((a = 1, b, c) => {
  console.log([a, b, c]);
});
fn()(2)(3); // Uncaught TypeError: fn(...) is not a function

在这种情况下,期望输出的是[1, 2, 3],而实际上fn()已经输出了[1, undefined, undefined],而不是返回闭包函数。所以fn()(2)将会报错。

from blog.

BugHshine avatar BugHshine commented on May 2, 2024 5

柯里化 是真的绕啊

from blog.

heyunjiang avatar heyunjiang commented on May 2, 2024 3

高颜值写法的 judge = (...args) 用的好巧妙

from blog.

olvvlo avatar olvvlo commented on May 2, 2024 3
var curry = (fn, ...args) =>
        fn.length <= args.length
            ? fn(...args)
            : curry.bind(null, fn, ...args)
var fn = curry(function(a, b, c){
  console.log([a,b,c])
})
fn(1,2,3)
fn(1,2)(3)
fn(1)(2,3)
fn(1)(2)(3)
[ 1, 2, 3 ]
[ 1, 2, 3 ]
[ 1, 2, 3 ]
[ 1, 2, 3 ]

参考_30s.js

from blog.

ChinaLiuRixing avatar ChinaLiuRixing commented on May 2, 2024 3

segmentfault 的@大笑平 补充的高颜值写法:

var curry = fn =>
    judge = (...args) =>
        args.length === fn.length
            ? fn(...args)
            : (arg) => judge(...args, arg)

这里依赖了fn.length
但是fn.length的取值逻辑可能是不与预期相符合的,会导致无效

const add = (a=1,b=1) => a + b;

console.log(add.length); // 预期是2,实际是0

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024 2

@iiicon 这算是个很细的知识啦,我也是很晚才知道的~

from blog.

NihilityT avatar NihilityT commented on May 2, 2024 2
function curry(length, fn) {
	if (typeof length === 'function')
		return curry.apply(this, Array.prototype.concat.apply([length.length], arguments));

	var _args = arguments;
	return function () {
		var args = Array.prototype.slice.call(_args);
		var i, next = 0, placeholderp = false;

		while (++next < args.length && args[next] != curry._);
		for (i = 0; i < arguments.length; i++) {
			args[next] = arguments[i];
			placeholderp |= args[next] === curry._;
			while (++next < args.length && args[next] != curry._);
		}

		if (placeholderp || next < 2 + length || next < args.length)
			return curry.apply(this, args);
		else
			return fn.apply(this, args.slice(2));
	};
}
curry._ = {};




var _ = curry._;

var fn = curry(function (a, b, c, d, e) {
	console.log([a, b, c, d, e]);
}, _, _, 3, 4, _);

fn(1, 2)(5);
fn(1, _)(2, _)(5);
// [1, 2, 3, 4, 5]

var arity3 = curry(3, function () {
	console.log(arguments);
});
var arity2 = arity3(1);
var arity1 = arity3(1, 5) || arity2(5);
arity2(1, 2);
// [1, 1, 2];
arity1(2);
// [1, 5, 2]

var square = curry(Math.pow)(_, 2);
square(3);
// 9

var cubic = curry(Math.pow, _, 3);
cubic(2);
// 8

from blog.

ab164287643 avatar ab164287643 commented on May 2, 2024 2
//函数柯理化  其本质是降低通用性,提高适用性,其实是对闭包的极致应用
//原理:利用闭包保存一部分参数,返回一个包含了一部分参数的闭包。
//适用场景: ...

function connect(a, b, c, d,e,f,g) {
    console.log(`${a}-${b}-${c}-${d}-${e}-${f}-${g}`);
}

//在闭包中,A闭包 由 B函数生成
//使用闭包可以引用函数的变量对象这一性质
//把闭包中存的变量和闭包接受的实参组合起来,传入目标函数
//简易版
function simpleCurry(fn){
    let args = [].slice.call(arguments, 1);
    return function () {
        fn.apply(this, args.concat([].slice.call(arguments)))
    }
}

//只可以分成两步,如果要可以分成任意层,就得用递归了
// simpleCurry(connect, 1, 2,5,67,8,4)(3);
// simpleCurry(connect, 1)(2, 3,4,5,6, 28);

//完整版,接受N层闭包,由于层数不定,递归也必须用到
//递归的过程中不断的 聚集参数,直到参数达到目标函数需要的个数,就执行函数
//如何知道函数接受的理想参数个数  fn.length
function curry(fn, args){
    let length = fn.length; //目标函数理想的参数个数
    let allArgs = args || [];
    return function () {
        let _args = [].slice.apply(arguments);
        let _allArgs = allArgs.concat(_args)
        //未达到理想参数个数就继续聚集参数, 达到了参数的个数,就可以运行目标函数
        if (_allArgs.length < length){
            //聚集参数的过程
            return curry.call(this, fn, _allArgs)
        }
        else{
            fn.apply(this, _allArgs);
        }
    }
}

curry(connect)(2, 3, 4, 5)(6, 1)(2);

//如果不想按顺序传入,则可以先用占位符,后面再填入数据
//比如
/**
 * 
let fn = curry(function(a, b, c) {
    console.log([a, b, c]);
});

fn("a", _, "c")("b") // ["a", "b", "c"]
 * 
 * 
 */
let _;
function curry2(fn, args){
    let allArgs = args || [];
    let length = fn.length;
    return function () {
        let _args = [].slice.call(arguments);
        let _allArgs = [].slice.call(allArgs);
        //在这里来调整参数的位置, 如果前面有占位符就向前补位

        if (_args.indexOf(_) !== -1){
            //有占位符  就直接concat
            _allArgs = _allArgs.concat(_args);
        }
        else{
                //没有占位符,说明这段参数可以向前补位
            _allArgs.forEach((v, i) => {
                if (v === _ && _args.length != 0) {
                    _allArgs.splice(i, 1, _args.shift());
                }
            })
            //剩下的还是添加进参数里面
            if (_args.length != 0){
                _allArgs = _allArgs.concat(_args);
            }
        }
            //是否达到理想参数个数  以及是否还含有空位
        if (_allArgs.length < length || _allArgs.indexOf(_) !== -1){
            //继续聚集参数
            return curry2.call(this, fn, _allArgs);
        }
        else{
            fn.apply(this, _allArgs);
        }
    }
}

curry2(connect)(2, _, 4, 5)(_, 1)(_)("占位1", "占位2")("占位3");

from blog.

yangtao2o avatar yangtao2o commented on May 2, 2024 2

segmentfault 的@大笑平 补充的高颜值写法:

var curry = fn =>
    judge = (...args) =>
        args.length === fn.length
            ? fn(...args)
            : (arg) => judge(...args, arg)

果然高颜值,这里稍稍有些手误:

console.log(fn(1)(2, 3));   // arg => judge(...args, arg)

改下就好了:

var curry = fn =>
  (judge = (...args) =>
    args.length === fn.length 
    ? fn(...args) 
    : (...arg) => judge(...args, ...arg));

from blog.

HypnosNova avatar HypnosNova commented on May 2, 2024 2

segmentfault 的@大笑平 补充的高颜值写法:

var curry = fn =>
    judge = (...args) =>
        args.length === fn.length
            ? fn(...args)
            : (arg) => judge(...args, arg)

这有个问题.
例如:

const add = (x, y, z) => x + y + z;
const test = curry(add);
test(1)(2, 3)
// 返回的是函数不是6。因为判断只积累了两个参数。

应该改成这样吧:

const curry = (fn) =>
    judge = (...args) =>
        fn.length === args.length
            ? fn(...args)
            : (...nextArgs) => judge(...args, ...nextArgs);

我觉得用函数的length属性去判断是不可取的。
比如const add = (x, y = 0, z = 0) => x+y+z;
就无法达到想要的效果。
又比如函数(...rest) => rest[0] + rest[1] + rest[2];
都无法用所说的实现方式去柯里化

from blog.

javaswing avatar javaswing commented on May 2, 2024 2

用ES6的写法,可以借助bind实现

function curry (fn, ...args) {
    return args.length >= fn.length ? fn(...args) : curry.bind(null, fn, ...args)
}

from blog.

jawil avatar jawil commented on May 2, 2024 2

搞个面试背诵版本

const curry = (fn, ...curryArgs) => (...args) =>
  args.length >= fn.length
    ? fn(...curryArgs, ...args)
    : curry(fn, ...curryArgs, ...args);

from blog.

lin2006yuo avatar lin2006yuo commented on May 2, 2024 2
let _curry = (fn) => {
  let len = fn.length
  function c(...args) {
    if(len === args.length) return fn(...args)
    else return c.bind(null, ...args)
  }
  return c
}

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024 1

@BugHshine 是这篇写得不好,日后修订时会重写

from blog.

Tan90Qian avatar Tan90Qian commented on May 2, 2024 1

@flymie sub_curry返回的这个函数,在参数不全(此处是调用次数不足)的情况是肯定不会触发,因为sub_curry永远都是返回一个新的函数,而不会去执行那个函数。来完整还原一下流程(去除了if条件):
首先是fn1

curry(fn0)
// 相当于
function(){
  // length = 4 
  return curry(sub_curry(fn0), --length)
}

然后是fn1()

(function() {
  return curry(sub_curry(fn0), --length);
})()
// 相当于
curry(function(){
  return fn0()
}, 3)
// 相当于
function() {
  // length = 3
  return curry(sub_curry(function(){
    return fn0();
  }), --length)
}

最后就是fn1()()了

(function() {
  return curry(sub_curry(function(){
    return fn0();
  }), --length)
})()
// 相当于
curry(function() {
  return (function(){
    return fn0();
  })()
}), 2)
// 相当于
function() {
  // length = 2
  return curry(sub_curry(function() {
    return (function(){
      return fn0();
    })()
  }), --length)
}

也就是说:只要你的调用次数没有到达规定限度,随着调用次数的增加,传给curry这个方法的函数层级会越来越深。直到调用次数够了,才会一口气将这个函数执行完,你想要的console.log(1)也才会触发

from blog.

zalatmza avatar zalatmza commented on May 2, 2024 1

版本二写成这样不知可不可行?

function add(a, b, c, d) {
  return a + b + c + d;
}

function curry(fn, length) {
  return function (...args) {
    if (args.length < length) {
      return curry(fn.bind(this, ...args), length - args.length )
    } else {
      return fn.apply(this, args)
    }
  }
}

var addCurry = curry(add, 4);
console.log(addCurry(1)(2, 3, 4))
console.log(addCurry(1, 2, 3, 4)) // 10

from blog.

inottn avatar inottn commented on May 2, 2024 1

@xiaohesong

rest 参数之后不能再有其他参数。

// 报错
function f(a, ...b, c) {
  // ...
}

// 正确
function f(a, b, ...c) {
  // ...
}

但调用函数时,... 是数组的扩展运算符 (spread) 。例如 fn(...[1, 2, 3, 4]) ,它用来把一个数组转换为用逗号分隔的参数序列。
扩展运算符与正常的函数参数可以结合使用,例如 fn(0, ...[1, 2, 3, 4], 5)

from blog.

SaebaRyoo avatar SaebaRyoo commented on May 2, 2024 1

curry化要求被传入函数所有参数都被明确的定义,因此当使用部分参数调用时,他会返回一个新的函数,在真正调用之前等待外部提供其余的参数。可以简单的理解为,在所有参数被提供之前,挂起或延迟函数的执行
--------------------------------以上是来自《javascript函数式编程指南》一书.
希望能帮助大家理解。

from blog.

theDrunkFish avatar theDrunkFish commented on May 2, 2024 1

占位符,那个地方,我看蒙住了T_T。
对于这个 fn(_, 2)(_, _, 4)(1)(3)(5)
想象中我以为等价为 fn(1, 2, 3, 5, 4)
可结果是 fn(1, 2, 3, 4, 5)
我是这样想的,先让占位符和非占位参数长度达到fn.length,之后再传进来的非占位参数依次替换掉之前的占位符。我这样想是不是错了,小白很慌,求救T_T
@mqyqingfeng

from blog.

zdyj3170101136 avatar zdyj3170101136 commented on May 2, 2024 1

柯里化还是会丢this,仍然不能把crry得到的函数等同一个不curry的函数,下个回答
我附了一个修改版,解决了这个毛病。
function curry(fn, args) {
var length = fn.length;

args = args || [];

return function() {

    var _args = args.slice(0),

        arg, i;

    for (i = 0; i < arguments.length; i++) {

        arg = arguments[i];

        _args.push(arg);

    }
    if (_args.length < length) {
        return curry.call(this, fn, _args);
    }
    else {
        return fn.apply(this, _args);
    }
}

}

var fn = curry(function(a, b, c) {
console.log(this.value)
});

var obj = {
value: 1,
fn: fn
}

obj.fn(1,2)(3);
undefined

from blog.

zjgyb avatar zjgyb commented on May 2, 2024 1

我试着写了一下,不知道对不对。

实现文中更易懂的实现方式

function curry(fn, args) {
  var length = fn.length;

  args = args || [];
  return function() {
    var _args = args.concat([].slice.call(arguments));
    if (_args.length < length) {
      return curry.call(this, fn, _args);
    }
    return fn.apply(this, _args);
  };
}

实现第三版

function curry(fn, args) {
  var length = fn.length;
  args = args || [];
  return function() {
    var newArgs = [].slice.call(arguments);
    for (var i = 0, len = args.length; i < len; i++) {
      if (args[i] === _) {
        args.splice(i, 1, newArgs.shift());
      }
      if (newArgs.length === 0) break;
    }
    var _args = args.concat(newArgs);
    var _filterArr = _args.filter(ele => ele !== _);
    if (_filterArr.length < length) {
      return curry.call(this, fn, _args);
    }
    return fn.apply(this, _args);
  };
}

from blog.

GeekaholicLin avatar GeekaholicLin commented on May 2, 2024 1
var curry = fn =>
    judge = (...args) =>
        args.length === fn.length
            ? fn(...args)
            : (arg) => judge(...args, arg)

这种写法有一些问题吧?this的绑定问题以及judge变量的污染。

// example
var judge = 'judge'
var name = 'window'
var obj = {
  name: 'obj',
  say: function(a, b, c, d){ return `${this.name}'s params: ${[a, b, c, d].join(',')}` }
}
console.log(typeof judge) // => "string"
var curriedSay = curry.call(obj, obj.say) // 无法修改`this`的指向
console.log(curriedSay('a', 'b')('c')('d')) // => "window's params: a,b,c,d"
console.log(typeof judge) // => "function"

from blog.

laoyangyu avatar laoyangyu commented on May 2, 2024 1

有点无法理解第二版里面为啥要传一个length,还有就是fn.length 代表什么

length || fn.length 前面传length是记录当前已经收到几个参数了(如果收够了就执行),后面 fn.length是第一层处理时记录下被柯里化的函数的参数总个数

from blog.

github307896154 avatar github307896154 commented on May 2, 2024 1
let _={};
function curry(fn, args) {
  var length = fn.length;

  args = args || [];

  return function() {

      var _args = args.slice(0),arg, i;
      _args.forEach((item,index,arr) =>{
        if(item==_&&arguments.length>0){
          arr[index]=[].shift.call(arguments)
        }
      });
      for (i = 0; i < arguments.length; i++) {
          arg = arguments[i];
          _args.push(arg);
      }
      if (_args.length < length||_args.includes(_)) {
          return curry.call(this, fn, _args);
      }
      else {
          return fn.apply(this, _args);
      }
  }
}
var fn = curry(function(a, b, c, d, e) {
  console.log([a, b, c, d, e]);
})
``` ```
这个最终版感觉比较简洁 @mqyqingfeng 

from blog.

KeithChou avatar KeithChou commented on May 2, 2024 1

经历了这么多次面试这种定长 curry 问题我好像一次都没遇到过. 反倒是不定长 curry 的考察频频出现:

如实现这样一个 add: (头条一面, 腾讯一面考了同一题)

add(1); // 1
add(1)(2); // 3
add(1)(2)(3); // 5

这样的题目其实是有问题的, 因为确实没有办法预先获取这个调用链的长度. 面试官应该传达一点, 其实给的注释并不代表 return 值...

因此, 相应的实现有:

const add = sum => {
    const fn = n => add(n + sum);

    fn.valueOf = () => sum;

    return fn;
}

/** Test **/
add(1); // Function
+add(1); // 1
+add(1)(2); // 3
+add(1)(2)(3); // 5

按照犀牛书的定义, 这个可能不属于 curry , 就只是纯粹的链式调用罢了. 尽管有些混淆, 还是跟大家分享一下.

这里不定参数的实现好赞呀.. 但是这里调用的时候只能传入单个参数,针对这种add(1)(2, 3)(4, 5, 6)就没有办法啦。按照楼上的方法,实现了个多参数的add版本

const add = (...param: number[]): Function => {
    const addSum = param.reduce((prev, next) => prev + next)
    const fn = (...args: number[]) => {
        const sum = args.reduce((prev, next) => prev + next)
        return add(addSum + sum)
    }
    fn.valueOf = () => addSum
    return fn
}

console.log(+add(1)(1, 1, 1)(1)) // 5
console.log(+add(1)(2)(3, 4)) // 10

from blog.

zxl-lxz avatar zxl-lxz commented on May 2, 2024 1

segmentfault 的@大笑平 补充的高颜值写法:

var curry = fn =>
    judge = (...args) =>
        args.length === fn.length
            ? fn(...args)
            : (arg) => judge(...args, arg)

这有个问题.
例如:

const add = (x, y, z) => x + y + z;
const test = curry(add);
test(1)(2, 3)
// 返回的是函数不是6。因为判断只积累了两个参数。

应该改成这样吧:

const curry = (fn) =>
    judge = (...args) =>
        fn.length === args.length
            ? fn(...args)
            : (...nextArgs) => judge(...args, ...nextArgs);

我觉得用函数的length属性去判断是不可取的。
比如const add = (x, y = 0, z = 0) => x+y+z;
就无法达到想要的效果。
又比如函数(...rest) => rest[0] + rest[1] + rest[2];
都无法用所说的实现方式去柯里化

确实有很多限制

from blog.

liuxinqiong avatar liuxinqiong commented on May 2, 2024

日常学习

from blog.

jawil avatar jawil commented on May 2, 2024

专题系列专不知不觉更新了这么多,我得好好抽个时间系统学习一下😂

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@jawil 哈哈~ 还有五篇就要完结了,可以等完结后一起看~

from blog.

yangchongduo avatar yangchongduo commented on May 2, 2024
var name = person.map(function (item) {
    return item.name;
})
const fn = function (item) {
    return item.name;
}
person.map(fn)

PS:这样也可以参数复用

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@yangchongduo 柯里化的应用更多在函数式编程中,可以看 JS 函数式编程指南,在 《JavaScript专题之函数组合》这篇文章中也有涉及部分。

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@yangchongduo 这样确实可以做到参数复用,其实跟

var name = person.map(prop('name'))

是一样的,不过如果我们要获得其他属性呢?比如 'age'、'friends' 等,如果使用 fn 的话,还需要写多个 fn,而如果使用 prop 函数,就可以直接使用 prop('age') prop('friend')

from blog.

yangchongduo avatar yangchongduo commented on May 2, 2024

function curry1(fn, args) {
var length = fn.length;
args = args || [];
return function (...arguments) {
args = [...args, ...arguments]
return args.length < length ? curry1.call(this, fn, args) : fn.apply(this, args);
}
}

from blog.

LiuYashion avatar LiuYashion commented on May 2, 2024

值得一看~

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@hlmjack 正是如此~ o( ̄▽ ̄)d

from blog.

fi3ework avatar fi3ework commented on May 2, 2024

在更易懂的写法里return curry.call(this, fn, _args);,为什么要用this呢,感觉用null是不是也可以呢

from blog.

bepromising avatar bepromising commented on May 2, 2024

我有个问题想请教下。
function (a, b, c){} 的参数有三个,fn('a', 'b', 'c', 'd') 正常工作,但 fn('a', 'b', 'c', 'd')('a') 就出错了。我知道这是因为 function (a, b, c){} 的参数个数,而导致的错误。
如果我想 fn('a', 'b',...n个参数)('a') 这样该如何写一个curry函数呢。

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@bepromising fn('a', 'b', 'c', 'd')('a') 是因为 fn('a', 'b', 'c', 'd') 就已经执行了该函数,该函数如果没有再返回一个函数,就肯定报错,说这并不是一个函数。

至于 fn('a', 'b',...n个参数)('a'),我不清楚为什么还要再传个 'a' 呢?

from blog.

izuomeng avatar izuomeng commented on May 2, 2024

第三版的代码是不是有bug呢,我试了一个稍微长一点的例子:

var _ = {}
var ary = curry(function(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z) {
  return [a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z]
})
console.log(ary(1,_,_)(_)(5,6,7,8,9,10)(11,12,13,14)(15,_,_,18,_)(20,21,22,_)(24,25,26)(2,3,4)(16)(17,19)(23))

结果输出是不对的,node下:

[Function]

chrome下:

ƒ () { 
              var _args = args.slice(0),
                  _holes = holes.slice(0),
                  argsLen = args.length,
                  holesLen = holes.length,
                  a…

顺便我自己用es6写了一个稍微简洁一点的,对应原文第三版,可能参数多的情况下性能会有问题,但感觉一般情况下更好理解一些

// hole为自己的指定占位符
function curry(fn, hole) {
  const __len = fn.length
  let args = [],
  return function h() {
    // 先把参数放入args数组
    args = [...args, ...Array.from(arguments)]
    // 如果长度超过原有函数参数列表长度,表示有占位
    let holeNum = args.length - __len
    // 第一个占位符对应的肯定是__len位置的变量,循环将所有占位符替换
    for (let i = 0; i < holeNum; i++) {
      args[args.indexOf(hole)] = args[__len]
      args.splice(__len, 1)
    }
    // 如果没有占位符且参数数目已经够了
    if (args.length < __len || args.indexOf(hole) > -1) {
      return h
    } else {
      return fn.apply(null, args)
    }
  }
}

经测试上面的例子可以输出正确的结果

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@izuomeng 这个是最终的版本吗?我这边有报错

<!DOCTYPE html>
<html>

<head>
    <title></title>
</head>

<body>
    <script>
    // hole为自己的指定占位符
    function curry(fn, hole) {
        const __len = fn.length
        let args = [];
        return function h() {
            // 先把参数放入args数组
            args = [...args, ...Array.from(arguments)]
            // 如果长度超过原有函数参数列表长度,表示有占位
            let holeNum = args.length - __len
            // 第一个占位符对应的肯定是__len位置的变量,循环将所有占位符替换
            for (let i = 0; i < holeNum; i++) {
                args[args.indexOf(hole)] = args[__len]
                args.splice(__len, 1)
            }
            // 如果没有占位符且参数数目已经够了
            if (args.length < __len || args.indexOf(hole) > -1) {
                return h
            } else {
                return fn.apply(null, args)
            }
        }
    }

    var _ = {};

    var fn = curry(function(a, b, c, d, e) {
        console.log([a, b, c, d, e]);
    });

    fn(1, 2, 3, 4, 5);
    fn(_, 2, 3, 4, 5)(1);
    fn(1, _, 3, 4, 5)(2);
    fn(1, _, 3)(_, 4)(2)(5);
    fn(1, _, _, 4)(_, 3)(2)(5);
    fn(_, 2)(_, _, 4)(1)(3)(5)
    </script>
</body>

</html>

default

from blog.

izuomeng avatar izuomeng commented on May 2, 2024

少了一行,抱歉😄

// hole为传入的占位符
function curry(fn, hole) {
  const __len = fn.length
  let args = [];
  return function h() {
      // 先把参数放入args数组
      args = [...args, ...Array.from(arguments)]
      // 如果长度超过原有函数参数列表长度,表示有占位
      let holeNum = args.length - __len
      // 第一个占位符对应的肯定是__len位置的变量,循环将所有占位符替换
      for (let i = 0; i < holeNum; i++) {
          args[args.indexOf(hole)] = args[__len]
          args.splice(__len, 1)
      }
      // 如果没有占位符且参数数目已经够了
      if (args.length < __len || args.indexOf(hole) > -1) {
          return h
      } else {
          fn.apply(null, args)
          return args = []
      }
  }
}

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@izuomeng 这个占位的 curry 比你想的要复杂一点…… 因为对于 fn(1, _, 3)(_, 4)(2)(5); 这样的例子,结果应该是 [1, 2, 3, 4, 5],如果使用这种方法的话,结果会是 [1, 2, 3, 5, 4]

from blog.

izuomeng avatar izuomeng commented on May 2, 2024

哦哦,看了几组执行结果才发现这个占位是边执行边填补的,我把他理解成从超出参数列表列表长度之后才开始填补的了,谢谢指教🙏

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@izuomeng 但是你说的问题还是存在的,而且现在的写法也很繁琐,我也在想更加简洁易懂的写法~

from blog.

Pa-wN avatar Pa-wN commented on May 2, 2024

请教下博住,第三版的填占位符是怎样一个规律。。。。

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@Wiolem 好方法,感谢补充~ ☆´∀`☆

from blog.

flymie avatar flymie commented on May 2, 2024

对于博主第二版的极简版的解释有点不太理解。
当执行 fn1()() 时,函数返回:

curry(sub_curry(function(){
   return fn0()
}))
// 相当于
curry(function(){
  return (function(){
    return fn0()
  })()
 })

那么

(function(){
   return fn0()
})()

这个函数立即执行了,那么fn0函数也就执行了。此时工作台就因该有‘1’出现了啊。


下面是我对于博主第二版的极简版的理解:如有错误还请指出。

var fn = curry(fn0)

当执行 fn() 时,函数返回:

curry(sub_curry(fn0))
// 相当于
curry(function(){
    return fn0();
})

此时我只需要把

(function(){
    return fn0();
}

看做传入函数(起个名字为fn1吧)

curry(fn1);
//对比curry(fn0),似是故人来。

当执行 fn()() 时,函数返回:

curry(sub_curry(fn1))
// 相当于
curry(function(){
    return fn1();
})

同样可以看做传入函数(起个名字为fn2)。

curry(fn2);

当执行 fn()()() 时,同样

curry(function(){
    return fn2();
})

同样可以看做传入函数(起个名字为fn3)。

curry(fn3);

当执行 fn()()()() 时,此时已不满足判断条件 if (length > 1) ,于是

return fn();

此时的传入的参数fn为fn3,

fn3()  就是 :
(function(){
    return fn2();
})();

fn2 =function(){
    return fn1();
};

fn1 =function(){
    return fn0();
};
此时工作台才会出现‘1’

from blog.

mqyqingfeng avatar mqyqingfeng commented on May 2, 2024

@flymie 不会执行呀

curry(sub_curry(function(){
   return fn0()
}))
// 相当于
curry(function(){
  return (function(){
    return fn0()
  })()
 })
// 相当于
curry(function(){
    return fn0()
})

这时候不会执行呀~

from blog.

flymie avatar flymie commented on May 2, 2024

@mqyqingfeng
可能是我的描述有问题。
感觉sub_curry(fn)应该加了一条输出比较好。

function sub_curry(fn){
    return function(){
        console.log(1);  //加了这条输出语句
        return fn()
    }
}

那么执行 fn1()()时候,

curry(sub_curry(function(){
   console.log(1);
   return fn0()
}))
// 相当于
curry(function(){
  return (function(){
    console.log(1);
    return fn0()
  })()
 })
// 相当于
curry(function(){
    return fnx();   //应该是相当于fnx吧。原句的这里是fn0,感觉就像函数执行过一样。
})

from blog.

hugeface avatar hugeface commented on May 2, 2024

好文,可惜现在内力不足,还不是很能消化

from blog.

wuyunjiang avatar wuyunjiang commented on May 2, 2024

我现在才知道 function 的 length 竟然就是参数的长度,太水了

很喜欢你的第二版,逻辑很清晰,很赞

其实表示的是未设置默认值的参数数量
比如

function test (arg1, arg2, arg3 = 3 ){
}

这里test.length=2

from blog.

SunLn avatar SunLn commented on May 2, 2024

segmentfault 的@大笑平 补充的高颜值写法:

var curry = fn =>
    judge = (...args) =>
        args.length === fn.length
            ? fn(...args)
            : (arg) => judge(...args, arg)

最后 (arg) => judge(...args, arg) , 修改为 (...arg) => judge(...args, ...arg) ,才进一步完善。

不然 fn("a")("b", "c")('d') 这种情况就会只接收了 a, b, d 三个参数而出现问题

from blog.

xiaohesong avatar xiaohesong commented on May 2, 2024

rest可以这样用麽,记忆中是must be last

from blog.

xiaohesong avatar xiaohesong commented on May 2, 2024

@inottn 嗯是的,看错了。

from blog.

shuzewu avatar shuzewu commented on May 2, 2024

我认为@大笑平老师的写法是非常赞的。
我在这里针对这个方法做了一个小的优化,
用于解决:curry4(1, 2)(3, 4)

const curry = fn =>
   judge = (...args) => 
      args.length === fn.length
         ? fn(...args)
         : (...arg) => judge(...args, ...arg)

from blog.

lockontan avatar lockontan commented on May 2, 2024

柯里化的同时可以传入参数
const currying = (fn, ...arg1) => (...arg2) => [...arg1, ...arg2].length >= fn.length ? fn.apply(null, [...arg1, ...arg2]) : currying(fn, ...arg1, ...arg2)

from blog.

CoolRice avatar CoolRice commented on May 2, 2024

我认为@大笑平老师的写法是非常赞的。
我在这里针对这个方法做了一个小的优化,
用于解决:curry4(1, 2)(3, 4)

const curry = fn =>
   judge = (...args) => 
      args.length === fn.length
         ? fn(...args)
         : (...arg) => judge(...args, ...arg)

这么写就不是柯里化了,柯里化一次传一个参数

from blog.

TanMichael avatar TanMichael commented on May 2, 2024

segmentfault 的@大笑平 补充的高颜值写法:

var curry = fn =>
    judge = (...args) =>
        args.length === fn.length
            ? fn(...args)
            : (arg) => judge(...args, arg)

实践了一下,这里最后一行的参数只能在接受单个。应该写成:

let curry = fn =>
  judge = (...args) =>
    args.length === fn.length
      ? fn(...args)
      : (...argMore) => judge(...args, ...argMore);

这样测试fn('a')('b','c')时才能跟之前一样

from blog.

1degrees avatar 1degrees commented on May 2, 2024

大大佬 你好,第三版的科里化,有个缺陷, 这种执行 fn(1, _, _, 4)(2, 3, 5) 就不能返回结果

from blog.

ab164287643 avatar ab164287643 commented on May 2, 2024

最后一种参数不定的,自己用自己的想法写了一种。本文作者讲得比较难理解的那种,看了半天,真的难以理解。

from blog.

autumnfield avatar autumnfield commented on May 2, 2024

大大佬 你好,第三版的科里化,有个缺陷, 这种执行 fn(1, _, _, 4)(2, 3, 5) 就不能返回结果

第三版存在的问题是无法同时传不连续的两个参,如:fn(1, _, , 4)(, 3)(2, 5)
问题是出在else if (holesLen) 这里, fn执行到(2,5)这一步时,_holes是 [1],当arguments循环到5时,仍然替换2时候的位置。只要添加个holesLen-- 就可以了。
else {
holesLen--
_args.splice(_holes[index], 1, arg);
_holes.splice(index, 1)
}

from blog.

yujun96 avatar yujun96 commented on May 2, 2024

大佬。 柯里化 return curry.call(this, fn, newArgs) 这个this本来就是指向的window, 为什么不直接 return curry(fn, newArgs)。

from blog.

struggle-fish avatar struggle-fish commented on May 2, 2024

看了好几遍,,一步步的console ,,终于懂了,,感谢大佬

from blog.

FrontCoder1 avatar FrontCoder1 commented on May 2, 2024

至此,我们已经实现了一个强大的 curry 函数,可是这个 curry 函数符合柯里化的定义吗?柯里化可是将一个多参数的函数转换成多个单参数的函数,但是现在我们不仅可以传入一个参数,还可以一次传入两个参数,甚至更多参数……这看起来更像一个柯里化 (curry) 和偏函数 (partial application) 的综合应用,可是什么又是偏函数呢?下篇文章会讲到。

那么符合函数柯里化的定义啊吗???

from blog.

sclchic avatar sclchic commented on May 2, 2024

试着写了个

function hasEmptyCurry (fn, hole = '_', ...args) {
        // 存储被柯里化函数的形参个数
        var beCurryFnLen = fn.length;
        return function (...curryArgs) {
          var j = 0,
          combinationArgs = [],
          holes = false;

          for (var i = 0, len = args.length; i < len; i++) {
            if (args[i] === hole) {
              if (curryArgs[j] === undefined || curryArgs[j] === hole) {
                ++j;
              } else {
                args[i] = curryArgs[j];
                curryArgs.splice(j, 1);
              }
            }
          }
          
          combinationArgs = args.concat(curryArgs);
          holes = combinationArgs.indexOf(hole) !== -1;
          
          if (holes || combinationArgs.length < beCurryFnLen) {
            // 如果实参个数小于形参个数,则继续柯里化
            return hasEmptyCurry.call(this, fn, hole, ...combinationArgs);
          } else {
            // 如果实参个数等于形参个数,则直接返回fn的执行结果
            return fn.apply(this, combinationArgs);
          }
        }
      }

from blog.

db46rt00ors avatar db46rt00ors commented on May 2, 2024

很久之前写过一个函数柯里化 无限层级 参数个数任意

var currying = function (fu) { 
    var _arg = [];
    return function cb() {
        if (arguments.length === 0) {

            return fu.apply(null, _arg)
        }
        Array.prototype.push.apply(_arg, [].slice.call(arguments))
        return cb
    }
}
var sum = function () {

    var total = 0;
    var argArray = Array.prototype.slice.call(arguments)
    argArray.forEach(function (item) {
        total += item
    });
    return total
}
var toUpperCase = function () {
    var total = []
    var argArray = Array.prototype.slice.call(arguments)
    argArray.forEach(function (item) {
        total.push(item.toUpperCase())
    });
    return total
}
var fun1 = currying(sum);
var fun2 = currying(toUpperCase);
fun1(1, 2, 3)(1, 2, 3)(1, 2, 3, 1, 2, 3)
fun2('a', 'a', 'a')('a', 'a', 'a')('a', 'a', 'a')('a', 'a', 'a')('a', 'a', 'a')('a', 'a', 'a')('a', 'a', 'a')('a', 'a', 'a')
console.log(fun1());
console.log(fun2());

from blog.

m2maomao avatar m2maomao commented on May 2, 2024

内力不够,看的真吃力...

from blog.

zdyj3170101136 avatar zdyj3170101136 commented on May 2, 2024

function curry(fn, args) {
var length = fn.length;
args = args || [];
var that = this;
return function() {

var _args = args.slice(0),

    arg, i;

if(that !== window)that_to = that;
else that_to = this;

for (i = 0; i < arguments.length; i++) {

    arg = arguments[i];

    _args.push(arg);

}
if (_args.length < length) {
    return curry.call(that_to, fn, _args);
}
else {
    return fn.apply(that_to, _args);
}

}
}
var fn = curry(function(a, b, c) {
console.log(this.value)
});
var obj = {
value: 1,
fn: fn
}
obj.fn(1,2)(3);
稍微改了一下,解决了丢this的毛病,不过这也只适用于非严格模式了

from blog.

Tankas avatar Tankas commented on May 2, 2024

简单点
`

function curry (func) {
  return function () {
    return arguments.length === func.length ? func(...arguments) : curry (func).bind(null, ...arguments)
  }
}

`

from blog.

RobinZhao00 avatar RobinZhao00 commented on May 2, 2024

const add = (...arg) => arg.reduce((prev, curr) => curr += prev, 0);
const currying = (fn, ...arg1) => (...arg2) => ((arg2.length === 0) ? fn(...arg1) : currying.call(null, fn, ...arg1, ...arg2))
const curryAdd = currying(add);
curryAdd(1, 2)(3)(4)();
curryAdd(1, 2)(3, 4)();
curryAdd(1)(2)(3)(4)();

from blog.

RobinZhao00 avatar RobinZhao00 commented on May 2, 2024

segmentfault 的@大笑平 补充的高颜值写法:

var curry = fn =>
    judge = (...args) =>
        args.length === fn.length
            ? fn(...args)
            : (arg) => judge(...args, arg)

from blog.

yzw7489757 avatar yzw7489757 commented on May 2, 2024

简单点
`

function curry (func) {
  return function () {
    return arguments.length === func.length ? func(...arguments) : curry (func).bind(null, ...arguments)
  }
}

`

参数有可能超过,不能等于

from blog.

Yanan123Zhao avatar Yanan123Zhao commented on May 2, 2024

好难啊 感觉自己得多看几遍了

from blog.

liuestc avatar liuestc commented on May 2, 2024

感觉像bind函数的实现

from blog.

Lirong6 avatar Lirong6 commented on May 2, 2024

有点无法理解第二版里面为啥要传一个length,还有就是fn.length 代表什么

from blog.

HomyeeKing avatar HomyeeKing commented on May 2, 2024

var combined = [fn].concat(slice.call(arguments));
这个slice是不是得写成[].slice,我这里报错

from blog.

bluewayne avatar bluewayne commented on May 2, 2024

第二版这样写是不是更简洁:

function curry(fn) {
    let totalArgLength = fn.length;
    let totalArguments = [];
    const slice = Array.prototype.slice;
    return function () {
        totalArguments = [].concat(totalArguments, slice.call(arguments, 0))
        let argLength = arguments.length;
        if (argLength < totalArgLength) {
            totalArgLength -= argLength;
            return arguments.callee
        } else {
            return fn.apply(null, totalArguments)
        }
    }
}

from blog.

Leopold1988 avatar Leopold1988 commented on May 2, 2024

bind就是柯里化的实现啊

function a(a, b){
    console.log(a, b);
}

var fn = a.bind(this, "a");
fn("b");

from blog.

iversonwool avatar iversonwool commented on May 2, 2024

var combined = [fn].concat(slice.call(arguments));
这个slice是不是得写成[].slice,我这里报错

你看漏了一行
var slice = Array.prototype.slice;
这个slice 其实是这个

from blog.

HypnosNova avatar HypnosNova commented on May 2, 2024

image
这个实现是有严重BUG的,举个例子:
const bugFn = (a, b, c = 1) => {};
柯里化这个函数就废了。此时bugFn的length是2,但是他是3个参数。所以不能够用这种方式柯里化有默认值的函数

from blog.

JiaJiaJiayi avatar JiaJiaJiayi commented on May 2, 2024

这么说, subcurry 和 高颜值版的 : (arg) => judge(...args, arg);有异曲同工之妙

from blog.

zxl-lxz avatar zxl-lxz commented on May 2, 2024

segmentfault 的@大笑平 补充的高颜值写法:

var curry = fn =>
    judge = (...args) =>
        args.length === fn.length
            ? fn(...args)
            : (arg) => judge(...args, arg)

这有个问题.
例如:

const add = (x, y, z) => x + y + z;
const test = curry(add);
test(1)(2, 3)
// 返回的是函数不是6。因为判断只积累了两个参数。

应该改成这样吧:

const curry = (fn) =>
    judge = (...args) =>
        fn.length === args.length
            ? fn(...args)
            : (...nextArgs) => judge(...args, ...nextArgs);

from blog.

zxl-lxz avatar zxl-lxz commented on May 2, 2024
var curry = fn =>
    judge = (...args) =>
        args.length === fn.length
            ? fn(...args)
            : (arg) => judge(...args, arg)

这种写法有一些问题吧?this的绑定问题以及judge变量的污染。

// example
var judge = 'judge'
var name = 'window'
var obj = {
  name: 'obj',
  say: function(a, b, c, d){ return `${this.name}'s params: ${[a, b, c, d].join(',')}` }
}
console.log(typeof judge) // => "string"
var curriedSay = curry.call(obj, obj.say) // 无法修改`this`的指向
console.log(curriedSay('a', 'b')('c')('d')) // => "window's params: a,b,c,d"
console.log(typeof judge) // => "function"

改成这样就行。至于你说的污染问题,不存在的。因为你开始你就要在父作用域去定义这个变量。

let judge;
const curry = function(fn) {return judge = (...args) => fn.length === args.length ? fn.call(this, ...args) : (...nextArg) => judge(...args, ...nextArg)};

from blog.

kongxiangyan avatar kongxiangyan commented on May 2, 2024

项目里自用的实现,几乎是纯函数式写的项目,所以不存在 this 的问题。

export const isObject = obj => Object.prototype.toString.call(obj) === '[object Object]'
export const hasOwnProperty = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key)

export const argPlaceholder = {
  // compatible with ramda.js
  '@@functional/placeholder': true,
  isArgPlaceholder: true
}
export const isArgPlaceholder = placeholder => isObject(placeholder) && hasOwnProperty(placeholder, 'isArgPlaceholder') && placeholder.isArgPlaceholder

export const simpleCurry = (fn, ...args) => args.length >= fn.length ? fn(...args) : (...args2) => curry(fn, ...args, ...args2)
export const internalCurry = (fn, filled, ...args) => {
  let innerArgs = filled || []
  innerArgs = innerArgs.map(innerArg => {
    return isArgPlaceholder(innerArg) ? (args.shift() || innerArg) : innerArg
  })
  innerArgs = innerArgs.concat(args)
  const innerLen = innerArgs.slice(0, fn.length).reduce((len, innerArg) => isArgPlaceholder(innerArg) ? len : len + 1, 0)
  if (innerLen >= fn.length) {
    return fn(...innerArgs)
  } else {
    return (...args2) => internalCurry(fn, innerArgs, ...args2)
  }
}
export const curry = (fn, ...args) => internalCurry(fn, [], ...args)

from blog.

OldDream avatar OldDream commented on May 2, 2024

献丑,来个不定长的,面试快乐版。。其实我感觉这。。不柯里,面试看到这种题,基本确定面试官不懂柯里化。

function add2() {
  let argsSum = Array.from(arguments).reduce((prev, next) => prev + next)
  let fn = function () {
    return add2(Array.from(arguments).reduce((prev, next) => prev + next) + argsSum)
  }
  fn.valueOf = () => argsSum
  return fn
}
console.log(+add2(1, 2)(1))

from blog.

anjina avatar anjina commented on May 2, 2024

搞个面试背诵版本

const curry = (fn, ...curryArgs) => (...args) =>
  args.length >= fn.length
    ? fn(...curryArgs, ...args)
    : curry(fn, ...curryArgs, ...args);

大佬, 这里 args.length >= fn.length 长度判断 应该还要加上 curryArgs.length 起始参数的长度把。

const curry = (fn, ...curryArgs) => (...args) =>
  (args.length + curryArgs.length) >= fn.length
    ? fn(...curryArgs, ...args)
    : curry(fn, ...curryArgs, ...args);

function add(a, b, c, d) {
  console.log(a + b + c + d);
}

const _curry = curry(add, 1, 2, 3);

_curry(4);

from blog.

cw84973570 avatar cw84973570 commented on May 2, 2024

第三版中好像有一个bug:

  • 如果占位符被消耗完了还继续添加参数的话只会添加到第一个位置而不会新增,原因是_args.splice(_holes[index], 1, arg);_holes[index]是undefined。测试函数:fn(1, _)(2, 3, 4, 5)

稍稍改动了下:

// 第三版
function curry(fn, args, holes) {
    length = fn.length;

    args = args || [];

    holes = holes || [];

    return function() {

        var _args = args.slice(0),
            _holes = holes.slice(0),
            argsLen = args.length,
            holesLen = holes.length,
            arg, i, index = 0;

        for (i = 0; i < arguments.length; i++) {
            arg = arguments[i];
            // 处理类似 fn(1, _, _, 4)(_, 3) 这种情况,index 需要指向 holes 正确的下标
            if (arg === _ && holesLen) {
                index++
                if (index > holesLen) {
                    _args.push(arg);
                    _holes.push(argsLen - 1 + index - holesLen)
                }
            }
            // 处理类似 fn(1)(_) 这种情况
            else if (arg === _) {
                _args.push(arg);
                _holes.push(argsLen + i);
            }
            // 处理类似 fn(_, 2)(1) 这种情况
            else if (holesLen) {
                // fn(_, 2)(_, 3)
                if (index >= holesLen) {
                    _args.push(arg);
                }
                // fn(_, 2)(1) 用参数 1 替换占位符
                else {
                   //  _args.splice(_holes[index], 1, arg);
                   //  _holes.splice(index, 1)
                  // 改动在这里
                  // 判断是否还存在占位符
                  if (_holes.length) {
                    _args.splice(_holes[index], 1, arg);
                    _holes.splice(index, 1)
                  } else {
                    _args.push(arg);
                  }
                }
            }
            else {
                _args.push(arg);
            }

        }
        if (_holes.length || _args.length < length) {
            return curry.call(this, fn, _args, _holes);
        }
        else {
            return fn.apply(this, _args);
        }
    }
}

var _ = {};

var fn = curry(function(a, b, c, d, e) {
    console.log([a, b, c, d, e]);
});

fn(1, _)(2, 3, 4, 5); // 改动前数组长度永远都是2

from blog.

cw84973570 avatar cw84973570 commented on May 2, 2024

占位符,那个地方,我看蒙住了T_T。
对于这个 fn(_, 2)(_, _, 4)(1)(3)(5)
想象中我以为等价为 fn(1, 2, 3, 5, 4)
可结果是 fn(1, 2, 3, 4, 5)
我是这样想的,先让占位符和非占位参数长度达到fn.length,之后再传进来的非占位参数依次替换掉之前的占位符。我这样想是不是错了,小白很慌,求救T_T
@mqyqingfeng

占位符是边传边填补的,也就是说fn(_, 2)(_, _, 4)(1)(3)(5)第二个函数里的占位符会填补第一个函数的占位符,我理解为占位符顺延。对于第二个函数的参数来说,第一个占位符表示填充第一个函数中的占位符,此时占位符填满了,第二个占位符会新增上去。然后参数1填充第一个占位符,参数3填充第二个占位符,此时占位符已经用完了,参数5添加到末尾。
数组分别是[_, 2][_, 2, _, 4][1, 2, _, 4][1, 2, 3, 4][1, 2, 3, 4, 5]

这里理解的关键是第二个占位符会顺延第一个占位符到下一个函数,而不是新增一个占位符。

from blog.

HomyeeKing avatar HomyeeKing commented on May 2, 2024

@lin2006yuo 06年的?

from blog.

EricWong1994 avatar EricWong1994 commented on May 2, 2024

当执行 fn1()() 时,函数为什么返回
curry(sub_curry(function(){ return fn0() }))
啊,不是很理解

from blog.

wustdong avatar wustdong commented on May 2, 2024

@EmiyaYang 这里打印的是 6 啊,为啥你写的是5?

from blog.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.