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);
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
:
-
Invoking the function with
call
orapply
: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 toapply
.) -
Creating a function linked to a specific
this
, with thebind
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.