var self =这个?


182

使用实例方法作为事件处理程序的回调将范围this“我的实例”更改为“无论什么叫回调”。所以我的代码看起来像这样

function MyObject() {
  this.doSomething = function() {
    ...
  }

  var self = this
  $('#foobar').bind('click', function(){
    self.doSomethng()
    // this.doSomething() would not work here
  })
}

它有效,但这是最好的方法吗?我觉得很奇怪


15
你应该避免self因为有一个window.self对象,你可能最终会使用意外,如果你忘了声明自己的self变种(如中移动一些代码时)。这可能很烦人,无法发现/调试。最好使用这样的东西_this
Alastair Maw 2014年


3
JavaScript的教程:“的值this是动态的JavaScript中这是当函数被确定。,而不是当它被宣布。”
DavidRR 2015年


问题是,在全球范围内self === this。因此,self在当地情况下有意义并遵循该模式。
程序员

Answers:


210

这个问题不是特定于jQuery,而是特定于JavaScript。核心问题是如何在嵌入式函数中“引导”变量。这是示例:

var abc = 1; // we want to use this variable in embedded functions

function xyz(){
  console.log(abc); // it is available here!
  function qwe(){
    console.log(abc); // it is available here too!
  }
  ...
};

此技术依赖于使用闭包。但这不能使用,this因为它this是一个伪变量,可能会随着范围的变化而动态变化:

// we want to use "this" variable in embedded functions

function xyz(){
  // "this" is different here!
  console.log(this); // not what we wanted!
  function qwe(){
    // "this" is different here too!
    console.log(this); // not what we wanted!
  }
  ...
};

我们可以做什么?将其分配给某个变量,并通过别名使用它:

var abc = this; // we want to use this variable in embedded functions

function xyz(){
  // "this" is different here! --- but we don't care!
  console.log(abc); // now it is the right object!
  function qwe(){
    // "this" is different here too! --- but we don't care!
    console.log(abc); // it is the right object here too!
  }
  ...
};

this在这方面不是唯一的:arguments是否应该以相同的方式对待其他伪变量-通过别名。


7
您确实应该将“ this”绑定到函数调用,而不要将其传递或遍历变量作用域
michael 2012年

10
@michael为什么?
克里斯·安德森

@michael,您可能正在管道,地图,订阅中工作,而在一个函数中而不是在调用函数,在这种情况下,“ this”正在更改,因此变量范围是解决方案
Skander Jenhani

@SkanderJenhani评论已8岁。我今天的回答将大不相同
michael

18

是的,这似乎是一个通用标准。一些编码人员使用自我,其他编码人员使用我。它用作对与事件相反的“真实”对象的引用。

这让我花了一点时间才能真正了解,起初看起来确实很奇怪。

我通常在对象的顶部执行此操作(对不起,我的演示代码-它比其他任何概念都更具概念性,并且不适合精通编码技术):

function MyObject(){
  var me = this;

  //Events
  Click = onClick; //Allows user to override onClick event with their own

  //Event Handlers
  onClick = function(args){
    me.MyProperty = args; //Reference me, referencing this refers to onClick
    ...
    //Do other stuff
  }
}

12
var functionX = function() {
  var self = this;
  var functionY = function(y) {
    // If we call "this" in here, we get a reference to functionY,
    // but if we call "self" (defined earlier), we get a reference to function X.
  }
}

编辑:尽管如此,对象中的嵌套函数还是采用全局窗口对象,而不是周围的对象。


您似乎正在描述做什么var self = this,但这不是问题要问的问题(问题是问这是否是解决问题的最佳方法)。
昆汀2015年

3
“核心问题是如何在嵌入式函数中“引导”变量。” 我同意接受的答案中的这一说法。除此之外,“那个”实践没有错。这很普遍。因此,作为“代码对我来说看起来很奇怪”部分的答案,我选择解释其工作原理。我相信“代码对我来说看起来很奇怪”的原因是由于代码的工作方式混乱。
serkan 2015年

12

如果您正在执行ES2015或正在执行类型脚本和ES5,则可以在代码中使用箭头函数,并且不会遇到该错误,这是指实例中所需的作用域。

this.name = 'test'
myObject.doSomething(data => {
  console.log(this.name)  // this should print out 'test'
});

5
作为说明:在ES2015中,箭头函数this从其定义范围捕获。普通的函数定义不会这样做。
defnull

@defnull我认为这没什么特别的。函数创建块作用域。因此,使用箭头符号代替函数会使您无法创建范围,因此,这仍将引用外部this变量。
Nimeshka Srimal '17

4

一种解决方案是使用javascript将所有回调都绑定到对象 bind方法。

您可以使用命名方法来执行此操作

function MyNamedMethod() {
  // You can now call methods on "this" here 
}

doCallBack(MyNamedMethod.bind(this)); 

或使用匿名回调

doCallBack(function () {
  // You can now call methods on "this" here
}.bind(this));

进行这些操作而不是诉诸于var self = this您将了解如何this javascript行为,并且不依赖于闭包引用。

另外,ES6中的胖箭头运算符基本上与.bind(this)匿名函数调用相同:

doCallback( () => {
  // You can reference "this" here now
});

就我个人而言,我认为.bind(this)只是类型更多,将对this的引用更改为我(或其他),然后仅使用它就可以使代码更简洁。胖箭头是未来。
davidbuttar

3

我没有使用jQuery,但是在Prototype之类的库中,您可以将函数绑定到特定范围。因此,请记住,您的代码将如下所示:

 $('#foobar').ready('click', this.doSomething.bind(this));

bind方法返回一个新函数,该函数使用您指定的范围调用原始方法。


类似:$('#foobar').ready('click', this.doSomething.call(this));对吗?
Muers

bind方法在较旧的浏览器中不起作用,请改用该$.proxy方法。
加法2015年

2

由于箭头功能,在ES6中只需添加一点,您就不需要这样做,因为它们捕获了this值。


1

我认为这实际上取决于您在doSomething函数内部要做什么。如果要MyObject使用此关键字访问属性,则必须使用它。但是我认为,如果您不使用object(MyObject)属性做任何特殊的事情,下面的代码片段也将起作用。

function doSomething(){
  .........
}

$("#foobar").ready('click', function(){

});
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.