Symbol.isConcatSpreadable 属性可控制对象在 concat() 中是否展开:设为 true 时类数组对象被扁平化,false 时数组整体作为单个元素;原生数组默认 true,普通对象默认 false,该属性仅影响 concat()。
你可以直接设置对象的 Symbol.isConcatSpreadable 属性为 true 或 false,来决定它在 concat() 中是否被展开成元素。这不是魔法,而是 JavaScript 明确赋予开发者的行为控制权。
DOM 集合、arguments 或自定义类数组对象,默认不会被 concat() 展开,哪怕它们有 length 和数字索引。
[Symbol.isConcatSpreadable] = true
const divs = document.querySelectorAll('div'); divs[Symbol.isConcatSpreadable] = true;
[1, 2].concat(divs),得到扁平结果,无需先用 Array.from() 转换有时你希望把整个数组当作一个“值”拼进去,而不是拆开它的元素——比如构建嵌套结构或保留数据层级。
arr[Symbol.isConcatSpreadable] = false
[4, 5].concat(arr) 就不会变成 [4, 5, 1, 2, 3],而是 [4, 5, [1, 2, 3]]
concat(),不影响其他方法(如 push、spread)不同对象在 concat() 中的表现差异,根源就在这个符号的默认值:
Symbol.isConcatSpreadable === true,所以总是展开undefined,等价于 false,因此整体作为一项加入false 来临时禁用展开这个特性自 ES6 起就已标准化,现代浏览器和 Node.js 环境均支持,但需留意:
spread 语法([...arr]),它走的是迭代协议,不是 concat 逻辑Array.isArray() 判断Array.isArray(obj) === true 且 obj[Symbol.isConcatSpreadable] === false,后者优先生效