0

Code 1 - this.kitchenStatus() inside forEach is unreachable

I am having trouble accessing the value of a function (this.kitchenStatus()) from inside a forEach, when I try the below I get "Uncaught TypeError: this.kitchenStatus is not a function":

const KitchenUtensil = function () {
    // Pay attention to this.kitchenStatus(), this is the function 
    // I want to get the values from inside the loops
    this.kitchenStatus = function () {
        let kStatus = "Kitchen open.";
        return kStatus;
    };
    let utensilsArray = ["spoon", "fork", "kettle"];

    // 1. WITH FOREACH FUNCTION
    utensilsArray.forEach(function (utensil) {
        let utensilLine = "In a forEach loop function:" + "\n";
        utensilLine += "It's a " + utensil 
        + ". " 
        // If you want to see it breaking uncomment the code below:
        // + this.kitchenStatus() 
        ;
        console.log(utensilLine);
    });

};

let teapot = new KitchenUtensil ();

Code 2 - this.kitchenStatus() inside for loop is accessible

So, I tried to use a simple for loop and it worked:

const KitchenUtensil = function () {
    // Pay attention to this.kitchenStatus(), this is the function 
    // I want to get the values from inside the loops
    this.kitchenStatus = function () {
        let kStatus = "Kitchen open.";
        return kStatus;
    };
    let utensilsArray = ["spoon", "fork", "kettle"];

    // 2. WITH FOR LOOP
    for (let i = 0; i < utensilsArray.length; i++) {
        let utensilLine2 = "In a simple for loop:" + "\n";
        utensilLine2 += "It's a " + utensilsArray[i] 
        + ". " 
        // Unlike the forEach, the for loop can access the function:
        + this.kitchenStatus() 
        ;
        console.log(utensilLine2);
    };
};

let teapot = new KitchenUtensil ();

Code 3 - this.kitchenStatus() value assigned to a new variable and invoking new variable from inside the forEach - it works, but hey it looks like a crappy solution

I didn't give up on the forEach and did a workaround. Instead of trying to access this.kitchenStatus from inside the forEach function, I created a new variable "letMeIn" outside the loop and assigned the value of this.kitchenStatus() to it then from inside the loop I invoked letMeIn. It works but it doesn't feel right at all, I just created a new piece of code which only function is to serve as a go-to to another piece of code just a few lines below:

const KitchenUtensil = function () {
    // Pay attention to this.kitchenStatus(), this is the function 
    // I want to get the values from inside the loops
    this.kitchenStatus = function () {
        let kStatus = "Kitchen open.";
        return kStatus;
    };
    let utensilsArray = ["spoon", "fork", "kettle"];

    // 3. THE ONLY WAY TO GET FOREACH TO ACCESS THE FUNCTION
    // Before the loop function is declared create a variable 
    // (e.g. letMeIn) and assign the value of this.kitchenStatus to it
    // This looks like a really crappy and unprofessional workaround:
    let letMeIn = "From a variable: " + this.kitchenStatus();
    utensilsArray.forEach(function (utensil) {
        let utensilLine = "In a forEach loop function:" + "\n";
        utensilLine += "It's a " + utensil 
        + ". " 
        // Once inside the loop invoke the variable:  
        + letMeIn 
        ;
        console.log(utensilLine);
    });

};

let teapot = new KitchenUtensil ();

Code 4 - this.kitchenStatus() value is found by forEach if the main constructor fucntion is invoked as a simple function instead of using new

Finally the last thing I tried was to invoke the constructor (?) function KitchenUtensil as a simple function by using "new KitchenUtensil ()" instead of "let teapot = new KitchenUtensil ()":

const KitchenUtensil = function () {
    // Pay attention to this.kitchenStatus(), this is the function 
    // I want to get the values from inside the loops
    this.kitchenStatus = function () {
        let kStatus = "Kitchen open.";
        return kStatus;
    };
    let utensilsArray = ["spoon", "fork", "kettle"];
    
    utensilsArray.forEach(function (utensil) {
        let utensilLine = "In a forEach loop function:" + "\n";
        utensilLine += "It's a " + utensil 
        + ". " 
        // Now it will work, why???:
        + this.kitchenStatus() 
        ;
        console.log(utensilLine);
    });

};

// 4. INVOKE FUNCTION WITHOUT NEW
// Just comment the next line, and instead of invoking as a constructor:
// let teapot = new KitchenUtensil ();
// Invoke the then constructor directly as a simple function:
KitchenUtensil ();

What is going on? What do I have to do in other to get the forEach to find and access the this.kitchenStatus()function?

Community
  • 1
  • 1

1 Answers1

0

A function creates a new context, so this refers to this function. In order to make it work as you expect, you need to change function to () => {} (arrow) function in your forEach:

utensilsArray.forEach((utensil) => {
    let utensilLine = "In a forEach loop function:" + "\n";
    utensilLine += "It's a " + utensil 
    + ". " 
    // Now it will work
    + this.kitchenStatus() 
    ;
    console.log(utensilLine);
});

Another solution is to save this to a variable before the forEach():

const self = this;
utensilsArray.forEach(function (utensil) {
    let utensilLine = "In a forEach loop function:" + "\n";
    utensilLine += "It's a " + utensil 
    + ". " 
    // Now it will work too
    + self.kitchenStatus() 
    ;
    console.log(utensilLine);
});

More on how this works can be found in this great answer.

Sebastian Kaczmarek
  • 7,135
  • 4
  • 17
  • 36