JavaScript:数组.为什么将带有填充数组的空数组连接成字符串?

vam*_*ire 4 javascript arrays concatenation

我正在解决扁平化数组的问题.我遇到了一些非常奇怪的东西,似乎无法在网上找到答案.

为什么

[] + [1,2] = '1,2'
Run Code Online (Sandbox Code Playgroud)

我似乎无法理解为什么在填充的数组中添加一个空数组会产生一个包含填充数组内容的字符串.

背后会发生什么导致这种情况?

我的代码示例:

arr = [1, [2], [3, 4]];
arr.reduce(flatten, []); // [1, 2, 3, 4]

function flatten(a, b) {
    return a.concat(b);
}
Run Code Online (Sandbox Code Playgroud)

据我所知,reduce会将'[]'设置为'初始值',因此对于原始数组中的每个元素,它会将它与一个空数组连接,从而"展平"数组.

lxe*_*lxe 5

发生这种情况是因为运算符触发了JavaScript 的隐式类型强制+。您不能简单地+对数组执行操作,因此它们会转换为字符串(其中包含数组的逗号分隔字符串转换值)。


Bad*_*bra 5

当您使用+对象之间(数组对象),JavaScript调用toString()和/或valueOf()内部.

var coercion1 = {} + {foo: 'Foo', bar: 'Bar'},
    coercion2 = [] + ['foo', 'bar'];

console.log(coercion1);
console.log(coercion2);
Run Code Online (Sandbox Code Playgroud)

这与以下内容相同:

var coercion1 = "".concat({}.toString(), {foo: 'Foo', bar: 'Bar'}.toString()),
    coercion2 = "".concat([].toString(), ['foo', 'bar'].toString());

console.log(coercion1);
console.log(coercion2);
Run Code Online (Sandbox Code Playgroud)

这又是一样的:

var coercion1 = "".concat({}.valueOf(), {foo: 'Foo', bar: 'Bar'}.valueOf()),
    coercion2 = "".concat([].valueOf(), ['foo', 'bar'].valueOf());

console.log(coercion1);
console.log(coercion2);
Run Code Online (Sandbox Code Playgroud)


要将对象转换为字符串,JavaScript需要执行以下步骤:

  • 如果对象具有toString()方法,则JavaScript会调用它.如果它返回原始值,JavaScript会将该值转换为字符串(如果它不是字符串)并返回该转换的结果.[...]
  • 如果对象没有toString()方法,或者该方法没有返回原始值,则JavaScript会查找 valueOf()方法.如果方法存在,JavaScript会调用它.如果返回值是基元,则JavaScript会将该值转换为字符串(如果尚未存在)并返回转换后的值.
  • 否则,JavaScript无法从toString()valueOf()获取原始值,因此会抛出TypeError.

David Flanagan,JavaScript:The Definitive Guide