-1

I have the next code:

const obj = {
    name:  'Hi',
    first: () => {
        return this
    },
    other: {
        name: 'last',
        sec: function() {
            this.c = '2'
            return function() {
                this.s = '3'
                return this; // expect {s:3}
            }
        }
    }
}


const t = obj.other.sec()
console.log(t())

In console.log i expect {s:3} but there is not that object.
Question: Why there is not {s:3}? Or function() should have its own context

Asking
  • 3,487
  • 11
  • 51
  • 106

1 Answers1

1

It's not there because this in JS is dynamic and depends on the scope.

  1. Arrow functions don't have their own scope, so obj.first() will not return you obj but instead returns the global context (in a browser, usually window) or undefined when running in strict mode!
  2. Functions via function do have a dedicated scope. However, when you call obj.other.sec(), the context of this in the sec function points to obj.other, not obj.
  3. The function returned by obj.other.sec() does (or rather: can) create a new scope, since it's called without a context. But since it's also called without new, this points to the global context (see point 1).

Depending on what you want to achieve, the simplest solution is to replace this with the correct context. For example, if you want all function to run in the context of obj, just replace every this with obj:

const obj = {
    name:  'Hi',
    first: () => {
        return obj;
    },
    other: {
        name: 'last',
        sec: function() {
            obj.c = '2'
            return function() {
                obj.s = '3'
                return obj;
            }
        }
    }
}


const t = obj.other.sec()
console.log(t()) // <-- now logs `obj` with a `c` and an `s` property added

Or maybe you want varying context's:

const obj = {
    name:  'Hi',
    first: () => {
        return obj;
    },
    other: {
        name: 'last',
        sec: function() {
            obj.other.c = '2'
            return function() {
                obj.other.s = '3'
                return obj.other;
            }
        }
    }
}


const t = obj.other.sec()
console.log(t()) // <-- now logs `obj.other` with a `c` and an `s` property added

And in case obj.other.sec() should return a new object that is not related to obj or obj.other, then... well... just return a new object:

const obj = {
    name:  'Hi',
    first: () => {
        return obj;
    },
    other: {
        name: 'last',
        sec: function() {
            obj.other.c = '2'
            return function() {
                return { s: 3 };
            }
        }
    }
}


const t = obj.other.sec()
console.log(t()) // <-- now logs a new object with an `s` property

You can read more about the dynamic nature of this on MDN

David
  • 3,552
  • 1
  • 13
  • 24
  • a question regarding `obj.other.sec()()`, why in this case i get undefined? In this case `sec` has a returned function, but why it is undefined, should't it use this context `this.c = '2'`? – Asking Dec 02 '22 at 10:02