中的push_JavaScript 中的反柯里化

1fc9e13e38ef3c9ac9c4c61f574c9dee.png

点小蓝字加关注!

作为函数式编程语言,JS带来了很多语言上的有趣特性,比如柯里化和反柯里化。

可以对照另外一篇介绍 JS 柯里化 的文章一起看~

1. 简介

柯里化,是固定部分参数,返回一个接受剩余参数的函数,也称为部分计算函数,目的是为了缩小适用范围,创建一个针对性更强的函数。核心思想是把多参数传入的函数拆成单参数(或部分)函数,内部再返回调用下一个单参数(或部分)函数,依次处理剩余的参数。

反柯里化,从字面讲,意义和用法跟函数柯里化相比正好相反,扩大适用范围,创建一个应用范围更广的函数。使本来只有特定对象才适用的方法,扩展到更多的对象。

2. 实现

先来看看反柯里化的通用实现吧~

Function.prototype.unCurrying = function() {

const self = this

return function(...rest) {

return Function.prototype.call.apply(self, rest)

}

}

解释下:

  1. 为Function原型添加 uncurrying方法,并在执行的时候保存执行 unCurrying的方法到self

  2. 借用apply把要借用的函数作为this环境赋给call,并传入之后的形参作为参数执行

还有一个实现:

Function.prototype.unCurrying = function() {

return this.call.bind(this)

}

如果你觉得把函数放在Function.prototype上不太好,也可以这样:

function unCurrying(fn) {

return function(tar, ...argu) {

return fn.apply(tar, argu)

}

}

3. 使用

3.1 简单使用

unCurrying通用实现简单的实用一下试试:

Function.prototype.unCurrying = function() {

const self = this // 这里的self就是Array.prototype.push方法

return function(...rest) { // rest为传入的两层参数[[1,2,3],4]

return Function.prototype.call.apply(self, rest)

}

}

const push = Array.prototype.push.unCurrying()

~function(...rest) { // rest:[1,2,3]

push(rest, 4)

console.log(rest) // [1, 2, 3, 4]

}(1, 2, 3)

3.2 借用其他方法

反柯里化其实反映的是一种思想,即扩大方法的适用范围,仍然调用刚刚的通用 unCurrying方法借用push方法:

const push = Array.prototype.push.unCurrying()

const obj = { a: '嘻嘻' }

push(obj, '呵呵', '哈哈', '嘿嘿')

console.log(obj) // { '0': '呵呵', '1': '哈哈', '2': '嘿嘿', a: '嘻嘻', length: 3 }

相当于 obj.push(...),obj不仅多了类似于数组一样以数字作为索引的属性,还多了个类似于数组的length属性,让引擎自动管理数组成员和length属性;(文后有V8引擎实现push方法的源码) 这样一个数组的push方法就被借用出来,可以应用于任何其他对象了。

只要是方法, unCurrying就可以借用, call方法也可以:

var call = Function.prototype.call.unCurrying();

function $(id) {

return this.getElementById(id);

}

call($, document, 'demo') // #demo 元素

相当于 document.$('demo'),成功的借用了call方法,当然可以把document改成你希望作为this绑定到$的任何对象,比如 {getElementById:T=>console.log(T+'呃')}// demo呃

3.3 借用自己

unCurrying本身也是方法,也可以借用自己...-。-

const unCurrying = Function.prototype.unCurrying.unCurrying()

const map = unCurrying(Array.prototype.map)

map({ 0: 4, 1: 'a', 2: null, length: 3 }, n => n + n) // [8, "aa", 0]

神奇吧~

4. 总结

简单说,函数柯里化就是对高阶函数的降阶处理,缩小适用范围,创建一个针对性更强的函数。举栗子:

function(arg1,arg2) // => function(arg1)(arg2)

function(arg1,arg2,arg3) // => function(arg1)(arg2)(arg3)

function(arg1,arg2,arg3,arg4) // => function(arg1)(arg2)(arg3)(arg4)

function(arg1,arg2,…,argn) // => function(arg1)(arg2)…(argn)

而反柯里化就是反过来,增加适用范围,让方法使用场景更大。使用 unCurrying, 可以把原生方法借出来,让任何对象拥有原生对象的方法。举个栗子:

obj.func(arg1, arg2) // => func(obj, arg1, arg2)

也可以这样理解:柯里化是在运算前提前传参,可以传递多个参数;反柯里化是延迟传参,在运算时把原来已经固定的参数或者this上下文等当作参数延迟到未来传递。


附:

V8引擎中Array.prototype.push方法源码实现:

function ArrayPush() {

var n = TO_UINT32(this.length);

var m = %_ArgumentsLength();

for (var i = 0; i < m; i++) {

this[i + n] = %_Arguments(i); // 属性拷贝

this.length = n + m; // 修正length

return this.length;

}

}


网上的帖子大多深浅不一,甚至有些前后矛盾,在下的文章都是学习过程中的总结,如果发现错误,欢迎留言指出~

参考:

  1. JS 柯里化

  2. 前端开发者进阶之函数反柯里化unCurrying

  3. JavaScript中有趣的反柯里化

  4. js柯里化适用场景,优缺点分别是什么,还有个反柯里化?

  5. JS进阶篇--JS中的反柯里化( uncurrying)

读完文章两步走

  • 如果你觉得文章不错,可以点一下右下角的「在看」或者分享该文章,让更多的人看到它

  • 加入我的「前端进阶群」,与群友讨论技术,了解前沿知识,具体可以加我微信「yck05016

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值