javascript - "TypeError no detectado: invocación ilegal" en Chrome
html5 google-chrome (4)
Cuando ejecuta un método (es decir, función asignada a un objeto), dentro de él puede usar this
variable para referirse a este objeto, por ejemplo:
var obj = {
someProperty: true,
someMethod: function() {
console.log(this.someProperty);
}
};
obj.someMethod(); // logs true
Si asigna un método de un objeto a otro, this
variable se refiere al nuevo objeto, por ejemplo:
var obj = {
someProperty: true,
someMethod: function() {
console.log(this.someProperty);
}
};
var anotherObj = {
someProperty: false,
someMethod: obj.someMethod
};
anotherObj.someMethod(); // logs false
Lo mismo sucede cuando asigna el método de window
requestAnimationFrame
a otro objeto. Las funciones nativas, como esta, tienen una protección incorporada que no se puede ejecutar en otro contexto.
Hay una Function.prototype.call()
, que le permite llamar a una función en otro contexto. Solo tiene que pasarlo (el objeto que se utilizará como contexto) como primer parámetro de este método. Por ejemplo alert.call({})
da TypeError: Illegal invocation
. Sin embargo, alert.call(window)
funciona bien, porque ahora la alert
se ejecuta en su alcance original.
Si usa .call()
con su objeto así:
support.animationFrame.call(window, function() {});
funciona bien, porque requestAnimationFrame
se ejecuta en el alcance de la window
lugar de su objeto.
Sin embargo, utilizar .call()
cada vez que desee llamar a este método, no es una solución muy elegante. En cambio, puede usar Function.prototype.bind()
. Tiene un efecto similar a .call()
, pero en lugar de llamar a la función, crea una nueva función que siempre se llamará en el contexto especificado. Por ejemplo:
window.someProperty = true;
var obj = {
someProperty: false,
someMethod: function() {
console.log(this.someProperty);
}
};
var someMethodInWindowContext = obj.someMethod.bind(window);
someMethodInWindowContext(); // logs true
El único inconveniente de Function.prototype.bind()
es que forma parte de ECMAScript 5, que no es compatible con IE <= 8 . Afortunadamente, hay un polyfill en MDN .
Como probablemente ya haya averiguado, puede usar .bind()
para ejecutar siempre requestAnimationFrame
en el contexto de la window
. Tu código podría verse así:
var support = {
animationFrame: (window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame).bind(window)
};
Entonces simplemente puede usar support.animationFrame(function() {});
.
Cuando uso requestAnimationFrame
para hacer alguna animación nativa compatible con el siguiente código:
var support = {
animationFrame: window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame
};
support.animationFrame(function() {}); //error
support.animationFrame.call(window, function() {}); //right
Llamando directamente a support.animationFrame
le dará ...
Unkeught TypeError: Invocación ilegal
en Chrome. ¿Por qué?
En su código, está asignando un método nativo a una propiedad de objeto personalizado. Cuando llama a support.animationFrame(function () {})
, se ejecuta en el contexto del objeto actual (es decir, soporte). Para que la función native requestAnimationFrame funcione correctamente, debe ejecutarse en el contexto de la window
.
Entonces, el uso correcto aquí es support.animationFrame.call(window, function() {});
.
Lo mismo ocurre con la alerta también:
var myObj = {
myAlert : alert //copying native alert to an object
};
myObj.myAlert(''this is an alert''); //is illegal
myObj.myAlert.call(window, ''this is an alert''); // executing in context of window
Otra opción es usar Function.prototype.bind() que es parte del estándar ES5 y está disponible en todos los navegadores modernos.
var _raf = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame;
var support = {
animationFrame: _raf ? _raf.bind(window) : null
};
También puedes usar:
var obj = {
alert: alert.bind(window)
};
obj.alert(''I´m an alert!!'');
tuve este error cuando tenía una conexión VPN, deshabilité la VPN y resolví el problema.