Function is rewriting variable. How is this possible? - javascript

This function seems to be rewriting the value for the 'pages' variable and I'm at my wit's end on this one.
I've tried returning the variable through a function, hardcoding the variable into the function, and a pile of other things, but this seems like it should work.
Any ideas?
EDIT:
The output from should be an array of objects formatted like this {default: "Tax Return", safe: "taxreturn"}. The function, when first called with getPages('Both', 'overview', null) and getPages('Both', null, 'overview') does this, but if you call it more times it will error and you will find that the 'pages' variable is now an array of objects.
var pages = [
"Dashboard",
"Overview",
"Contacts",
"Records",
"Cash Flow",
"Transactions",
"Income",
"Expenses",
"Tax Return"
];
var getPages = function(format, includeOne, excludeOne)
{
var pageStrings = pages;
if(includeOne)
for(var p = 0; p < pageStrings.length; p++)
if(uriSafe(pageStrings[p]) == uriSafe(includeOne))
pageStrings = [pageStrings[p]];
if(excludeOne)
for(var c = 0; c < pageStrings.length; c++)
if(uriSafe(pageStrings[c]) == uriSafe(excludeOne))
pageStrings.splice(c, 1);
var outputArray = [];
switch(format)
{
case 'UriSafe':
for(var i = 0; i < pageStrings.length; i++)
pageStrings[i] = uriSafe(pageStrings[i]);
break;
case 'Both':
for(var x = 0; x < pageStrings.length; x++)
{
pageStrings[x] = {
default: pageStrings[x],
safe: uriSafe(pageStrings[x])
};
}
break;
default:
}
function uriSafe(str)
{
return str.replace(' ', '').toLowerCase();
}
console.log(pageStrings);
return pageStrings;
}

var pageStrings = pages;
is creating a reference to the very same array object. When you access it via pageString, you alter the same object which pages does refer to. To create a copy of it (from which you then can splice, assign properties to, etc without altering pages), use
var pageStrings = pages.slice();

I think your confusion is around the following line
var pageStrings = pages;
This does not create a copy of pages it simply creates a reference to pages. This means any edit you make to the value of pageStrings (clearing, changing elements, etc ...) will show up on pages because they refer to the same variable.
If you want pageStrings to have a copy of the pages array then do the following
var pageStrings = pages.slice(0);

var pageStrings = pages; is your hangup. Keep in mind that when you use = in this way, your new var will be a reference if the argument on the right is and array, object, or function. With strings and numbers you will get the copy you were expecting.

Related

How to keep changing the the reference name by loop which is pointing to the object in javascript? [duplicate]

I'm working on an ajax google maps script and I need to create dynamic variable names in a for loop.
for (var i = 0; i < coords.length; ++i) {
var marker+i = "some stuff";
}
What I want to get is: marker0, marker1, marker2 and so on.
and I guess there is something wrong with marker+i
Firebug gives me this: missing ; before statement
Use an array for this.
var markers = [];
for (var i = 0; i < coords.length; ++i) {
markers[i] = "some stuff";
}
I agree it is generally preferable to use an Array for this.
However, this can also be accomplished in JavaScript by simply adding properties to the current scope (the global scope, if top-level code; the function scope, if within a function) by simply using this – which always refers to the current scope.
for (var i = 0; i < coords.length; ++i) {
    this["marker"+i] = "some stuff";
}
You can later retrieve the stored values (if you are within the same scope as when they were set):
var foo = this.marker0;
console.log(foo); // "some stuff"
This slightly odd feature of JavaScript is rarely used (with good reason), but in certain situations it can be useful.
Try this
window['marker'+i] = "some stuff";
In regards to iterative variable names, I like making dynamic variables using Template literals. Every Tom, Dick, and Harry uses the array-style, which is fine. Until you're working with arrays and dynamic variables, oh boy! Eye-bleed overload. Since Template literals have limited support right now, eval() is even another option.
v0 = "Variable Naught";
v1 = "Variable One";
for(i = 0; i < 2; i++)
{//console.log(i) equivalent is console.log(`${i}`)
dyV = eval(`v${i}`);
console.log(`v${i}`); /* => v0; v1; */
console.log(dyV); /* => Variable Naught; Variable One; */
}
When I was hacking my way through the APIs I made this little looping snippet to see behavior depending on what was done with the Template literals compared to say, Ruby. I liked Ruby's behavior more; needing to use eval() to get the value is kind of lame when you're used to getting it automatically.
_0 = "My first variable"; //Primitive
_1 = {"key_0":"value_0"}; //Object
_2 = [{"key":"value"}] //Array of Object(s)
for (i = 0; i < 3; i++)
{
console.log(`_${i}`); /* var
* => _0 _1 _2 */
console.log(`"_${i}"`); /* var name in string
* => "_0" "_1" "_2" */
console.log(`_${i}` + `_${i}`); /* concat var with var
* => _0_0 _1_1 _2_2 */
console.log(eval(`_${i}`)); /* eval(var)
* => My first variable
Object {key_0: "value_0"}
[Object] */
}
You can use eval() method to declare dynamic variables. But better to use an Array.
for (var i = 0; i < coords.length; ++i) {
var str ="marker"+ i+" = undefined";
eval(str);
}
In this dynamicVar, I am creating dynamic variable "ele[i]" in which I will put value/elements of "arr" according to index. ele is blank at initial stage, so we will copy the elements of "arr" in array "ele".
function dynamicVar(){
var arr = ['a','b','c'];
var ele = [];
for (var i = 0; i < arr.length; ++i) {
ele[i] = arr[i];
] console.log(ele[i]);
}
}
dynamicVar();
var marker = [];
for ( var i = 0; i < 6; i++) {
marker[i]='Hello'+i;
}
console.log(marker);
alert(marker);
var marker+i = "some stuff";
coudl be interpreted like this:
create a variable named marker (undefined); then add to i; then try to assign a value to to the result of an expression, not possible.
What firebug is saying is this:
var marker; i = 'some stuff';
this is what firebug expects a comma after marker and before i;
var is a statement and don't (apparently) accepts expressions.
Not so good an explanation but i hope it helps.

Javascript loop push into global array

1.I want to push id[i] into global array.After I pushed then it will be id.length numbers items in each array,but it will be error and says y is not a function.how to solve it?
2.the sendrequest in the bottom will send a xmlhttprequest to server,but I don't understand why it will run first and then the function(parResponse) will be fire after tmpReadRequest.sendReadRequest(); has down.
Thanks a lot
var tes0=new Array();
var tes1=new Array();
var tes2=new Array();
var tes4=new Array();
var tes5=new Array();
function ReadValuePath(id, Variable,id_2) {
var tmpReadCB = function(parResponse)
{
for (var tmpIndex = 0; tmpIndex < parResponse.length; tmpIndex++)
{
var tmpItemValue = parResponse[tmpIndex];//console.log(tmpItemValue);
var tmpValue = (tmpItemValue.mItemValue) ? tmpItemValue.mItemValue : tmpItemValue.mItemResultId;
if(document.getElementById(id[tmpIndex]) != null && document.getElementById(id_2[tmpIndex]).value != 0)
{
document.getElementById(id[tmpIndex]).value = parseFloat(tmpValue).toFixed(2);
}
}
return true;
}
var tmpReadRequest = new OPCReadRequest("DE", tmpReadCB);
for(var z=0;z<5;z++ ){
for(var i = 0; i < id.length; i++)
var y="tes"+z;
y.push(id[i]);
tmpReadRequest.addItem("ab", Variable[i]);
}
}
tmpReadRequest.sendReadRequest();
}
"A variable declared outside a function, becomes GLOBAL.
A global variable has global scope: All scripts and functions on a web page can access it. " # Source
Y is not an array so .push() won't work on it. # Source
To access the global scope through a string literal like you are trying you can use the window object which is the current global scope.
So in your case it would be window[y].push(id[i]);
Another option would be to change you scructure slightly as personally i don't like accessing the window directly.
so you could define your arrays like
var arrays = {
tes0: [],
tes2: [],
tes3: [],
tes4: [],
tes5: [],
}
and access them like:
arrays[y].push(id[i])
EDIT according to comments
So you want to access global variable in a loop. You are half way there. What your doing is building a string y which contains the property name then using that in the square brackets to access that property.
So with the window option that would be:
for(var z=0;z<5;z++ ){
var y="tes"+z;
for(var i = 0; i < id.length; i++)
window[y].push(id[i]);
}
}
or with the second object option
/*
Because arrays is an object we can use Object.keys
This will return an array of the keys in our object which we can loop over to access each one
*/
Object.keys(arrays).forEach(function(key) {
for(var i = 0; i < id.length; i++)
arrays[key].push(id[i]);
}
});
Hope that helps explain

Create variables based on array

I have the following array and a loop fetching the keys (https://jsfiddle.net/ytm04L53/)
var i;
var feeds = ["test_user_201508_20150826080829.txt:12345","test_user_list20150826:666","test_list_Summary20150826.txt:321"];
for (i = 0; i < feeds.length; i++) {
var feed = feeds[i];
alert(feed.match(/\d+$/));
}
The array will always contain different number of keys, What I would like to do is either use these keys as variables and assign the value after the : semicolon as its value or just create a new set of variables and assign the values found on these keys to them.
How can I achieve this? so that I can then perform some sort of comparison
if (test_user > 5000) {dosomething}
update
Thanks for the answers, how can I also create a set of variables and assign the array values to them? For instance something like the following.
valCount(feeds.split(","));
function valCount(t) {
if(t[0].match(/test_user_.*/))
var testUser = t[0].match(/\d+$/);
}
Obviously there is the possibility that sometimes there will only be 1 key in the array and some times 2 or 3, so t[0] won't always be test_user_
I need to somehow pass the array to a function and perform some sort of matching, if array key starts with test_user_ then grab the value and assign it to a define variable.
Thanks guys for all your help!
You can't (reasonably) create variables with dynamic names at runtime. (It is technically possible.)
Instead, you can create object properties:
var feeds = ["test_user_201508_20150826080829.txt:12345","test_user_list20150826:666","test_list_Summary20150826.txt:321"];
var obj = {};
feeds.forEach(function(entry) {
var parts = entry.split(":"); // Splits the string on the :
obj[parts[0]] = parts[1]; // Creates the property
});
Now, obj["test_user_201508_20150826080829.txt"] has the value "12345".
Live Example:
var feeds = ["test_user_201508_20150826080829.txt:12345","test_user_list20150826:666","test_list_Summary20150826.txt:321"];
var obj = {};
feeds.forEach(function(entry) {
var parts = entry.split(":");
obj[parts[0]] = parts[1];
});
snippet.log(obj["test_user_201508_20150826080829.txt"]);
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
You can do it like this, using the split function:
var i;
var feeds = ["test_user_201508_20150826080829.txt:12345","test_user_list20150826:666","test_list_Summary20150826.txt:321"];
for (i = 0; i < feeds.length; i++) {
var feed = feeds[i];
console.log(feed.split(/[:]/));
}
This outputs:
["test_user_201508_20150826080829.txt", "12345"]
["test_user_list20150826", "666"]
["test_list_Summary20150826.txt", "321"]
Use the split method
var feeds = ["test_user_201508_20150826080829.txt:12345","test_user_list20150826:666","test_list_Summary20150826.txt:321"];
feedMap = {}
for (i = 0; i < feeds.length; i++) {
var temp = feeds[i].split(':');
feedMap[temp[0]] = temp[1];
}
Yields:
{
"test_user_201508_20150826080829.txt":"12345",
"test_user_list20150826":"666",
"test_list_Summary20150826.txt":"321"
}
And can be accessed like:
feedMap["test_user_201508_20150826080829.txt"]
Here is a codepen
it is not very good idea but if you really need to create variables on-the-run here's the code:
for (i = 0; i < feeds.length; i++)
{
var feed = feeds[i];
window[feed.substring(0, feed.indexOf(":"))] = feed.match(/\d+$/);
}
alert(test_user_201508_20150826080829)
Of course you cannot have any variable-name-string containing banned signs (like '.')
Regards,
Michał

Javascript pass by object by reference then update

I've been searching all over SO and I know there are a lot of topics about this but I haven't found one that answered my question.
I saw a question about getting an object value back from a string like this:
function getPropertyByString(str) {
var properties = str.split(".");
var myTempObject = window[properties[0]];
for (var i = 1, length = properties.length; i < length; i++) {
myTempObject = myTempObject[properties[i]];
}
return myTempObject;
}
So if there is a global variable called myGlobalVar, you could pass the string 'myGlobalVar.someProp.stateName' and assumming that is all valid you would get back the value of stateName say Arizona for example.
How could I update that property to California now?
If I try
var x = getPropertyByString('myGlobalVar.someProp.stateName');
x = 'California';
that will update the value of x and not the object.
I tried
var x = getPropertyByString('myGlobalVar.someProp.stateName');
x.value = 'California';
that didn't work either.
Can someone please help me to understand this with my example?
Thanks
Try the following;
function setPropertyByString(path, value) {
var steps = path.split("."),
obj = window,
i = 0,
cur;
for (; i < steps.length - 1; i++) {
cur = obj[steps[i]];
if (cur !== undefined) {
obj = cur;
} else {
break;
};
};
obj[steps[i]] = value;
}
It'd work by using it such as;
setPropertyByString('myGlobalVar.someProp.stateName', 'California');
You can see it in action here; http://jsfiddle.net/xCK8J/
The reason yours didn't work is because strings are immutable in JavaScript. You are re-assigning the variable x with the value 'California', rather than updating the location it points to to be 'California'.
If you'd have done;
var x = getPropertyByString('myGlobalVar.someProp');
x.stateName = 'California';
You'd see it works; as you're manipulating the object pointed to by x, rather than reassigning x to be something else. The above is what the setPropertyByString() method does behind the scenes; it just hides it from you.
This would do the trick:
myGlobalVar.someProp.stateName = "California"
So would this:
myGlobalVar["someProp"].stateName = "California"
or this:
myGlobalVar["someProp"]["stateName"] = "California"
Alternatively,
var x = getPropertyByString('myGlobalVar.someProp');
x.stateName = "California"
Note that if, in my last example, I do something like this:
x = {stateName:"California"};
It will not change the value of myGlobalVar.someProp.stateName.
Using = assigns a new value to the variable on the LHS. This is not the same thing as assigning a new value to the referent of the variable.

remove json attribute where attribute is a variable

I have a news feed where items in the feed are created from JSON returned from a server. When the user takes an action on an item, I want to remove it from the object via javascript.
The feed looks like this:
{"newsFeed":[{"feedId":"1",
"title":"item1 title",
"desc":"description of the item"},
{"feedId":"2",
"title":"item2 title",
"desc":"description of the item"}]}
I'm trying to remove a JSON attribute or entry where the feedId is passed in via a variable using jQuery. I'm not sure exactly where I'm going wrong here, but when I alert the feed before and after the removal of the object, I'm getting the same response:
function removeFromFeed(feedId){
var newsFeed=jQuery('div#newsFeed').data('newsFeed');
alert(newsFeed.toSource());
delete newsFeed.feedId[feedId]
jQuery('div#newsFeed').data('newsFeed',newsFeed);
alert(newsFeed.toSource());
}
If I undertand you correctly you want to remove e.g. this whole entry {"feedId":"1", "title":"item1 title", "desc":"description of the item"} if removeFromFeed(1) is called.
So what we need to do is remove an entry from an array.
New version which should work now. (btw. what is this toSource() my browser doesn't know this method)
//http://ejohn.org/blog/javascript-array-remove/
Array.prototype.remove = function(from, to) {
var rest = this.slice((to || from) + 1 || this.length);
this.length = from < 0 ? this.length + from : from;
return this.push.apply(this, rest);
};
function removeFromFeed(feedId){
var data = jQuery('div#newsFeed').data('newsFeed');
var len = data.newsFeed.length;
for (var i = 0; i < len; i++) {
if (data.newsFeed[i].feedId == feedId) {
data.newsFeed.remove(i);
break;
}
}
jQuery('div#newsFeed').data('newsFeed', data);
}
Demo: http://jsbin.com/ekali3 (Code view: http://jsbin.com/ekali3/edit)
I'm not sure why the 'Array.prototype.remove' stuff was breaking my page, but I created a new array and just left out the object I wanted to remove.
var newsFeed=jQuery('div#newsFeed').data('newsFeed');
var newFeed={"feed":[]};
alert(newsFeed.toSource());
for (var i = 0; i < newsFeed.length; i++) {
if(newsFeed.feed[f].shiftId!=shiftId){
newFeed.feed.push(newsFeed.feed[f]);
}
}
seems to work.

Categories

Resources