对象

时间:2016-06-30 16:16:46

标签: javascript

这(下面)最终给出了“超出最大调用堆栈大小”错误。看起来这是由于“this.actions”对象中“this”的解释方式。在该对象中,“this”是指那个对象,还是Unit类的实例?如果是前者,将.bind(this)放在“this.actions”对象的末尾,使“this”引用类实例代替?如果是这样,为什么?如果没有,为什么不呢?

function Unit(){
  this.move = function(direction){
    switch(direction){
      case 'up': { console.log('foo'); break; }
      case 'down': { console.log('foooo'); break; }
    }
    console.log('bar');
  }
  this.shoot = function(){console.log('zap')}

  this.actions = {
    'moveUp' : function(){ this.move('up') },
    'moveDown' : function(){ this.move('down') },
    'shoot' : function(){ this.shoot() }
  }

  return this
}

4 个答案:

答案 0 :(得分:2)

使用bind

原因:

让我们说:

var r = new Unit();

当你拨打r.actions.moveup()时,这个'传递函数中传递的是动作。

function Unit(){
  this.move = function(direction){
    switch(direction){
      case 'up': { console.log('foo'); break; }
      case 'down': { console.log('foooo'); break; }
    }
    console.log('bar');
  }
  this.shoot = function(){console.log('zap')}

  this.actions = {
    'moveUp' : function(){ this.move('up') }.bind(this),
    'moveDown' : function(){ this.move('down') }.bind(this),
    'shoot' : function(){ this.shoot() }.bind(this)
  }

  return this
}

答案 1 :(得分:2)

this对象中的关键字actions将引用actions对象。

一些可能的修复可能如下所示:

function Unit(){
  var self = this;
  this.move = function(direction){
    switch(direction){
      case 'up': { console.log('foo'); break; }
      case 'down': { console.log('foooo'); break; }
    }
    console.log('bar');
  }
  this.shoot = function(){console.log('zap')}

  this.actions = {
    'moveUp' : function(){ this.move('up') }.bind(self),
    'moveDown' : function(){ this.move('down') }.bind(self),
    'shoot' : function(){ this.shoot() }.bind(self)
  }

  return this
}

或者,当您调用这些方法时,可以使用callapply

例如:

var coolUnit = new Unit();
Unit.actions.moveUp.call(coolUnit);

在对象的上下文中理解this需要一些工作,但这里有一些资源:

How does the "this" keyword work?

http://unschooled.org/2012/03/understanding-javascript-this/

http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/

TL; DR - 有一系列心理规则"您可以使用它来帮助跟踪给定上下文中this的内容。例如。 左边的规则,其中"点"左边的对象得到this绑定。

Object.foo() <- `this` in the method `foo` will point to `Object`

使用&#34;规则&#34;如上所述,您可以合理化new Unit.actions.moveUp()this绑定集设置为指向actions对象,因为它的是左边的

或者您可以使用call / bind / applythis绑定到您希望的上下文,如上所示。

答案 2 :(得分:1)

另一种解决方案:this不是变量。嵌套函数可以访问“父”函数(clousure)中定义的所有变量 - 您可以创建变量,为其分配this,并使用它而不是this,它会做你做的事情想要和期待:

function Unit(){
  var self = this;
  self.move = function(direction){
    switch(direction){
      case 'up': { console.log('foo'); break; }
      case 'down': { console.log('foooo'); break; }
    }
    console.log('bar');
  }
  self.shoot = function(){console.log('zap')}

  self.actions = {
    'moveUp' : function(){ self.move('up') },
    'moveDown' : function(){ self.move('down') },
    'shoot' : function(){ self.shoot() }
  }

  return self
}

答案 3 :(得分:0)

最近我遇到了关于此问题的this article

在4.2节中,他使用了一个类似于你的代码的例子,突出了遗忘&#39; new&#39;的缺陷。 &#39;这&#39;在函数调用中指向全局对象(窗口或浏览器),因此当您返回它时,将函数放在全局对象上,然后返回对它的引用。如果您使用了新的Unit()并且没有返回它,那么您将得到一个包含您的函数的对象。

你可以使用bind,但我认为它会像Unit.bind(Unit)那样看起来很奇怪。

您也可以使用工厂功能返回对象,您不必担心忘记新的

function Unit(){

  var move = function(direction){
    switch(direction){
       case 'up': { console.log('foo'); break; }
       case 'down': { console.log('foooo'); break; }
    }
    console.log('bar');
  };
  var shoot = function(){console.log('zap')};

  var actions = {
    moveUp : function(){ move('up') },
    moveDown : function(){ move('down') },
    shoot : shoot
  };

 return {
    actions:actions
 };
}

var player1=Unit();

player1.actions.shoot();
player1.actions.moveDown();
player1.actions.moveUp();

我从调用移动中移除了这个,部分问题是动作是一个对象而不是一个函数,所以虽然你可以在对象内部的函数上使用bind,你可以像我在代码中那样关闭在函数上然后公开它。

此外,如果您使用self = this并且不使用new关键字,您仍然可以引用窗口/浏览器对象并创建全局范围。