0

I have an object and in the scope of the current function I want to be able to turn its properties into variables of the same name.

The following code doesn't work but seem like the starting place for something like this:

let thingObject = {Thing: "Value",Thing2: "Value2"}

for ([key, value] of Object.entries(thingObject)) {
    eval(`let ${key} = '${value}'`)
}

I know in the browser there is the window object and in Node.js there is global so if I didn't care about scope I could probably do something like:

for ([key, value] of Object.entries(thingObject)) {
    global[key] = value
}

This is much better as it properly retains the type value but I need to do this many times without polluting any global object.

Object destruction syntax would do the trick with something like:

let {Thing, Thing2} = thingObject

Except I don't know the keys ahead of time.

This answer to another question seems relevant but I am struggling to make use of it to solve this problem.

How can I create variables from properties of an object without knowing the property names within the current scope?


Context:

This is used to process templates where the creators of the templates will use template literals like `${Thing}-other stuff/${Thing2}`.

They will then call my generic function passing in an object that contains properties for each of the variables they used in the template.

They will both know the names when calling my function and reference those names in their template but my code in between will be generalized not to care about either side.

The reason to use variables is to make the templates cleaner as having to include the name of some variable container object in the templates makes them more verbose than needed, Ex: `${VariablesObject.Thing}-other stuff/${VariablesOjbect.Thing2}`.

Chris Magnuson
  • 5,780
  • 7
  • 34
  • 37
  • 5
    And why would you want to do that? If you don't know their names, you won't be able to use them afterwards. Why not use the properties of the object directly? They are the same as variables. – jorbuedo Apr 29 '19 at 22:35
  • `with(thingObject) { console.log(Thing); }`. But since you don't know the properties, you cannot actually access `Thing`. So yeah, quite unclear what problem you are trying to solve here. – Felix Kling Apr 29 '19 at 22:46

3 Answers3

1

You can't, and you shouldn't. How are you going to use those variables if you don't know their names? Simply use them as you have them, as object properties.It's the same thing as variables and they already have a scope, the object itself, so no pollution outside of it.

jorbuedo
  • 2,041
  • 1
  • 8
  • 20
  • This is used to process templates where all the creators of the template will use template literals like ```${Thing}-other stuff/${Thing2}```. They will then call my generic function passing in an object that contains properties for each of the variables they used in the template. They will both know the names when calling my function and reference those names in their template but my code in between will be generalized not to care about either side. – Chris Magnuson Apr 30 '19 at 00:50
  • Still, no can do. You'll have to rethink your needs a little bit, because the way you want it isn't possible. How are these templates made? How much code do you users provide? If there's webpack and different files involved, you could try something with the imports. Otherwise, your best bet is use it as an object, and teachyour users to use object destructuring to remove the verbosity. – jorbuedo Apr 30 '19 at 07:58
0

You can use this to attach the key and assign the variable:

let thingObject = {Thing: "Value",Thing2: "Value2"}
for ([key, value] of Object.entries(thingObject)) {
    this[key] = value;
    console.log(this[key]);
}
Matt Kuhns
  • 1,328
  • 1
  • 13
  • 26
0

It looks like if it was possible with eval the following would be a way to do this:

let variablesObject = {Thing: "Value", Thing2: "Value2"}

let destructureFragment = []
let keys = Object.keys(variablesObject)

for (let i = 0; i < keys.length; i++) {
    destructureFragment.push(`[keys[${i}]]: variablesObject[keys[${i}]]`)
}

let joinedDestructuredFragments = destructureFragment.join(", ")
let destructureStatement = `({${joinedDestructuredFragments}} = variablesObject)`

eval(destructureStatement)

This however doesn't work as it looks like variables defined in an eval are only available in the rest of the code executed in the eval when in strict mode.

The work around listed in that link also did not in NodeJS 12:

var geval = eval
geval(destructureStatement)

At this point it doesn't seem possible but with some more thought it might be possible to take all the code that needs those variables and execute it within the eval as well and just get the return value from the whole process.

Will update if I find more.

Chris Magnuson
  • 5,780
  • 7
  • 34
  • 37