1

前言

能点进这篇文章的掘友,应该都是因为看了这道面试题吧。

123['toString'].length + 123 = ?

这道题的本意可能是想考察 Number 重写了 toString 方法,可以通过传递参数改变数字的进制

console.log((10).toString()) // 10
console.log((10).toString(2)) // 1010

这算一个蛮实用的知识点,但几乎所有的人,都是栽在了函数的 length 上,而且这道题本身,也存在着问题。

很多人应该是第一次听说,函数还有个 length 属性?

本文会向你详细介绍这个属性,并指出这道面试题的败笔。

ES 标准

在 ECMAScript 标准中,确实规定了函数的 length 属性,是函数形参的个数。

image.png

我们来测试一下:

const fun1 = () => {}
const fun2 = (a) => {}
const fun3 = (a, b) => {}

console.log(fun1.length) // 0
console.log(fun2.length) // 1
console.log(fun3.length) // 2

可以看出,普通形参的函数表现是正常的,有几个形参,函数的长度就是多少。

特殊参数

但是,ES6 新增了两种参数:默认参数剩余参数,看看这两种参数对结果的影响。

const fun1 = (a, b = 1) => {}
const fun2 = (a, b = 1, c) => {}
const fun3 = (a, ...b) => {}

console.log(fun1.length) // 1
console.log(fun2.length) // 1
console.log(fun3.length) // 1

标准中对此并未说明,我们只能通过测试得出结果:

函数的长度取决于第一个默认参数之前的参数;剩余参数不计算在函数的长度中

看到这你或许会疑惑,Number 原型上的 toString 方法可以不加参数调用的呀,不算默认参数吗?

对,我也很疑惑,这就是这道面试题的败笔了,请接着往下看。

败笔

上面咱们得出的规则,并不适用于原生函数。

原生函数指的就是 JS 内部自己定义的函数,它们在控制台打印时函数体显示为 [native code]

console.log(Number.prototype.toString) // ƒ toString() { [native code] }
console.log(Array.prototype.slice) // ƒ slice() { [native code] }

而它们的 length 就很奇怪了

console.log(Number.prototype.toString.length) // 1
console.log(Array.prototype.slice.length) // 2

console.log(Array.prototype.map.length) // 1
console.log(Array.prototype.forEach.length) // 1

这四个函数都是有默认参数的,而前两个将默认参数算进了 length 中,后两个则不算。

原生函数的长度并没有统一的规则!除非你亲自测试过这个函数的 length,不然形参是否参与计算,根本无从推断。

谁会没事把原生函数的长度都测一遍啊,这就是面试题的败笔!

可能许多人不知道 map 和 forEach 还有第二个参数,用以指定回调函数内部的 this 指向,前提是传入的回调函数不是箭头函数。

离谱

有关函数的长度,还有更为离谱的现象,在此展示。

原生函数中的奇葩

看看 pushFunction 这两个函数的长度

console.log(Array.prototype.push.length) // 1
console.log(Function.length) // 1

你知道它们调用时的参数是什么样的吗?

Array.prototype.push (...items)
Function (p1, p2, … , pn, body)

只能说,我不理解函数的 length 有何意义?

有关这两个方法可以详见 push 与 [Function](https://tc39.es/ecma262/multi...
) 的标准。

删除函数的 length

目前的 ES 标准中, 函数的长度是可配置的,然后就出现了下面的 bug?

const fun = (a, b) => {}
console.log(fun.length) // 1

delete fun.length
console.log(fun.length) // 0
备注:在之前的 ES 版本中,函数的长度是不可配置的。

结语

在我们的实际开发中,根本用不到函数的 length,这个属性设计的毫无意义,本文就请当个乐子看看就好了,或者在他人面前装个13~

如果喜欢或者有所启发,欢迎点赞关注,鼓励一下新人作者。


清隆
29 声望2 粉丝

学完某项技能一定要写写文章,用的时候都是照搬代码,写出来才能深入理解!