"Uncaught TypeError: незаконный вызов" в Chrome
когда я использую requestAnimationFrame
чтобы сделать некоторые собственные поддерживаемые анимации с ниже кода:
var support = {
animationFrame: window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame ||
window.oRequestAnimationFrame
};
support.animationFrame(function() {}); //error
support.animationFrame.call(window, function() {}); //right
непосредственно вызова support.animationFrame
дадут...
Uncaught TypeError: незаконный вызов
В Chrome. Зачем?
4 ответа:
в коде вы присваиваете собственный метод свойству пользовательского объекта. Когда вы звоните
support.animationFrame(function () {})
, он выполняется в контексте текущего объекта (т. е. поддержка). Для собственной функции метод requestAnimationFrame, чтобы работать должным образом, она должна быть выполнена в контекстеwindow
.так что правильное использование здесь
support.animationFrame.call(window, function() {});
.то же самое происходит и с alert:
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
другой вариант-использовать
когда вы выполняете метод (т. е. функцию, назначенную объекту), внутри него вы можете использовать
this
переменная для ссылки на этот объект, например:var obj = { someProperty: true, someMethod: function() { console.log(this.someProperty); } }; obj.someMethod(); // logs true
если вы назначаете метод от одного объекта к другому, его
this
переменная ссылается на новый объект, например:var obj = { someProperty: true, someMethod: function() { console.log(this.someProperty); } }; var anotherObj = { someProperty: false, someMethod: obj.someMethod }; anotherObj.someMethod(); // logs false
то же самое происходит, когда вы назначаете
requestAnimationFrame
методwindow
на другой объект. Собственные функции, такие как это, имеет встроенную защиту от выполнения его в другом контексте.есть
Function.prototype.call()
функция, которая позволяет вызвать функцию в другом контексте. Вы просто должны передать его (объект, который будет использоваться в качестве контекста) в качестве первого параметра для этого метода. Напримерalert.call({})
даетTypeError: Illegal invocation
. Однако,alert.call(window)
отлично работает, потому что теперьalert
выполняется в исходном объеме.если вы используете
.call()
С вашим объектом, как что:support.animationFrame.call(window, function() {});
он отлично работает, потому что
, используяrequestAnimationFrame
выполняется в областиwindow
вместо вашего объекта..call()
каждый раз, когда вы хотите вызвать этот метод, не очень элегантное решение. Вместо этого, вы можете использоватьFunction.prototype.bind()
. Он имеет аналогичный эффект.call()
, но вместо вызова функции, он создает новую функцию, которая всегда будет называться в определенном контексте. Для пример:window.someProperty = true; var obj = { someProperty: false, someMethod: function() { console.log(this.someProperty); } }; var someMethodInWindowContext = obj.someMethod.bind(window); someMethodInWindowContext(); // logs true
единственный недостаток
Function.prototype.bind()
заключается в том, что он является частью спецификации ECMAScript 5, который не поддерживается в IE . К счастью, есть полифилл на MDN.как вы, наверное, уже поняли, вы можете использовать
.bind()
всегда выполняетсяrequestAnimationFrame
в контекстеwindow
. Ваш код может выглядеть так:var support = { animationFrame: (window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || window.oRequestAnimationFrame).bind(window) };
затем вы можете просто использовать
support.animationFrame(function() {});
.