1. 代码重现
let r = [1, 2, 3, 4, 5][0..toString.length];
输出 r 的值如下
2. 语句分析
先分析一下结构
[1, 2, 3, 4, 5] 是一个数组,显然 [0…toString.length] 就是数组的下标,这个下标是一个表达式
看到 0…toString ,作为新人的我还是比较陌生的。我们来打印一下
console.log(0..toString);
console.log(0..toString());
console.log(typeof (0..toString()));
答案是数值 0 调用了 toString() 方法
3. 0…toString()
为什么要用两个点而不是一个点呢?我们来试试一个点
console.log(123.toString());
在一位大佬的博客中,我得知这个点是为了将其转化为小数,再调用 toString 方法
这种说法不难验证,既然是转为小数,那么我们先手动转为小数再调用试试
console.log(0.0.toString());
console.log(1.);
看看结果
并没有报错,说明没有问题,但是第二行却打印了整数 1
。这就涉及到 javaScript 数据的存储了,javaScript 是没有 int 和 float 之分的。当小数点后为 0
时,javaScript 会自动省略并当作整数存取。这一点大家可以下去自行验证
以 toString() 为例,数字调用方法有 3 种
123..toString();
123['toString']();
123.0.toString();
所以 0…tostring 就是 number 的 toString 方法体,请注意这里没有调用
4. function.length
function.length 最常见的说法是,代表函数的形参的个数,不禁让人想起函数的实参的个数 arguments.length
function fun1(a, b, c) {
console.log(arguments.length);
}
fun1(10, 20);
console.log(fun1.length);
fun1 的实参个数为 2 ,形参个数为 3
function fun2(a, b, c, d, e, f, g) {
console.log(arguments.length);
}
fun2(10, 20, 30, 40);
console.log(fun2.length);
fun2 函数实参个数为 4 ,形参个数为 7
乍一看好像没什么毛病,但是如果是带默认值的函数呢?
function fun3(a, b, c, d, e, f = 1, g = 2) {
console.log(arguments.length);
}
fun2(10, 20, 30, 40);
console.log(fun2.length);
请看
fun3 的 arguments 有 4 个,fun2.length 只显示了 5
arguments 有 4 个,是因为 arguments 接收的是动态参数,也就是调用函数时传入的实参。所以参数 f 和 g 的默认值不会放入到 arguments 中
fun2.length 为 5 是因为函数形参的默认值会导致 function.length 失真。请往下看
function fun4(a, b, c, d = 1, e = 2, f, g) {}
console.log(fun4.length);
function fun5(a = 1, b, c, d, e = 2, f, g) {}
console.log(fun5.length);
相信你已经看出来规律了,function.length 就是从首个形参开始,计算没有默认值的形参个数,遇见带有默认值的形参则停止计数。所以,仅在所有的形参没有默认值的时候,function.length 才表示函数形参的个数
5. 回到面试题
所以开头面试题的意思就是,数值 0
的 toString 方法的形参个数作为下标,取数组 [1, 2, 3, 4, 5] 对应下标的项
数值 0 的 toString 方法的形参个数为 1。所以就等价于
let res = [1, 2, 3, 4, 5][1];
console.log(res);
取数组 [1, 2, 3, 4, 5] 第二项的值,所以结果为 2