Chrome'da "Yakalanmayan TypeError: Yasadışı çağrı"


137

requestAnimationFrameAşağıdaki kod ile bazı yerel desteklenen animasyon yapmak için kullandığımda :

var support = {
    animationFrame: window.requestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        window.oRequestAnimationFrame
};

support.animationFrame(function() {}); //error

support.animationFrame.call(window, function() {}); //right

Doğrudan support.animationFrameirade vermek ...

Yakalanmayan TypeError: Geçersiz çağrı

Chrome'da. Neden?

Yanıtlar:


195

Kodunuzda, özel nesnenin bir özelliğine yerel bir yöntem atarsınız. Aradığınızda support.animationFrame(function () {}), geçerli nesne bağlamında yürütülür (yani destek). Yerel requestAnimationFrame işlevinin düzgün çalışması için, işlevi bağlamında yürütülmelidir window.

Yani burada doğru kullanım support.animationFrame.call(window, function() {});.

Aynı şey uyarı ile de olur:

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 

Başka bir seçenek de ES5 standardının bir parçası olan ve tüm modern tarayıcılarda bulunan Function.prototype.bind () yöntemini kullanmaktır .

var _raf = window.requestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        window.oRequestAnimationFrame;

var support = {
   animationFrame: _raf ? _raf.bind(window) : null
};

1
Chrome 33'ten itibaren "Yasadışı çağrı" ile ikinci çağrı da başarısız oluyor. Yanıt güncellendikten sonra downvote'u kaldırmak mutlu !
Dan Dascalescu

@DanDascalescu: Ben krom 33 kullanıyorum ve bu benim için çalışıyor.
Nemoy

1
Kodunuzu kopyalayıp yapıştırdım ve Yasadışı çağrı hatasını aldım. İşte ekran görüntüsü.
Dan Dascalescu

24
Kesinlikle yasadışı çağırma hatası alacaksınız, çünkü ilk stamt myObj.myAlert('this is an alert');yasadışı. Doğru kullanım myObj.myAlert.call(window, 'this is an alert'). Lütfen cevapları doğru bir şekilde okuyun ve anlamaya çalışın.
Nemoy

3
Burada aynı şekilde çalışmak için console.log.apply almaya çalışırken sıkışan tek kişi ben değilim, "bu" pencere değil, konsol olmalıdır: stackoverflow.com/questions/8159233/…
Alex

17

Ayrıca kullanabilirsiniz:

var obj = {
    alert: alert.bind(window)
};
obj.alert('I´m an alert!!');

2
Bu soruya tam olarak cevap vermiyor. Bence bir cevap değil, bir yorum olmalı.
Michał Perłakowski

2
Ayrıca, uygun bir nesneye bağlanmak önemlidir, örneğin history.replaceState ile çalışırken aşağıdakileri kullanmalısınız: var realReplaceState = history.replaceState.bind(history);
DeeY

@DeeY: soruma cevap verdiğiniz için teşekkürler! Gelecekteki insanlar için localStorage.clear, yapmanızı .bind(localStorage)istemez .bind(window).
Samyok Nepal

13

Bir yöntemi (yani bir nesneye atanan işlev) yürüttüğünüzde, içinde thisbu nesneye başvurmak için değişken kullanabilirsiniz , örneğin:

var obj = {
  someProperty: true,
  someMethod: function() {
    console.log(this.someProperty);
  }
};
obj.someMethod(); // logs true

Bir nesneden diğerine bir yöntem atarsanız, thisdeğişkeni yeni nesneyi ifade eder, örneğin:

var obj = {
  someProperty: true,
  someMethod: function() {
    console.log(this.someProperty);
  }
};

var anotherObj = {
  someProperty: false,
  someMethod: obj.someMethod
};

anotherObj.someMethod(); // logs false

Başka bir nesneye requestAnimationFrameyöntemi atadığınızda da aynı şey olur window. Bunun gibi yerel işlevler, onu başka bağlamda yürütmeye karşı yerleşik bir korumaya sahiptir.

Bir Orada Function.prototype.call()başka bir bağlamda bir işlevi çağırmak için izin verir fonksiyonu. Bu yöntemin ilk parametresi olarak (bağlam olarak kullanılacak nesne) iletmeniz yeterlidir. Örneğin alert.call({})verir TypeError: Illegal invocation. Ancak, iyi alert.call(window)çalışır, çünkü şimdi alertorijinal kapsamında yürütülür.

Eğer kullanırsanız .call()o şekilde nesneyle:

support.animationFrame.call(window, function() {});

gayet iyi çalışıyor, çünkü nesneniz yerine onun yerine requestAnimationFrameyürütülüyor window.

Ancak, .call()bu yöntemi her aramak istediğinizde kullanmak çok şık bir çözüm değildir. Bunun yerine kullanabilirsiniz Function.prototype.bind(). Buna benzer bir etkiye sahiptir .call(), ancak işlevi çağırmak yerine, her zaman belirtilen bağlamda çağrılacak yeni bir işlev oluşturur. Örneğin:

window.someProperty = true;
var obj = {
  someProperty: false,
  someMethod: function() {
    console.log(this.someProperty);
  }
};

var someMethodInWindowContext = obj.someMethod.bind(window);
someMethodInWindowContext(); // logs true

Bunun tek dezavantajı, IE <8'de desteklenmeyenFunction.prototype.bind() ECMAScript 5'in bir parçası olmasıdır . Neyse ki, MDN'de bir çoklu dolgu var .

Muhtemelen anladığınız gibi, .bind()her zaman requestAnimationFramebağlamında yürütmek için kullanabilirsiniz window. Kodunuz şöyle görünebilir:

var support = {
    animationFrame: (window.requestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.msRequestAnimationFrame ||
        window.oRequestAnimationFrame).bind(window)
};

Sonra sadece kullanabilirsiniz support.animationFrame(function() {});.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.