symbol.isconcatspreadable 属性可精准控制对象在concat()中是否展开:数组默认true(展开),设false则整体保留;类数组默认false,需设true才展开;该属性不可配置,仅影响concat行为。

直接通过设置 Symbol.isConcatSpreadable 属性,就能决定一个对象在 concat() 中是被整体放入、还是逐项展开。它不修改数组本身结构,只改变合并时的“展开策略”,是控制扁平化层级最底层、最精准的方式。
数组默认展开,但可主动禁用
普通数组的 [Symbol.isConcatSpreadable] 默认为 true,所以 [1,2].concat([3,4]) 得到 [1,2,3,4]。若想保留子数组结构,只需设为 false:
const nums = [3, 4]; nums[Symbol.isConcatSpreadable] = false;-
[1, 2].concat(nums)→[1, 2, [3, 4]](不再扁平)
类数组对象默认不展开,需显式启用
像 {0: 'a', 1: 'b', length: 2} 这类对象,即使有索引和 length,concat() 也把它当普通对象处理,整个塞进去。要让它像数组一样展开,必须手动开启:
const fakeArr = {0: 'a', 1: 'b', length: 2};fakeArr[Symbol.isConcatSpreadable] = true;-
['x'].concat(fakeArr)→['x', 'a', 'b']
注意属性不可配置,且仅影响 concat 行为
Symbol.isConcatSpreadable 是非可写、非可枚举、非可配置的属性,一旦设置,不能用 delete 或 Object.defineProperty 覆盖其特性。它只对 Array.prototype.concat() 生效,不影响扩展运算符(...)、push(...arr) 或其他方法——那些行为由 Symbol.iterator 控制。
适合封装成工具函数统一管理
频繁切换展开逻辑时,可封装辅助函数避免重复赋值:
function asItem(arr) { arr[Symbol.isConcatSpreadable] = false; return arr; }function asList(obj) { obj[Symbol.isConcatSpreadable] = true; return obj; }- 后续调用
[1].concat(asItem([2,3]), asList({0:'a',length:1}))就很清晰










