鉴于以下<img id="f1" src="img/fish1.gif">
,我创建了一个对象构造函数,如下所示(缩小代码用于演示目的):
$(function(){
function fish(i){
this.f = $('#f'+i)[0];
this.d = '-=1px';
this.animateFish = function(){
$(this.f).animate({"left": this.d} ,10, "linear", this.checkCollision);
}
this.checkCollision = function(){
this.animateFish(); //TypeError: this.animateFish is not a function
}
}
var f1 = new fish(1);
f1.animateFish();
})
我应该为img
设置动画(在这种情况下是#f1),检查碰撞然后回想起this.animate
会引发上述错误,是否有任何修复?
答案 0 :(得分:2)
在animate()
的回调函数中,this
将引用被动画的元素,而不是fish
对象。因此,调用this.animateFish()
会给你一个找不到错误的函数。
要解决此问题,请在事件处理程序范围内的变量中存储对fish
对象的引用,然后您可以在事件处理程序中使用该变量。试试这个:
function fish(i) {
var _this = this;
_this.$f = $('#f' + i);
_this.d = '-=1px';
_this.animateFish = function() {
_this.$f.animate({ "left": _this.d }, 10, "linear", _this.checkCollision);
}
_this.checkCollision = function() {
_this.animateFish();
}
}
答案 1 :(得分:1)
每次声明一个新的function () {}
时,其中的任何this
都将引用该函数中新创建的上下文。在您的构造函数中,您拥有
this.animateFish = function(){
$(this.f).animate({"left": this.d} ,10, "linear", this.checkCollision);
}
因此,函数内的this.f
,this.d
和this.checkCollision
并不引用您正在构造的对象的属性,而是引用了到该函数创建的新this
上下文中。
正如罗里·麦克罗斯桑(Rory McCrossan)的回答所说,您可以创建一个新变量var _this = this
(尽管我更喜欢var self = this
,但这只是我的风格)。但是,在ES6中,您现在可以使用arrow functions,它们没有自己的this
上下文。
function fish(i){
this.f = $('#f'+i)[0];
this.d = '-=1px';
this.animateFish = () => {
$(this.f).animate({"left": this.d} ,10, "linear", this.checkCollision);
}
this.checkCollision = () => {
this.animateFish();
}
}
当您声明一个新的() => {}
函数时,内部的任何this
都将“继承”,即引用声明该函数的同一this
上下文。因此,在上面的代码中,this.f
,this.d
,this.checkCollision
和this.animateFish
指的是新建对象的属性,这就是您想要的。
答案 2 :(得分:1)
最好不要在构造函数中定义对象的方法,而应在原型上定义。如果在构造函数中定义方法,则每次构造new fish()
时,它都会获得这些方法的副本。相反,您可以通过将方法分配给原型来节省空间,以便所有fish实例可以共享相同的方法。
有两种方法可以做到这一点。一种是使用旧的ES5技术,实际上是访问原型。
function fish(i){
this.f = $('#f'+i)[0];
this.d = '-=1px';
}
fish.prototype.animateFish = function () {
$(this.f).animate({"left": this.d} ,10, "linear", this.checkCollision);
}
fish.prototype.checkCollision = function () {
this.animateFish();
}
这将同时修复代码中的错误,因为每个原型函数中的this
确实引用了fish实例。为了让您完全理解此代码的工作方式,您需要熟悉the prototype chain,这就是为什么我推荐以下技术-“可以正常工作”的原因。
第二种方法是使用ES6类(如果可以支持的话)。
class fish {
constructor(i){
this.f = $('#f'+i)[0];
this.d = '-=1px';
}
animateFish() {
$(this.f).animate({"left": this.d} ,10, "linear", this.checkCollision);
}
checkCollision() {
this.animateFish();
}
}
这还将解决您的错误,因为每种方法中的this
都引用了fish实例。
答案 3 :(得分:-1)
首先,有一个无限循环var myFunction = function() {
var age = 20;
this.name = "bar";
this.show = function() {
console.log(age);
}
}
var obj = new myFunction();
obj.show();
调用animateFish
,反之亦然。
其次,在您的动画调用中,您必须在调用checkCollision
时绑定this
,否则checkCollision
内引用的this
将成为DOM对象。
checkCollision