"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() {});.