在forEach中调用类函数:Javascript如何处理“this”关键字

时间:2015-01-22 00:06:31

标签: javascript foreach this bind

我是Javascript的新手,只是想确保我理解它如何处理this关键字,因为......好吧,它看起来很混乱。我已经在StackOverflow上查看了类似的问题,并希望确保我没有向前推进错误的想法。

所以我正在定义一个类似的类,并希望处理构造函数中收到的每个点。

function Curve(ptList) {
  this.pts = [];

  if(ptList.length > 2) {
    // I want to call "addPoint" for every item in ptList right here
  }
}

Curve.prototype.addPoint = function(p) { 
  this.pts.push(p);
  /* some more processing here */ 
}

所以,最初我以为我可以做到:

ptList.forEach(this.addPoint);

但我不能,因为那只是传递指向原型函数的指针,这意味着this中的addPoint指的是全局对象。

然后我尝试了:

ptList.forEach(function(p) { this.addPoint(p); });

但我不能,因为this只要我输入内部函数(它不再引用正在构造的Curve对象)就引用全局范围,所以{{1}是未定义的。

解决这个问题的方法是在一个范围内创建一个引用addPoint的变量,我仍然可以在子功能中与之交谈:

this

这最终有效(但对没有JS经验的人来说看起来很奇怪)。但后来我发现了var _this = this; ptList.forEach(function(p) { _this.addPoint(p); }); 函数,它让我无法定义一个简单的函数包装器:

bind

看起来,最后,这是最好,最简洁的方法,甚至认为它看起来很傻。如果没有ptList.forEach(this.addPoint.bind(this)); 函数,bind无法理解调用它的对象,如果没有第一个addPoint,我甚至无法找到this函数。< / p>

有没有更好的方法来做这个看似简单的事情,还是推荐的最后一行代码?

2 个答案:

答案 0 :(得分:7)

forEach()方法和其他类似的数组方法(如map()filter())专门为此提供了一个名为thisArg的可选参数。

这用作调用函数时提供给函数的this“参数”:

ptList.forEach(this.addPoint, this);

当这样的参数不可用时,选择使用闭包变量(变量名self通常用于此)或.bind()主要是偏好问题。请注意,另一个选项是在构造函数中定义函数并捕获闭包中的所有内容:

function Curve(ptList) {
  var pts = [];
  function addPoint(p) {
      pts.push(p);
  }

  if(ptList.length > 2) {
    ptList.forEach(addPoint);
  }

  this.addPoint = addPoint;
}

这需要比将函数放在原型上更多的内存,因为每个实例都有自己的副本(并且还排除了原型允许你做的一些事情),但Douglas Crockford(JSON和JSLint的发明者) )最近说他甚至不再使用this,理由是内存便宜,但CPU周期不是(遍历原型链需要相当多的处理)。

答案 1 :(得分:0)

通常的做法是var that = this。 JavaScript中的继承一开始看起来很奇怪,但你应该坚持使用常用的东西。像ptList.forEach(this.addPoint.bind(this))这样的事情会让下一个人混淆使用你的代码。

What does 'var that = this;' mean in JavaScript?