Renaming Array with Variable - javascript

One of the problems with teaching yourself how to code is that you miss some things that might be fairly simple:
I have written a function which takes text files (e.g. "someData1.txt", "someData2.txt" etc.) turns their contents into an array ("myArray"), and extracts their title as a variable ("fileName").
I am at the stage where I have parsed the filenames and the arrays, but I would like to rename each array with the variable, so that the first array becomes "someData1", and so on. I already have a bunch of code which will do various things with each different array, so it would useful if I could name them the way I wish.
I thought I could use valueOf to do it, as in
fileName.valueOf() = myArray;
but that does not work. So how do I do this?
Thanks!

Probably the easiest way would be to use an object and then use array notation to assign keys to it. Let me show you:
var myObj = {};
myObj.someProperty = 1;
is the same as
myObj['someProperty'] = 1; // note the quotes
So, that makes possible to use variable names as keys. In your example:
var fileName = 'someData1';
var myObj = {};
myObj[fileName] = myArray; // myArray being file contents from your example
and now when you want to access the contents, you can simply do:
myObj.someData1
or:
myObj['someData1']
Just make sure you have no duplicate file names and you're good to go.

What you want to do is defining a variable name dynamically.
It is not possible in Javascript though, but you can be tricky.
You have then two options :
Use the global scope object to store your variables (not a good practice) :
global[variableName] = array;
And then you will be able to access it in the scope :
global['toto'] = 42;
console.log(toto);
=> 42
This is NOT a good practice but is the only way to define a variable in the scope dynamically.
Use an object to store it :
var myArrays = [];
myArrays[variableName] = array;
In each case you define in fact a property of an object.
You have to keep in mind that :
myArrays['toto'] = 42;
is the same that :
myArrays.toto = 42;
So to access your array, just do :
myArrays.toto

Related

JavaScript: Finding a variable's value by its name, is eval acceptable here?

WARNING: As other have stated here, this problem is based upon an inflexible customer requirement. While the question is valid, you should definitely use the simpler solutions (ex: putting your settings in a single object) if possible!
I have an array of variables I want to be "watching out" for. That is: if they were previously defined in the code, I need to be able operate on their values.
var a = 'foo'; // only a gets defined
// ...more code here... IMPORTANT: I can only control what comes BELOW this line!
var target = 'exmple.com/?';
var gets = ['a', 'b', 'c']; // these are the names of the variables I want to check for
gets.forEach(function(element) { // checking each one
if(typeof element !== 'undefined') { // if it's previously defined
target += "&"+element+"="+eval(element); // add `&a=foo` to target
}
});
alert(target);
I'd like the alert to be printing example.com/?&a=foo
I've seen the tons of other answers not to use the eval function, and I have tried window[element] in place without success. How would it be best to do this without having to write an if/else for every variable I want to check?
Assuming you can't do otherwise and everything lives in the global scope, you could do without resorting to using eval(). (I'm pretty sure there must be some valid use cases for eval but I don't think this is one is one of them.)
Since you shouldn't trust the content of these variables you shouldn't be using eval. What if your customer options get compromised? (Or simply your customer doesn't know what they're doing.)
var css_color = 'tweet(document.cookie)';
You can simply leverage the fact that the variables will be accessible from the global scope:
const serialize_options = (...vars) =>
vars
.filter(v => typeof this[v] !== 'undefined')
.map(v => `${v}=${this[v]}`)
.join('&');
console.log(serialize_options('a'));
console.log(serialize_options('a', 'b'));
console.log(serialize_options('a', 'b', 'c'));
console.log(serialize_options('a', 'x', 'y'));
<script>
var a = '10';
var b = '20';
var c = '30';
</script>
The answer to this kind of question is almost always "You're thinking about the problem wrong.", as is the case here.
You make the assumption that this should be done with variables and that backs you into the corner of only being able to use eval() to get out of that corner. I understand that the customer may have asked for regular variables, but if I were a house builder and the customer asked me to build a house out of marshmallow, I'd say "no", that's not the way to do it.
The solution is to use an object with keys and values from the start, which allows you to use array indexing syntax later, instead of eval.
// Keep the items you need to check in an object
var obj = {
a:'foo' // only a gets defined
}
var target = 'exmple.com/?';
var gets = ['a', 'b', 'c'];
// Check each array element
gets.forEach(function(element) {
// Objects can use array indexing syntax where a string is passed as the index
// because objects actually have keys, rather than numeric indexes
if(obj[element]) { // if it's previously defined
target += "&" + element + "=" + obj[element]; // add `&a=foo` to target
}
});
alert(target);

JavaScript Conceptual Issue with a code. Please give an explanation for the output i am getting

I am having difficulty in understanding the following code, i have put a comment where i do not understand the concept, what exactly is going on
var ob = {};
var ob2 = ['name'];
for(var op of ob2)
{
ob[op]='at'; // here i dont understand what is happening, why here is an array type brackets
}
console.log(ob);
OUTPUT IS
name:'at'
That is just the syntax for accessing or assigning properties of an object dynamically in javascript.
You can think of it as though you are doing: ob.name = 'at'.
There are two ways to access object properties in JavaScript
var person = {
name: 'Jane'
}
person.name
// or
person['name']
// both return jane
in your case, that iterates through members of the array called ob2
first and only element of that array is a string name and it's given to that object as a prop, which becomes like following
ob['name'] = 'at';
// or
ob.name = 'at';
When to use brackets([]) over dot(.)
If you don't know the prop name at runtime you need to go with brackets, if you do know it you can choose either dot notation or brackets
Basically, it's accessing a property of the object ob. In this case, is accessing and creating new properties.
The loop is getting each index value, and for each assign/create a new property using that index value.
That approach is a dynamically way of creating property-names in an object.
ob['name'] = 'at';
ob.name = 'at'; // Just to illustrate
Read a little the docs here -> JavaScript object basics - Learn web development | MDN

Why does push of local array mutate global array?

I am puzzled why this following bit of code will return mutations of both the local and global array:
var globalarray = [1,2,3];
function test(){
let localarray = globalarray;
localarray.push(4);
console.log(localarray);
console.log(globalarray);
}
setInterval(test, 2000);
Returns:
[1,2,3,4] for both
My impression was that localarray would be a copy of globalarray. I saw another answer that said in order to make a copy of an array you need to use .slice().reverse(), which seems like a workaround. Why does it not just create a new local copy? Is there a simple and efficient way to make a local copy of a global array? Otherwise it seems like making multiple mutations to a global array is terrible for performance.
The reason for this in your code is because you are simply telling your test function to point to the globalarray with the = operator. This is because in JavaScript, variable assignments do not inherently "copy" objects into the new variables; this might seem confusing, so just think of the = operator as a sign that points your code to the location of an object.
The only times that the = operator is making new copies is when you are working with primitive types. In those cases, you cannot inherently change what those objects are, so = is sufficient to make a copy like you would expect.
The reason for the .slice().reverse() is to work around the problem you are seeing. Another way you could do this is by using let localarray = globalarray.map(e => e), or as samee suggested, by using let localarray = [...globalarray]. The .map operator takes the function given to it as the first argument and applies it to every element, and then it stores the result in a different array at another location that is not the same as globalarray.
Keep in mind that these methods, and any others that might be suggested to you, are shorthand ways of doing
let localarray = new Array(globalarray.length);
for (let i = 0; i < globalarray.length; i++) {
localarray[i] = globalarray[i];
}
// localarray can now be freely modified because it does not point to the same array as globalarray
Also keep in mind that if you need to also create copies of the elements inside of the arrays, then you will have to use more comprehensive copying code. There are libraries that can do this sort of heavy-duty copying if you really need it.
In JavaScript (as in many other languages), objects are passed by reference. Arrays are also passed by reference (because an array is actually a type of object). So when you say: let localarrray = globalarray, you are actually setting localarray to a pointer that resolves to globalarray.
There are several strategies for obtaining a true copy. If you're trying to get a fresh copy of the original array, the Array prototype function of .map() is one of the most targeted tools for the job. It would look like this:
let localarray = globalarray.map(element => element);
Simple way to clone an array is just
let localarray = globalarray.slice();
I do it a different way to deep cloning:
clone: function() {
var clone = undefined;
var instance = this;
if ( XScript.is.xobject(instance) ) {
clone = {};
for ( var prop in instance ) {
if ( instance.hasOwnProperty(prop) ) {
var p = instance[prop];
if ( XScript.is.xobject(p) ) p = p.clone();
clone[prop] = p;
}//END IF this
}//END FOR prop
return clone;
}//END IF xobject
if ( XScript.is.xarray(instance) ) {
clone = instance.slice(0);
return clone;
}
return clone;
}//END FUNCTION clone
This clone will require you attaching the clone object to the object prototype and check to see if its an array, object, or other. I am not changing the function to fit all your needs because one should learn to somewhat how to change it and what to do instead of copy pasta. Plus it is just an example.

Accessing value of key inside object

There's a handful of questions extremely similar to this, I know, but I can't seem to get anything to work.
For sake of brevity, I'll summarize this. I have this constructor function with strings assigned as values of the keys (assignment).
var Quote = function() {
this.quote1 = 'You can discover more about a person in an hour of play than in a year of conversation.';
this.quote2 = 'Nothing is at last sacred but the integrity of your own mind.';
this.quote3 = 'We have to fight them daily, like fleas, those many small worries about the morrow, for they sap our energies.';
this.quote4 = 'Ethics are so annoying. I avoid them on principle.';
this.quote5 = "Never trust anything that can think for itself if you can't see where it keeps its brain.";
};
module.exports = Quote;
Using AJAX I am printing the value of the keys inside the constructor to a static page. However... I am only successful in printing "quote1", "quote2", etc... (Just the name of the keys).
This is what my function for accessing the constructor looks like. My question is: How can I access the string values assigned to the keys inside the constructor? Is that possible?
Thank you in advance.
module.exports = function(object) {
var propArray = Object.keys(object);
var randomProp = propArray[Math.floor(Math.random() * propArray.length)];
return {quote: randomProp};
};
Inside your function, you should be able to access the quote by key using this:
object[randomProp]
In JavaScript, object properties can be accessed using square bracket notation. See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects.
As you might have expected, there are several things wrong with your code :)
I've rewritten it with pretty thorough comments.
<script>
// create your 'Quote' class, which can be instantiated as many times as necessary
var Quote = function() {
this.quote1 = 'You can discover more about a person in an hour of play than in a year of conversation.';
this.quote2 = 'Nothing is at last sacred but the integrity of your own mind.';
this.quote3 = 'We have to fight them daily, like fleas, those many small worries about the morrow, for they sap our energies.';
this.quote4 = 'Ethics are so annoying. I avoid them on principle.';
this.quote5 = "Never trust anything that can think for itself if you can't see where it keeps its brain.";
};
// now let's set up the 'exports' method on the function's prototype
// this will allow any new instance of the Quote function to call or override this method
// without affecting the master 'Quote' class
Quote.prototype.exports = function() {
// you don't need to explicitly pass an object to this function
// just have it reference itself using the 'this' keyword
var propArray = Object.keys(this);
var randomProp = propArray[Math.floor(Math.random() * propArray.length)];
// objects in JavaScript can be handled like associative arrays
// simply access the key of 'this' with the value provided by 'randomProp'
return {quote: this[randomProp]};
};
// create a new instance of 'Quote'
// this guy can be used and manipulated independent of the master 'Quote' class
var module = new Quote();
// let's store the value returned by 'exports' in randomQuote
// note the () at the end of module.exports -- this tells JavaScript to treat the object as a function
var randomQuote = module.exports();
// write your quote to the document -- or do whatever else you want to with it at this point
document.write(randomQuote.quote);
</script>
Instead of return { quote: randomProp } you should use return object[randomProp].
You can access object properties via dot notation or square bracket notation.
Here's an example from jsbin
https://jsbin.com/yopeli/edit?js,console

Why do variables in object-nested array not change?

function Dealership = function(){
this.car1="Honda";
this.car2="Chevy";
this.car3="Toyota";
this.carList=[this.car1,this.car2,this.car3];
};
var tomsauto = new Dealership();
tomsauto.car2="Subaru";
console.log(tomsauto.carList); //returns honda chevy toyota
I'm confused as to how the array is processed. Is it static, holding only the variable values it had at instantiation, or should "this.car1" change when I change tom.car1?
When you create the array via that array instantiation expression, the runtime system copies the values of each of those object properties into the array. If you later change the values of the properties, they'll change independently of the array elements.
There's no way in JavaScript to make a property of one object "mirror" the property of another. (Well, no intrinsic way; you can write code to do it.)
As Teemu said: your carList is populated with values, not references.
An easy workaround is to change it to a function getCarList:
var Dealership = function () {
this.car1 = "Honda";
this.car2 = "Chevy";
this.car3 = "Toyota";
this.getCarList = function() {
return [this.car1, this.car2, this.car3];
}
};
var tomsauto = new Dealership();
tomsauto.car2 = "Subaru";
console.log(tomsauto.getCarList());
I think you are running into that problem because of how closures work in JavaScript.
When you declare the function as you did, the value of car1, car2, car3 get evaluated in that scope and then are assigned to the array.
When you do the new Dealership() bit, the values of that array are pretty much set as they were when the function was evaluated. After you do
tomsauto.car2 = "Subaru";
the value of car2 will change, but the array will not because the values are not being re-evaluated.
If you want to know more about how and why, I suggest you read more about closures in javascript and functional languages in general.

Categories

Resources