休息参数是否允许优化?

zer*_*298 6 javascript ecmascript-6

argumentsBluebird关于优化杀手的文章中的管理部分指出:

arguments对象不能被传递或任何泄露.

换句话说,不要执行以下操作:

function leaky(){
    return arguments;
}
Run Code Online (Sandbox Code Playgroud)

但这样做:

function not_leaky(){
    var i = arguments.length,
        args = [];
    while(i--) args[i] = arguments[i];
    return args;
}
Run Code Online (Sandbox Code Playgroud)

随着Rest参数的引入,传递其余参数数组仍会导致优化问题吗?从我的理解,问题是我们不能让实际的arguments对象松散.有限的,定义的副本arguments都可以,但不是实际的Object本身.如果是这种情况,那么arguments当以下列方式使用时,rest参数是否被视为OK和可优化的副本?

function maybe_optimizable(...args){
    return args;
}
Run Code Online (Sandbox Code Playgroud)

具体来说,我正在尝试编写一个debounce基于David Walsh debounce函数(基于Underscore.js')的函数,我相信argumentsdebounce函数的最高范围内分配一个变量存在问题.为了纠正这个问题,我写了以下内容:

function debounce(func, wait, immediate) {
    let timeout;
    return function (...args) {
        let context = this,
            now = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(() => {
            timeout = null;
            if (!immediate) {
                func.apply(context, args);
            }
        }, wait);
        if (now) {
            func.apply(context, args);
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

tri*_*cot 5

arguments对象面临的挑战之一是它需要是参数值的实时集合,即使它们被重新分配也是如此.查看具有原始值的(参数)变量如何在没有任何显式赋值的情况下进行更改,并且它发生在函数之外:

function modify(arr) {
    arr[0] = 3;
}

(function (a) {
    console.log('arguments is an ' + arguments.constructor.name);
    console.log('a is ', a);
    modify(arguments);
    console.log('after calling modify, a is ', a);
})(0); 
Run Code Online (Sandbox Code Playgroud)

有关此类行为的更多信息,请参阅此博客

可以想象,当这样的物体四处移动时,代码优化成为一场噩梦,永远不会失去这种神奇的能力.

当然,这不会发生在普通数组中,并且使用扩展语法获得的数组确实是一个普通的数组:

(function (...args) {
    console.log('args is an ' + args.constructor.name);
})(0); 
Run Code Online (Sandbox Code Playgroud)

你可以休息(没有双关语)保证提到的代码优化问题arguments不适用...args.

严格的模式解决了这一切

正如Bergi所说.在现场语义的arguments不再存在时,函数,它的arguments变量时,是写在严格模式下的JavaScript:

function modify(arr) {
    arr[0] = 3;
}

(function (a) {
    "use strict"; // <-----
    console.log('In strict mode');
    console.log('arguments is still an ' + arguments.constructor.name);
    console.log('a is ', a);
    modify(arguments);
    console.log('after calling modify, a is still ', a);
})(0); 
Run Code Online (Sandbox Code Playgroud)

正如mdn关于严格模式的文章中所述:

严格模式代码不会为其中arguments创建的对象的属性设置别名.在第一个参数为的函数中的普通代码中arg,设置arg也设置arguments[0],反之亦然(除非没有提供或arguments[0]删除参数).arguments严格模式函数的对象在调用函数时存储原始参数.arguments[i]不跟踪相应命名参数的值,命名参数也不跟踪相应的值arguments[i].

  • 不要忘记严格模式可以解决所有问题.这只是类似数组的对象(而不是真正的数组)的奇怪之处. (2认同)