对象内“this”的范围

问题描述 投票:0回答:4

这(如下)最终给了我一个“超出最大调用堆栈大小”错误。这似乎是由于“this”在“this.actions”对象中的解释方式造成的。在该对象中,“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
}
javascript this
4个回答
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
}

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

call
apply

例如:

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

在对象的背景下理解

this
需要一些工作,但这里有一些资源:

“this”关键字如何工作?

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

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

TL;DR - 您可以使用一系列心理“规则”来帮助跟踪给定上下文中的

this
是什么。例如。 left-of-the-dot 规则,其中“点”左侧的对象获得
this
绑定。

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

使用上面提到的“规则”,您可以合理地认为

new Unit.actions.moveUp()
this
绑定设置为指向操作对象,因为它是 left-of-the-dot

或者您可以使用

call
/
bind
/
apply
this
绑定到您想要的上下文,如上所示。


2
投票

使用绑定

原因:

可以说:

var r = new Unit();

当你调用 r.actions.moveup() 时,moveup 函数中传入的 'this' 是 actions。

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
投票

另一种解决方案:

this
不是变量。嵌套函数可以访问“父”函数(闭包)中定义的所有变量——您可以创建变量,为其分配
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
}

0
投票

最近我遇到了这篇文章关于这个。

在第 4.2 节中,他使用了一个与您的代码类似的示例,并强调了忘记“new”的陷阱。函数调用中的“this”指向全局对象(窗口或浏览器),因此当您返回它时,您将函数放在全局对象上,然后返回对其的引用。如果您使用 new Unit() 并且不返回它,您将获得一个带有您的函数的对象。

你可以使用bind,但我认为它会类似于Unit.bind(Unit),这看起来很奇怪。

您还可以使用工厂函数来返回对象,并且您不必担心忘记 new

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();

我从 move 的调用中删除了 this ,部分问题是 actions 是一个对象而不是函数,所以虽然你可以在对象内部的函数上使用绑定,但你可以像我在代码中那样,只需关闭函数然后公开它。

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

© www.soinside.com 2019 - 2024. All rights reserved.