JavaScript数组的splice()方法的参数问题

最近在使用splice方法的时候,遇到了一个百思不得其解的一个问题?话不多说上代码:
<script>

    var arr=[1,2,3,7,8,9,2,6,9,9,8,5,2,3,1];
    console.log('原始数据',arr);

    arr.splice(undefined,1)
    console.log('传入undefined',arr);

    arr.splice(null,1)
    console.log('传入null',arr);

    arr.splice(NaN,1)
    console.log('传入NaN',arr);

    arr.splice(true,1)
    console.log('传入true',arr);

    arr.splice(false,1)
    console.log('传入false',arr);

    arr.splice(" ",1)
    console.log('传入空格字符串',arr);

    arr.splice('',1)
    console.log('传入空字符串',arr);

    arr.splice(new Object(),1)
    console.log('传入空对象',arr);

    arr.splice([],1)
    console.log('传入空数组',arr);

    arr.splice(2.3,1)
    console.log('传入小数',arr);        

    arr.splice(-2.3,1)
    console.log('传入负小数',arr);

    arr.splice(-2,1)
    console.log('传入负整数',arr);        

    arr.splice(-2,1)
    console.log('传入负整数',arr);
</script>

打印出的结果如下图;

clipboard.png
这个时候我有点晕了,splice方法第一个参数是指定替换或删除的起始位置,按理是一个索引值,对于非数字型的参数,如果它调用的是number对象的话,undefined转换成数字应该是NaN啊,应该会报错啊,但是打印台还是正常打印出结果

上面的情况都有一个共同点,好像都转换成了数字0了,才有打印台的结果表现
有没有大佬解释一下,我看MDN上面也没有这种情况的说明

阅读 10k
5 个回答
上面的情况都有一个共同点,好像都转换成了数字0了,才有打印台的结果表现

显然并不都是把start当成0处理的....

1.先说MDN上写了的,也就是负整数的情况。

对于start,MDN描述为:

...如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取,slice(-2)表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)。

也就是对于题目中arr.splice(-2, 1)的例子,提取之前arr = [9, 8, 2, 1],此时start为-2 + 4 = 3,因此行为等价于arr.splice(3, 1),结果2被抽走了,符合描述。

2.剩下的都是MDN未描述清楚的,这里要去看ECMA-262规范,这里以最新的规范做说明。

首先找到22.1.3.25 Array.prototype.splice的描述:

关于start的处理在这两步完成,最后起作用的值是actualStart。

clipboard.png

所以第一步是把start进行ToInteger处理:

clipboard.png

然后发现又进了一个ToNumber处理....

clipboard.png

以入参undefined为例,首先经过ToNumber,返回NaN

然后根据ToInteger的第二点,返回+0

最后根据Splice的第四点,返回min(+0, length),也就是+0

因此undefined作为start传入,最后是被当做+0处理的。

剩下的你自己分析吧...

传送门:Array.prototype.splice

你的问题标准的这两步都说明好啦:
为了方便对应加了前缀ABCDEFG,可以对应起来。

A、Let relativeStart be ? ToInteger(start).
B、If relativeStart < 0, let actualStart be max((len + relativeStart), 0); else let actualStart be min(relativeStart, len).

深入看看ToInteger内部方法。

C、Let number be ? ToNumber(argument).
D、If number is NaN, return +0.
E、If number is +0, -0, +∞, or -∞, return number.
F、Return the number value that is the same sign as number and whose magnitude is floor(abs(number)).

再进一步看看ToNumber内部方法,大致写写了。

FLAG 类型 结果
G Undefined NaN
H Null +0
I Boolean true---1 false---0
J String 有效数字转化为相应数字类型。空字符串转化为0。有效数字转化为NaN
K Object 先 ToPrimitive(argument, hint Number) ,所得结果再toNumber

回到你的问题。
undefined:对应 C(G)、D。转化为 0
null:对应 C(H)、E。转化为 0
NaN:对应 D。转化为 0
true:对应 C(I)。转化为 1
false:对应 C(I)。转化为 0
" ":对应 C(J)、D。转化为 0
''::对应 C(J)、D。转化为 0
new Object():对应 C(K)、D。转化为 0
[]:对应 C(K)、D。转化为 0
2.3:对应 F。转化为 2
-2.3:对应 F、B。转化为 5-2=3
-2:对应 B。转化为 4-2=2

数值为NaN就相当于是0

clipboard.png

负数从后面开始计数

clipboard.png

小数是直接舍弃小数部分

你这个之所以迷惑,主要是样本数据前后有点协同,不好区分

第一个参数进来后会做

  1. 如果是布尔型,true当做1,false当做0
  2. 其余情况使用parseInt处理,如果得到NaN一律当成0处理。否则就用转换后的数值。
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏