Search code examples
javascriptconsole.logfunction-calls

JavaScript alter function arguments and use for function.apply


I defined a replacement for console.log which basically adds a global int variable to the beginning of the log.

In the function I'm iterating the arguments array backwards until index equals 1 and move each element by one forwards.

Then I'm adding the global int value at index 1 and change the format string, at index 0, to respect the new argument.

When doing this, console.log uses the new format string and argument but seems to ignore the second – originally first – format argument.

So I created some test functions to compare their output behaviour:

var globalInt = 25;
function log() {
    if (arguments.length > 0 && arguments[0].length > 0) {
        var keys = Object.keys(arguments);

        for (var i = keys.length - 1; i > 0; i--) {
            arguments[parseInt(keys[i]) + 1] = arguments[keys[i]];
        }

        arguments['0'] = '%d: ' + arguments['0'];
        arguments['1'] = globalInt;
    }

    console.log('  %s', JSON.stringify(arguments));
    console.log.apply(console.log, arguments);
}
function log_t1() {
    console.log('  %s', JSON.stringify(arguments));
    console.log.apply(console.log, arguments);
}
function log_t2() {
    if (arguments.length > 0 && arguments[0].length > 0) {
        arguments[0] = '%d: ' + arguments[0];
    }

    console.log('  %s', JSON.stringify(arguments));
    console.log.apply(console.log, arguments);
}

log('test "%s"', 'hello world');

log_t1('%d: test "%s"', globalInt, 'hello world');
log_t2('test "%s"', globalInt, 'hello world');


>> 
  {"0":"%d: test \"%s\"","1":25,"2":"hello world"}
25: test "%s"
  {"0":"%d: test \"%s\"","1":25,"2":"hello world"}
25: test "hello world"
  {"0":"%d: test \"%s\"","1":25,"2":"hello world"}
25: test "hello world"

Comparing those functions, their calls, their outputs and especially the equal JSON prints, I really wonder about the first result.

Can someone see any issue in the code or can confirm this behaviour?


Solution

  • You did not alter the length property of the arguments object. The arguments object is not a simple array, it is something different, and does not alter it's own length property when overindexing.

    I suggest you to convert the arguments object to an array first, and favour array methods over loops:

    var globalInt = 25;
    ...
    function log() {
        var args = Array.prototype.slice.call(arguments, 0);
        if (args.length > 0 && args[0].length > 0) {
            args = ['%d:  ' + args[0], globalInt].concat(args.slice(1));
        }
    
        console.log('  %s', JSON.stringify(args));
        console.log.apply(console, args);
    }