0

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())

4

1 Answer 1

3

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()
Sign up to request clarification or add additional context in comments.

1 Comment

Holy... (I don't know if we're allowed to complete that on here). That worked!! Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.