slice能转类数组但直接调用报错,因类数组无slice方法;须借用array.prototype.slice并绑定this,常用call、apply或空数组简写,现代推荐array.from或扩展运算符。

为什么 slice 能转类数组,但直接调用会报错
因为类数组(如 arguments、NodeList)没有 slice 方法,它只在 Array.prototype 上。直接写 arguments.slice(0) 会抛出 TypeError: arguments.slice is not a function。必须借用数组原型的方法,且确保 this 指向类数组对象。
正确借用 slice 的三种写法及适用场景
核心是让 Array.prototype.slice 的 this 绑定到类数组上:
-
Array.prototype.slice.call(arguments):兼容性最好,适用于所有 ES5 环境,包括老旧浏览器 -
Array.prototype.slice.apply(arguments):语义等价,但不推荐——apply会把参数展开,当类数组长度极大时可能触发栈溢出 -
[].slice.call(arguments):更简短,本质同第一种;但需注意空数组字面量创建的是干净实例,无污染风险
现代项目中优先用 Array.from(arguments) 或扩展运算符 [...arguments],它们语义更清晰、支持映射回调、且能处理 null/undefined;但若需兼容 IE8–9,slice.call 仍是唯一可靠选择。
slice 借用的边界行为和坑点
类数组只要具备 length 属性和数字键(0, 1, …),slice 就会按索引顺序提取值,不管是否为连续或存在空洞:
const arrayLike = { 0: 'a', 2: 'c', length: 3 };
Array.prototype.slice.call(arrayLike); // ['a', undefined, 'c']
常见陷阱:
-
NodeList在旧版 Safari 中可能不支持length或数字索引访问,导致结果为空数组 - 自定义类数组若
length不是原始数字(如字符串"2"),slice会隐式转为NaN,返回空数组 - 使用
slice(1)时,若类数组length === 0或length === null,结果不可预测,建议先校验
替代方案对比:什么时候不该用 slice.call
当目标对象不是“真类数组”时,slice.call 很容易静默失败:
-
document.querySelectorAll('div')返回NodeList—— 可用;但若用 jQuery 的$('div'),返回的是 jQuery 对象,length存在但索引属性被封装,slice.call会得到空数组 -
new Map()或{ length: 2, 0: 'x' }—— 后者可用,前者不行,因为Map没有数字索引 - 函数参数含非标准属性(如
arguments.callee)——slice不会包含它,因它不是数字键
真正需要转换时,先确认对象满足两个硬条件:typeof obj.length === 'number' 且 obj[i] !== undefined 对足够多的 i in [0, obj.length) 成立。否则,别硬套 slice.call,换 Array.from 或手动遍历更稳妥。










