Why doesn’t Google Chrome allow you to copy a reference to the console.log function?

Asked

Viewed 409 times

19

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

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

Already in Mozilla Firefox the script runs without errors. Why is this happening? And how can I modify the script to run on 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 the Jsfiddle (in Google Chrome press Ctrl + Shift + J to view the error in the Console)

1 answer

18


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

A quick solution:

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

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


How so?

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

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

  1. Calling 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 should be passed - in sequence to call, or as an array for apply.)

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

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

    (Note: bind (Function.prototype.bind) is not supported in older browsers. It has a Shim ["steppe"? "substitute"] available at MDN.)

The object console is a Object host, that is, an object provided 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, there is a requirement that methods need to be invoked with console as this, or the invocation is considered unlawful.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.