Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

JavaScript this is undefined when function called in a loop

I have the following code with the behavior explained in the comments. What could be the reason why "this" is undefined in the anonymous function?

const getLength = (str) => {
  return str.length
}

const getDefaultValues = () => {
  const valueGetters = {
    A: {
      AA: {
        xpath: 'path',
        getValue: function () {
          return getLength(this.xpath) // <---- this is not undefined and returns value
        }
      },
      AB: {
        xpath: 'path',
        getValue: function () {
          return getLength(this.xpath) // <---- this is not undefined and returns value
        }
      },
      AC: {
        xpath: 'path',
        getValue: function () {
          return getLength(this.xpath) // <---- this is not undefined and returns value
        }
      },
      AD: {
        xpath: 'path',
        getValue: function () {
          return getLength(this.xpath) // <---- this is not undefined and returns value
        }
      },
      AE: {
        xpath: 'path',
        getValue: function () {
          return getLength(this.xpath) // <---- this is not undefined and returns value
        }
      },
      GROSS: function () { // <--- when called in the loop, this returns 0 because all the ternary operators evaluate to false and return 0
        // console.log('this', this) // <---- this is undefined
        const aa = this?.AA ? this.AA.getValue() : 0
        const ab = this?.AB ? this.AB.getValue() : 0
        const ac = this?.AC ? this.AC.getValue() : 0
        const ad = this?.AD ? this.AD.getValue() : 0
        const ae = this?.AE ? this.AE.getValue() : 0

        return aa + ab + ac + ad + ae
      }
    }
  }

  console.log('Calling without looping', valueGetters.A.GROSS()) // <--- This prints the correct value for gross without any problem

  // get the numerical values from the getters
  const valueEntries = Object.entries(valueGetters).map(([key, defaultValueGetter]) => {
    return [
      key,
      Object.entries(defaultValueGetter).map(
        ([defaultValueKey, defaultValue]) => [
          defaultValueKey,
          typeof defaultValue === 'function' ? defaultValue() : defaultValue.getValue() // <--- I suspect that the problem is with this line
        ]
      )
    ]
  })

  return makeObject(valueEntries)
}

const makeObject = (arr) => {
  return Object.fromEntries(
    arr.map(([key, val]) => (Array.isArray(val) ? [key, makeObject(val)] : [key, val]))
  )
}

console.log(getDefaultValues())

>Solution :

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

You’re just calling the function in the form defaultValue(), which doesn’t provide a this context. You need to provide the this value explicitly, which you can do with .call().

typeof defaultValue === 'function' ? 
    defaultValue.call(defaultValueGetter) : 
    defaultValue.getValue()
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading