jQuery does good jobs when you're dealing with browser compatibility. But we're living in an age that fewer and fewer people use old-school browsers such as IE <= 7. With the growing of DOM APIs in modern browsers (including IE 8), most functions that jQuery provides are built-in natively.
When targeting only modern browsers, it is better to avoid using jQuery's backward-compatible features. Instead, use the native DOM API, which will make your web page run much faster than you might think (native C / C++ implementaion v.s. JavaScript).
If you're making a web page for iOS (e.g. UIWebView), you should use native DOM APIs because mobile Safari is not that old-school web browser; it supports lots of native DOM APIs.
If you're making a Chrome Extension, you should always use native APIs, not only because Chrome has almost the latest DOM APIs available, but this can also avoid performance issue and unnecessary memory occupation (each extension needs a separate memory space for its jQuery; it is not shared).
As long as you know the actual ID of the target element, why don't you use getElementById
?
document.getElementById("header");
// instead of $("#header");
This works for IE >= 5.5
Use querySelectorAll()
instead:
document.querySelectorAll("#header ul li");
// instead of $("#header ul li")
// or when you're finding in the context of #header
var header = document.getElementById("header");
header.querySelectorAll("ul li");
// instead of $("#header").find("ul li");
This works for IE >= 8.
jQuery(html)
is useful when you're doing DOM tree manipulation with that html snippet. But if you only have to create a new element, use the native DOM API createElement
instead:
var element = document.createElement("a");
element.href = "http://www.example.com/";
element.className = "blah";
element.innerText = "hi";
The element.className
lets you access the class
attribute of that element. More about this in the section below.
jQuery provides some class manipulation functions such as addClass()
, removeClass()
, toggleClass()
as well as hasClass()
. With the new DOM API classList
, we can avoid these functions.
Unfortunately IE <= 9 does not support classList
. In this case you can use polyfills like classList.js or this polyfill for IE 9, or implement it manually by tokenizing the className
string into an array like how jQuery does, or by working with space-wrapped strings like how MooTools does.
var element = document.getElementById("header");
// add class
element.classList.add("holiday-special");
// instead of $(element).addClass("holiday-special")
// for IE <= 9, we can do this: // mind the space!
element.className += " holiday-special";
// remove class
element.classList.remove("holiday-special");
// instead of $(element).removeClass("holiday-special")
// toggle a class
element.classList.toggle("hide");
// instead of $(element).toggleClass("hide")
// test if the element has some class
element.classList.contains("hide");
// instead of $(element).hasClass("hide")
jQuery's .css()
is useful for style manipulation (merging one set into another set). But if you only have to assign one attribute or override the whole style rule, don't use it.
Alternatives:
e.g. Width
element.style.width = "320px";
// instead of $(element).css("width", "320px");
Write the style directly with element.style.cssText=
. Note that this is just like writing inline style directly, so mind that semicolon ;
.
e.g. Width = 320px, Height = 640px
element.style.cssText = "width: 320px; height: 640px;"; // Mind the semicolon
// instead of $(element).css({"width": "320px", "height": "640px"});
jQuery's $.each()
is convenient when dealing with both Array
and Object
types, but why are we so lazy to know the actual data type?
Although $.each()
doesn't often create performance issue, we can use native for
loop (for array) and for..in
iterator (for object).
The only benefit of $.each
is that it uses a callback, so if you need an isolated variable scope, then $.each
is better.
jQuery's .data()
implements its own storage, which may cause lots of overhead.
If you're only supporting browsers with native HTML5 DataSet implementation, use element.dataset
and its corresponding API to access the bounded data. Also see HTML5 Doctor's Guide on HTML5 data-* Attributes.
Say that we have the following HTML:
<div id="long-cat" data-cat-length="30km">Nyan</div>
Access the cat-length
data with dataset
:
var element = document.getElementById("long-cat");
// read the existing data:
element.dataset.catLength; // => "30km"
// write the existing data:
element.dataset.catLength = "42km";
element.dataset.catLength; // => "42km"
// same way to create a new data dynamically:
element.dataset.catWeight = "100t";
element.dataset.catWeight; // => "100t"
Note that the name of data will be converted to camelCase, see the spec for more details.
If you need to support old browsers, take a look at this polyfill, or use createAttribute
and setAttributeNode
:
// use the same HTML structure above
var element = document.getElementById("long-cat");
// read the existing data:
element.getAttributeNode("data-cat-length").nodeValue; // => "30km";
// write the existing data:
element.getAttributeNode("data-cat-length").nodeValue = "42km";
element.getAttributeNode("data-cat-length").nodeValue// => "42km";
// create a new data dynamically:
var attribute = document.createAttribute("data-cat-weight");
attribute.nodeValue = "100t";
element.setAttributeNode(attribute);
element.getAttributeNode("data-cat-weight").nodeValue; // => "100t"
- Statements - JavaScript Reference - MDN
- HTML5 Cross Browser Polyfills · Modernizr/Modernizr Wiki
- WWDC 2012 Session 601 (I learnt
classList
andquerySelectorAll
in the video)
p.s. This is made public from my private Gist.