如何让自定义类数组对象支持JavaScript的concat方法?
让类数组对象支持
concat方法的解决方案 当然可以搞定这个问题!你遇到的核心问题是:原生Array.prototype.concat对普通类数组对象(只带数字索引和length)会直接把它当作单个元素插入,而不是像数组那样展开元素。要解决这个,我们只需要让类数组对象被concat识别为可迭代对象,或者让它具备数组的行为特征就行,下面给你两种实用方案:
方案1:给类数组添加迭代器接口(推荐)
JavaScript的concat方法会优先检查目标对象是否实现了Symbol.iterator接口——如果实现了,就会遍历这个对象把元素逐个加进去。我们可以直接借用数组的迭代器逻辑,因为类数组的结构和数组完全匹配:
let arr = ['a','b']; // 修改后的arrLike,添加迭代器 let arrLike = { ...arr, length: arr.length, [Symbol.iterator]: Array.prototype[Symbol.iterator] }; // 测试concat console.log(['z'].concat(arr)); // ["z", "a", "b"] console.log(['z'].concat(arrLike)); // ["z", "a", "b"] 完美符合预期!
这个方案的好处是:只给类数组加了一个迭代器方法,不会改变它的其他行为,依然是纯纯的类数组对象,同时满足concat的需求。
方案2:让类数组继承数组原型
如果你不介意类数组对象拥有数组的其他原型方法(比如push、pop),也可以让它继承Array.prototype,这样concat会直接把它当成数组处理:
let arr = ['a','b']; // 基于数组原型创建类数组 let arrLike = Object.create(Array.prototype); // 把数组的元素和length赋值过去 Object.assign(arrLike, arr, { length: arr.length }); console.log(['z'].concat(arrLike)); // ["z", "a", "b"]
不过要注意,这种方式下arrLike instanceof Array会返回true,如果你的场景严格要求它不是数组实例,那方案1更合适。
为什么原来的arrLike不行?
原生concat的逻辑是:
- 如果参数是数组或者可迭代对象,就展开它的元素
- 如果是普通对象,就直接把整个对象作为单个元素添加
你之前的arrLike只是带了数字索引和length的普通对象,没有迭代器接口,所以concat会把它当成单个元素插入,就出现了不符合预期的结果。
内容的提问来源于stack exchange,提问作者lonewarrior556
相关产品推荐
相关产品推荐

