Why check for element/attributes before removing it? - javascript

In the Working with the Attribute Node chapter in Learning Javascript - A Hands-On Guide to the Fundamentals of Modern Javascript, the author Tim Wright said on Page 73:
Removing an attribute is as simple as getting one. We just target the element node and use the method removeAttribute() to get it out of there. There are no Javascript exceptions thrown if you try to remove an attribute that doesn't exist, but it's still best practive to use the same hasAttribute() method we mentioned earlier, shown in Listing 4.6.4
Listing 4.6.4 Javascript Used to Remove the Class Value of Our Image
if(document.getElementById("pic").hasAttribute("class")) {
document.getElementById("pic").removeAttribute("class");
}
If there's no exceptions thrown either way, isn't checking whether it exists or not redundant? The same outcome will arise. The argument that the book says is that check for the paramenter before removing it saves the browser parsing through unneccesary code, but if(document.getElementById("pic").hasAttribute("class")) {} is even longer than document.getElementById("pic").removeAttribute("class"); on its own!
Why is this best practice then?

In my opinion your assumption is absolutely right. I think the "advice" in the book is kind of catastrophic (to use a dramatic term). Havent heard about that "best practice" anywhere before. There is absolutely nothing you could achieve by using element.hasAttribute prior to removing / changing an attribute but slow down your code. A browser does not magically have a lookup list for attributes to check for their existence that is not used when it set or get an attribute. It may be best practice - in the authors opinion - for producing readable and understandable code, though.
Furthermore, in my opinion you should never use setAttribute at all! Use setAttribute only then there is no built in standard method for getting or setting a certain attribute. Here class is in question, use
element.className = 'myclass';
instead of
element.setAttribute('class', 'myclass');
Browsers have optimized routines when using such standardized methods. If not being used when you assign or delete an attribute to an element then the browser has to figure out what kind of attribute it is, and may perhaps trigger special operations afterwards - not everytime nessecary.
You can check if a browser supports a specific attribute-method like this
if (typeof window.document.body.className === 'string') {
//className is supported for node elements
}
Most of those attribute-methods acts like getters and setters. You can read and write, and the use of some them are even more effective than other approaches. Example :
element.outerHTML = '';
clean more memory up than
element = null;
It is of course not an attribute to an element, but to show why one should prefer using built in methods targeting a specific part of an element.
There is many, many standard methods as element.className you can use to target a specific standard attribute. They are mostly named as the attribute name in camelcase notation. Use setAttribute only for your own custum attributes, like
element.setAttribute('data-my-custum-attribute', 'hello');
Which is perfectly legal markup according to the HTML5 standard. Or use it as a fallback, if the browser doenst support a certain attribute method. This can be the case for very old browsers. But even IE6 supports className.
I will recommend two books which I think is really valuable for understanding javascript in the depth (not claiming that I do in full, but those books have helped me a lot) :
Javascript - the good parts, by Douglas Crockford
Secrets of the JavaScript Ninja, by John Resig (the guy behind jQuery)
Buy the books! They are gold as reference on your desk.

One thing I have on my mind is that removeAttribute might be a much heavier function call regarding the operations it does, i.e., it modifies the DOM and HTML, and could also affects meta data in the browser.
In comparison, hasAttribute is just a read operation, which is much lighter and won't have impact on meta data. So it's better to check if the element has the attribute or not.
If removeAttribute itself already does hasAttribute checking, then I agree it is pretty much redundant.

its useful for when you are writing a large program or working in a group.... you need to check that you dont remove something that is being used by something/someone else. if there is a more technical answer, hopefully someone else will supply it.

Related

JavaScript: Extending Element prototype

I have seen a lot of discussion regarding extending Element. As far as I can tell, these are the main issues:
It may conflict with other libraries,
It adds undocumented features to DOM routines,
It doesn’t work with legacy IE, and
It may conflict with future changes.
Given a project which references no other libraries, documents changes, and doesn’t give a damn for historical browsers:
Is there any technical reason not to extend the Element prototype. Here is an example of how this is useful:
Element.prototype.toggleAttribute=function(attribute,value) {
if(value===undefined) value=true;
if(this.hasAttribute(attribute)) this.removeAttribute(attribute);
else this.addAttribute(attribute,value);
};
I’ve seen too many comments about the evils of extending prototypes without offering a reasonable explanation.
Note 1: The above example is possibly too obvious, as toggleAttribute is the sort of method which might be added in the future. For discussion, imagine that it’s called manngoToggleAttribute.
Note 2: I have removed a test for whether the method already exists. Even if such a method already exists, it is more predictable to override it. In any case, I am assuming that the point here is that the method has not yet been defined, let alone implemented. That is the point here.
Note 3: I see that there is now a standard method called toggleAttribute which doesn’t behave exactly the same. With modification, the above would be a simple polyfill. This doesn’t change the point of the question.
Is it ok? Technically yes. Should you extend native APIs? As a rule of thumb no. Unfortunately the answer is more complex. If you are writing a large framework like Ember or Angular it may be a good idea to do so because your consumers will have Benifits if better API convenience. But if you're only doing this for yourself then the rule of thumb is no.
The reasoning is that doing so destabilizes the trust of that object. In other words by adding, changing, modifying a native object it no longer follows the well understood and documented behavior that anyone else (including your future self) will expect.
This style hides implementation that can go unnoticed. What is this new method?, Is it a secret browser thing?, what does it do?, Found a bug do I report this to Google or Microsoft now?. A bit exaggerated but the point is that the truth of an API has now changed and it is unexpected in this one off case. It makes maintainability need extra thought and understanding that would not be so if you just used your own function or wrapper object. It also makes changes harder.
Relevant post: Extending builtin natives. Evil or not?
Instead of trying to muck someone else's (or standard) code just use your own.
function toggleAttribute(el, attribute, value) {
var _value = (value == null ? true : value;
if (el.hasAttribute(attribute)) {
el.removeAttribute(attribute);
} else {
el.addAttribute(attribute, _value);
}
};
Now it is safe, composible, portable, and maintainable. Plus other developers (including your future self) won't scratch their heads confused where this magical method that is not documented in any standard or JS API came from.
Do not modify objects you don't own.
Imagine a future standard defines Element.prototype.toggleAttribute. Your code checks if it has a truthy value before assigning your function. So you could end up with the future native function, which may behave differently than what you expected.
Even more, just reading Element.prototype.toggleAttribute might call a getter, which could run some code with undesired sideways effects. For example, see what happens when you get Element.prototype.id.
You could skip the check and assign your function directly. But that could run a setter, with some undesired sideways effects, and your function wouldn't be assigned as the property.
You could use a property definition instead of a property assignment. That should be safer... unless Element.prototype has some special [[DefineOwnProperty]] internal method (e.g. is a proxy).
It might fail in lots of ways. Don't do this.
In my assessment: no
Massive overwriting Element.prototype slow down performance and can conflict with standardization, but a technical reason does not exist.
I'm using several Element.prototype custom methods.
so far so good until I observe a weird behaviour.
<!DOCTYPE html >
<html >
<body>
<script>
function doThis( ){
alert('window');
}
HTMLElement.prototype.doThis = function( ){
alert('HTMLElement.prototype');
}
</script>
<button onclick="doThis( )" >Do this</button>
</body>
</html>
when button is clicked, the prototype method is executed instead of the global one.
The browser seems to assume this.doThis() which is weird. To overcome, I have to use window.doThis() in the onclick.
It might be better if w3c can come with with diff syntax for calling native/custom methods e.g.
myElem.toggleAttribute() // call native method
myElem->toggleAttribute() // call custom method
Is there any technical reason not to extend the Element prototype.
Absolutely none!
pardon me:
ABSOLUTELY NONE!
In addition
the .__proto__, was practically an a illegal (Mozilla) prototype extension until yesterday. - Today, it's a Standard.
p.s.: You should avoid the use of if(!Element.prototype.toggleAttribute) syntax by any means, the if("toggleAttribute" in Element.prototype) will do.

what is benefit of $(e).attr(name,value) vs e.setAttribute(name,value)?

Case: e is of type HtmlElement and not css selector
I am talking about any attribute, not just standard allowed ones, like atom-type or data-atom-type, whatever may be the name, will it work without jQuery?
I suspect $(e).attr(name,value) is too slow, first of all it is creating an entire jQuery object ($(e) !== $(e) // two objects are not same) (jsPerf: http://jsperf.com/jquery-attr-vs-native-setattribute/28) and then it invokes certain checks and then sets value, which most browsers easily support e.setAttribute.
Is there any problem replacing $(e).attr(name,value) to e.setAttribute(name,value)?
IE8 supports setAttribute as per MSDN documentation. Is there any mobile browser or any browser which will not support it?
Eventually I want to improve performance of my JavaScript framework, initially we used jQuery extensively for its cross browser DOM features.
We have now understood that unless you are using css selector, most functions such as attr,val,text are better called with their direct DOM counter part when you have instance of HtmlElement.
I suspect $(e).attr(name,value) is too slow, first of all it is creating an entire jQuery object and then it invokes certain checks and then sets value, which most browsers easily support e.setAttribute.
If you measure it, you'll find that the difference in performance is large-ish in relative terms, but miniscule in absolute terms, and it's absolute terms we normally care about. It just doesn't matter in 99.999999% of cases. If you run into a specific performance problem, and trace it to using jQuery, then consider optimizing at that point.
what is benefit of $(e).attr(name,value) vs e.setAttribute(name,value)?
In the specific case you mention, where e is an HTMLElement, there are only a couple of benefits:
There are a couple of IE-specific bugs in setAttribute that jQuery works around for you
There are some "attributes" people set when they really should be setting a property, for instance checked or disabled; jQuery maps those (this is mostly a legacy feature these days, as people should be using prop)
It does some pre-processing on boolean values for you, letting you use $(e).attr("checked", true) when true really should be "checked"
IE8 supports setAttribute as per MSDN documentation. Is there any mobile browser or any browser which will not support it?
All browsers support setAttribute. As I mention earlier, various versions of IE have had various bugs in it, but it's there and mostly works.

How to "correctly" create an object which inherits from Element?

I am writing an HTML5 application that involves a lot of XML manipulation, part of this manipulation involves comparing the versions of two different XML Elements.
What I need is for every Element, Attr, and TextNode (all of which inherit from Node, AFAIK) object that gets created to have associated version information, but still be able to behave like a normal Element, Attr, or TextNode. The current working solution I am using to store the version information, is the following:
Node.prototype.MyAppAnnotation = {
Version : null
};
Now, I understand that augmenting built-in types is considered bad form, but beyond this technique, I'm at a loss for how to get the desired functionality. I don't think I can encapsulate the Node in a wrapper because I need the Node related properties and functions exposed on the wrapper. I might be able to write some sort of pass-through functions for the wrapper, but that seems really clunky.
I feel that because the app I'm writing is an HTML5 app, and as such only has to run on the most modern browsers (all of which support the augmentation of built-ins), makes this technique appropriate. Also, by providing a sufficiently obscure name to my augmentation object, I can avoid all naming collisions (except for intentional collisions). I've also explored inheritance-based solution using Google's Closure library. However, it appears that because Element, Node and TextNode don't have direct constructors (i.e. they're created off of a Document object), this technique will not work either.
I was wondering if someone could either a) recommend an elegant way of achieving this effect without augmenting Element, or b) provide a compelling reason for why I shouldn't break the "don't augment built-ins" rule in this case.
Many Thanks,
Jarabek
Your idea is theoretically valid, but there's a weird feeling I get when reading about it.
First of all - you don't have to augment any prototypes. If you just do somedomnode.myweirdname='foo' it will become a field of that object. That's what javascript does ;)
So when there is no version you'll get undefined instead of null.
But, if you want to add more functionality or wrap dom node in anything - there's a bit of history of doing that. Most of that history is dominated by stuff like jQuery :)
Just create an object that has a field containing the node. And then you can access it really simply:
myobject.node
And create the object with some constructor or just factory function:
var myobject = createDomNodeWrapper(domnode)

Which is better - Ext.get() or document.getElementById()

What is the difference between Ext.get() and document.getElementById() in terms of performance? Will Ext.get() be slower as it may internally call document.getElementById() ? Or is there any specific advantage of using Ext.get() ?
The principle advantage of Ext.get over getElementById is that it returns to you an Ext.Element instance. This instance not only contains the DOM node reference that getElementById would give you but also significantly extends it - offering a suite of convenience methods, event normalization, and an ironing out of cross-browser differences.
On the surface getElementById may have some minuscule speed gain over Ext.get simply on the basis of one less function before getting to the same fundamental DOM call. However, in terms of overall performance what you do with the element after retrieval will likely have much more impact than the retrieval itself. Having the Ext.Element wrapper on hand may prove to be quite beneficial.
You may want to have a look at Ext.fly as well. This method is similar to Ext.get with exception that it returns to you a singleton Ext.Element instance. It won't be any good if you need to store the element for later use, but if you are doing simple, one-off operations against unique DOM nodes it may be cheaper than Ext.get.
document.getElementById() is native JavaScript and so will be faster than Ext.get()
Now why Ext.get() is there at all,
document.getElementById() returns a DOM element, while Ext.get() returns an Ext object which is apt for chaining purposes.
And this is also the reason why jQuery have a $("#elm_id"). Please note that Ext.get() is also much easier to type :)
Ext.get() allows for using a String ID, an existing HTMLElement, or a Ext.Element - so it's a little bit more flexible. document.getElementById() only accepts the String ID.
That said, I'd just use document.getElementById() if it meets your needs. It's native to the browser and should be a little faster - and it's one less call that you're chaining yourself to a specific JavaScript framework with.
In terms of performance, native JS functions will always be faster.
However, I am not saying not to use JS Libraries, they are great as they:
reduce the time when writing your code
it make your code more readable
you write less code (reducing file-size and download time)
And in the end, maybe you even save time because less code means faster download and in some cases it could even beat the performance.
So yeah, it is the same to use one over the other, since in one hand you save time by performance ("document.getElementById()") and in the other you reduce file size and download time ("Ext.get()").
You can use both and there shouldn't be any noticeable difference.
As others have eluded to here the method used depends upon need, if you just want to get a reference to the dom element for some non Ext purpose you may as well use the native function, but if you intend to perform actions on the returned object in an Ext context, then Ext.get will return you an Element reference which offers additional methods.
Ext.get is shorthand for Ext.ComponentManager.get and whilst it is a call to a library function and may be less efficient is should be noted that there are ~180 methods available on Ext.Element, so if you need these it may be worth including wrapper call.
As owlness has mentioned, Ext.fly() is designed when you need to perform a single function on an element, eg. Ext.fly("myDiv").hide(); whereas Ext.get() is intended when you need a get a reference to an element for later use, eg. var something = Ext.get("myDiv"); then perhaps something.sort(); something.badger(); return something;
I'm unfamiliar with the Ext library, but with vanilla Javascript, there's only a handful of ways to get a particular element; you can get it by its ID, search for it after getting all elements by a tag name (this is how JQuery gets elements by class name I believe), or, new to HTML5, get an element by a class name. There's a few other ways if you get creative ;)
Just getting it by ID is the quickest, assuming you didn't save a local reference.
So, if all you're trying to do is get an element without doing whatever Ext.js does via that function call, vanilla Javascript will be much faster.

jQuery - the good parts?

I have embarked on a mission to start using jQuery and JavaScript properly. I'm sad to say that historically I have fallen into the class of developer that makes a lot of really terrible mistakes with jQuery (polluting the global namespace, not caching jQuery selectors, and much more fun stuff - some of which I'm sure I have yet to discover).
The fact of the matter is that jQuery allows people to easily implement some really powerful functionality. However, because everything "just works", performance concerns and best practices immediately take a back seat.
As I've been reading articles on JavaScript and jQuery performance and best practices, I've learned just enough to fully realize how inexperienced I really am. I'm left feeling frustrated because I'm unsure of when I should be using jQuery or just plain JavaScript. The main reason jQuery is so appealing to me is that it takes care of browser compatibility. From what I understand though, there are things you can do with jQuery that you can also do with regular JavaScript that aren't subject to compatibility issues. Basically I'm looking for a guide that explains when using jQuery over regular JavaScript is wise.
A few questions to recap:
Are there parts of jQuery that you shouldn't use due to performance?
What are the parts of jQuery that you should always use to avoid browser inconsistencies?
What are the parts of jQuery that you shouldn't use because there is a reliable and faster way to do the same thing natively in JavaScript?
What are the parts of jQuery that offer multiple ways to do the same thing, with one way being more efficient? For example, the :not() selector versus the .not() method.
I'm looking for existing articles, blog posts, books, videos, etc. I know where the docs are. I read them frequently. I'm hoping for more of an overview that addresses the above issues.
Thanks!
EDIT:
Check out this very similar question: When to use Vanilla JavaScript vs. jQuery?
Wow, I simply cannot believe noone has mentioned storing objects in variables for future use.
Consider this scenario.
You have a complex menu that you're going to write 100 lines of jQuery for.
VERY OFTEN I see something like
$(".menu").fadeIn("slow");
$(".menu li").each(bla bla);
$(".menu li").hover(more bla bla);
if($(".menu").attr('id') == 'menu1') {some hoo ha}
If you're going to reuse an element in jQuery, ALWAYS store it in a variable. It's also common practice to add a dollar sign ($) before the variable name to indicate a jQuery object.
var $menu = $(".menu"); // store once and reuse a million times
var $menu_item = $("li", $menu); // same here
$menu.fadeIn("slow");
$menu_item.each(bla bla);
$menu_item.hover(more bla bla);
if($menu.attr('id') == 'menu1') {some hoo ha}
I definitely say
use the event model as it abstracts the differences across browsers and also provides a means to raise your own custom events too.
don't use .each() or $.each() unneccessarily. Sometimes it can help as it introduces a closure, but often a simple loop will suffice.
the only way to know whether a complicated selector string or a bunch of chained function calls is going to be faster is to benchmark all approaches.
use event delegation when binding the same event handler to more than three elements (I'll see if I can dig out the resource for more than three elements, I seem to remember an article that benchmarked direct binding versus delegation on a number of different factors and found more than three to be the magic numbers).
Above all else, don't worry about performance unless it's a problem. 200ms compared to 300ms, who'll know the difference? 200ms compared to 1000ms, maybe time to look at optimizing something :)
be as specific as possible with your selectors and help those poor older versions of IE out.
Several of your questions focus on performance.
As a rule, jQuery cannot possibly perform better than the underlying native Javascript. jQuery does not interact directly with the browser or operating system; it's just providing a wrapper around built-in Javascript functions. So at an absolute minimum calling a jQuery function incurs the overhead of an extra function call.
In many cases, jQuery is indeed doing quite a bit of heavy lifting in order to produce a result, when hand-written "pure" Javascript might be able to avoid that work.
The point of the framework is to make the programmer's life easier, and historically everything that's ever made programmers' lives easier cost performance. Hand-written machine language is almost universally more efficient than the best compiled code ever assembled.
So the best answer to your questions about performance is: don't worry about it. If you ever encounter a performance problem, then consider jQuery as one possible target for optimization.
As far as browser inconsistencies, one of the major purposes of the framework is to avoid them entirely. There have been bugs historically where certain features didn't work in one browser or another, but these were bugs specific to a particular version of the library. So avoiding them entirely wouldn't be quite the right solution. And trying to identify them here (rather than jQuery's own bug reports) would make this discussion almost instantly out of date.
Nowadays, the primary rule of thumb with javascript is that it has wicked-fast execution time (on non-ie modern browsers), but dom access/manipulation is crazy slow. The faster the JS runtimes get, the more the DOM becomes the bottleneck.
As a rule, you shouldn't really overly worry about performance until it becomes an issue, since most code doesn't need to be fast, and you usually don't know where the problems will be until you test it. That being said, try to minimize dom interaction wherever you can.
as a side note, idiomatic jquery is using javascript the right way. Favor composing functions over OOP, use closures for encapsulation, don't mix javascript handlers (or heaven forbid, script blocks) in your html, and treat objects as property bags that you can attach or detach things to at will.
I'm no expert but I learnt a couple of things.
Don't abuse HTML attributes, that means don't store your intended roll-over images in a rel/rev, use a background image instead. This also helps with the performance of roll overs in IE, as IE doesn't like it when you are changing the src attribute on the fly.
Also hover-intent is very useful to have instead of just using .hover :)
My two cents: do not underestimate the power of the jQuery team (Resig an Co.)---their intent is not to lead you easily into performance gotchas. That being said, here's one: when you use a selector (which is the query in jQuery), do insure to use [context].
So let's say you have a table with 243 rows---and you have not tagged each tr with an id (because you are cool). So you click, say, a button in a row with an event. The event for the button needs to search the current row for a select widget. The innards of the click() event might have these lines:
var tr = $(this).closest('tr'); //where $(this) is your button
$('td select', tr).css('color', 'red');
So the last line there does a search for select elements in the context of a table row (tr). This search means to be faster than searching the entire table (or the entire page) for an id or something similar.
What is also implied here is that I'm putting my trust in the jQuery team that their implementation of the jQuery.closest() method is fast and efficient. So far, I've no reason not to have this trust.

Categories

Resources