Are JavaScript variables a reference, value or pointer - javascript

A search didn't quite get me the answer I was looking for.
I am curious if setting a variable to a queryselector is a reference, pointer or value.
Example 1:
// lets assume there is only one ".class"
var element = document.queryselector(".class");
element.classList.remove("effect1");
element.classList.add("effect2");
Example 2:
document.queryselector(".class").classList.remove("effect1");
document.queryselector(".class").classList.add("effect2");
Are these exactly the same thing? Or by setting the variable to the selector, are you saving overhead?
My thought is that if the variable is a value, then the query selector won't search the DOM when the variable is used.
Hope that makes sense.

In Javascript objects are always passed by reference so both examples have the same effect since document.querySelector returns a DOM Element (which is an object).
As a short FYI:
Primitive types are always passed by value
Arrays are also passed by reference
Your first example is much more efficient because you only have to search the DOM once and there is absolutely no difference in their effect.

Javascript is always pass by value, but when a variable refers to an object (including arrays), the "value" is a reference to the object.
var element = document.queryselector(".class"); // element is an object
So both examples are exactly the same. Under the hood is just accessing classList property of element object.
Yes, first code snippet is efficient because we are saving a cycle to fetch DOM nodes again. If we are just accessing dom element nodes a few times let say 10-100 (normally in a mid to large project) then the performance won't be impacted much. I mean you can just ignore that. That won't be a drastic effect.
But yes if we are accessing dom nodes a million times then that effect is noticeable.
Let's check for 1 million times, just to access DOM element nodes.
first = performance.now();
new Array(1000000).fill(1).forEach(() => {
div = document.querySelector('div');
})
second = performance.now();
console.log(`${second - first} milliseconds`); //337.2850000159815 milliseconds
// Result can alter from machine to machine
Hope it is clear now.

Related

Right way to free memory in JavaScript

Being a C developer, I feel the urgent need to free memory as accurately as possible. But after reading some posts about memory management in JavaScript I still have some questions about that topic. As far as I understand, there is a garbage collector that will automatically free the memory when an object isn't referenced anymore and the GC can find the time. So an object that is held in a local variable is very likely to be freed when the variable goes out of scope.
Let's assume I have some custom elements (tab control, data table, inputs etc.). The classes of those custom elements have member variables where several data for the specific element is stored. Also event listeners can be attached to the elements the custom element consists of.
Let's say I have following html markup:
<my-tabbar>
<my-tab id="myTab">
<my-input></input>
<my-dataTable></my-dataTable>
</my-tab>
</my-tabbar>
Now I want to remove <my-tab>. Is it sufficient to just do
var element = document.getElementById ("myTab");
element.parentNode.removeChild (element);
element = null;
Or do I have to dereference every object of the child elements and remove their event listeners?
Setting an object to null makes it an empty object. Once the object is out of scope, the GC (when it runs) will clear it up. Setting local objects to null won't do you any good.
Example:
function whatever()
{
var something = null;
console.log( typeof( something ) );
}
whatever();
Output:
"object"
For the removal of a child node, please see this:
Does removeChild really delete the element?
Source(s):
https://www.w3schools.com/js/js_datatypes.asp
It is sufficient to remove the element. You don't even have to set the variable to null afterwards – you can trust the JS engine to free the memory when it goes out of scope.

Does jQuery/JS return actual DOM nodes, or just references to them?

The reason I ask is because I'm thinking of storing a bunch of DOM nodes in this huge and multi-dimensional array I have.
Cost: takes up space in memory. The question is how much space, and that depends on whether I'm getting references or actual DOM nodes.
Benefits: 1) It'll make my code a lot simpler. 2) I could avoid traversing and instead just reference the DOM node from my array.
Thoughts?
From jQuery site:
… jQuery() — which can also be written as $() — searches through the
DOM for any elements that match the provided selector and creates a
new jQuery object that references these elements
jQuery Documentation
jQuery returns the actual DOM Node. It's why you will find yourself writing $(this) most of the time. This is because you want to wrap your node in jQuery to be able to use some jQuery methods. However, it's recommended (almost in the guidelines) to cache your DOM nodes through references. For example,
var div = $('div');
div.dosomeMethod();
div.append();
This ensures that you are not traversing the entire DOM tree (the expensive DOM part) whenever you're trying to access some element. Whenever you do updates, ensure you're doing them as a batch.
in this example I show how to clone existing DOM element to object in memory, also create object in memory without pushing it to body, created collection objects, appended elements from collection to body and keep referenced objects, removed from body.
and so many operations...
var $newElement1 = $(selector).clone(); // create new element from existing and store in memory
var $newElement2 = $('<div>blabla</div>'); // create new element from html code and store in memory
var elements = [];
elements.push($newElement1);
elements.push($newElement2);
for(var i in elements) {
elements[i].appendTo($('body'));
}
$newElement1.remove(); // will remove it from body
** but I recommend You to use frameworks like: angularjs, reactjs, emberjs to save Your time
A reference to the object is returned. See here: https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById
This answer is wrong, please see the comments below.
Document.getElementById() and methods or wrappers that rely on it return a reference.
Likewise for Document.querySelector().
This all stems from the DOM4 spec, which states that (emphasis mine):
A collection is an object that represents a lists of DOM nodes. A collection can be either live or static. Unless otherwise stated, a collection must be live.
From a programming point of view this notion is easy to understand, you waste less memory and no time is spent copying things around, leading to faster execution.
However, for Document.querySelectorAll() we have an interesting case:
The NodeList object returned by the querySelectorAll() method must be static.
This means, as MDN puts it, that Document.querySelectorAll()
Returns a non-live NodeList of all the matching element nodes.
This means that the returned set is not a set of references to the original nodes, but instead to a set of nodes that represent the nodes at the time the query was executed. This means that a copy of all the matching nodes had to be made and you're no longer working with references to the live nodes.
In short:
Some JavaScript methods return references to the DOM Node.
Some JavaScript methods return array-like objects that contain references to the DOM Nodes. These objects aren't very big(?).
jQuery returns a jQuery object that contains references to the DOM Node(s). These jQuery objects could get quite big, depending on how many chained calls are made.
The actual DOM nodes are never actually returned "by value".
The size of the references themselves are small. Typically the size of a pointer.
JavaScript:
getElementById and querySelector(?) return references to the DOM Node.
getElementsByClassName and getElementsByTagName return live HTMLCollections.
getElementsByName returns a live NodeList.
getElementsByNameNS returns a live NodeList or a live HTMLCollection, depending on the browser.
querySelectorAll returns a non-live NodeList.
HTMLCollection and NodeList contain references to DOM nodes. They don't seem to be very big objects.
Live vs. Non-Live
From MDN:
In some cases, the NodeList is a live collection, which means that
changes in the DOM are reflected in the collection. For example,
Node.childNodes is live:
var parent = document.getElementById('parent');
var child_nodes = parent.childNodes;
console.log(child_nodes.length); // let's assume "2"
parent.appendChild(document.createElement('div'));
console.log(child_nodes.length); // should output "3"
In other cases,
the NodeList is a static collection, meaning any subsequent change in
the DOM does not affect the content of the collection.
document.querySelectorAll returns a static NodeList.
jQuery
From learn.jquery.com
A jQuery object is an array-like wrapper around one or more DOM elements. To get a reference to the actual DOM elements (instead of the jQuery object), you have two options. The first (and fastest) method is to use array notation:
$( "#foo" )[ 0 ]; // Equivalent to document.getElementById( "foo" )
The second method is to use the .get() function:
$( "#foo" ).get( 0 ); // Identical to above, only slower.
You can also call .get() without any arguments to retrieve a true array of DOM elements.

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

Detecting if an object is changed in javascript

I have a function that is called every 1 second.
var latestObject; //this updated separately, it depends on user input so it may not be different every second
var previousObject;
function Tick(object) {
if (latestObject !== previousObject) { //Problem is here
previousObject = latestObject; //or here
//do stuff with latestObject;
}
}
However when latestObject is updated it's properties are changed, the variable is not set to a different object. So previousObject and latestObject are always equal and the do stuff never happens.
I could do:
function Tick(object) {
var latestObjectString = JSON.stringify(latestObject);
if (latestObjectString !== previousObject) { //Problem is here
previousObject = latestObjectString; //or here
//do stuff with latestObject;
}
}
But then I'm doing JSON.stringify once every second, this seems inefficient, especially as latestObject is quite big, and quite deep.
Wouldn't it be better set previousObject to be a copy of latestObject, so that when properties on latestObject are changed, previousObject stays the same, and then this only happens when the objects are different which is less often than every second? But wouldn't there be a problem as copyOfObject == Object would never be true?
(the object is mostly properties, but has a few functions that don't ever change).
(No jQuery)
Description of the problem
The problem here is indeed related to the fact, that the same object is assigned to two different variables. Even if you change it in one place, the other changes it also.
This example shows you what really happens (jsFiddle: http://jsfiddle.net/tadeck/4hFC2/):
var objA = {'a':10, 'b': 20};
var objB = objA; // same instance assigned to both names
objB.a = 30; // instance is modified, its "a" property is changed
// now, both objA.a and objB.a show "30", as objA and objB is the same instance
However, having two different objects is not so ideal either, as comparing them is non-trivial (proof here: http://jsfiddle.net/tadeck/GN2m4/).
Solution no. 1. for comparing the objects
To solve this problem:
You need to use two different objects (eg. by using some solution similar to jQuery's .extend() to construct new object from existing object). You currently achieve that part using unnecessary serialization.
You need to compare them in a little more complex way (pretty universal solution for that is here: https://stackoverflow.com/a/1144249/548696).
In comparison to this, your solution may look less complex (at least in terms of code). I suggest using some JS performance tests to find out, which is more reasonable. JSON.stringify() is not always natively supported, so it may be doing things similarly complex (and resource-consuming), as the alternative solution I mentioned.
Solution no. 2. for solving the overall issue of detecting the changes
The other option is to rebuild your script and use eg. flags for marking the object as changed by user input. That would save you the processing of whole objects each second and may result in large efficiency gains.
The things you need to do in this case, are:
In your user-input handlers set the flag whenever user changes some part of the object,
Optionally, you could first compare the specific value with the original object (if user has changed it quickly and then reverted the change, just mark the value as not changed),
To limit the processing of the changed object, you could even mark, which properties were changed (so you process only these properties, nothing else),
To achieve part of this solution, you could even use JavaScript setters and getters, as described by John Resig.
But, as I mentioned, it may require rebuilding your script (which we haven't seen, so we cannot say if it is necessary or it can be applied rather easily).

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