JS object custom variables - javascript

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.

Related

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).

JavaScript best practice naming convention for DOM element

Is there a best practice, or industry-wide standard for JavaScript naming convention for DOM element?
Take the following example:
var tarzan = document.getElementById('foobar');
What would be the most acceptable name to use so that a DOM element could be differentiated from another type of var? Should it be...
DOM_tarzan
DOMtarzan
elementTarzan
.... so on and so forth?
I want to be able to tell the difference by just looking at the variable. For example, if I see:
DOM_tarzan.remove();
... I know straightaway that "DOM_tarzan" is a DOM element, and that it is employing the standard JavaScript remove() method.
There is no mistaking or guesswork that "DOM_tarzan" is a custom object that has a user-defined "remove()" method.
Thanks.
For indicating that a JS object variable references a DOM element object, I append El (or Elem) as a suffix to the variable name, as in
var tarzanElem = document.getElementById('foobar');
Whether I include jQuery in my projects or not, i like my naming convention of variables to be $variable. Then I can easily see if the variable is a DOM element.

What is the cost to convert a javascript variable to jQuery Object?

Sometimes I see in Javascript functions that, if the conversion of a variable to jQuery is used repeatedly, then it can be assigned to a local variable first:
$variable = $(variable);
Is this necessary, and how much is the cost of conversion?
No matter what, storing the object is faster than having to re-instantiate a jQuery object every time you want to use jQuery methods on it...even if it's miniscule for caching $(this) or $(anObject).
A term used to describe this method of "store now, use later" is "caching". The reason it's often called "caching" is because caching refers to storing a reference to something once and using that, without going back out to grab the same thing again, later (very non-technical, non-100% accurate description).
The major point is dealing with selectors. jQuery has to query the DOM every time, which is the expensive part. Generating the object and storing references isn't that expensive compared to DOM manipulation (and jQuery processing your selection in the first place).
If you're simply creating a jQuery object out of an object reference, it's not nearly as devastating, as the processing that takes place is the creation of the jQuery object...so it's really limited to whatever jQuery does for that. It's still good practice and still prevents some unnecessary processing. For example, this:
var element = document.getElementById("div_id");
$(element).someMethod();
// Later:
$(element).someOtherMethod();
is slightly inefficient, since a new jQuery object is created each time. It could easily be condensed to store a reference to a single jQuery object in a variable, and reference that.
The one caveat I can think of is that it isn't a live list of elements (if selecting DOM elements). For example, you may want to cache all elements with the class testing-class, like so:
var myelements = $(".testing-class");
But if another element is added to the DOM with the testing-class class, myelements will not be reflected. It will have the same, previous list. So in that case, the DOM will obviously need to be re-queried and update myelements.
To me, the best practice for caching is within a scope....not the entire page. If you are running a function, and it selects some elements, cache it at the beginning, and use that. But don't cache it globally and use it throughout your page; cache it for an execution cycle.
For example, I would do this:
function someFunc() {
var elements = $(".class-stuff");
// Use `elements` here
// code
// Use `elements` here
someOtherFunc(elements);
}
function someOtherFunc(el) {
// Use `el` here
}
someFunc();
// Some time later:
someFunc();
but I wouldn't do this:
var elements = $(".class-stuff");
function someFunc() {
// Use `elements`
}
function someOtherFunc() {
// Use `elements`
}
someFunc();
someOtherFunc();
// Some time later
someOtherFunc();
It depends on what the variable is. If the original variable is just a single DOM element then it's not particularly expensive - the DOM traversal has already been done so all you're doing is wrapping that element in the jQuery pseudo-array and attaching the prototype.
However if the original variable is a selector, then you absolutely should cache the result to avoid repeated conversions from DOM -> element list.
In any event, it's good practise not to repeat yourself, so caching $(variable) is just good code hygiene.
If the $(variable) is being called anyway this assignment has basically no cost -- this is only storing a reference to the object in memory.
Purists might point out that because the jQuery object is now stored it can't be garbage collected, and this is true. So I guess if you had lots of these it could cause a memory issue, but in itself it has no cost to speak of.
The reason it is done is because there is a cost associated with creating the object, that is the $(variable) part. That if done many times could be expensive. Store a reference to the object means only one needs to be created.
Another important point: The following statement
var $variable = $(variable);
could act different if it is done in a calling context of a closure. That is if there is a function defined in the scope of the var statement that variable will "stick around" for the function to use. This could have the same effects as described above (no gc and pointer memory) with the addition of a longer lifetime. (Because it will stay as long as the function has potential to be called.)

javascript: array of variables or separate variables?

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.

Categories

Resources