JavaScript 函数 Currying 化

JavaScript 和我了解的其他编程语言,例如 C/C++、C#、Java,有一个很独特的语法特性,函数也是一种对象。既然作为对象,那么也有属性、方法。今天恰好有一个问题引入,对于 argumentsapply()call() 以及 Currying 有了初步的了解,简单做个记录。

arguments 对象

这是一种类似于 Array 的对象,可以在每个函数内部调用。例如:

function foo(a, b, c) {
    console.log(arguments[0]);
    console.log(arguments.length);
}

foo(1, 2, 3); // expected output 1

arguments 对象并不是 Array,没有继承 Array 的方法,比如 slice()pop()。但是可以使用 call 的方式使用 Array 的函数,例如以下几种方式:

var args1 = Array.prototype.slice.call(arguments);

// 使用子面值,书写更短但是会创建空的数组对象
var args2 = [].slice.call(arguments);

// ES2015
var args3 = Array.from(arguments);

// spread syntax
var args4 = [...arguments];

好了,挖了一个新坑 Array.from() 以及 spread syntax operator,以后再整理。

除了 length 这个属性外,还有其他几个属性,这里暂不展开讨论:

apply()call()

其实上一段已经出现过了,这里做个解释。

function Foo() {
    this.x = 42;
}

Foo.prototype.getX = function(callback) {
    if (typeof callback === "function")
        callback(this.x);
};

var cb = function(arg) {
    console.log(arg);
}

var a = new Foo();

a.getX(cb); // 42

Foo.prototype.getX.apply(a, [cb]); // 42

Foo.prototype.getX.call(a, cb); // 42

例子可能略显啰嗦,仅仅是语法示例。apply() 第一个参数用于绑定函数调用时使用到的 this 指针,第二个则是参数数组。call() 相当于语法糖(syntax suger),和 apply() 几乎相同,区别在于它的语法是 call(thisArg, arg1, arg2, ... )

Currying 化示例

这也是个很大的话题,简单说是把多个参数的函数变成单一参数的函数。在其他编程语言中可以很方便的创建多维数组,而在 JavaScript 中可以这样实现:

// http://stackoverflow.com/a/966938/975097
function createArray(length) {
    var arr = new Array(length || 0),
        i = length;

    if (arguments.length > 1) {
        var args = Array.prototype.slice.call(arguments, 1);
        while (i--) arr[length-1 - i] = createArray.apply(this, args);
    }

    return arr;
}

createArray();     // [] or new Array()
createArray(2);    // new Array(2)
createArray(3, 2); // [new Array(2),
                   //  new Array(2),
                   //  new Array(2)]

这里就借用到了前两节所提到的语法特性,用一种灵活的方式弥补了语法中缺少的部分。当然为啥要创建多维数组呢?Dynamic programming 呀!

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名 IronBlood(包含链接)。