Does anyone know whether there are any performance trade-offs/advantages to assigning an object's fields at creation rather than later e.g.
var exObj = new exampleObject(name, date);
OR
var exObj = new exampleObject();
exObj.name = "blah";
exObj.date = "blah";
(assuming you've created your class accordingly)
Also, as a side thought, given that JS arrays are stored as objects, am I correct in assuming that there are no performance differences between using one over the other ? (For some reason using an array with a numeric index "feels" faster.)
Cheers
N
Test it yourself - http://jsperf.com/assign-object-fields-at-creation-or-later
Related
I am fetching data from db and storing it in an array in key value pair, so that i can get values of respective keys as below
var test = [];
for () //fetching and storing from db
{
test[key_array[i]] = "value i";
.
.
.
}
test["id_1"] = "value 1"; //to get the value of id_<number>
we can achive this though objects too. I wanted to know which is the better option to consider, if we want a fast and optimized code
Is array better than objects for storing and searching key value pairs in javascript?
No. In fact, you're not using the array as an array, you're using it as an object. You could literally change your
var test = [];
to
var test = {};
// or
var test = Object.create(null); // To avoid it having a prototype
and it would do the same thing you're seeing now:
var test = {};
test["id_1"] = "value_1";
console.log(test["id_1"]);
var test2 = Object.create(null);
test2["id_2"] = "value_2";
console.log(test2["id_2"]);
(And you should change it, since using an array only for its object features is confusing to people maintaining your code.)
[] is a property accessor that accepts the property name as a string. (We use it with standard arrays as well, using numbers, but in theory they get converted to strings before the property is looked up, because standard arrays aren't really arrays at all¹.)
In ES2015+, of course, you'd probably use a Map, not an object:
const test = new Map();
test.set("id_1", "value_1");
console.log(test.get("id_1"));
¹ That's a post on my anemic little blog.
Arrays, are just a kind of object specialized for storing sequences of things. If you evaluate typeof [], it produces "object".
https://eloquentjavascript.net/04_data.html#h_cqg63Sxe3o
The idea of an array is store sequences of data with the same type or logic structure. Thus, is logic put the data come from a db into an array.
Note that you should avoid this because it can become very confusing :
var test = [];
test["id_1"] = "value_1";
test[-1] = "value_0";
console.log(test[-1],test["id_1"]);
console.log(test.length,Array.isArray(test));
It lets you think that test is an array (and it is) but test[-1] and test["id_1"] are not part of the array (that's why Array.isArray(test) returns true, but test.length is still equal to 0. See explanation on link provided by mister T.J. Crowder
I'm coming to javascript from C background. In javascript, when I use the assignment operator to assign one object to another, does it copy the values from one to the another, or do they both now point to the same data?. Or does the assignment operator do anything in this case?
function point_type()
{
this.x = 0;
this.y = 0;
}
var pnt1 = new point_type();
var pnt2 = new point_type();
pnt1.x = 4;
pnt1.y = 5;
pnt2 = pnt1;
pnt1.x = 8;
pnt2.y = 9;
In the example above, does pnt2.x now equal 8, or does it still equal 4, or does it still equal 0?
Yes, I realize I can test this myself, and I will be doing that while I wait for the community to come up with an answer. However, I'm hoping the answer to my question will go one step past just answering this one example and might shine some light on how javascript objects work and some best practices.
Follow up question:
The answer seems to be that the reference is copied. pnt2 and pnt1 now point to the same data. Is it possible to set up my object so that the values are copied? How is this usually accomplished in javascript? Clearly I don't want to set each attribute individually every time I need to copy this object.
Whenever I need to copy one object to another in JS, I just cast it to a primitive:
var newObject = JSON.stringify(oldObject);
Then when I need to use it:
var evenNewerObj = JSON.parse(newObject);
Hope this helps someone.
In JavaScript, primitive types are copied by value and reference types are copied by reference. More info here: http://docstore.mik.ua/orelly/web/jscript/ch09_03.html
It equals 8.
pnt2 = pnt1
That statement is pointing the pnt2 object to the pnt1 object so any modification you do to pnt1 will show up in pnt2.
Given the object you showed in your example, it is setting a reference to the object. If it were a primitive type (number, date) then it would copy the object.
I prefer to declare all global variables at the beginning of my code using self-explanatory, full-named variables:
var $interval_start_dates = []; // date intervals
var $interval_end_dates = [];
var $interval_start_milli = []; // convert dates to milliseconds
var $interval_end_milli = [];
var $interval_start_milli_sorted = []; // sort millisecond dates
var $interval_end_milli_sorted = [];
This naming convention often results in long variable-names which I find unhandy when using them in the code. Therefore I also prefer to use abbreviations for the variables in the code:
var _isd = $interval_start_dates;
var _ied = $interval_end_dates;
var _ism = $interval_start_milli;
var _iem = $interval_end_milli;
var _isms = $interval_start_milli_sorted;
var _iems = $interval_end_milli_sorted;
My questions in this regard are the following:
(1) Is it possible to output the intermediate variable (e.g. $interval_start_dates) using the abbreviation (e.g. _isd)?
(2) Does this naming convention result in worse performance of the code (e.g. speed) and if so is there a better way to use abbreviations?
One remark: I know that I could just use comments to inform about the full name of an abbreviated variable. But this means that I would have to repeat those comments many times in my code. I am looking for a more "slick" solution which allows me to use for example console.log to display the full name of a variable (if this is possible).
why not use some data structure. the advantage is the more readable format and you can use abbreviation for accessing the variables.
var interval = {
start: {
dates: [], // date intervals
milli: [], // convert dates to milliseconds
milli_sorted: [] // sort millisecond dates
},
end: {
dates: [],
milli: [],
milli_sorted: []
}
};
// use
var ie = interval.end;
alert(ie.dates);
Is it possible to output the intermediate variable (e.g. $interval_start_dates) using the abbreviation (e.g. _isd)?
Yes. They both refer to the same array, so it doesn't matter which you use to output the array.
(2) Does this naming convention result in worse performance of the code (e.g. speed) and if so is there a better way to use abbreviations?
No. They both refer to the same array, each is just as direct a reference as the other.
But, there are other potential issues. For instance, if you had need of filtering or mapping those arrays, it would be really easy to update one reference and forget the other, e.g.:
_isd = _isd.filter(function(entry) { return entry.foo < bar; });
// OOOPS! Now `_isd` and `$interval_start_dates` don't refer to the same array anymore!
If it's just typing out the names, any good IDE can make that easier for you.
I am looking for a more "slick" solution which allows me to use for example console.log to display the full name of a variable (if this is possible).
I'm not sure what you're asking here, but if you mean that you want to use _isd somewhere (for instance, a function) and have that function display $interval_start_dates in its output instead of _isd, then you can't (reasonably) do that. There is no link between _isd and $interval_start_dates, other than that they refer to the same array. But then, you can't do that anyway — if you passed $interval_start_dates into a function, it still can't infer the name of it, because the function's argument that receives the value isn't linked in any way to $interval_start_dates (other than that they refer to the same array).
Side note: If all of these things are arrays, and you want to have some way of knowing a "name" of the array based on an array reference, you can take advantage of the fact that standard arrays in JavaScript aren't really arrays at all, they're just objects and assign them a property with the name in, for instance:
var $interval_start_dates = []; // date intervals
$interval_start_dates.name = "$interval_start_dates";
// ...
var _isd = $interval_start_dates;
console.log(_isd.name); // "$interval_start_dates"
If you do that, be sure you're not using for-in to loop through the arrays (but there are better ways anyhow). Or use Object.defineProperty to define the name instead:
var $interval_start_dates = []; // date intervals
Object.defineProperty($interval_start_dates, "name", {
value: "$interval_start_dates"
});
...and properties added that way are non-enumerable by default.
Performance-wise this does not matter. Your code will becoming less readable though. So you will have to decide what is more important to you: readability or coding faster. You can achieve both though by using an IDE which autocompletes your variable names.
Also, most of the time your variable names can be made shorter while not losing any meaning, for example:
var $interval_start_milli could be changed to var interval_start_ms or even var start_ms, since an interval has a start and an end, which would mean you would either have var interval_ms or start_ms and end_ms. Where var interval_ms is an array of objects with a start and an end property.
But that also depends on which other global variables you have declared though.
Another thing is that you shouldn't rely on global variables too much in javascript.
I've added a field "max" to the JS array prototype. I'm having trouble seeing this addition when I stringify the array. I've tried to overwrite the toJSON function but to no avail.
Array.prototype.max = 0;
Array.prototype.toJSON = function(){
var o = this;
o.max = this.max;
return o;
};
var a = [1,2,3];
a.max = 10;
console.log(JSON.stringify(a));
//'[1,2,3]'
I'd like to avoid doing something like {array_field:a,max_field:max} and just use the array object - is this possible? What am I doing wrong?
You have a few options here, none of them will do exactly what you want.
Since JSON arrays are strictly limited to integer keys[1], you can't send down the value of max directly.
Your choices include:
Using an object instead of an array. You loose all of the array magic, but it might work better for you.
Send down meta-data outside your array, such as a configuration object that includes both max and your array values
Force the array to be max long before sending it down. JSON will encode unused array elements with null.
Use a custom serialzer/deserializer. You could even code things in JSONS + the extras. In reality, this pretty much turns out the same as the second option.
[1] Unlike JavaScript Objects
I'm working with phylogentic trees and I want an object for the tree itself and then an object for each species, 4 species total. I'm trying to have the tree contain the species objects under tree.leaf and then assign an array of attributes to each species but through the tree object, because I'm randomizing the order of the species so I can't depend on species names but I can use leaf placement(Hope that makes sense). I'm having trouble updating the html, a div inside a table though.
Simplified Version:
var tree = new Object();
var speciesA = new Object();
tree.leaf1 = speciesA;
//Not sure if this next line assigns to speciesA or what exactly happens
tree.leaf1.attributes = new Array("Attr1","Attr2",etc);
var count = 1;
for(attr in speciesA.attributes)
{
//There are 4 divs per speices to display attributes
document.getElementById("A"+String(count)).innerhtml = speciesA.attributes[attr];
count++;// used to specify divs ie A1 = attribute1, A2 = attribute2 etc
}
So I guess my main question is will this work/do what I think it does?
If needed I can pastebin my html and full js files.
What you have should work, but it can be written a bit cleaner. I would suggest this:
var tree = {
leaf1: {attributes: ["Attr1", "Attr2"]}
};
var attributes = tree.leaf1.attributes;
for (var i = 0; i < attributes.length; i++) {
document.getElementById("A"+(i+1)).innerHTML = attributes[i];
}
Things I changed:
Used a javascript literal to make the definition a lot more compact
Used {} and [] for defining arrays and objects rather than new Object() and new Array().
Used for (var i = 0; i < xxx.length; i++) syntax to iterate array elements only, not all properties. This is the "safe" way to iterate elements of an array.
Remove the String(count) as it is not needed. Javascript will auto-convert a number to a string when adding to another string.
Cached the value of the attributes array to save having to deep reference it each time.
Removed separate count variable as the for index can be used
To answer one of your other questions, when you do this:
tree.leaf1 = speciesA;
you have assigned a "reference" to speciesA to tree.left1. A reference is like a pointer. It is not a copy. So, the both refer to exactly the same object. Any change you make to speciesA or to tree.leaf1 is make a change to the exact same object.
So, when you then do this:
//Not sure if this next line assigns to speciesA or what exactly happens
tree.leaf1.attributes = new Array("Attr1","Attr2",etc);
you are indeed modifying the speciesA object since speciesA and tree.leaf1 point to the same object.
In javascript, arrays, objects and strings are assigned by reference. That means that when you assign one to a variable, it just points to the original object. A copy is not made. So, change the object via either either one will change the other (since they both point to the same object). Strings are immutable (a string is never actually changed). Things that feel like modifications to a string always just return a new string so this aspect of javascript doesn't affect strings so much. But, it is very important to know that arrays and objects are assigned by reference.