Object构造函数和TypeError中的递归函数

时间:2017-01-25 17:59:50

标签: javascript jquery object recursion this

鉴于以下<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会引发上述错误,是否有任何修复?

4 个答案:

答案 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.fthis.dthis.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.fthis.dthis.checkCollisionthis.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