Pass array to function by value [duplicate] - javascript

This question already has answers here:
JavaScript: How to pass object by value?
(14 answers)
Closed 5 years ago.
This is my first function, i pass to json
end if it is the first time i save the json is original.
function loadchart2(div, json, lista,tipo) {
var listaId = lista;
if(l==0){
jsonSecCall =JSON.parse(JSON.stringify(json));
listaSecCall=listaId;
l++;
}
I modify json ,and click a button.
Call second function and call loadcart2 and pass the json original but actually receives the json modify, What???
$("#giorni").on('click',function () {
var nuova=jsonSecCall;
$("#svgDateLine2").remove();
loadchart2("content", nuova,listaSecCall,"giorni");
checkContainer();
});
Probably the json it is gone for reference, is possible??
This is an example https://jsfiddle.net/tsjvmsd0/.
First console log print json modified, is ok, the next console log they should
print the original json, but print json modified.

This is the con of javascript. Everything in JS is passed by value, except objects, due to they are collections of references. That was done in performance reasons - it is costly to make copy of whole object.
To modify object without mutating the original, you should copy it. One way is to use Object.assign. It's probably better than making so deep copy of object ;-)
Then the snippet will be
var copy = {}
Object.assign(copy, source)

I dont know the types of your variables but normally I use Array.prototype.slice for copying.
var a = [1, 2, 3];
var b = a.slice(0); //Creates a new array
For copying objects see #alexcleac answer.

Firstly, it doesn't look like you are dealing with JSON, it looks like you are dealing with an object (or an array). JSON is a string.
Secondly, you aren't passing in the original JSON to loadchart2 (as you have figured out). You already modified the object reference by the variable jsonSecCall
What you probably want to do is actually maintain the original JSON (string) form of the object and use that as your original, unmodified object. You can do a JSON.parse on it whenever you want an object reference of your original.

Related

count the number of JSON objects in object using javascript or jquery

i have a JSON data from AJAX response as below
{
"2015001":{"sname":"name1","01-07-2015":null,"02-07-2015":"0","03-07-2015":"0","04-07-2015":"0","05-07-2015":null,"06-07-2015":"0","07-07-2015":"0","08-07-2015":"0","09-07-2015":"0","10-07-2015":"0","11-07-2015":null,"12-07-2015":null,"13-07-2015":"0","14-07-2015":"1","15-07-2015":null,"16-07-2015":"2","17-07-2015":null,"18-07-2015":null,"19-07-2015":null,"20-07-2015":"2","21-07-2015":"0","22-07-2015":"0","23-07-2015":"0","24-07-2015":"1","25-07-2015":"1","26-07-2015":null,"27-07-2015":"2","28-07-2015":null,"29-07-2015":"2","30-07-2015":"2","31-07-2015":"2"},
"2015002":{"sname":"name2","01-07-2015":null,"02-07-2015":"0","03-07-2015":"1","04-07-2015":"1","05-07-2015":null,"06-07-2015":"0","07-07-2015":"0","08-07-2015":"0","09-07-2015":"0","10-07-2015":"2","11-07-2015":null,"12-07-2015":null,"13-07-2015":"1","14-07-2015":"1","15-07-2015":null,"16-07-2015":"2","17-07-2015":null,"18-07-2015":null,"19-07-2015":null,"20-07-2015":"0","21-07-2015":"0","22-07-2015":"0","23-07-2015":"0","24-07-2015":"0","25-07-2015":"0","26-07-2015":null,"27-07-2015":"0","28-07-2015":null,"29-07-2015":"0","30-07-2015":"0","31-07-2015":"0"},
"2015003":{"sname":"name3","01-07-2015":null,"02-07-2015":"2","03-07-2015":"2","04-07-2015":"2","05-07-2015":null,"06-07-2015":"2","07-07-2015":"2","08-07-2015":"0","09-07-2015":"2","10-07-2015":"2","11-07-2015":null,"12-07-2015":null,"13-07-2015":"2","14-07-2015":"0","15-07-2015":null,"16-07-2015":"2","17-07-2015":null,"18-07-2015":null,"19-07-2015":null,"20-07-2015":"2","21-07-2015":"2","22-07-2015":"0","23-07-2015":"2","24-07-2015":"2","25-07-2015":"2","26-07-2015":null,"27-07-2015":"2","28-07-2015":null,"29-07-2015":"2","30-07-2015":"2","31-07-2015":"2"},
"2015004":{"sname":"name4","01-07-2015":null,"02-07-2015":"2","03-07-2015":"2","04-07-2015":"2","05-07-2015":null,"06-07-2015":"0","07-07-2015":"2","08-07-2015":"2","09-07-2015":"2","10-07-2015":"2","11-07-2015":null,"12-07-2015":null,"13-07-2015":"2","14-07-2015":"2","15-07-2015":null,"16-07-2015":"2","17-07-2015":null,"18-07-2015":null,"19-07-2015":null,"20-07-2015":"0","21-07-2015":"2","22-07-2015":"2","23-07-2015":"2","24-07-2015":"2","25-07-2015":"0","26-07-2015":null,"27-07-2015":"2","28-07-2015":null,"29-07-2015":"0","30-07-2015":"2","31-07-2015":"2"},
"2015005":{"sname":"name5","01-07-2015":null,"02-07-2015":"2","03-07-2015":"2","04-07-2015":"0","05-07-2015":null,"06-07-2015":"2","07-07-2015":"2","08-07-2015":"2","09-07-2015":"2","10-07-2015":"2","11-07-2015":null,"12-07-2015":null,"13-07-2015":"2","14-07-2015":"2","15-07-2015":null,"16-07-2015":"2","17-07-2015":null,"18-07-2015":null,"19-07-2015":null,"20-07-2015":"0","21-07-2015":"2","22-07-2015":"2","23-07-2015":"2","24-07-2015":"2","25-07-2015":"2","26-07-2015":null,"27-07-2015":"2","28-07-2015":null,"29-07-2015":"2","30-07-2015":"2","31-07-2015":"2"},
"2015006":{"sname":"name6","01-07-2015":null,"02-07-2015":"2","03-07-2015":"2","04-07-2015":"2","05-07-2015":null,"06-07-2015":"2","07-07-2015":"2","08-07-2015":"2","09-07-2015":"2","10-07-2015":"2","11-07-2015":null,"12-07-2015":null,"13-07-2015":"2","14-07-2015":"2","15-07-2015":null,"16-07-2015":"2","17-07-2015":null,"18-07-2015":null,"19-07-2015":null,"20-07-2015":"2","21-07-2015":"0","22-07-2015":"2","23-07-2015":"2","24-07-2015":"2","25-07-2015":"2","26-07-2015":null,"27-07-2015":"2","28-07-2015":null,"29-07-2015":"2","30-07-2015":"2","31-07-2015":"2"}
}
each object has same number of objects. Here i want to count the number of objects in the first object(2015001). The key will change upon every request.
i tried
console.log(Object.keys(data[2015001]).length)
and i got what i need
but how can i do without key(2015001)
If you always want to know the number of keys of the first object, then you should use Object.keys(data[Object.keys(data)[0]]).length
Note that if the order is important to you, you should send the keys inside an array and not inside an object, as according to the specification, an object is an unordered set of name/value pairs.
You could get the first key and use it to access the object, probably the fastest way, but then again your information is a bit unclear, you are talking about objects and more objects but I am unsure when you talk about the outer object or when about the inner object.
for (var k in Object) {
break
}
console.log(Object.keys(data[k]).length)

JSON.stringify turned the value array into a string

I have a JS object
{
aString:[aNumber, aURL]
}
JSON.stringify() returns
{
"aString":"[number, \"aURL\"]"
}
I thought that valid JSON can have arrays as values. Can I have stringify return the JSON string without converting the array into a string? Basically I need turn the whole JS object straight into a string, without any modification.
Is there a better way to do this? I've been looking around but everyone suggests using JSON.stringify if I want an object to string, and no one has raised this problem.
EDIT: Thanks for the quick responses. Here is how I created my JS object, please let me know if I messed up and how!
cookie = {};
// productURL is a string, timer is a number, imageSrc is a URL string
cookie[productURL] = [timer, imageSrc];
// then, I just stringified cookie
newCookie = JSON.stringify(cookie);
If it is also relevant, I am setting an actual cookie's value as the resulting JSON string, in order to access it in another set of functions. Setting the cookie's value does do some URI encoding of its own, but I've actually been grabbing the value of newCookie in the Chrome console as well and it also returns the Array as a string.
If an object you're trying to stringify has a toJSON function, that will be called by JSON.stringify. Most likely you have an external library that's adding Array.prototype.toJSON.
For example, an old version (1.6) of Prototype JS will "conveniently" add that for you.
Prototype 1.6.1:
alert(JSON.stringify([1, 2, 3]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.6.1/prototype.min.js"></script>
Whereas a newer version will not.
Prototype 1.7.2:
alert(JSON.stringify([1, 2, 3]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.7.2/prototype.min.js"></script>
You could try deleting Array.prototype.toJSON just to see if that's what's causing the problem. If it is, you might want to look into upgrading/deprecating any libraries in your code that do weird things like that.
Prototype 1.6.1 (after deleting toJSON)
delete Array.prototype.toJSON;
alert(JSON.stringify([1, 2, 3]));
<script src="https://cdnjs.cloudflare.com/ajax/libs/prototype/1.6.1/prototype.min.js"></script>
Based on your description this is not what should happen.
If you have code like this:
var obj = {
aString:[123, "test"]
}
document.getElementById("out").value = JSON.stringify(obj);
it will generate the expected json:
{"aString":[123,"test"]}
also see https://jsfiddle.net/zudrrc13/
in order to produce your output the original object would have to look something like:
var obj = {
aString:"[123, \"test\"]"
}

Javascript array becomes an object structure

I'm experiencing an odd behavior (maybe it isn't odd at all but just me not understanding why) with an javascript array containing some objects.
Since I'm no javascript pro, there might very well be clear explanation as to why this is happening, I just don't know it.
I have javascript that is running in a document. It makes an array of objects similar to this:
var myArray = [{"Id":"guid1","Name":"name1"},{"Id":"guid2","Name":"name2"},...];
If I print out this array at the place it was created like JSON.stringify(myArray), I get what I was expecting:
[{"Id":"guid1","Name":"name1"},{"Id":"guid2","Name":"name2"},...]
However, if I try to access this array from a child document to this document (a document in a window opened by the first document) the array isn't an array any more.
So doing JSON.stringify(parent.opener.myArray) in the child document will result in the following:
{"0":{"Id":"guid1","Name":"name1"},"1":{"Id":"guid2","Name":"name2"},...}
And this was not what I was expecting - I was expecting to get the same as I did in teh parent document.
Can anyone explain to me why this is happening and how to fix it so that the array is still an array when addressed from a child window/document?
PS. the objects aren't added to the array as stated above, they are added like this:
function objTemp()
{
this.Id = '';
this.Name = '';
};
var myArray = [];
var obj = new ObjTemp();
obj.Id = 'guid1';
obj.Name = 'name1';
myArray[myArray.length] = obj;
If that makes any difference.
Any help would be much appreciated, both for fixing my problem but also for better understanding what is going on :)
The very last line might be causing the problem, have you tried replacing myArray[myArray.length] = obj; with myArray.push(obj);? Could be that, since you're creating a new index explicitly, the Array is turned into an object... though I'm just guessing here. Could you add the code used by the child document that retrieves myArray ?
Edit
Ignore the above, since it won't make any difference. Though, without wanting to boast, I was thinking along the right lines. My idea was that, by only using proprietary array methods, the interpreter would see that as clues as to the type of myArray. The thing is: myArray is an array, as far as the parent document is concerned, but since you're passing the Array from one document to another, here's what happens:
An array is an object, complete with it's own prototype and methods. By passing it to another document, you're passing the entire Array object (value and prototype) as one object to the child document. In passing the variable between documents, you're effectively creating a copy of the variable (the only time JavaScript copies the values of a var). Since an array is an object, all of its properties (and prototype methods/properties) are copied to a 'nameless' instance of the Object object. Something along the lines of var copy = new Object(toCopy.constructor(toCopy.valueOf())); is happening... the easiest way around this, IMO, is to stringency the array withing the parent context, because there, the interpreter knows it's an array:
//parent document
function getTheArray(){ return JSON.stringify(myArray);}
//child document:
myArray = JSON.parse(parent.getTheArray());
In this example, the var is stringified in the context that still treats myArray as a true JavaScript array, so the resulting string will be what you'd expect. In passing the JSON encoded string from one document to another, it will remain unchanged and therefore the JSON.parse() will give you an exact copy of the myArray variable.
Note that this is just another wild stab in the dark, but I have given it a bit more thought, now. If I'm wrong about this, feel free to correct me... I'm always happy to learn. If this turns out to be true, let me know, too, as this will undoubtedly prove a pitfall for me sooner or later
Check out the end of this article http://www.karmagination.com/blog/2009/07/29/javascript-kung-fu-object-array-and-literals/ for an example of this behavior and explanation.
Basically it comes down to Array being a native type and each frame having its own set of natives and variables.
From the article:
// in parent window
var a = [];
var b = {};
//inside the iframe
console.log(parent.window.a); // returns array
console.log(parent.window.b); // returns object
alert(parent.window.a instanceof Array); // false
alert(parent.window.b instanceof Object); // false
alert(parent.window.a.constructor === Array); // false
alert(parent.window.b.constructor === Object); // false
Your call to JSON.stringify actually executes the following check (from the json.js source), which seems to be failing to specify it as an Array:
// Is the value an array?
if (Object.prototype.toString.apply(value) === '[object Array]') {
//stringify

Creating multi-dimensional arrays in javascript, error in custom function

I was trying to define an array (including other arrays as values) in a single javascript statement, that I can loop through to validate a form on submission.
The function I wrote to (try to) create inline arrays follows:
function arr(){
var inc;
var tempa = new Array(Math.round(arguments.length/2));
for(inc=0; inc<arguments.length; inc=inc+2) {
tempa[arguments[inc]]=arguments[inc+1];
}
return tempa;
}
This is called three times here to assign an array:
window.validArr = arr(
'f-county',arr('maxlen',10, 'minlen',1),
'f-postcode',arr('maxlen',8, 'minlen',6)
);
However in the javascript debugger the variable is empty, and the arr() function is not returning anything. Does anyone know why my expectations on what this code should do are incorrect?
(I have worked out how to create the array without this function, but I'm curious why this code doesn't work (I thought I understood javascript better than this).)
Well from what your code does, you're not really making arrays. In JavaScript, the thing that makes arrays special is the management of the numerically indexed properties. Otherwise they're just objects, so they can have other properties too, but if you're not using arrays as arrays you might as well just use objects:
function arr(){
var inc;
var tempa = {};
for(inc=0; inc<arguments.length; inc=inc+2) {
tempa[arguments[inc]]=arguments[inc+1];
}
return tempa;
}
What you're seeing from the debugger is the result of it attempting to show you your array as a real array should be shown: that is, its numerically indexed properties. If you call your "arr()" function as is and then look at (from your example) the "f-county" property of the result, you'll see something there.
Also, if you do find yourself wanting a real array, there's absolutely no point in initializing them to a particular size. Just create a new array with []:
var tempa = [];
Your code works. Just inspect your variable, and you will see that the array has the custom keys on it. If not expanded, your debugger shows you just the (numerical) indixed values in short syntax - none for you.
But, you may need to understand the difference between Arrays and Objects. An Object is just key-value-pairs (you could call it a "map"), and its prototype. An Array is a special type of object. It has special prototype methods, a length functionality and a different approach: to store index-value-pairs (even though indexes are still keys). So, you shouldn't use an Array as an associative array.
Therefore, their literal syntax differs:
var array = ["indexed with key 0", "indexed with key 1", ...];
var object = {"custom":"keyed as 'custom'", "another":"string", ...};
// but you still can add keys to array objects:
array.custom = "keyed as 'custom'";

Does jQuery have something like .map() which returns an object rather than an array?

jQuery has the .map() function which takes as input either an array or an object but can only output an array.
It seems there are plenty of times when you want to output something more like an associative array so is there another function in jQuery that can output a JavaScript Object?
(I'm pretty sure I've used something like this in another programming language, possibly Perl.)
You can get the same result by declaring the object first, then building it out in the .map() function instead of returning the data.
This example gets all the checkboxes on the page and creates an object out of their ids and values:
var result = new Object();
$(':checkbox').map(function() {
result[this.id] = this.value;
});

Categories