This is also fast in Safari because the array isn't sparse enough for JavaScriptCore to send it down the fallback path.
EDIT: In order to go down the fallback path the array needs to be both sufficiently large and sufficiently sparse (< 12.5% occupied). You can see the difference in algorithms by modifying your test case like so:
Dense, fast path:
var a = [];
for (var i = 1; i < 4e6; i++)
a[i * 5] = i.toString();
a.sort();
Sparse, fallback path: var a = [];
for (var i = 1; i < 4e6; i++)
a[i * 10] = i.toString();
a.sort();