javascript – Why doesn't Google Chrome allow copying a reference to the console.log function?

Question:

I have a method that takes a reference to a function and uses that reference to display data (code below). The problem is that when I use the console.log function on Google Chrome, an exception occurs, which in this case is the following:

Uncaught TypeError: Illegal invocation range_methods.foreach (anonymous function)

In Mozilla Firefox the script runs without errors. Why is this happening? And how can I modify the script to run in both browsers?

JavaScript:

function Range(from, to) {
    'use strict';
    var range_obj, range_methods = {
        from: from,
        to: to,
        includes: function (x) {
            return this.from <= x && x <= this.to;
        },
        foreach: function (f) {
            var x;
            for (x = Math.ceil(this.from) ; x <= this.to; x += 1) {
                f(x);
            }
        },
        toString: function () {
            return "(" + this.from + "..." + this.to + ")";
        }
    };

    range_obj = Object.create(range_methods);

    return range_obj;
}

var r = new Range(1, 3); // Cria um objeto range
r.includes(2); // => true: 2 está no intervalo
r.foreach(console.log); // Exibe 1 2 3
console.log(r); // Exibe (1...3)

Code in JSFiddle (in Google Chrome press Ctrl + Shift + J to see the error in the Console)

Answer:

The problem is that Chrome's console wants log be called in console context – that is, with console like this – but you're calling the function with no value set for this .

A quick fix:

var log = console.log.bind(console);
r.foreach(log);

http://jsfiddle.net/y5evq/1/


As well?

In JavaScript, the value of this inside a function depends on how it is called. For example:

var obj = {
   fn: function() { console.log(this) }
};
var f = obj.fn;
obj.fn();        // loga obj
f();             // loga null no strict mode, ou o objeto global
                 // este é o caso do seu exemplo

The language offers two ways to force a value of this :

  1. Invoking the function with call or apply :

     f.call(obj); f.apply(obj);

    (In this case both methods are equivalent as they only differ in the way the parameters must be passed – in sequence to call , or as array to apply .)

  2. Creating a function linked to a specific this , with the bind method that every function has (remember that functions are objects in JavaScript):

     var g = f.bind(obj); g();

    (Note: bind ( Function.prototype.bind ) is not supported in older browsers. There is a shim ["steppe"? "replacement"] available on MDN .)

The console object is a host object , that is, an object provided by the browser, which is not part of the language's hard core. As such, he is entitled to certain perks , including quirks in each implementation. In the case of the Chrome console, there is this requirement that methods must be invoked with console like this , or the invocation is considered illegal.

Scroll to Top