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.