类数组对象可借用数组方法,核心是利用原型链机制将类数组作为this调用array.prototype方法;三种方式:call最兼容,array.from语义清晰,扩展运算符简洁但依赖迭代器。

类数组对象(如 arguments、NodeList、HTMLCollection)长得像数组(有 length 和数字索引),但不是真正的 Array 实例,因此不能直接调用 push、slice、forEach 等方法。要高效复用数组方法,核心是利用 JavaScript 的原型链机制——把类数组对象作为 this,借用 Array.prototype 上的方法。
为什么能借用?原型链是关键
JavaScript 中所有函数都有 prototype 属性,而 Array.prototype 上定义了大量实例方法(如 slice、map、filter)。这些方法内部只依赖两个条件:存在 length 属性 和 拥有从 0 开始的连续数字索引属性。只要类数组对象满足这两点,就可以通过 call 或 apply 把它“冒充”成数组来调用方法。
三种主流借用方式及适用场景
1. Array.prototype.method.call(obj, ...args)
最通用、兼容性最好(支持 IE6+),适合单次调用或需传参的场景:
-
Array.prototype.slice.call(arguments, 1)—— 获取arguments除第一个外的参数 -
Array.prototype.forEach.call(document.querySelectorAll('div'), fn)—— 遍历节点列表
2. Array.from(obj)
ES6+ 推荐,语义清晰,自动转换为真数组,适合需要后续多次操作或使用现代数组方法的场景:
Array.from(document.querySelectorAll('input')).map(el => el.value)- 支持第二个参数作为映射函数:
Array.from('hello', c => c.toUpperCase())→['H','E','L','L','O']
3. 扩展运算符 [...obj]
简洁现代,本质是调用 obj[Symbol.iterator];对原生可迭代类数组(如 NodeList、arguments)有效,但不适用于无迭代器的老式类数组(如 HTMLCollection):
[...document.querySelectorAll('p')].filter(p => p.textContent.length > 10)[...arguments].reduce((a, b) => a + b, 0)
性能与注意事项
借用本身几乎无性能损耗(只是函数调用),但要注意:
-
Array.prototype.push、pop、unshift等会修改原对象,慎用于只读类数组(如NodeList) -
HTMLCollection是实时集合,借用slice后得到的是快照,后续 DOM 变化不影响该数组 - 避免反复借用:若需多次操作,优先用
Array.from或扩展运算符一次性转为真数组,而非每次调用都call
手动挂载方法(进阶技巧)
如果频繁操作某类类数组对象,可临时扩展其原型链(不推荐污染全局,仅作理解):
const arrLike = {0: 'a', 1: 'b', length: 2};<br>
Object.setPrototypeOf(arrLike, Array.prototype);<br>
arrLike.map(x => x + '!'); // ['a!', 'b!']
实际开发中更推荐封装工具函数,例如:
const toArray = obj => Array.isArray(obj) ? obj : Array.from(obj);<br>
toArray(document.getElementsByTagName('div')).forEach(...);Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











