numblock numblock - 18 days ago 6
Javascript Question

es6 exported object values not updated?

I'm exporting a factory function in ES6, which returns an object with properties.
When calling the factory, the object is created, but its values don't update.

Example:

// factory.js
let counter = 1;
let factory = () => {
let increment = function(){
counter++;
}

return { counter, increment };
}

export default factory;


// main.js
import factory from './factory';

let f = factory();
console.log(f.counter); // =>1
f.increment();
console.log(f.counter); // => stil 1, not 2?


Can someone explain why this is happening? Is it an ES6 feature, or something to do with the fact that I am using webpack and babel (es2015-preset)?

I have found this, but that doesn't describe the same use-case: http://exploringjs.com/es6/ch_modules.html#sec_imports-as-views-on-exports

Answer

In JavaScript primitive types are passed by value.

let counter = 1;

let factory = () => {

  ...

  // The property `counter` in this object gets passed a value of the `counter` declared in the scope of `factory.js`.
  // It does not get a reference.
  return { counter, increment };
}

When you return the object from the factory function, its property counter is assigned a value from the counter declared in the scope of factory.js. This essentially means the counter property on the object received a copy of the value – there is nothing linking the value of the counter variable and the counter property.

let counter = 1;

let factory = () => {
  let increment = function () {
    // The `++` operates on the `counter` variable declared in the scope of `factory.js`.
    // There is no link between the value `counter` in the scope of `factory.js` and the `counter` as the property of the object returned.
    // As a result when the `counter` variable is incremented, the `counter` property remains the same as the value initially passed to it.
    counter++;
  };
};

When you increment the counter, you are incrementing the value of the variable declared in the scope of factory.js. The variable's value is a Number therefore being a primitive. Primitive values are passed by value so there is no link between the variable counter and the property counter.

Hopefully all that makes sense. If you want to do some more reading on this idea of passing by value (compared to passing by reference) you can see the following StackOverflow questions:

At this point in time you might be asking how can I fix this?

Instead of incrementing counter you need to increment this.counter. Like this:

let increment = () => {
  this.counter++;
};

This works because the context of this is the function factory. The counter property is on the variable you assigned the result of calling factory.