休息参数是否允许优化?

时间:2017-07-26 17:24:08

标签: javascript ecmascript-6

The Managing arguments section in Bluebird's article on Optimization killers声明:

  

arguments对象不得在任何地方传递或泄露。

换句话说,请勿执行以下操作:

function leaky(){
    return arguments;
}

但要这样做:

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

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

function maybe_optimizable(...args){
    return args;
}

具体来说,我正在尝试根据David Walsh's debounce function (which is based on Underscore.js')编写debounce函数,我认为将arguments分配给{{debounce的顶部范围内的变量存在问题。 1}}功能。为了纠正这个问题,我写了以下内容:

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);
        }
    };
}

1 个答案:

答案 0 :(得分:5)

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



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); 




有关此类行为的详情,请参阅this blog

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

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



(function (...args) {
    console.log('args is an ' + args.constructor.name);
})(0); 




您可以放心(没有双关语)确保arguments提及的代码优化问题不适用于...args

严格模式将其全部修复

正如Bergi所说。当使用arguments变量的函数以严格模式JavaScript编写时,arguments live 语义不再存在:



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); 
&#13;
&#13;
&#13;

mdn's article on strict mode中所述:

  

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