为什么我的对象的属性不能在JavaScript中更新?

时间:2017-05-19 22:29:43

标签: javascript

我有一个函数,我为构造函数调用 ...

准备了这个函数
function Queue() {
  if (!(this instanceof Queue)) return new Queue();
    this.capacity = {};
    this._count = 0;
}

这些方法正在Queue的原型属性上设置......一切都是正确的吗?

  Queue.prototype.enqueue = function(name, options) {
    this.capacity[name] = options || {};
    this.count();
    if (this._count > 5) {
      return 'Max capacity has been reached—which is five, please dequeue....'
    }
  };

  Queue.prototype.count = function() {
    var total = Object.keys(this.capacity);
      total.forEach(function(elem) {
        this._count++
      });
      if (this._count == 1) {
        console.log(this.capacity[Object.keys(this.capacity)])
      console.log( 'There is one item in the queue');
      } else {
        console.log(this.capacity[Object.keys(this.capacity)])
        console.log( 'There are ' + this._count + ' items in the queue');
      }
   };

我的问题如何在enqueue / count方法触发时让this._count递增?我一直在说:

There are 0 items in the queue

我知道我可以将它添加到.prototype属性上并将其放在count函数中并让它引用一个局部变量...

Queue.prototype.count = function() {
    var total = Object.keys(this.capacity), count = 0;
    total.forEach(function(elem) {
      this.count++
    });

Queue.prototype.call = call //< - 奇怪的没有?

if (this.count == 1) {
    console.log(this.capacity[Object.keys(this.capacity)])
  console.log( 'There is one item in the queue');
} else {
     console.log(this.capacity[Object.keys(this.capacity)])
  console.log( 'There are ' + this.count + ' items in the queue');
}

};

但这似乎并不优雅......

提前致谢!

3 个答案:

答案 0 :(得分:2)

您需要在forEach

中绑定它
Queue.prototype.count = function() {
    var total = Object.keys(this.capacity);
      total.forEach(function(elem) {
        this._count++
      }.bind(this)); //bind the context
      if (this._count == 1) {
        console.log(this.capacity[Object.keys(this.capacity)])
      console.log( 'There is one item in the queue');
      } else {
        console.log(this.capacity[Object.keys(this.capacity)])
        console.log( 'There are ' + this._count + ' items in the queue');
      }
   };

答案 1 :(得分:1)

尝试以下修改(绑定函数):

total.forEach(function(elem) {
   this._count++
}.bind(this));

问题是this引用了与父函数不同的对象,因为在JS中,闭包不保留this,而是调用者决定this值。或者,您可以使用foreach的第二个thisArg参数。

答案 2 :(得分:1)

现有的答案为问题本身提供了很好的解决方案,我只是想我会详细说明原因。

this是执行上下文分配的引用。更明显地,它是由函数的调用站点确定的引用。由于您可以像在任何其他值中一样在JavaScript中传递函数,因此可能会导致该引用成为移动目标而导致的问题。

您的代码存在的问题是您在this内引用了forEachforEach将一个函数作为一个参数并调用它,因为this所指向的是由调用函数的位置决定的,而不是它定义的位置,当它得到的值是不同的调用。如果您处于严格模式,它最终会回落到任何全球环境或未定义。

有许多不同的方法可以解决这个问题。

您可以在变量上存储对外this的引用,并在其他函数中使用它。

var self = this;
total.forEach(function(elem) {
  self._count++;
});

您可以使用.bind。它是一个函数方法,它返回一个函数,该函数使用传入的对象作为this的引用,无论你在何处调用它。

total.forEach(function(elem) {
  this._count++;
}.bind(this));

或者您可以使用箭头功能。箭头函数不会创建自己的上下文,因此它们只会保持周围的this值。

total.forEach(() => {
  this._count++;
});

这是一个常见问题,这些都是有效的解决方案。在我看来,它们从最不优雅到最优雅。