在ES6中,我们可以使用rest
参数,有效地创建参数数组。 TypeScript使用for
循环将其转换为ES5。我想知道是否有使用for
循环方法比使用Array.prototype.slice
更好的选择?也许在某些情况下slice
选项无法解决?
// Written in TypeScript
/*
const namesJoinTS = function (firstName, ...args) {
return [firstName, ...args].join(' ');
}
const res = namesJoinTS('Dave', 'B', 'Smith');
console.log(res)
*/
// TypeScript above transpiles to this:
var namesJoinTS = function (firstName) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
return [firstName].concat(args).join(' ');
};
var res = namesJoinTS('Dave', 'B', 'Smith');
console.log(res); //Dave B Smith
// Vanilla JS
var namesJoinJS = function (firstName) {
var args = [].slice.call(arguments, 1);
return [firstName].concat(args).join(' ');
};
var res = namesJoinJS('Dave', 'B', 'Smith');
console.log(res); // //Dave B Smith
答案 0 :(得分:2)
这种奇怪的移植是老版本V8曾经(可能仍然)有偏差优化的副作用。他们极大地优化了某些模式,但并不关心整体性能,因此某些奇怪的模式(例如将for
复制到数组*的arguments
循环)的运行速度更快。因此,图书馆和转译者的维护者开始寻找相应的方法来优化其代码,因为它们的代码可以在数百万个设备上运行并且每毫秒都在计数。现在,随着V8中的优化变得更加成熟并专注于平均性能,这些技巧中的大多数不再起作用。将它们从代码库中重构出来只是时间问题。
此外,JavaScript正在朝着一种可以更轻松地优化的语言的方向发展,诸如arguments
之类的较早功能已被更严格的新功能(其余属性)取代,从而具有更高的性能。使用它们以良好的代码获得良好的性能,arguments
是过去的错误。
我想知道是否存在使用for循环方法比使用Array.prototype.slice更好的选择?
在较旧的V8版本上,速度更快,但仍然需要测试。如果您为项目编写代码,我将始终选择更优雅的解决方案,在99%的情况下,理论上可能会松散的毫秒数无关紧要。
也许在某些情况下,切片选项无法涵盖?
否(AFAIK)。
*您可能会问“为什么速度更快?”,那是因为:
arguments
本身很难进行优化
1)可以重新分配(arguments = 3
)
2)它必须是“实时的”,更改的参数将反映到arguments
因此,只有直接访问它,才能对其进行优化,因为编译器随后可能会用变量引用替换类似数组的访问器:
function slow(a) {
console.log(arguments[0]);
}
// can be turned into this by the engine:
function fast(a) {
console.log(a);
}
如果您内联循环并且如果参数数量发生变化又回退到另一个版本(可能会更慢),这也适用于循环:
function slow() {
for(let i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
slow(1, 2, 3);
slow(4, 5, 6);
slow("what?");
// can be optimized to:
function fast(a, b, c) {
console.log(a);
console.log(b);
console.log(c);
}
function fast2(a) {
console.log(a);
}
fast(1,2,3);
fast(4, 5, 6);
fast2("what?");
现在,如果您调用另一个函数并传递arguments
,事情将会变得非常复杂:
var leaking;
function cantBeOptimized(a) {
leak(arguments); // uurgh
a = 1; // this has to be reflected to "leaking" ....
}
function leak(stuff) { leaking = stuff; }
cantBeOptimized(0);
console.log(leaking[0]); // has to be 1
这不能真正优化,这是性能问题。
因此,调用函数并传递arguments
是一个坏主意。