资讯专栏INFORMATION COLUMN

You need to know curry

BigNerdCoding / 1540人阅读

Functions are first-class citizen

Functions are first-class citizen in JavaScript, as the same as other types(e.g. number, array, object). They can be used as arguments, as well as return value from other function.

Take a simple example, if we aim to print out all the elements in an array, most people probably will do it this way:

function printWithLoop(arr) {
    for (let i = 0, len = arr.length; i < len; i++) {
        console.log(arr[i]);
    }
}

If you"re a bit familar with higher-order function, you may be inclined to use Array.prototype.forEach:

function printWithIterator(arr) {
    (arr || []).forEach(it => {
        console.log(it);
    });
}

We can then simplify the code further with:

function simplePrint(arr) {
    (arr || []).forEach(console.log);
}

Have a second thought here, is the output from simplePrint exactly the same as printWithIterator? If not, can you explain what makes the difference?

Function overloading

Function overloading gives the ability for functions to behave differently based on the number or type of the arugments. E.g. Array.from.

When given a single argument, it simplely creates a new Array instance from an array-like or iterable object

let set = new Set(["foo", "bar", "foo"]);
console.log(Array.from(set)); //["foo", "bar"]

When given a second argument mapFn which is optioinal, it will apply mapFn to each element when creating the new array.

console.log(Array.from([1, 2, 3], x => x + x)); // [2, 4, 6] 
Curry

Curry, also called partial application. Currying a function basically means that a function will absord some arguments and return another function for later invocation. The returning function can have access to the already absorded arguments through closure.

Parameters vs Arugments

First we need to understand two basic concepts in functions.

Parameters: the placeholders in function declarations. We can use function.length to get the number of parameters.

function A(a, b) {}
// a and b are parameters
console.log(A.length); //2

Arguments: the values passed to functions when functions are applied. We can use arguments to get the list of arguments.

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

B(1,2,3); // 1,2,3

To conclude, parameters are what you expect while arguments are what you got.

Curry example

Assume we have a function to compute the sum of three numbers.

function sum(x, y, z) {
    console.log(x + y + z);
}

sum(1,2,3); //6

If we want to achieve the following result:

sum(1,2,3); //6
sum(1)(2,3); //6
sum(1,2)(3); //6

Have a deep look, what we want to achieve is that when the function sum receives the arguments it expects (i.e. three numbers), it will compute their sum and return the value. Otherwise, it will keep returning another function (e.g. sum(1) and sum(1,2) both return another function) which can be invoked with more numbers. This is Curry!

function curry(fn) { //Let"s ignore the function context for simplicity
    return function f(...args) {
        /**
         * if the number of passed in arguments is more than what we expect
         * invoke the function and return the result
         */
        if(args.length >= fn.length) { 
            return fn.apply(this, args);
        } else {
            //return another function which can access to the passed arguments through closure
            return function(...arr) { 
                return f.apply(this, args.concat(arr));
            }
        }
    }
}

let sumWithCurry = curry(sum);
sumWithCurry(1,2,3); //6
sumWithCurry(1)(2,3); //6
sumWithCurry(1,2)(3); //6
Function.prototype.bind

Function.prototype.bind has two main functionalities:

binding the function context this

curry

function sayHi(greeting, ending) {
    console.log(`My name is ${this.name}, ${greeting}. ${ending}!`);
}

let fn = sayHi.bind({name: "mike"}, "Love you"); // greeting is absorded
fn("Thanks!"); // My name is mike, Love you. Thanks!!

In development, we can use curry to write more elegant code:

function print(arr) {
    console.log(arr.join("|"));
}

let arr = [1,2,3];
setTimeout(function(){
    print([1,2,3]);
}, 1000);
// 1|2|3

is equivalent to

function print(arr) {
    console.log(arr.join("|"));
}

let arr = [1,2,3];
setTimeout(print.bind(null, arr), 1000);
// 1|2|3
Reference

Effective JavaScript

Notice

If you want to follow the latest news/articles for the series of reading notes, Please 「Watch」to Subscribe.

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93424.html

相关文章

  • 2017-10-24 前端日报

    摘要:前端日报精选请求终极解决方案微信小程序之小白教程系列微信小程序样式常用命令使用教程如何在三年内快速成长为一名技术专家浅谈前后端分离与实践之中间层服务二中文框架教程阮一峰的网络日志的组合功能如何用选项连接组合文件外部定义的容器众 2017-10-24 前端日报 精选 JS HTTP 请求终极解决方案[微信小程序之小白教程系列] 微信小程序 -- 样式(WXSS)常用Git命令使用教程如何...

    BLUE 评论0 收藏0
  • Prettier document you need to know【1】 -- 概要内容

    摘要:都有个规则范畴格式化规则例减轻了对这整个类别规则的需求以一致的方式从头开始输出整个程序,所以程序员不可能再犯错误了。代码质量规则例不针对与此项。在这方面还是有无可替代的功劳译者建议配合使用来管理维护更好的代码输出。 以下内容为个人参照Prettier官网部分文档翻译+理解,用以罗列部分you need to know,文档内容经供参考,详细内容参考官网 安装 (由于node.js的火热...

    MadPecker 评论0 收藏0
  • 277. Find the Celebrity

    摘要:题目解答每一次比较只有两种情况,是的话,那么肯定不是是的话,那么肯定不是所以一直比较到最后会留下一个,然后我们再验证这个是不是正解。 题目:Suppose you are at a party with n people (labeled from 0 to n - 1) and among them, there may exist one celebrity. The defini...

    chavesgu 评论0 收藏0
  • [LeetCode] 277. Find the Celebrity

    Problem Suppose you are at a party with n people (labeled from 0 to n - 1) and among them, there may exist one celebrity. The definition of a celebrity is that all the other n - 1 people know him/her ...

    jasperyang 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<