Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing this in a forEach loop results in undefined

Tags:

I'm iterating through an array using forEach in one of my Class's methods. I need access to the instance of the class inside the forEach but this is undefined.

var aGlobalVar = {};  (function () {      "use strict";    aGlobalVar.thing = function() {       this.value = "thing";      }    aGlobalVar.thing.prototype.amethod = function() {       data.forEach(function(d) {       console.log(d);       console.log(this.value);   }); } })();  var rr = new aGlobalVar.thing(); rr.amethod();  

I have a fiddle I'm working on here: http://jsfiddle.net/NhdDS/1/ .

like image 754
Mike Rifgin Avatar asked Oct 18 '13 09:10

Mike Rifgin


People also ask

Why does forEach return undefined?

The "Cannot read property 'forEach' of undefined" error occurs when calling the forEach method on an undefined value. To solve the error make sure to initialize the variable to the correct value and only call the forEach method on the correct data type.

How do you return a value from a forEach loop?

Using reduce() JavaScript's reduce() function iterates over the array like forEach() , but reduce() returns the last value your callback returns.

Does forEach skip undefined?

The premise is just wrong: forEach won't skip elements that are null or undefined. It skips elements that don't exist at all.


2 Answers

In strict mode if you call a function not through a property reference and without specifying what this should be, it's undefined.

forEach (spec | MDN) allows you to say what this should be, it's the (optional) second argument you pass it:

aGlobalVar.thing.prototype.amethod = function() {   data.forEach(function(d) {     console.log(d);     console.log(this.value);   }, this);   // ^^^^ } 

Alternately, arrow functions were added to JavaScript in 2015. Since arrows close over this, we could use one for this:

aGlobalVar.thing.prototype.amethod = function() {   data.forEach(d => {     console.log(d);     console.log(this.value);   }); } 
like image 57
T.J. Crowder Avatar answered Sep 23 '22 18:09

T.J. Crowder


Since you're using strict mode, when a function is called that isn't a property of an object, this will have the value undefined by default (not the global object). You should store its value manually:

var aGlobalVar = {};  (function () {     "use strict";      aGlobalVar.thing = function () {         this.value = "thing";        };      aGlobalVar.thing.prototype.amethod = function () {         var self = this;         data.forEach(function (element) {           console.log(element);           console.log(self.value);         });     }; })();  var rr = new aGlobalVar.thing(); rr.amethod(); 

Nowadays, with ES2015 you can also use arrow functions, which uses the this value of the outside function:

function foo() {   let bar = (a, b) => {     return this;   };    return bar(); }  foo.call(Math); // Math 

T.J. Crowder's solution of using the second argument of forEach also works nicely if you don't like the idea of the temporary variable (ES5 code: works in pretty much any browser these days, except IE8-).

like image 24
Qantas 94 Heavy Avatar answered Sep 22 '22 18:09

Qantas 94 Heavy