Sample object:
const myArray = {'attributes':{ 'fullName': 'Foo Bar'};
During code review, I found that one key(string type) was being used to access the object in multiple functions.
Now my question is, should we access the object directly by using the string literal as key, e.g. myArray['attributes']['fullName']
or use a constant instead, like :
const ATTRIBUTES = 'attributes';
const FULLNAME = 'fullName';
someVar = myArray[ATTRIBUTES][FULLNAME];
According to my knowledge, the latter approach is better because it reserves only one memory block.
But my friend had a different opinion, he told if we use the string literal for key, then it won't have any impact on memory.
Now, I am confused and don't know which approach is better.
Could anyone help me understanding which one is better with explanation?
Something like this will make no performance difference. In my opinion the second option is less readable too.
I would take
myArray.attributes.fullName
because it shows the compilter to use a constant to a value, instead of using brwacket notation where the structure is aimed for dynamic use.
I don't know about the memory, and I'm using the first option, but in case of the key changing I'll have to modify it at several places rather than one so for code retake it's not so good
Related
I have a REST endpoint that returns large array (100K+ elements) with objects that have properties that contain dates in ISO format (like 2021-08-08T10:48:39.637Z) and I need to parse them to Date type.
I currently have something like:
const res = await fetch(...);
const json = await res.json();
for (let x of json.arr) {
x.d = new Date(x.d);
}
I'm worried that this might cause some unwanted slowness by messing with V8 Hidden Classes and also because of the type change (string => Date) for d property.
I read here that changing property type messes with V8 inner optimizations:
Changing the property or element type typically causes V8 to create a different HiddenClass which can lead to type pollution which prevents V8 from generating optimal code.
One alternative might be to use JSON.parse() with revival() param, that allows to parse values based on key name, but I'm not sure how the internals are handled with V8 in this and is there even a difference compared to what I'm doing currently.
const json = JSON.parse(txt, (key, val) => {
if (key === "d") {
return new Date(val);
}
return val;
});
Another approach might be to remap the objects returned from await res.json() like
const json = await res.json();
const objArr = json.map(x => ({ ...x, d: new Date(x.d) }));
With this approach I'm concerned about the overhead of cloning 100K+ objects and will they all have the same V8 Hidden Class?
I'm not concerned about JSON.parse() performance by itself, only about messing up V8 Hidden Classes or messing with some internal optimizations due to property type change to Date. It's a large array of objects and performance is very important for this WebApp, so I want to make sure I'm not making any huge mistakes.
What would be the most efficient way to parse Date types, taking into consideration the V8 optimzations?
(V8 developer here.)
It's fine, just write code that makes sense and let the engine worry about making it fast. There's nothing wrong with your current approach.
Also, if it did turn out that the most obvious way to write some code wasn't running as well as it could, then it'd be our job to fix that; we wouldn't want JavaScript developers to have to go through contortions to work around engine deficiencies.
is there even a difference compared to what I'm doing currently
Generally speaking, the only way to make sure which of two (or more) approaches is better, and whether there even is a difference, is to implement both and measure. When you do that, be sure to use realistic data, ideally your own full production app, or a snapshot/simulation of it. Reduced microbenchmarks with just a couple of lines are usually misleading (i.e.: what they appear to be telling you is unrelated to, and maybe even the opposite of, what effect you'll see in your full app), because dramatically simplifying the scenario usually changes the decisions that an engine will make under the hood. You may think "but in my full app, I won't see the impact of such a small detail" -- well, if that's the case, then that's your answer: it doesn't matter.
To preface, I have found a solution that works for me in the situations I have tried it, but I am fairly new to javascript and RXJS and don't fully understand what the solution is doing so I can't be sure if it will work in every instance.
I am using reactive forms and have arrays of checkboxes, what I would like to do is get an array of all of the keys used to generate the checkboxes, but without any of the unchecked boxes. Ideally, I could use this to return additional values as well such as a user-readable string, but that is far from important as I can do that in a separate step fairly easily. I have come up with a few methods of my own, but they don't seem to be very robust or performant.
I would have replied on this thread, but I lack the reputation.
This is the best solution I have found, which I would be totally happy to use, but I don't have much experience with RXJS or maps in javascript so I am not totally sure what it is doing:
this.controlNames = Object.keys(this.checkboxGroup.controls).map(_=>_); //This seems to just produce an object of control keys as properties and their value
this.selectedNames = this.checkboxGroup.valueChanges.pipe(map(v => Object.keys(v).filter(k => v[k]))); //Some sort of magic happens and an array is generated and contains only the keys whose values are 'true'
I have tried breaking that snippet apart and using console.log to test what it is doing in each step, but it really didn't give me much useful information. Any advice or or better ideas would be thoroughly appreciated, there seem to be a lot of conventions in javascript that people adhere to and it can be hard to sort through what is a convention and what is actually doing something.
I think I found a way to break it down and get a grip on it and want to post my explanation for anyone who comes looking.
In this part, it is just creating an iterable map of the 'checkboxGroup.controls' object. This could have been used to loop over in the template and make all of the checkboxes. Since my form structure is already generated from arrays of objects with known properties, I don't need this. The underscores aren't doing anything special here, people just like to use them for private variables.
this.controlNames = Object.keys(this.checkboxGroup.controls).map(_=>_);
For those who are new to arrow functions or some of the conventions of javascript, the code above is not quite, but essentially shorthand for this:
this.controlNames = [];
Object.keys(this.checkboxGroup.controls).forEach(function(key) {
this.controlNames.push(key);
}
I have changed the short variables to longer ones to make them easier to understand in this second part. This maps the value changes observable as an iterable 'changesObj', retrieves the keys, and filters the keys by instances where the key has a true value. The code filter(key => changesObj[key]) returns the key if the key is not null, undefined, or false.
this.selectedNames = this.checkboxGroup.valueChanges.pipe(map(changesObj => Object.keys(changesObj).filter(key => changesObj[key])));
This is essentially just shorthand for this:
function propNotFalse (changes, prop) {
return changes[prop] == true;
}
this.selectedNames = this.alternateFilter = Object.keys(this.checkboxGroup.valueChanges).filter(this.propNotFalse.bind(null, this.checkboxGroup.valueChanges));
I'm hoping to take advantage of underscore to avoid writing for loops throughout my code base. I'm using map in place of a for loop like so:
body.tags = _.map(body.tags, function(tag) {
return {
id: tag.id,
userId: tag.userId,
createDate: tag.createDate,
tag: tag.tag.toLowerCase(),
};
});
My question is, is there a way to do this without specifying the properties that won't be changing (everything but tag)? It seems like overkill to specify fields like id: tag.id.
You don't even need underscore for this:
body.tags.forEach(function(t) { t.tag = t.tag.toLowerCase();});
map (whether native, underscore or others) is used to transform whole values, it's not a typical use case to do what you tried to do with it. Also, using a simple for might perform better since you don't need function calls here, but that depends on runtime optimizations.
By the way, if you replace the mapping function with the function from this answer and not set the return value back to body.tags, you'll also get your desired result.
You could try the following code to change a single property in a collection using underscore.
_.map(body.tags, function(tag) {
tag.tag = tag.tag.toLowerCase();
return tag;
});
There is one benefit in using lodash's map method (similar to underscore library) over native forEach and its performance. Based on why lodash is faster than native forEach post, maybe it's justifiable to use lodash in favour of both underscore and native forEach to loop. However I would agree with the user who commented below "Choose the approach that is most writable, readable, and maintainable".
If I have a whitelist of strings that I want to check everything the user inputs into my javascript program, what's the most efficient way to do that? I could just have an array and loop through it until a match has been found but that's O(N). Is there an yway to do it that's better and doesn't involve any sort of key value lookup, just checking to see if that value exists?
EDIT: I guess what I'm looking for is the equivalent of a set in C++ where I can just check to see if a value I'm given already exists in the set.
Just make it a simple js object instead of an array.
var whitelist = {
"string1":true,
"string2":true
}
and then you can just check if(whitelist[str]) to check if its available.
Or use if(str in whitelist).
I expect that the first will have slightly better performance (I haven't verified that), but the second is more readable and makes the purpose clear. So its your choice of which is a better fit.
Sort the array, use binary search for the look-ups.
Or
Create an object where the key is the item and use the hash look-up whitelist[value] != undefined
I think you'll find that key-value lookup is almost identical in performance to some kind of set implementation without values. (Many standard libraries actually just implement a set using a map)
I've got an array with about 250 entries in it, each their own array of values. Each entry is a point on a map, and each array holds info for:
name,
another array for points this point can connect to,
latitude,
longitude,
short for of name,
a boolean,
and another boolean
The array has been written by another developer in my team, and he has written it as such:
names[0]=new Array;
names[0][0]="Campus Ice Centre";
names[0][1]= new Array(0,1,2);
names[0][2]=43.95081811364498;
names[0][3]=-78.89848709106445;
names[0][4]="CIC";
names[0][5]=false;
names[0][6]=false;
names[1]=new Array;
names[1][0]="Shagwell's";
names[1][1]= new Array(0,1);
names[1][2]=43.95090307839151;
names[1][3]=-78.89815986156464;
names[1][4]="shg";
names[1][5]=false;
names[1][6]=false;
Where I would probably have personally written it like this:
var names = []
names[0] = new Array("Campus Ice Centre", new Array[0,1,2], 43.95081811364498, -78.89848709106445, "CIC", false, false);
names[1] = new Array("Shagwell's", new Array[0,1], 43.95090307839151, -78.89815986156464, 'shg", false, false);
They both work perfectly fine of course, but what I'm wondering is:
1) does one take longer than the other to actually process?
2) am I incorrect in assuming there is a benefit to the compactness of my version of the same thing?
I'm just a little worried about his 3000 lines of code versus my 3-400 to get the same result.
Thanks in advance for any guidance.
What you really want to do here is define a custom data type which represents your data more accurately. I'm not sure what language you are using so here is some psuedocode:
class Location
{
double latitude;
double longitude;
String Name;
String Abbreviation;
bool flag1;//you should use a better name
bool flag2;
}
Then you can just create an array to hold all the Location objects and it would be much more readable and maintainable.
Locations = new Array;
Locations[0] = new Location("Shagwell's",...);
....
===EDIT===
Because you said you are using javascript then the best practise would probably be to store your data in a json text file, this has the benefit of removing the data from the code file and having a very easily editable data source if you want to make changes.
your JSON file would look like this
[{"lat":"23.2323", "long":"-72.3", "name":"Shagwell's" ...},
{"lat":"26.2323", "long":"-77.3", "name":"loc2" ...},
...]
You could then store the json text in an accesible place on your webserver say "data.json", then if you are using jquery you can load it in by doing something like this:
$.getJSON("data.json", function(data) { //do something with the data});
With structured data, like your example, both you and your co-worker are relatively "wrong". From the looks of things, you should have implemented an array of structures, assuming of course that the data you are presenting is truly unordered, which I would be willing to guess it probably isn't. Arrays are used too often, because they are amongst the first data structures we learn, but very often aren't the best choice.
As to performance, that more often comes down to the data access code than the data type itself. Frankly too, unless you are dealing with gigantic datasets or literally real time applications, performance should be a non issue.
As to the two examples you have posted, after the compiler is done with them, they will be virtually identical.
I personally find the former much more readable. From a performance perspective, the difference is probably minimal.
Leaving the other answers aside (although I agree with the others that you need structs here) your co-workers way seems better to me. Like Serapth says, the compiler will optimize away the differences and the original code has better readability.