函数的length

364 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

前言

函数有一些很重要的属性,不起眼。 所谓的存在即有意义,我们今天就一起来看看吧。

定义

length 是函数对象的一个属性值,指该函数有多少个必须要传入的参数,即形参的个数。

function add(num1, num2) {
  return num1 + num2;
}

console.log("length:", add.length);  // 2

与 arguments.length的区别

arguments.length是实际参数的长度, Function.length是形参的长度。

function add(num1, num2) {
  console.log("arguments.length:", arguments.length);
  return num1 + num2;
}

console.log("Function.length:", add.length);  // Function.length: 2
add(1,2,3) // arguments.length: 3

不包含剩余参数

可以看到剩余参数 args 并没有被包含

function add(num1, num2, ...args) {
  console.log("arguments.length:", arguments.length);
  return num1 + num2;
}
console.log("Function.length:", add.length);  
// Function.length: 2

不包含有默认值的参数

下面的例子,对两个参数都设置了默认自,结果length直接变成了0。

function add(num1 = 0, num2 = 0) {
  console.log("arguments.length:", arguments.length);
  return num1 + num2;
}
console.log("Function.length:", add.length);  
// Function.length: 0

仅包括第一个具有默认值之前的参数个数


function fun(a, b=1, c){}

console.log(fun.length);  // 1

bind之后的length

简单说:bound之后的length = 函数的length - bound的参数个数

function add(num1, num2, num3){
}

console.log("add.length", add.length);
// add.length 3

const boundAdd0 = add.bind(null);
console.log("boundAdd0.length:", boundAdd0.length);
// boundAdd0.length: 3

const boundAdd1 = add.bind(null, 1);
console.log("boundAdd1.length:", boundAdd1.length);
// boundAdd1.length: 2

const boundAdd2 = add.bind(null, 1,2);
console.log("boundAdd2.length:", boundAdd2.length);
// boundAdd2.length: 1

const boundAdd3 = add.bind(null, 1,2,3);
console.log("boundAdd3.length:", boundAdd3.length);
// boundAdd3.length: 0

const boundAdd4 = add.bind(null, 1,2,3,4);
console.log("boundAdd4.length:", boundAdd4.length);
// boundAdd4.length: 0

可以看到,绑定的参数个数越多,length的值越小。 当然不可能为负数。

用途

一个典型的用途就是科里化, 看这个版本github.com/mqyqingfeng…, 就利用length计算参数个数。

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);
        }
    }
}

lodash版本 www.lodashjs.com/docs/lodash…

_.curry(func, [arity=func.length])

也有利用这个length属性

切记,只是形参的长度。

一个有趣的例子

这是一个有意思的面试题,

[1,2,3].map(parseInt)

// results: [ 1, NaN, NaN ]

这个题目,无非考察

  1. map的参数函数传递两个参数,(value, index),第一个是值,第二个是索引值
  2. 的就是parseInt方法的函数参数,parseInt有两个参数

parseInt(string, radix);

  • string

    要被解析的值。如果参数不是一个字符串,则将其转换为字符串(使用  ToString 抽象操作)。字符串开头的空白符将会被忽略。

  • radix`` 可选

    从 2 到 36,表示字符串的基数。例如指定 16 表示被解析值是十六进制数。请注意,10不是默认值!

等同于

[
    parseInt(1,0), // 被默认为10进制
    parseInt(2,1), // 2 -36为有效值
    parseInt(3,2)  // 2 进制的数,不能出现大于2的数
]

小结

接下来我们继续学习

  • Function.name
  • Function.prototype.caller
  • Function.prototype.callee
  • Function.prototype.arguments
  • Function.prototype.toString 今天你收获了吗?