javascript: array of variables or separate variables? - javascript

I used to store variables separately, for example, if I have an old element I would save it in a variable called "ele_old", and then later if I have a new element I would save that in a variable called "ele_new". However, it just occurred to me that I can save the 2 variables in 1 array variable, so I could do something like this:
eles_arr['old'] = //old element;
eles_arr['new'] = //new element;
this way would allow me to put variables of the same type into the same array for better organization, e.g. elements together in 1 array, and then ids together in another array.
The problem is I am quite new to javascript (and any other programming languages, for that matter), so I'm wondering if this is an inferior way than just keeping each variable separate. Will doing this cause any problems? for example, poor runtime performance?
Thanks!

What you're doing is setting properties on the eles_arr object. It's akin to saying:
eles_arr.oldEl = //old element
eles_arr.newEl = //new element
It's not storing them in an array, so it's similar to having the variables separated -- they're just grouped in the eles_arr object. To put them in an array you'd do:
eles_arr.push(oldEl);
eles_arr.push(newEl);
That being said I wouldn't put these two variables in an array. I would keep them separated to increase readability. It might make sense to you to have the values in the same array, and you may remember their positioning. Other developers may not though, which could lead to problems in the future.
Finally, having an array of two values for 'old' and 'new' will in no way affect performance in your case, but I still would not recommend using an array for readability's sake.
Update
I changed the variables from 'old' and 'new' to 'oldEl' and 'newEl' to reflect Šime's comment on the reserved keyword 'new'.

You can use an object to create a namespace / module, and so reduce the number of global / local variables:
var eles = {};
eles.foo = document.getElementById("foo");
eles.bar = document.getElementById("bar");
But that probably makes sense only if you have like 20 or more elements and you need them in various event handlers / functions. In that case, it makes sense to create the eles namespace and populate it with all your element references.

Related

AngularJS - Which scope is better performance wise? Object.key or Some Variable?

Let's say I have to store customer information, and to manage two-way binding I'll use $scope here.
So my doubt here is, which approach is better?
$scope.firstname = "foo";
$scope.lastname = "bar";
$scope.cellno = "1234567890";
$scope.email = "foobar#example.com";
OR
$scope.customerDetailsObj = {};
$scope.customerDetailsObj.firstname = "foo";
$scope.customerDetailsObj.lastname = "bar";
$scope.customerDetailsObj.cellno = "1234567890";
$scope.customerDetailsObj.email = "foobar#example.com";`
I've been wondering about this because I have a large angular application and sometimes the scope watchers count goes beyond 1500. I'm using a chrome extension to see watchers count.
Please share your views. Thank You.
In my opinion and as-per angularjs guide first approach (binding to properties directly) will be more efficient. Excerpt from the guide:
Dirty checking can be done with three strategies: By reference, by
collection contents, and by value. The strategies differ in the kinds
of changes they detect, and in their performance characteristics.
Watching by reference (scope.$watch (watchExpression, listener)) detects a change when the whole value returned by the watch expression
switches to a new value. If the value is an array or an object,
changes inside it are not detected. This is the most efficient
strategy.
Watching collection contents (scope.$watchCollection (watchExpression, listener)) detects changes that occur inside an
array or an object: When items are added, removed, or reordered. The
detection is shallow - it does not reach into nested collections.
Watching collection contents is more expensive than watching by
reference, because copies of the collection contents need to be
maintained. However, the strategy attempts to minimize the amount of
copying required.
Watching by value (scope.$watch (watchExpression, listener, true)) detects any change in an arbitrarily nested data structure. It is the
most powerful change detection strategy, but also the most expensive.
A full traversal of the nested data structure is needed on each
digest, and a full copy of it needs to be held in memory.
Talking only about performance, I think option 1 (having plain variables) it's more efficient.
Watching plain properties
the $watch() function, by default only checks object reference equality. So within each $digest it will check to see if the new and old values pointing to the same object.
Watching objects and arrays
If you want to $watch() an object, you have to switch to the deep watch and that means that within each $digest, it will check the whole tree to see if the structure or values are changed. So, bigger the object, more expensive the check.
$watchGroup(), an alternative to objects/array watchers
If you have a group of related properties like ie a person (name, surname, age), you could define it like plain properties, and use $watchGroup(), that works on the same way like a common $watch() but taking a list of properties to watch rather than one.

Best (most performant) way to declare (class) properties with unknown values in v8

So I learned a bit about the hidden class concept in v8. It is said that you should declare all properties in the constructor (if using prototype based "pseudo classes") and that you should not delete them or add new ones outside of the constructor. So far, so good.
1) But what about properties where you know the type (that you also shouldn't change) but not the (initial) value?
For example, is it sufficient to do something like this:
var Foo = function () {
this.myString;
this.myNumber;
}
... and assign concrete values later on, or would it be better to assign a "bogus" value upfront, like this:
var Foo = function () {
this.myString = "";
this.myNumber = 0;
}
2) Another thing is with objects. Sometimes I just know that an object wont have a fixed structure, but I want to use it as a hash map. Is there any (non verbose) way to tell the compiler I want to use it this way, so that it isn't optimized (and deopted later on)?
Update
Thanks for your input! So after reading your comments (and more on the internet) I consider these points as "best practices":
Do define all properties of a class in the constructor (also applies for defining simple objects)
You have to assign something to these properties, even if thats just null or undefined - just stating this.myString; is apparently not enough
Because you have to assign something anyways I think assigning a "bogus" value in case you can't assign the final value immediatly cannot hurt, so that the compiler does "know" ASAP what type you want to use. So, for example this.myString = "";
In case of objects, do assign the whole structure if you know it beforehand, and again assign dummy values to it's properties if you don't know them immediatly. Otherwise, for example when intending to use the Object as a hashmap, just do: this.myObject = {};. Think its not worth indicating to the compiler that this should be a hashmap. If you really want to do this, I found a trick that assigns a dummy property to this object and deletes it immediatly afterwards. But I won't do this.
As for smaller Arrays it's apparently recommended (reference: https://www.youtube.com/watch?v=UJPdhx5zTaw&feature=youtu.be&t=25m40s) to preallocate them especially if you know the final size, so for example: this.myArray = new Array(4);
Don't delete properties later on! Just null them if needed
Don't change types after assigning! This will add another hidden class and hurt performance. I think thats best practice anyways. The only case where I have different types is for certain function arguments anyways. In that case I usually convert them to the same target type.
Same applies if you keep adding additional properties later on.
That being said, I also think doing this will lean to cleaner and more organized code, and also helps with documenting.
Yeah, so one little thing I am unsure remains: What if I define properties in a function (for example a kind of configure() method) called within the constructor?
Re 1): Just reading properties, like in your first snippet, does not do anything to the object. You need to assign them to create the properties.
But for object properties it doesn't actually matter much what values you initialise them with, as long as you do initialise them. Even undefined should be fine.
The concrete values are much more relevant for arrays, where you want to make sure to create them with the right elements (and without any holes!) because the VM tries to keep them homogeneous. In particular, never use the Array constructor, because that creates just holes.
Re 2): There are ways to trick the VM into using a dictionary representation, but they depend on VM and version and aren't really reliable. In general, it is best to avoid using objects as maps altogether. Since ES6, there is a proper Map class.

Associate Data With HTML Element (without jQuery)

I need to associate some data with an HTML Element, hopefully avoiding any memory leaks. Obviously a simple solution would be to throw some kind of identifier on the element, and then create a dictionary mapping that identifier to the data I need. However, this is in a javascript library that users will add to their page, thus I don't have control over when elements are added or removed.
What I'm looking to do is associate data with an HTML element while it's on the page, while allowing for that data to be GC'd when/if the element is removed. Is there a way to do this that doesn't involve writing my own periodic GC to clean up orphaned data? Is it safe to add properties to HTML elements?
Attribute approach
You can store data in elements using custom data-* attributes.
This has the limitation that you can only store strings, but you can use JSON to store plain objects or arrays (not by reference).
To avoid conflicts with other code, it would be a good idea to include the name of your library in the attribute.
They can be set directly in the HTML:
<div data-mylibrary-foo="bar"></div>
And they can be read or written with JavaScript:
element.getAttribute('data-mylibrary-foo'); // read (old way)
element.setAttribute('data-mylibrary-foo', 'bar'); // write (old way)
element.dataset.mylibraryFoo; // read (new way)
element.dataset.mylibraryFoo = 'bar'; // write (new way)
They can also be read by CSS, using some attribute selector.
Property approach
This is much more flexible than the attribute approach, allowing to store arbitrary data in your element.
To avoid conflicts with other code, better wrap all properties in an object with the name of your library:
element.mylibrary = {};
element.mylibrary.foo = 'bar';
The problem is that a future HTML standard could define mylibrary as a native property, so there could be problems.
Symbol approach
ECMAScript 6 introduces symbols, which can be used as properties. The advantage is that each symbol has an unique identity, so you don't need to worry about some other library or a future standard using the same properties as your code.
var foo = Symbol("foo");
element[foo] = 'bar';
WeakMap approach
ECMAScript 6 introduces WeakMaps, which allow you to associate data with objects in a way that, if the objects are no longer referenced anywhere else, they will be garbage collected.
Like the property approach, they allow you to store arbitrary data.
Since the data is not stored in the elements themselves, there is no risk of conflicts.
var allData = new WeakMap();
var data1 = allData.get(element1) || {}; // read
data1.foo = "bar";
allData.set(element1, data1); // write
An HTML element in JavaScript is just a JavaScript object, so you can certainly add arbitrary properties to it. JavaScript will handle the garbage collection just fine.
The data- attribute is another option and might be a better choice if your properties are strings; their values will be visible in the DOM (which might be a good thing for debugging). If your properties are themselves objects, then you'd have to stringify them (and reverse the process to retrieve their values).

Re-implement javascript delete keyword

As many of you are aware, the javascript delete keyword is a little tricky to use (see here). Is it possible to re-implement, or modify it? I have an object referenced multiple times and I want delete to remove all the references first. Like so:
var oj = new OrangeJuice();
var juice = oj;
var beverage = oj;
var allRightSunnyD = oj;
delete oj; //I want this to delete the actual object
I do not expect the garbage collector to find all of the references, lets say I know where the references are, i just want to re-implement delete to also get rid of juice, beverage and allRightSunnyD. I realize I could just implement a OrangeJuice.delete() function, but I wanted to know if there was a way to do it right. Like if javascript would call an onDelete() callback function prior to deleting objects.
delete is a keyword, so it should not be altered even if you can
delete is for deleting properties of objects, so you can not delete objects contained in single variables
look here how garbage collection in Javascript is explained: How does garbage collection work in JavaScript?

JS object custom variables

I read somewhere that objects were basically hash tables, and you could assign values to them willy nilly. Well, I am hoping to take advantage of this, but I want to know if it is even possible, if it is considered "correct", and, if there are any unwanted situations.
My situation:
I have a serious of objects (the kind which CANNOT be stored in the DOM!) which I want to assign to DOM objects. My plan is to:
FInd a dom object (A div, or area of some form), and then assign that to the variable myVar
I will then call: myVar.customVal = value
customVal of course is not defined in the DOM specification. Will that even work, though? Will it show up in the DOM, or stay a virtual variable? Is there any way to assign custom values to members of the DOM for access later?
You can do it:
var foo = document.getElementById('sidebar');
foo.party = 3;
console.dir(foo);
But no, it's not considered good practice. Rather, consider using HTML5's custom data attributes, or better yet, jQuery's abstraction of them.

Categories

Resources