0

New to Js, sorry if this is an obvious one.

I have some strings in my code that correspond to the names of variables. I'd like to put them into a function and have the function be able to make changes to the variables that have the same names as the strings.

The best example is where this 'string' is passed through from a data tag in html, but I have some other situations where this issue appears. Open to changing my entire approach too is the premise of my question is backwards.

<html>
<div  data-location="deck" onClick="moveCards(this.data-location);">
</html>
var deck = ["card"];
function moveCards(location){
location.shift();};

Thanks!

Pat Mifsud
  • 41
  • 2
  • Check out how to create variable variables in JS: https://stackoverflow.com/questions/5187530/variable-variables-in-javascript – Nick Parsons Sep 07 '19 at 05:59

4 Answers4

1

A script should not depend on the names of standalone variables; this can break certain engine optimizations and minification. Also, inline handlers are nearly universally considered to be pretty poor practice - consider adding an event listener properly using Javascript instead. This will also allow you to completely avoid the issue with dynamic variable names. For example:

const deck = ["card", "card", "card"];

document.querySelector('div[data-location="deck"]').addEventListener('click', () => {
  deck.shift();
  console.log('deck now has:', deck.length + ' elements');
});
<div data-location="deck">click</div>
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • Thanks! updating my script to use query selectors and event listeners. The only problem that this suggestion gives me, and one that I should have probably described better in my question, is that I would need a bespoke function for each location (e.g. deck) in this case, and there are a lot of locations that all need the same thing to happen. Is there any way I could make that function once for a variety of variables? – Pat Mifsud Sep 07 '19 at 06:21
  • Iterate over all elements that need the event listener added, and add the listener, eg `querySelectorAll(..).forEach((elm) => elm.addEventListener(...` including a `NodeList.prototype.forEach` polyfill if needed – CertainPerformance Sep 07 '19 at 06:24
0

I'm not sure I 100% follow what you're trying to do, but rather than trying to dynamically resolve variable names you might consider using keys in an object to do the lookup:

const locations = {
  deck: ['card']
}

function moveCards (location) {
  // if 'deck' is passed to this function, this is
  // the equivalent of locations['deck'].shift();
  locations[location].shift();
};

Here's a working demo:

const locations = {
  deck: ['card 1', 'card 2', 'card 3', 'card 4']
};

function move (el) {
  const location = el.dataset.location;
  const item = locations[location];
  item.shift();
  updateDisplay(item);
}

// update the display so we can see the list
function updateDisplay(item) {  document.getElementById('display').innerHTML = item.join(', ');
}

// initial list
updateDisplay(locations['deck']);
#display {
  font-family: monospace;
  padding: 1em;
  background: #eee;
  margin: 2em 0;
}
<div data-location='deck' onclick="move(this)">click to shift deck</div>

<div id="display">afda</div>
ray
  • 26,557
  • 5
  • 28
  • 27
0

I think this can technically be done using eval, but it is good practice to think more clearly about how you design this so that you only access objects you directly declare. One example of better design might be:

container = { 
             obj1: //whatever this object is 
             ...
             objn: 
             }
function applyMethodToObject(object_passed){
     container[object_passed].my_method();
}
0

When you assign a value to an object in javascript you can access with dot or array notation. IE

foo = {};
foo.bar = "bar";

console.log(foo.bar);
console.log(foo["bar"]);

Additionally, global variables are added to the window object, meaning deck is available at window["deck"] or window[location] in your case. That means your moveCards function could do:

function moveCards(location) {
    // perform sanity checks since you could change data-location="foo"
    // which would then call window.foo.shift()
    if (window[location]) { 
        window[location].shift();
    }
}

That said, this probably isn't a great approach, though it's hard to say without a lot more context.

Jonathan Bennett
  • 1,055
  • 7
  • 14