The usual acc.concat(val) makes sense to me. What I don't understand is the decompositional syntax part. From my understanding, when you use .concat(...arr), the spread operator will pass all the values of arr into the .concat method, which means it should be [1, 2, [3,4]]. Why is it that it actually flattened the 1 level deep nested array in the process to return [1,2,3,4]?
Almost right - it is not [1, 2, [3, 4]] though (that would be an array again) but it would be a tuple of 1, 2, [3, 4].
Writing fn(1, ...[2, 3, 4], 5) is the same as fn(1, 2, 3, 4, 5). So in this case, we are doing [].concat(...[1, 2, [3, 4]]) which is the same as [].concat(1, 2, [3, 4]), so concat is called with three arguments: 1, 2 and [3, 4].
The last puzzle piece is that concat behaves differently for arrays and non-arrays as arguments (see docs):
The concat method creates a new array consisting of the elements in the object on which it is called, followed in order by, for each argument, the elements of that argument (if the argument is an array) or the argument itself (if the argument is not an array). It does not recurse into nested array arguments.
This means that [1, 2].concat(3, [4], 5, [6, 7], 8) produces an array [1, 2, 3, 4, 5, 6, 7, 8] because the arguments 123 and [123] are handled the same. This differentiation between arrays and non-array values in the arguments to concat is what causes the "flattening effect", because it means that [].concat(1, 2, [3, 4]) is valid and returns [1, 2, 3, 4].
Usually, concat is used with arrays, and I myself normally consider x.concat(y, z) as the same as [...x, ...y, ...z] (which wouldn't cause any flattening) but in fact it does support non-array arguments and handles them the same way as if they were the only element in an array - in my example it would be the same as [...x, ...Array.isArray(y) ? y : [y], ...Array.isArray(z) ? z : [z]] which actually is the same as [...x, ...[y, z].flat()]! - I haven't seen non-array arguments to concat used much but it works and that's the key reason why [].concat(...arr) does a one-level-deep flattening!
(By the way, this also applies to the reduce example. It should actually have made equally little sense to you!)