2

I've broken down my source code so that certain classes are responsible for creating and updating key objects in my application. The trouble is when I move those objects into separate modules and they are updated outside of the module, other modules do not reflect the updated object because it's not aware of the changes which have happened outside of the module.

For example below is a simplified example:

// config.js

class Config {
  constructor() {
    this.value = false
  }
  set(value) {
    this.value = value
  }
}

const config = new Config()

export default config
//output.js

import config from './config'

console.log(config.value) // -> false

// Use the config to return a new value
class Output {
  constructor() {
    this.data = config.value
  }
}

const output = new Output()

export default output
//index.js

import config from './config'
import output from './output'

config.set(true) // Value set by user of application

console.log(config.value) // -> true
console.log(output.data) // -> false

I know why this doesn't work as I want, but I don't know how to I should be dealing with this situation. Currently, the only way I can think to get around this issue is to pass the updated object to each class as a parameter of its constructor. However, in my actual application, it's much more complicated than this example and it gets very messy having to import the updated object into each class or function which needs it.

You can see an example of the actual source code where I am passing config, theme and data through the constructor to get around it.

What's the better way to deal with this issue?

3
  • this.data = config.value this line is your problem. config.value is a boolean, which is copied by value on write. It doesn't hold the reference to the config object. This has nothing to do with imports/exports. Also please don't used reserved key words as method names, that's asking for trouble. Commented Sep 3, 2019 at 14:31
  • I realise that this isn't exclusive to imports and exports, but I didn't know how else to explain my situation (because when all in one file the problem doesn't necessarily show itself). How should I be correctly referencing the config object? Thanks for the advice about avoiding using reserved keywords as method names. Commented Sep 3, 2019 at 14:44
  • 1
    see FullStackGuy's answer. The thing is, just like pretty much every other language, in Javascript you have primitive types (undefined, strings, numbers, booleans, symbols) and reference types (everything else like arrays, objects, etc). When you make an assignment like let foo = x if x evaluates to a primitive type the value of foo is determined on assignment (write). But if x is a reference type, then foo is a reference to x and what value foo has is determined when it is dereferenced (read). And it doesn't matter if it's x or x.someProperty, the same rules apply. Commented Sep 3, 2019 at 15:45

1 Answer 1

3

In your output.js file, you are copying the value of config.value in the constructor when the object is instantiated. After the instantiation you are exporting the object initialized with false.

Now in the index.js you are accessing the value of output.data after you changed the value property in config to true, but the thing is when the output object was instantiated the value of the data property was copied over from the config.value and does not maintain a reference to it. This is because the value is a primitive and not an object reference.

So to fix this you need to use the config object reference which is already imported in your module, so that when the object state is changed you get the updated value through the reference:

import config from './config.js'

class Output {
  get data(){
    return config.value;
  }
}

Here I created a getter having the name data which reads the data directly from the config object reference.

Now when you change the value through the set method of config the new value would be reflected:

config.set(true);

console.log(config.value) // -> true
console.log(output.data) // -> true
Sign up to request clarification or add additional context in comments.

4 Comments

you don't have to add config to a class instance since it's already in scope and can be accessed through config.value
@marzelin oh my how can I miss the import! you're right, let me update that right away!
Thanks very much for showing me that. I knew that there was an issue with the way the object was instantiating a value which didn't maintain a reference to it, but I couldn't explain as clearly as you have. I would like to maintain the source code for using the updated config value, inside the output.js module, therefore from your example, I have concluded that I will need to call the getter output.data, when config.set(true) is called (inside the Config class set method). This will mean I'll need to import the instance of output into config.js as well. Is this an ok practice?
Here is a jsfiddle with an example. I've commented out where the imports would be if there were in separate files. jsfiddle.net/6emxbzkg/2

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.