Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do rest parameters allow for optimization?

The Managing arguments section in Bluebird's article on Optimization killers states that:

The arguments object must not be passed or leaked anywhere.

In other words, don't do the following:

function leaky(){
    return arguments;
}

But do do this:

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

With the introduction of Rest paramters, will passing the rest parameter array still cause optimization issues? From what I am understanding, the issue is that we can't let the actual arguments Object get loose. Finite, defined copies of arguments are OK, but not the actual Object itself. If that is the case, is the rest argument treated as an OK and optimizable copy of arguments when used in the following way?

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

Specifically, I'm trying to write a debounce function based on David Walsh's debounce function (which is based on Underscore.js') and I believe there is an issue with assigning arguments to a variable within the top scope of the debounce function. To rectify this I wrote the following:

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);
        }
    };
}
like image 835
zero298 Avatar asked Jul 26 '17 17:07

zero298


People also ask

What is the purpose of rest parameters?

The rest parameter syntax allows a function to accept an indefinite number of arguments as an array, providing a way to represent variadic functions in JavaScript.

What happens if you do not use rest parameter as a last argument?

Note: The rest parameter have to be the last argument, as its job is to collect all the remaining arguments into an array. So having a function definition like the code below doesn't make any sense and will throw an error.

What is the difference between rest parameters and arguments object?

Rest parameters represent the unknown number of arguments inside the function, whereas the arguments object represents all arguments passed to the function.

What is the difference between rest and spread operator?

The main difference between rest and spread is that the rest operator puts the rest of some specific user-supplied values into a JavaScript array. But the spread syntax expands iterables into individual elements.


1 Answers

One of the challenges with the arguments object, is that it needs to be a live collection of the parameters values, even when they are reassigned. See how even a (parameter) variable with a primitive value gets changed without any explicit assignment to it, and it happens outside of the function:

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

See this blog for more on such behaviour.

One can imagine that code optimisation becomes a nightmare when such an object travels around, never losing such magical capabilities.

This of course, does not happen with a normal array, and the array you get with the spread syntax is indeed a normal array:

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

You can rest (no pun intended) assured that the mentioned code optimisation problems with arguments do not apply to ...args.

Strict mode fixes it all

As Bergi mentioned. The live semantic of arguments is no longer there when the function, whose arguments variable is used, is written in strict mode 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); 

As stated in mdn's article on strict mode:

strict mode code doesn't alias properties of arguments objects created within it. In normal code within a function whose first argument is arg, setting arg also sets arguments[0], and vice versa (unless no arguments were provided or arguments[0] is deleted). arguments objects for strict mode functions store the original arguments when the function was invoked. arguments[i] does not track the value of the corresponding named argument, nor does a named argument track the value in the corresponding arguments[i].

like image 120
trincot Avatar answered Oct 10 '22 00:10

trincot