jQuery劫持了TypeScript的“ this”参考

时间:2018-08-17 15:31:51

标签: jquery typescript

我在TypeScript类中使用jQuery。

export class RedTextBox {
 private element : HTMLInputElement;
 private changed : Boolean;

 Attach(textbox : HTMLInputElement) {
   this.element = textbox;
   ChangeColor();
 }

 ChangeColor() {
  $(this.element).css("background", "red");

  $(this.element).on("change", function() { 
       this.Changed = true;  // 'this' here is not the object of Typescript      
   });
 }
}

在上面的代码中,我收到一条错误消息,指出未定义this.Changed。我检查了调试器,发现在jQuery事件中,“这”实际上是HTML元素而不是TypeScript对象。有替代的“ this”,还是我们可以强迫jQuery单独保留“ this”(无双关语)?

3 个答案:

答案 0 :(得分:3)

当您使用function定义匿名函数时,this未绑定到您在其中定义的实例,并且jQuery利用call / apply给出了一个匿名函数。这些回调中的this的值。

最简单的解决方案是交换到箭头功能:

$(this.element).on("change", () => {
  this.Changed = true;      
});

定义箭头功能时,箭头功能内部的this的值与该功能定义范围内的this的值相关。

另一种不太理想的选择是thatself的经典用法:

const self = this;
$(this.element).on("change", function() {
  self.Changed = true;      
});

编辑

最后一点,如果您已经有一个函数并且不能使用上述选项之一来访问外部作用域的上下文,则可以使用以下命令强制this成为函数内部的内容Function.prototype.bind。如果您的事件处理程序/回调是类的成员,则此示例最相关。

ChangeColor() {
  $(this.element).on("change", this.HandleChange.bind(this))
}

HandleChange() {
  this.Changed = true;
}

这仅适用于对bind的调用,如果您忘记绑定它,那么最终会遇到与开始时相同的问题。另外,由于每次调用bind都必须创建一个新函数,因此这样的动态绑定会变得很昂贵。因此,通常情况下,您可以将您分发的函数预先绑定到构造函数中。

class RedTextBox {
  constructor() {
    this.HandleChange = this.HandleChange.bind(this);
  }

  ChangeColor() {
    $(this.element).on("change", this.HandleChange);
  }

  HandleChange() {
    this.Changed = true;
  }
}

请注意,我如何仅在构造函数中绑定一次,然后将引用自由传递给this.HandleChange作为回调。

答案 1 :(得分:2)

好吧,劫持不是jquery。这就是javascript的工作方式。当您传递回调时,回调“调用方”将范围“ this”带到自身。 当使用ES6或更高版本时(如果我没记错的话),您可以使用=>函数,并通过这样做来保持顶点。像这样:

export class RedTextBox {
private element : HTMLInputElement;
 private changed : Boolean;

 Attach(textbox : HTMLInputElement) {
   this.element = textbox;
   ChangeColor();
 }

 ChangeColor() {
  $(this.element).css("background", "red");

  $(this.element).on("change", /* THIS PART */() => { 
       this.Changed = true;  // 'this' here is not the object of Typescript      
   });
 }
}

答案 2 :(得分:2)

此行为是Javascript函数工作的标准方式。如果将函数传递给jQuery,则jQuery将决定将什么this传递给函数,即使该函数最初是类的方法。

ES2015添加箭头函数(=>),它们从声明上下文中捕获this,这可能是您应该使用的:

$(this.element).on("change", () => { 
   this.Changed = true;  // this is capture from the class 
});