Should I just use a loop and not worry about it?
That's what I'd do.
If you really care that much about performance here, then what you should really do is profile it with a realistic dataset (over all the platforms you plan to support, probably and weighing what you get by how much you care about each one). Web browser devtools usually give you the ability to profile over time and memory consumption.
If the answer is "it depends", please say what it depends on (e.g. on the JS engine, sizes of the object and of the array, lower execution time vs lower memory use etc.)
Uh, ... Yes.
And this (and the number of variables, and the fact that how JS engines implement the spec is up to them, and could change in new releases) is why you should profile (regularly, assuming you target platforms where end-user software auto-updates and you don't get to choose the engine version), if this really matters to you.
I don't think I've personally ever found myself worrying over or caring about that degree of performance with a setup like this. This is JS. Though people have put commendable work into making performant engines, and I commend you about caring about performance (as for many other considerations that benefit the end-user, I wish people cared more about it), the language just wasn't really built for performance. It's not that practical to worry about it for every single thing, and so you should profile and focus your attention to where it will make the most difference, when that difference reaches the threshold of mattering to you.
The degree to which I'd care is in deciding whether obj here would be more fitting as a JS object, or as a Map. In general, if the keys of the map are going to be relatively dynamic over the thing's lifetime, and especially if there will be many keys, go with a Map. JS objects and Maps are typically implemented differently. If you want to read about details of what sorts of optimization a JS engine might do for a JS object, see for example What's up with monomorphism (from which you might take away that if you're going to be doing this operation in question many times, and each time, with the same keys in the same order of visitation, with a target object with the same shape, and you don't expect keys to be removed from those objects in different ways afterwards, it might be a good case to use a JS object; but if it really matters, again, profile).
If this is some routine worth optimizing to you, I'd also be thinking about (if you can) the structure/type of the input. Ex. if the input types are numeric, there could be benefit in refactoring to use typed arrays.
As an aside here, check out if your engine has a blog where they talk about performance things. v8 does, and you can find things like this, this, this.
So basically (and these are explicitly frame challenges),
- Profile, and focus your attention and time on what matters.
- Choose data types that suit the workload. Get performance from picking appropriate types.
Note that your arr.forEach(pair => { obj[pair.key] = pair.value; }); can also be written as arr.forEach(({key,value}) => obj[key] = value); (and if your array of key-value pairs contained arrays of length 2 instead (like [key, value]), you could do arr.forEach(([k,v]) => obj[k] = v);), but this would mostly just be a matter of syntax preference (if you had to really care about platform support, I'd check platform support tables about whether that destructuring syntax is available on all your platforms).
You could also use Array.prototype.reduce instead of Array.prototype.forEach, and one could make an argument that this semantically makes more sense, but personally, I think that would be a matter of preference. If the performance really mattered, again, profile/benchmark.
For educational purposes, note that if your key-value pairs were arrays of length 2 (like [k, v]), you could also write this as Object.assign(obj, Object.fromEntries(arr)).
arr.forEach(({ key, value }) => obj[key] = value);Alternativefor (const { key, value } of arr) obj[key] = value;{...obj, ...arr}, but it seems that doesn't work.