Forked from yorkxin/avoid-jquery-when-possible.md
Created
January 11, 2013 00:34
Revisions
-
yorkxin revised this gist
Jul 30, 2012 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -84,6 +84,8 @@ element.classList.contains("hide"); jQuery's [`.css()`](http://api.jquery.com/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. Especially, if you care about performance, or doing lots of style manipulation, you should avoid `.css()` as possible as you can, because `.css` is really slow and will be your performance bottleneck. ([Experiment](http://jsperf.com/style-versus-jquery-css/8); [another experiment](http://jsperf.com/jquery-css-vs-dom-style) by me.) Alternatives: ### Assigning One Attribute -
yorkxin revised this gist
Jul 20, 2012 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -149,6 +149,8 @@ element.dataset.catWeight; // => "100t" Note that the name of data will be converted to camelCase, see [the spec](http://dev.w3.org/html5/spec/global-attributes.html#embedding-custom-non-visible-data-with-the-data-attributes) for more details. ### Sometimes `.data()` is Useful The following scenarios shows when `.data()` is more useful than DataSet: ```javascript -
yorkxin revised this gist
Jul 20, 2012 . 1 changed file with 0 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -116,8 +116,6 @@ For Arrays, there is a native [`for` loop](https://developer.mozilla.org/en/Java However `for` statements does not provide **isolated variable scope** (i.e. process each item with a callback function), which `$.each()` does provide. Fortunately in ECMAScript 5 there is an [`array.forEach`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach) function that provides an isolated variable scope with a callback function ([polyfill](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach#Compatibility) or [ES5-Shim][es5-shim]), just like `$.each`. But so far there is no `object.forEach` available. In this case you may need `$.each`. ## `.data()` → use HTML5 `dataset` (for string) jQuery's [`.data()`](http://api.jquery.com/data/) can store various types of data within a given element. However it implements its own storage, which causes a lot of overhead if you're only storing Strings with it. -
yorkxin revised this gist
Jul 20, 2012 . 1 changed file with 21 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -196,13 +196,30 @@ $(element2).data("scaling"); // => function(n) {...}, a Function, as expected ### Support for Old Browsers If you need to support old browsers, take a look at [this polyfill](http://eligrey.com/blog/post/html-5-dataset-support), or use [`getAttribute`](https://developer.mozilla.org/en/DOM/element.getAttribute) and [`setAttribute`](https://developer.mozilla.org/en/DOM/element.setAttribute). For browsers without getAttribute and setAttribute support, e.g. IE 7, you need [`createAttribute`](https://developer.mozilla.org/en/DOM/document.createAttribute), [`getAttributeNode`](https://developer.mozilla.org/en/DOM/element.getAttributeNode) and [`setAttributeNode`](https://developer.mozilla.org/en/DOM/element.setAttributeNode), although they're [deprecated in DOM 4 spec](http://www.w3.org/TR/dom/#dom-core). Example: Use `getAttribute` and `setAttribute` ```javascript // use the same HTML structure above var element = document.getElementById("long-cat"); // read the existing data: element.getAttribute("data-cat-length"); // => "30km" // write the existing data: element.setAttribute("data-cat-length", "42km"); element.getAttribute("data-cat-length"); // => "42km" // write a new data dynamically: element.setAttribute("data-cat-weight", "100t"); element.getAttributeNode("data-cat-weight"); // => "100t" ``` Example: Use `createAttribute`, `getAttributeNode` and `setAttributeNode` (deprecated in DOM 4) ```javascript // use the same HTML structure above var element = document.getElementById("long-cat"); @@ -242,4 +259,4 @@ Desktop WebKit browsers like Chrome and Safari, as well as Internet Explorer 9+, p.s. This is made public from my [private Gist](https://gist.github.com/034fe1d3b0a5c9952eba). [es5-shim]: https://github.com/kriskowal/es5-shim/ "ES5-Shim" -
yorkxin revised this gist
Jul 20, 2012 . 1 changed file with 5 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -114,7 +114,7 @@ For Arrays, there is a native [`for` loop](https://developer.mozilla.org/en/Java ### Isolated Variable Scope However `for` statements does not provide **isolated variable scope** (i.e. process each item with a callback function), which `$.each()` does provide. Fortunately in ECMAScript 5 there is an [`array.forEach`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach) function that provides an isolated variable scope with a callback function ([polyfill](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach#Compatibility) or [ES5-Shim][es5-shim]), just like `$.each`. But so far there is no `object.forEach` available. In this case you may need `$.each`. Although `$.each()` doesn't often create performance issue @@ -238,5 +238,8 @@ Desktop WebKit browsers like Chrome and Safari, as well as Internet Explorer 9+, - [HTML5 Cross Browser Polyfills · Modernizr/Modernizr Wiki](https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills) - [WWDC 2012 Session 601](https://developer.apple.com/videos/wwdc/2012/?id=601) (I learnt `classList` and `querySelectorAll` in the video) - [ECMAScript 5 compatibility table](http://kangax.github.com/es5-compat-table/) - [ES5-Shim: ECMAScript 5 compatibility shims for legacy JavaScript engines][es5-shim] p.s. This is made public from my [private Gist](https://gist.github.com/034fe1d3b0a5c9952eba). [es5-shim]: https://github.com/kriskowal/es5-shim/ "ES5-Shim" -
yorkxin revised this gist
Jul 20, 2012 . 1 changed file with 9 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -106,13 +106,17 @@ element.style.cssText = "width: 320px; height: 640px;"; // Mind the semicolon // instead of $(element).css({"width": "320px", "height": "640px"}); ``` ## `$.each()` → use `for` statement or `.forEach` (ECMAScript 5) jQuery's [`$.each()`](http://api.jquery.com/jQuery.each/) is convenient when dealing with both `Array` and `Object` types, but we should already know the actual data type and process it properly. For Arrays, there is a native [`for` loop](https://developer.mozilla.org/en/JavaScript/Reference/Statements/for); for Objects, there is a native [`for..in` iterator](https://developer.mozilla.org/en/JavaScript/Reference/Statements/for...in). ### Isolated Variable Scope However `for` statements does not provide **isolated variable scope** (i.e. process each item with a callback function), which `$.each()` does provide. Fortunately in ECMAScript 5 there is an [`array.forEach`](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach) function that provides an isolated variable scope with a callback function ([polyfill](https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach#Compatibility)), just like `$.each`. But so far there is no `object.forEach` available. In this case you may need `$.each`. Although `$.each()` doesn't often create performance issue ## `.data()` → use HTML5 `dataset` (for string) @@ -233,5 +237,6 @@ Desktop WebKit browsers like Chrome and Safari, as well as Internet Explorer 9+, - [Statements - JavaScript Reference - MDN](https://developer.mozilla.org/en/JavaScript/Reference#s26545) - [HTML5 Cross Browser Polyfills · Modernizr/Modernizr Wiki](https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills) - [WWDC 2012 Session 601](https://developer.apple.com/videos/wwdc/2012/?id=601) (I learnt `classList` and `querySelectorAll` in the video) - [ECMAScript 5 compatibility table](http://kangax.github.com/es5-compat-table/) p.s. This is made public from my [private Gist](https://gist.github.com/034fe1d3b0a5c9952eba). -
yorkxin revised this gist
Jul 20, 2012 . 1 changed file with 48 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -114,11 +114,13 @@ Although `$.each()` doesn't often create performance issue, we can use native `f The only benefit of `$.each` is that it uses a callback, so if you need an isolated variable scope, then `$.each` is better. ## `.data()` → use HTML5 `dataset` (for string) jQuery's [`.data()`](http://api.jquery.com/data/) can store various types of data within a given element. However it implements its own storage, which causes a lot of overhead if you're only storing Strings with it. Modern browsers has [native HTML5 DataSet](http://caniuse.com/#feat=dataset) implementation. With [`element.dataset`](https://developer.mozilla.org/en/DOM/element.dataSet) and its corresponding APIs, you can access the data bounded by `data-*` attributes. Also see HTML5 Doctor's [Guide on HTML5 data-* Attributes](http://html5doctor.com/html5-custom-data-attributes/). The only limitation of HTML5 DataSet is that **it can only store String** type. `.data()` in jQuery can store any type of data, not only a nested Object or Array, but also a Function. If you do need to store types other than String, it is better to use `.data()`. It is also a better way to store a Number, because if you use DataSet you'll need to `parseInt` every time before you process the data. Say that we have the following HTML: @@ -145,6 +147,49 @@ element.dataset.catWeight; // => "100t" Note that the name of data will be converted to camelCase, see [the spec](http://dev.w3.org/html5/spec/global-attributes.html#embedding-custom-non-visible-data-with-the-data-attributes) for more details. The following scenarios shows when `.data()` is more useful than DataSet: ```javascript var element1 = document.createElement("div"), element2 = document.createElement("div"); /* Storing a Number */ element1.dataset.length = 42000; element1.dataset.length; // => "42000", a String, not a Number $(element2).data("length", 42000); $(element2).data("length"); // => 42000, a Number, as expected /* Storing an Object */ element1.dataset.profile = { name: "Nyan", age: 3}; element1.dataset.profile; // => [object Object], not what we want. $(element2).data("profile", { name: "Nyan", age: 3}); $(element2).data("profile"); // => { name: "Nyan", age: 3}, an Object, as expected /* Storing an Array */ element1.dataset.primes = [2, 3, 5, 7, 11, 13]; element1.dataset.primes; // => "2,3,5,7,11,13", a String, not an Array $(element2).data("primes", [2, 3, 5, 7, 11, 13]); $(element2).data("primes"); // => [2, 3, 5, 7, 11, 13], an Array, as expected /* Storing a Function */ var scaling = function(n) { return n * 3; }; element1.dataset.scaling = scaling; element1.dataset.scaling; // => "function(n) {...}", a String representing the function literally, not a Function $(element2).data("scaling", scaling); $(element2).data("scaling"); // => function(n) {...}, a Function, as expected ``` ### Support for Old Browsers If you need to support old browsers, take a look at [this polyfill](http://eligrey.com/blog/post/html-5-dataset-support), or use [`createAttribute`](https://developer.mozilla.org/en/DOM/document.createAttribute) and [`setAttributeNode`](https://developer.mozilla.org/en/DOM/element.setAttributeNode). However attribute node manipulation is [deprecated in DOM 4 spec](http://www.w3.org/TR/dom/#dom-core) (in favor of `setAttribute`?). If you care about the web standard, maybe polyfilling `dataset` is a better solution. -
yorkxin revised this gist
Jul 20, 2012 . 1 changed file with 2 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -152,6 +152,8 @@ If you need to support old browsers, take a look at [this polyfill](http://eligr Example: ```javascript /* Note: element.*AttributeNode and document.createAttribute are deprecated in DOM 4 */ // use the same HTML structure above var element = document.getElementById("long-cat"); -
yorkxin revised this gist
Jul 20, 2012 . 1 changed file with 3 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -147,7 +147,9 @@ Note that the name of data will be converted to camelCase, see [the spec](http:/ ### Support for Old Browsers If you need to support old browsers, take a look at [this polyfill](http://eligrey.com/blog/post/html-5-dataset-support), or use [`createAttribute`](https://developer.mozilla.org/en/DOM/document.createAttribute) and [`setAttributeNode`](https://developer.mozilla.org/en/DOM/element.setAttributeNode). However attribute node manipulation is [deprecated in DOM 4 spec](http://www.w3.org/TR/dom/#dom-core) (in favor of `setAttribute`?). If you care about the web standard, maybe polyfilling `dataset` is a better solution. Example: ```javascript // use the same HTML structure above -
yorkxin revised this gist
Jul 7, 2012 . 1 changed file with 3 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -155,11 +155,11 @@ If you need to support old browsers, take a look at [this polyfill](http://eligr 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"); -
yorkxin revised this gist
Jul 7, 2012 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -6,7 +6,7 @@ When targeting only modern browsers, it is better to avoid using jQuery's backwa 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 jQuery-driven extension needs a separate memory space for its jQuery's compiled machine code; they're not shared across extensions). One exception is the app-like extension, which works just like another tab, and no need to care about memory occupation. ## `$("#header")` → `getElementById()` -
yorkxin revised this gist
Jul 7, 2012 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -6,7 +6,7 @@ When targeting only modern browsers, it is better to avoid using jQuery's backwa 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 jQuery-driven extension needs a separate memory space for its jQuery's compiled machine code; they're not shared across extensions). One exceptions is that when you're making an isolated app-like extension, which works just like another tab, and no need to care about memory occupation. ## `$("#header")` → `getElementById()` -
yorkxin revised this gist
Jul 7, 2012 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -171,7 +171,7 @@ element.getAttributeNode("data-cat-weight").nodeValue; // => "100t" ## How to Tell the Performance Improvement? Desktop WebKit browsers like Chrome and Safari, as well as Internet Explorer 9+, have built-in JavaScript CPU Profilers. Use them to trace function running time and determine the bottleneck of your javascript code: - [Chrome Developer Tools: CPU Profiling](https://developers.google.com/chrome-developer-tools/docs/cpu-profiling) - [Safari Developer Tools Guide: Optimizing Your Website](https://developer.apple.com/library/safari/documentation/AppleApplications/Conceptual/Safari_Developer_Guide/OptimizingYourWebsite/OptimizingYourWebsite.html#//apple_ref/doc/uid/TP40007874-CH9-SW1) -
yorkxin revised this gist
Jul 7, 2012 . 1 changed file with 9 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -169,6 +169,15 @@ element.setAttributeNode(attribute); element.getAttributeNode("data-cat-weight").nodeValue; // => "100t" ``` ## How to Tell the Performance Improvement? Desktop WebKit browsers like Chrome and Safari, as well as Internet Explorer 9+, have built-in JavaScript CPU Profilers. Use them to trace function running time and decide the bottleneck of your javascript code: - [Chrome Developer Tools: CPU Profiling](https://developers.google.com/chrome-developer-tools/docs/cpu-profiling) - [Safari Developer Tools Guide: Optimizing Your Website](https://developer.apple.com/library/safari/documentation/AppleApplications/Conceptual/Safari_Developer_Guide/OptimizingYourWebsite/OptimizingYourWebsite.html#//apple_ref/doc/uid/TP40007874-CH9-SW1) - [Internet Explorer - Using the Profiler Tool to analyze the performance of your code](http://msdn.microsoft.com/en-us/library/ie/gg699341.aspx) (also includes invocation counter) ## References 1. [Gecko DOM Reference - MDN](https://developer.mozilla.org/en/Gecko_DOM_Reference) -
yorkxin revised this gist
Jul 7, 2012 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -6,7 +6,7 @@ When targeting only modern browsers, it is better to avoid using jQuery's backwa 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 unless you're making an app-like extension (each jQuery-driven extension needs a separate memory space for its jQuery's compiled machine code; they're not shared across extensions). ## `$("#header")` → `getElementById()` -
yorkxin revised this gist
Jul 7, 2012 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -76,7 +76,7 @@ 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") ``` -
yorkxin revised this gist
Jul 7, 2012 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -53,7 +53,7 @@ The [`element.className`](https://developer.mozilla.org/en/DOM/element.className jQuery provides some [class manipulation functions](http://api.jquery.com/category/manipulation/class-attribute/) 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](https://github.com/eligrey/classList.js) or [this polyfill for IE 9](https://gist.github.com/1381839), or implement it manually by tokenizing the `className` string into an array like [how jQuery does](https://github.com/jquery/jquery/blob/master/src/attributes.js#L36), or by working with space-wrapped strings like [how MooTools does](https://github.com/mootools/mootools-core/blob/master/Source/Element/Element.js#L697). ### `classList` Usage -
yorkxin revised this gist
Jul 7, 2012 . 1 changed file with 3 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -174,4 +174,6 @@ element.getAttributeNode("data-cat-weight").nodeValue; // => "100t" 1. [Gecko DOM Reference - MDN](https://developer.mozilla.org/en/Gecko_DOM_Reference) - [Statements - JavaScript Reference - MDN](https://developer.mozilla.org/en/JavaScript/Reference#s26545) - [HTML5 Cross Browser Polyfills · Modernizr/Modernizr Wiki](https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills) - [WWDC 2012 Session 601](https://developer.apple.com/videos/wwdc/2012/?id=601) (I learnt `classList` and `querySelectorAll` in the video) p.s. This is made public from my [private Gist](https://gist.github.com/034fe1d3b0a5c9952eba). -
yorkxin revised this gist
Jul 7, 2012 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -173,4 +173,5 @@ element.getAttributeNode("data-cat-weight").nodeValue; // => "100t" 1. [Gecko DOM Reference - MDN](https://developer.mozilla.org/en/Gecko_DOM_Reference) - [Statements - JavaScript Reference - MDN](https://developer.mozilla.org/en/JavaScript/Reference#s26545) - [HTML5 Cross Browser Polyfills · Modernizr/Modernizr Wiki](https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-Browser-Polyfills) - [WWDC 2012 Session 601](https://developer.apple.com/videos/wwdc/2012/?id=601) (I learnt `classList` and `querySelectorAll` in the video) -
yorkxin created this gist
Jul 7, 2012 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,176 @@ # Avoid jQuery When Possible 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). ## `$("#header")` → `getElementById()` As long as you know the actual ID of the target element, why don't you use [`getElementById`](https://developer.mozilla.org/en/DOM/document.getElementById)? ```javascript document.getElementById("header"); // instead of $("#header"); ``` This works for IE >= 5.5 ## `$(selector)` & `.find()` → `querySelectorAll()` Use [`querySelectorAll()`](https://developer.mozilla.org/en/DOM/Element.querySelectorAll) instead: ```javascript 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. ## `$("<a class='blah' href='…'>hi</a>")` → `createElement()` [`jQuery(html)`](http://api.jquery.com/jQuery/) 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`](https://developer.mozilla.org/en/DOM/document.createElement) instead: ```javascript var element = document.createElement("a"); element.href = "http://www.example.com/"; element.className = "blah"; element.innerText = "hi"; ``` The [`element.className`](https://developer.mozilla.org/en/DOM/element.className) lets you access the `class` attribute of that element. More about this in the section below. ## `class` manipulation: use `classList` & `className` jQuery provides some [class manipulation functions](http://api.jquery.com/category/manipulation/class-attribute/) 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](https://github.com/eligrey/classList.js) or [this polyfill for IE 9](https://gist.github.com/1381839), or implement it manually by tokenizing the `className` string into an array, just like [what jQuery does](https://github.com/jquery/jquery/blob/master/src/attributes.js#L36). ### `classList` Usage ```javascript 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.contains("hide"); // instead of $(element).hasClass("hide") ``` ## `.css()` → `style` attribute & `style.cssText` jQuery's [`.css()`](http://api.jquery.com/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: ### Assigning One Attribute e.g. Width ```javascript element.style.width = "320px"; // instead of $(element).css("width", "320px"); ``` ### Overriding the Whole Style Rule Write the style directly with [`element.style.cssText=`](https://developer.mozilla.org/en/DOM/cssRule.cssText). Note that this is just like writing inline style directly, so mind that semicolon `;`. e.g. Width = 320px, Height = 640px ```javascript element.style.cssText = "width: 320px; height: 640px;"; // Mind the semicolon // instead of $(element).css({"width": "320px", "height": "640px"}); ``` ## `$.each()` → use `for` statement jQuery's [`$.each()`](http://api.jquery.com/jQuery.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. ## `.data()` → use HTML5 `dataset` jQuery's [`.data()`](http://api.jquery.com/data/) implements its own storage, which may cause lots of overhead. If you're only supporting browsers with native [HTML5 DataSet](http://caniuse.com/#feat=dataset) implementation, use [`element.dataset`](https://developer.mozilla.org/en/DOM/element.dataSet) and its corresponding API to access the bounded data. Also see HTML5 Doctor's [Guide on HTML5 data-* Attributes](http://html5doctor.com/html5-custom-data-attributes/). Say that we have the following HTML: ```html <div id="long-cat" data-cat-length="30km">Nyan</div> ``` Access the `cat-length` data with `dataset`: ```javascript 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](http://dev.w3.org/html5/spec/global-attributes.html#embedding-custom-non-visible-data-with-the-data-attributes) for more details. ### Support for Old Browsers If you need to support old browsers, take a look at [this polyfill](http://eligrey.com/blog/post/html-5-dataset-support), or use [`createAttribute`](https://developer.mozilla.org/en/DOM/document.createAttribute) and [`setAttributeNode`](https://developer.mozilla.org/en/DOM/element.setAttributeNode): ```javascript // 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" ``` ## References 1. [Gecko DOM Reference - MDN](https://developer.mozilla.org/en/Gecko_DOM_Reference) - [Statements - JavaScript Reference - MDN](https://developer.mozilla.org/en/JavaScript/Reference#s26545) - [WWDC 2012 Session 601](https://developer.apple.com/videos/wwdc/2012/?id=601) (I learnt `classList` and `querySelectorAll` in the video)