1

Why variable "OnDone" stays unmodified inside factory scope?

const foo = () => {
  let OnDone = null;

  const Do = function() {
    console.log(OnDone);
    if (typeof OnDone === 'function')
      OnDone();
  }

  return {
    Do,
    OnDone
  };
}


let f = foo();
f.OnDone = () => {
  console.log('OnDone');
};

f.Do();

Outputs null. https://jsfiddle.net/xe4j9hmc/6/

Heretic Monkey
  • 11,687
  • 7
  • 53
  • 122
Borys Shobat
  • 258
  • 1
  • 3
  • 13

3 Answers3

2

let onDone = null defines a variable onDone inside foo function scope not a property, but when you do

f.onDone it adds value to onDone property on f which can be accessed using this.onDone but in your code you're using onDone which still refers to onDone defined in local scope


You probably wanted to do this

function foo(){
  this.OnDone = null;

  const Do = function() {
  console.log(this.OnDone);
  if (typeof this.OnDone === 'function')
    this.OnDone();
  }

  return {Do, onDone:this.OnDone};
}


let f = new foo();
f.OnDone = () => {
  console.log('OnDone');
};

f.Do();
Code Maniac
  • 37,143
  • 5
  • 39
  • 60
1
   return { OnDone };

equals ...

   return { onDone: onDone };

or in other words: The local variable onDone gets resolved, and the object reference it resolves to gets stored in the returned objects onDone property. Both will reference the same thing, * but* if you reassign either the local variable or the objects property, this will change the * reference*, thus the property and the variable will reference different things then.

To resolve the problem, change the object itself:

 const context = { onDone }
 context.Do = function () {
   // Access context.onDone here
 };

 return context;

Or, as an alternative, as f.Do() will call Do with this being f, you can access the objects property as this.OnDone from within the Do function.

Jonas Wilms
  • 132,000
  • 20
  • 149
  • 151
1

The other answers already explained what the problem is but I figured it would be useful to see a simplified example of the issue:

var foo = null;
var obj = {foo};
obj.foo = 42;
console.log(foo);

Here as well, logging the value of foo will print null. Assigning a new value to the obj.foo property does not change the variable foo. That's because when we create the object with {foo}, a copy of the value of foo is assigned to the property.

In your specific case you want the assignment to the property to also change the variable. You can do this via a setter (and we add a getter for good measure):

const foo = () => {
  let OnDone = null;

  const Do = function() {
    console.log(OnDone);
    if (typeof OnDone === 'function')
      OnDone();
  }

  return {
    Do,
    get OnDone() {
      return OnDone;
    },
    set OnDone(value) {
      OnDone = value;
    },
  };
}


let f = foo();
f.OnDone = () => {
  console.log('OnDone');
};

f.Do();

Now when you assign to the property f.OnDone we are really executing the setter function which in turn updates the variable value.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143