Why does Google Chrome not allow copying a reference to the console.log function?

19

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

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

In Mozilla Firefox, the script runs without any 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)

    
asked by anonymous 09.01.2014 / 19:33

1 answer

18

The problem is that the Chrome console wants log to be called in the context of console - that is, with console as this -, but you are calling the function no value set to this .

A quick fix:

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

link

What do you mean?

In JavaScript, the value of this within 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

Language offers two ways to force a value of this :

  • Invoking the function with call or < a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply"> apply :

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

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

  • Creating a function bound to a specific this , using the bind that every function has (remember which functions are JavaScript objects):

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

    (Note: bind ( Function.prototype.bind ) is not supported in older browsers.) You have a shim ["spare" MDN .)

  • The console object is a host object , that is, an object made available by the browser, which is not part of the hard core of the language. As such, it is entitled to certain perks , including peculiarities in each implementation . In the case of the Chrome console, this requirement exists that methods must be invoked with console as this , or the invocation is considered illegal.

        
    09.01.2014 / 19:45