I am dynamically building an array of objects using a process that boils down to something like this:
//Objects Array
var objects = [];
//Object Structure
var object1 = {"id":"foobar_1", "metrics":90};
var object2 = {"id":"some other foobar", "metrics":50};
objects[0] = object1;
objects[1] = object2;
(Let it be said for the record, that if you can think of a better way to dynamically nest data such that I can access it with objects[i].id I am also all ears!)
There's ultimately going to be more logic at play than what's above, but it's just not written yet. Suffice it to say that the "object1" and "object2" parts will actually be in an iterator.
Inside that iterator, I want to check for the presence of an ID before adding another object to the array. If, for example, I already have an object with the ID "foobar_1", instead of pushing a new member to the array, I simply want to increment its "metrics" value.
If I wasn't dealing with an array of objects, I could use inArray to look for "foobar_1" (a jQuery utility). But that won't look into the object's values. The way I see it, I have two options:
Keep a separate simple array of just the IDs. So instead of only relying on the objects array, I simply check inArray (or plain JS equivalent) for a simple "objectIDs" array that is used only for this purpose.
Iterate through my existing data object and compare my "foobar_1" needle to each objects[i].id haystack
I feel that #1 is certainly more efficient, but I can't help wondering if I'm missing a function that would do the job for me. A #3, 4, or 5 option that I've missed! CPU consumption is somewhat important, but I'm also interested in functions that make the code less verbose whether they're more cycle-efficient or not.
I'd suggest switching to an object instead of an array:
var objects = {};
objects["foobar_1"] = {metrics: 90};
objects["some other foobar"] = {metrics: 50};
Then, to add a new object uniquely, you would do this:
function addObject(id, metricsNum) {
if (!(id in objects)) {
objects[id] = {metrics: metricsNum};
}
}
To iterate all the objects, you would do this:
for (var id in objects) {
// process objects[id]
}
This gives you very efficient lookup for whether a given id is already in your list or not. The only thing it doesn't give you that the array gave you before is a specific order of objects because the keys of an object don't have any specific order.
Hmm , i wonder why dont you use dictionary cause that is perfectlly fits your case. so your code will be as below:
//Objects Array
var objects = [];
//Object Structure
var object1 = {"metrics":90};
var object2 = {"metrics":50};
objects["foobar_1"] = object1;
objects["some other foobar"] = object2;
// An example to showing the object existence.
if (!objects["new id"]){
objects["new id"] = {"metrics": 100};
}
else {
objects["new id"].matrics++;
}
Related
I'm not sure if this is a bug or if I have a complete misunderstanding of Javascript, but this is what happens:
I take an object with two arrays inside it, one representing the current queue of IDs and another representing the total queue of IDs (hypothetical situation)
var mainObject = {
object1:[],
object2:[]
};
In a function, we set the two property arrays to the same variable which holds the array needed before we can start processing the queue.
var randomVar = [1,2,3,4];
mainObject.object1 = randomVar;
mainObject.object2 = randomVar;
Now we want to make use of the splice method to remove the first index from object1 while keeping it on object two.
mainObject.object1.splice(0,1);
The result of the object is now as follows:
mainObject = {
object1:[2,3,4],
object2:[2,3,4]
};
meaning that both of the properties were spliced when we only asked Javascript to run it once.
See JS Fiddle for live example:
https://jsfiddle.net/ypow6y8g/
Is there something I'm missing or is this just another night spent with loose JS?
You have one array, and two variables whose value is a reference to that array. When you modify the value of one of those variables, you modify the other one as it's the same.
If you want your arrays to be independent, clone one:
var randomVar = [1,2,3,4];
mainObject.object1 = randomVar;
mainObject.object2 = randomVar.slice(); // slice returns a new array
Struggling with some javascript array manipulation/updating. Hope someone could help.
I have an array:
array('saved_designs'=array());
Javascript JSON version:
{"saved_design":{}}
I will be adding a label, and associated array data:
array("saved_designs"=array('label'=array('class'='somecssclass',styles=array(ill add more assoc elements here),'hover'=array(ill add more assoc elements here))))
Javascript version:
{"saved_designs":{"label":{"class":"someclass","style":[],"hover":[]}}}
I want to be able to append/modify this array. If 'label' already defined...then cycle through the sub data for that element...and update. If 'label' doesnt exist..then append a new data set to the 'saved_designs' array element.
So, if label is not defined, add the following to the 'saved_designs' element:
array('label2' = array('class'=>'someclass2',styles=array(),'hover=>array()')
Things arent quite working out as i expect. Im unsure of the javascript notation of [], and {} and the differences.
Probably going to need to discuss this as answers are provided....but heres some code i have at the moment to achive this:
//saveLabel = label the user chose for this "design"
if(isUnique == 0){//update
//ask user if want to overwrite design styles for the specified html element
if (confirm("Their is already a design with that label ("+saveLabel+"). Overwrite this designs data for the given element/styles?")) {
currentDesigns["saved_designs"][saveLabel]["class"] = saveClass;
//edit other subdata here...
}
}else{//create new
var newDesign = [];
newDesign[saveLabel] = [];
newDesign[saveLabel]["class"] = saveClass;
newDesign[saveLabel]["style"] = [];
newDesign[saveLabel]["hover"] = [];
currentDesigns["saved_designs"].push(newDesign);//gives error..push is not defined
}
jQuery("#'.$elementId.'").val(JSON.stringify(currentDesigns));
thanks in advance. Hope this is clear. Ill update accordingly based on questions and comments.
Shaun
It can be a bit confusing. JavaScript objects look a lot like a map or a dictionary from other languages. You can iterate over them and access their properties with object['property_name'].
Thus the difference between a property and a string index doesn't really exist. That looks like php you are creating. It's called an array there, but the fact that you are identifying values by a string means it is going to be serialized into an object in javascript.
var thing = {"saved_designs":{"label":{"class":"someclass","style":[],"hover":[]}}}
thing.saved_designs.label is the same thing as thing["saved_designs"]["label"].
In javascript an array is a list that can only be accessed by integer indices. Arrays don't have explicit keys and can be defined:
var stuff = ['label', 24, anObject]
So you see the error you are getting about 'push not defined' is because you aren't working on an array as far as javascript is concerned.
currentDesigns["saved_designs"] == currentDesigns.saved_designs
When you have an object, and you want a new key/value pair (i.e. property) you don't need a special function to add. Just define the key and the value:
**currentDesigns.saved_designs['key'] = newDesign;**
If you have a different label for every design (which is what it looks like) key is that label (a string).
Also when you were defining the new design this is what javascript interprets:
var newDesign = [];
newDesign is an array. It has n number of elements accessed by integers indices.
newDesign[saveLabel] = [];
Since newDesign is a an array saveLabel should be an numerical index. The value for that index is another array.
newDesign[saveLabel]["class"] = saveClass;
newDesign[saveLabel]["style"] = [];
newDesign[saveLabel]["hover"] = [];
Here explicitly you show that you are trying to use an array as objects. Arrays do not support ['string_key']
This might very well 'work' but only because in javascript arrays are objects and there is no rule that says you can't add properties to objects at will. However all these [] are not helping you at all.
var newDesign = {label: "the label", class: saveClass};
is probably what you are looking for.
Say I have multiple arrays.
var array1= [];
var array2= [];
var array3= [];
And I have another array of objects, each with a health parameter.
Say I push the first object in this array into array1, array2 and array3.
Now if I edit the health parameter of array1's object:
array1[0].health -= 50
it changes the health for each arrays object. How can I do it so it only does it for the array im calling into?
If you want a copy of the object in each array, and you don't want the modification of one to affect the others, then you will need to clone the object. The answers on this post will help you with this:
What is the most efficient way to deep clone an object in JavaScript?
Objects in javascript are assigned by reference so if you put the same object into two separate arrays, each array element points at exactly the same object.
If you want separate objects in each array, then you have to explicitly make a new object for the second array (copying properties from the first object if that's what you want).
In jQuery, you can use $.extend() to make a copy of an object. See this answer for two different ways to use it.
Or, in plain Javascript, here's a function that makes a shallow copy of a plain JS object.
function copyObj(src) {
var copy = {};
for (var prop in src) {
if (src.hasOwnProperty(prop)) {
copy[prop] = src[prop];
}
}
return copy;
}
var array1 = []
var array2 = []
array1.health = 50
array2.health = 10
console.log(array1.health)
50
it still remains 50. On the other hand if your question relates to changing array elements as such
var array1= [0,1]
array1[0].health = 50
array1[1].health = 10
console.log(array[0].health) will print out 10 because health is an property of the array object not the element.
I'm making a web app where a user gets data from PHP, and the data consists of MySQL rows, so I want to save the used ones in a global variable, something like a buffer, to prevent extra AJAX requests.
I'm doing this right now :
window.ray = []; // global variable
$(function(){
data = getDataWithAjax(idToSearch);
window.ray[data.id] = data.text;
});
but when the id is big, say 10 for now, window.ray becomes this :
,,,,,,,,42
so it contains 9 unnecessary spots. Or does it? Is it only visible when I'm doing console.log(window.ray);
If this is inefficient, I want to find a way like PHP, where I can assign only indices that I want, like :
$array['420'] = "abc";
$array['999'] = "xyz";
Is my current way as efficient as PHP, or does it actually contain unnecessary memory spots?
Thanks for any help !
Use an object instead of an array. The object will let you use the id as the key and be more efficient for non-sequential id values.
window.ray = {}; // global variable
$(function(){
data = getDataWithAjax(idToSearch);
window.ray[data.id] = data.text;
});
You can then access any element by the id:
var text = window.ray[myId];
If you are assigning values directly by property name, then it doesn't make any difference in terms of performance whether you use an Array or an Object. The property names of Arrays are strings, just like Objects.
In the following:
var a = [];
a[1000] = 'foo';
then a is (a reference to) an array with length 1,001 (always at least one greater than the highest index) but it only has one numeric member, the one called '1000', there aren't 1,000 other empty members, e.g.:
a.hasOwnProperty['999']; // false
Arrays are just Objects with a special, self–adjusting length property and some mostly generic methods that can be applied to any suitable object.
One feature of sparse arrays (i.e. where the numeric properties from 0 to length aren't contiguous) is that a for loop will loop over every value, including the missing ones. That can be avoided and significant performance gains realised by using a for..in loop and using a hasOwnProperty test, just like an Object.
But if you aren't going to use any of the special features of an Array, you might as well just use an Object as suggested by jfriend00.
I know that in JavaScript sometimes the system creates a fake array, meaning it is actually an object and not an instance of Array, but still has part of the functionality of an array. For example, the arguments variable you get inside functions is a fake array created by the system. In this case I know that to turn it into a real array you can do:
var realArray = Array.prototype.slice.call(fakeArray);
But what if the fake array wasn't created by the system, what if fakeArray was simply:
var fakeArray = { "0": "some value", "1": "another value" };
In this case, and I tested it, using the method above will result in an empty array. The thing I want to be able to turn a fake array like in the example I gave (created by me and not by the system) into a real array. And before you tell me to simply make the fake array a real array from the beginning, you should know that I get the fake array from a resource which I have no control of.
So, how do I turn a fake array not created by the system into a real array?
Your example will work if your "fake array" is given a .length property appropriately set.
This will not work in some older versions of Internet Explorer.
"one of the purposes of turning the fake array into a real array is to get its length"
If you want the number of properties in the object, use Object.keys...
var len = Object.keys(fakeArray).length;
To shim Object.keys for older browsers, you can do this...
if (!Object.keys) {
Object.keys = function(o) {
var keys = [];
for (var k in o)
if (o.hasOwnProperty(k))
keys.push(k)
return keys;
};
}
If the fake Array is "sparse", you'll need a solution like #Rocket shows.
You can just simply loop through the "array" and save the values into a real array.
var fakeArray = { "0": "some value", "1": "another value" };
var realArray = [];
for(var i in fakeArray){
realArray[i] = fakeArray[i];
}
You can iterate the object properties, while pushing the ones you want to your new array:
var array = [];
for (var i in fakeArray) if (fakeArray.hasOwnProperty(i)) {
array.push(fakeArray[i]);
}