2017-05-19 13 views
0

私はコンストラクタ呼び出しのために準備している機能を、持っている...JavaScriptでオブジェクトのプロパティが更新されないのはなぜですか?

function Queue() { 
    if (!(this instanceof Queue)) return new Queue(); 
    this.capacity = {}; 
    this._count = 0; 
} 

そして、これらの方法は、Queueのprototypeプロパティ...すべてコーシャ右側に設定されていますか?

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'); 
     } 
    }; 

私はときエンキュー/カウント方法火災インクリメントするthis._countを得るのですか私の質問は?私は得続ける:

There are 0 items in the queue 

は私が.prototype性質上、それを追加することができます知っていると置くカウント機能で、それは地元のVARを参照持っている...その

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

Queue.prototype.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'); 
} 

}

しかし、それはエレガントではないようです...

ありがとうございます!あなたが修正(機能をバインドする)は、次の試してみてください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'); 
     } 
    }; 
+0

'this._count + = Object.keys(this.capacity).length'に単純化することができます。そして、 '_count'をゼロにリセットするか、' + = 'の代わりに' = 'を使うことを意味しませんでしたか? –

答えて

2

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

問題は、thisは親関数とは異なるオブジェクトを参照するということですJSではクロージャがthisを保持しないので、代わりに呼び出し側がthisの値を決定するためです。または、foreachの2番目のthisArg引数を使用することもできます。

+0

を使用するか、またはレキシカルのこのバインディングに矢印関数を使用するか、古い 'var self = this;'を実行し、コールバック内で 'self'を使います。 –

+1

合意。解決策がたくさんあります。しかし私の推測では、ユーザーはソリューションがIE10、IE 11で動作することを望んでいます。他の方が、ES6構文をどこでも使用していたはずです。 – karthick

1

これをバインドする必要があり

1

既存の回答は問題自体に良い解決策を提供していますが、私はちょっと理由を詳しく説明したいと思っていました。

は、実行コンテキストによって割り当てられた参照です。より明白には、関数の呼び出しサイトによって決定される参照です。他の値と同様にJavaScriptで関数を渡すことができるので、その参照が動くターゲットであるという問題が発生する可能性があります。

コードに問題があるとは、thisの中にforEachが含まれていることです。 forEachは引数として関数を受け取り、それを呼び出します。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++; 
}); 

これは一般的な問題であり、これらはすべて有効な解決方法です。彼らは私の意見では、少なくとも最もエレガントに行く。

関連する問題