By Burke Holland
When I first started using jQuery, I was so excited. I was using vanilla JS and really struggling with understanding when elements on a page were ready and how I could access them. When I learned about jQuery, I think I did what many people do. With tears of joy running down my face, I opened up a document ready function and then just vomited up massive amounts of jQuery.
Some of the worst jQuery code ever written was written by me – I can assure you of that.
Since then, I’ve spent a few years at the Bayside of jQuery. I’ve had my heart broken a few times and learned a some things along the way. In doing so, I’d like to share 5 things in jQuery that I think you should think twice about doing.
1. Stop Using Document Ready
Back in the day of heavy server frameworks, knowing that your page was fully constructed before you tried to mutate it was a big deal. This was especially true if you were using partial views of some sort that were injected into the layout/master page by the server at runtime.
Nowadays, it’s considered best practice to include your scripts at the bottom of the page. The HTML5 async attribute notwithstanding, scripts are loaded and executed synchronously by the browser. That means that if you have a large script in the head of your page, it will delay loading of the DOM and make your page seem slower than it actually is. Loading all scripts last will at least make your application seem to load faster. It also gives you a chance to use a spinner or loading overlay if you are completely dependent on JavaScript for your UI.
If you are adhering to the “scripts at the bottom” best practice, then you have no need for jQuery’s document ready function as the HTML is already loaded by the time the script is run.
<p id="zack">This element is on the page <strong>BEFORE</strong> all the scripts. No document ready needed.</p>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type="text/javascript" charset="utf-8">
// if you include your scripts at the very bottom, you don't need document ready
(function($) {
$("#zack").css("color", "green");
$("#slator").css("color", "red");
}(jQuery));
</script>
<p id="slater">This element comes after the scripts and won't be available.</p>
2. Stop Using The Wrong Iterator
I’ve got no hard evidence to back this up, but I’d be willing to guess that the each function is the most used of the jQuery utility methods. I base this on how often I am tempted to use it and how often I see it in other people’s code. It’s incredibly convenient for looping over DOM elements and JavaScript collections. It’s also terse. There is nothing wrong with it, except that its not the only iteration function the jQuery provides. People use each like it’s Zack Morris, at which point every looping problem starts looking like Kelly Kapowski.
MAP
If you have an array of items and you want to loop through it and filter out some of the items, you might be tempted to use the each method like so:
(function($) {
var allStarCast = [
{ firstName: "Zack", lastName: "Morris" },
{ firstName: "Kelly", lastName: "Kapowski" },
{ firstName: "Lisa", lastName: "Turtle" },
{ firstName: "Screech", lastName: "Powers" },
{ firstName: "A.C.", lastName: "Slater" },
{ firstName: "Jessie", lastName: "Spano" },
{ firstName: "Richard", lastName: "Belding" }
]
// iterate through the cast and find zack and kelly
var worldsCutestCouple = [];
$.each(allStarCast, function(idx, actor) {
if (actor.firstName === "Zack" || actor.firstName === "Kelly") {
worldsCutestCouple.push(actor);
}
});
console.log(worldsCutestCouple);
}(jQuery));
That works, but jQuery actually provides a method specifically for this scenario and it’s called map. What it does is takes any items that get returned and adds them to a new array. The looping code then looks like this…
(function($) {
var allStarCast = [
{ firstName: "Zack", lastName: "Morris" },
{ firstName: "Kelly", lastName: "Kapowski" },
{ firstName: "Lisa", lastName: "Turtle" },
{ firstName: "Screech", lastName: "Powers" },
{ firstName: "A.C.", lastName: "Slater" },
{ firstName: "Jessie", lastName: "Spano" },
{ firstName: "Richard", lastName: "Belding" }
]
// iterate through the cast and find zack and kelly
var worldsCutestCouple = $.map(allStarCast, function(actor, idx) {
if (actor.firstName === "Zack" || actor.firstName === "Kelly") {
return actor;
}
});
console.log(worldsCutestCouple);
}(jQuery));
Did you notice that the arguments for the .map() callback and the .each() callback are reversed? Watch out for that because it can bite you when you start using map.
The map function allows you to modify the items before they get slapped into the new array. I’m not currently doing that, so technically I’m still not using the “right” iterator. I should really be using grep.
GREP
If you spend most of your days on Windows, then this term might be foreign to you. The term is typically used for a Unix command line utility for searching files that contain text matching a given regular expression.
In jQuery, grep is a function whose purpose is to reduce a collection by removing elements that don’t pass the test in the callback. The provided callback returns a boolean value. Return true if you want the item to remain, and false(y) if you don’t. It will not affect the original array. You cannot modify the items as you reduce them.
(function($) {
var allStarCast = [
{ firstName: "Zack", lastName: "Morris" },
{ firstName: "Kelly", lastName: "Kapowski" },
{ firstName: "Lisa", lastName: "Turtle" },
{ firstName: "Screech", lastName: "Powers" },
{ firstName: "A.C.", lastName: "Slater" },
{ firstName: "Jessie", lastName: "Spano" },
{ firstName: "Richard", lastName: "Belding" }
]
// iterate through the cast and find zack and kelly
var worldsCutestCouple = $.grep(allStarCast, function(actor) {
return (actor.firstName === "Zack" || actor.firstName === "Kelly");
});
console.log(worldsCutestCouple);
}(jQuery));
3. Stop Using “this”
This isn’t a jQuery issue, but jQuery can definitely exacerbate the problem. The context of “this” is always changing. jQuery sometimes changes the context to something that you might not be expecting. In the each callback, this is the current item or element in the collection. In the map function, it’s the window object. You can see how you could get yourself confused pretty quickly.
Have a look at the following example and then we’ll talk about why it blows up.
(function($) {
var sbtb = {
log: function(message) {
$("#log").append("").html(message);
},
cast: [
{ firstName: "Zack", lastName: "Morris", soExcited: false },
{ firstName: "Kelly", lastName: "Kapowski", soExcited: true },
{ firstName: "Lisa", lastName: "Turtle", soExcited: true },
{ firstName: "Screech", lastName: "Powers", soExcited: false },
{ firstName: "A.C.", lastName: "Slater", soExcited: false },
{ firstName: "Jessie", lastName: "Spano", soExcited: true },
{ firstName: "Richard", lastName: "Belding", soExcited: false }
],
soExcited: function() {
// use "this" to get a reference to the cast on this object
$.each(this.cast, function(idx, actor) {
// call the log function
this.log(actor.firstName + " " + actor.lastName); // BOOM! Splosions.
// "this" is now a cheesy actor, not the sbtb object anymore
});
}
};
sbtb.soExcited();
}(jQuery));
I wanted to log out everyone who was “so excited”. I’m in an object so I can get a reference to the object with this. Then I loop through the object and look for the “isExcited” flag. However, as soon as I enter the loop callback, the context of this has changed and I can’t access the object anymore.
Since jQuery is changing the scope for you in these loops, it’s a good idea to store the reference to this somewhere so that you know it’s not going to change on you.
(function($) {
var sbtb = {
log: function(message) {
$("#log").append("
").append(message);
},
cast: [
{ firstName: "Zack", lastName: "Morris", isExcited: false },
{ firstName: "Kelly", lastName: "Kapowski", isExcited: true },
{ firstName: "Lisa", lastName: "Turtle", isExcited: true },
{ firstName: "Screech", lastName: "Powers", isExcited: false },
{ firstName: "A.C.", lastName: "Slater", isExcited: false },
{ firstName: "Jessie", lastName: "Spano", isExcited: true },
{ firstName: "Richard", lastName: "Belding", isExcited: false }
],
soExcited: function() {
// store this in that so we don't get confused later on when
// our the context of "this" changes out from underneath us
var that = this;
// use "that" to get a reference to the cast on this object
$.each(that.cast, function(idx, actor) {
// call the log function
if (actor.isExcited) {
that.log(actor.firstName + " " + actor.lastName);
// the value of "that" doesn't change - it's still the object
}
});
}
};
sbtb.soExcited();
}(jQuery));
4. Stop Using ALL THE jQUERIES
jQuery has steadily kept increasing in size. This is only natural as new functionality is added. Even though the size has steadily been reduced since 1.8.3, It’s led to some decry from the community claiming it “unsuitable” for mobile development due to it’s sheer mass.
However, jQuery is not an all or nothing library anymore. jQuery now supports custom builds. I know it’s really tempting to use the jQuery CDN and just rock on, but it is important to think about all the code that you are asking your users to download that they might not even need. That’s no big deal on a desktop, but bits get precious on mobile devices, and there is no point in sending down a bunch of code to support legacy browsers if your app is a mobile one.
You have two choices here. You can head over to the GitHub site and create a custom build with Git. It’s actually really easy and I had no issues getting it to work. But, if pounding out node commands is not your thing, John Resig tweeted about a web UI for custom builds the other day.
5. Stop Using jQuery…
…when you don’t need to.
I got to a point in my development career where the first thing that I did with any project was add jQuery, even if I was just creating very simple projects and samples. I did this mainly so that I could just use the DOM selection utilities. Back in the day of older browsers, this was easier to justify, but modern browsers have this whole DOM selection thing already nailed down for you.
DOCUMENT.QUERYSELECTOR
If you are using at least IE version 8 and above, you can just map the $ to document.querySelector, which will return you the first matched element from the selector. You can pass any CSS selector to the function.
Note that IE 8 only supports CSS 2.1 selectors for querySelector.
<div class="container">
<ul>
<li id="pink">Pink</li>
<li id="salmon">Salmon</li>
<li id="blue">Blue</li>
<li id="green">Green</li>
<li id="red">Red</li>
</ul>
</div>
<script>
// create a global '
Try It
Of course, there is no chaining when using the native "style" method, so item logs out "salmon" which is what the backgroundColor method returned.
Having a DOM node is sometimes more handy than having a jQuery wrapped one. For instance, let's say we want to get a reference to an image and change it's source. Have a look at how you would do it with jQuery as opposed to a straight up DOM node.
// the jQuery way
$("#picture").attr("src", "https://placekitten.com/200/200");
// Vanilla JS with $ mapped to querySelector
$("#picture").src = "https://placekitten.com/200/200";
The DOM object gives you direct access to the “src” property of the image because you have a node of type “image” that has access that property. In the case of jQuery, everything is a jQuery object, so you have to go through the attr function to set the image source.
The document.querySelector method only gets you one element. If you call that on a collection of elements, it will return you only the first matched node. You can use document.querySelectorAll to get the entire list.
DOCUMENT.QUERYSELECTORALL
A neat trick is to map $ to querySelector (1 result) and map $$ to querySelectorAll which will give you all matched DOM elements. The tricky part of this is that querySelectorAll returns a node list which isn’t terribly helpful. You are probably going to need this as an array which you can slice up. You can convert the node list to an array by using Array.prototype.slice.call(nodeList).
<div class="container">
<ul>
<li id="pink">Pink</li>
<li id="salmon">Salmon</li>
<li id="blue">Blue</li>
<li id="green">Green</li>
<li id="red">Red</li>
</ul>
</div>
<script>
// custom lightweight selector implementation
// nickname: dolla
window.$ = function(selector) {
return document.querySelector(selector);
};
window.$ = function(selector) {
var items = {},
results = [],
length = 0,
i = 0;
// this doesn't work on IE 8- and Blackberry Browser
results = Array.prototype.slice.call(document.querySelectorAll(selector));
length = results.length;
// add the results to the items object
for ( ; i < length; ) {
items[i] = results[i];
i++;
}
// add some additional properties to this items object to
// make it look like an array
items.length = length;
items.splice = [].splice();
// add an 'each' method to the items
items.each = function(callback) {
var i = 0;
for ( ; i < length; ) {
callback.call(items[i]);
i++;
}
}
return items;
};
// end custom selector API
(function() {
// select the green item and crank up the font size
$("#green").style.fontSize = "2em";
// select item1 by id and change it's background color to salmon
$("li").each(function() {
this.style.backgroundColor = this.id;
});
}());
</script>
Note that converting a nodeList to an array is not supported on IE 8 and below.
At this point you may think to yourself, “That’s a lot of JavaScript to write when I can just include jQuery bro,” and that’s fair. This could be reduced no doubt, but jQuery puts so much convenience on objects and collections that when you start rolling without it, you see what sort of code it takes to recreate just a small piece of it – and this implementation doesn’t even support IE 8 and below or Blackberry browser. Depending on what your application needs to do though, it could be far less code than including jQuery.
Leland Richardson and Jonathan Sampson helped me add a few more features to and clean up the above code. We created a repo called “Dolla“. It’s not meant to be a replacement for jQuery in any way whatsoever, but rather a chance for us to learn what it’s like to say “I don’t need jQuery”. It’s a fair bit more code than you might anticipate.
Stop Reading Articles That Tell You To Stop Doing Something
Seriously though. This is just to underscore the point that these are suggestions, not absolute rules of law. There are a thousand ways that you can argue and or justify any of these items. This is merely to get you thinking about how you use jQuery and how you might be able to do it better than you do now.
So enjoy jQuery, be happy, and stay in school.
variable
window.$ = function(selector) {
return document.querySelector(selector);
};
(function() {
// select item1 by id and change it's background color to salmon
var item = $("#salmon").style.backgroundColor="salmon";
console.log(item);
}());
</script>
Try It
Of course, there is no chaining when using the native “style” method, so item logs out “salmon” which is what the backgroundColor method returned.
Having a DOM node is sometimes more handy than having a jQuery wrapped one. For instance, let’s say we want to get a reference to an image and change it’s source. Have a look at how you would do it with jQuery as opposed to a straight up DOM node.
The DOM object gives you direct access to the “src” property of the image because you have a node of type “image” that has access that property. In the case of jQuery, everything is a jQuery object, so you have to go through the attr function to set the image source.
The document.querySelector method only gets you one element. If you call that on a collection of elements, it will return you only the first matched node. You can use document.querySelectorAll to get the entire list.
DOCUMENT.QUERYSELECTORALL
A neat trick is to map $ to querySelector (1 result) and map $$ to querySelectorAll which will give you all matched DOM elements. The tricky part of this is that querySelectorAll returns a node list which isn’t terribly helpful. You are probably going to need this as an array which you can slice up. You can convert the node list to an array by using Array.prototype.slice.call(nodeList).
Note that converting a nodeList to an array is not supported on IE 8 and below.
At this point you may think to yourself, “That’s a lot of JavaScript to write when I can just include jQuery bro,” and that’s fair. This could be reduced no doubt, but jQuery puts so much convenience on objects and collections that when you start rolling without it, you see what sort of code it takes to recreate just a small piece of it – and this implementation doesn’t even support IE 8 and below or Blackberry browser. Depending on what your application needs to do though, it could be far less code than including jQuery.
Leland Richardson and Jonathan Sampson helped me add a few more features to and clean up the above code. We created a repo called “Dolla“. It’s not meant to be a replacement for jQuery in any way whatsoever, but rather a chance for us to learn what it’s like to say “I don’t need jQuery”. It’s a fair bit more code than you might anticipate.
Stop Reading Articles That Tell You To Stop Doing Something
Seriously though. This is just to underscore the point that these are suggestions, not absolute rules of law. There are a thousand ways that you can argue and or justify any of these items. This is merely to get you thinking about how you use jQuery and how you might be able to do it better than you do now.
So enjoy jQuery, be happy, and stay in school.
The following:
(function($) {
}(jQuery));
is a short cut for document ready.
Robb, actually that is not a shortcut for document ready. That is a self-executing anonymous function. It just scopes the variable jQuery as the $ symbol. This would allow you to safely use another library that overwrites the value of the $ variable.
$(function() {}); is the same as document ready. Notice that you are invoking the jQuery function constructor and passing a function callback as opposed to a selector, like you normally do.
Just a tiny reminder that the terminology has changed to IIFE (immediate-invoked function expression)!
Why do you need to pass it a variable anyway. And what values does variable $ (or jQuery) contains?
Robb, your example is not a shortcut for document ready. Your example illustrates a self executing function with jQuery passed as the argument. This will not wait for document to be ready before executing. It only gives you a way to alias jQuery as $. The shortcut for doc ready:
jQuery(function($){
// code here
});
This also allows you to alias jQuery.
Nop… you are thinking in $(function (){}); that’s the shortcut. This is just an annonymous self invoking function.
No it’s not. It’s an self-executing function that is run immediately, creating a privately scoped $ variable.
This, on the other hand, is a shortcut for document.ready:
$(function()
// ready
});
https://stackoverflow.com/questions/3907527/shortcuts-for-jquerys-ready-method
Nope.
The following is a short cut for document reader
$(function( ) {
// code
})
What they all said /\/\/\/\ 😉
the shortcut is:
$(function(){
})
Pass your function to $( YOUR_FUNCITON )
Robb, don’t say that on a javascript job interview – you will be immediately rejected.
Wow, this site must have a time machine function or something. Robb’s comment was posted 33 minutes ago, but the first comment by Joel was posted 14 hours ago. That’s some pretty awesome sauce.
@camainc – yeah, a quirk in the template that I need to get fixed.
Actually that isn’t. That is just an immediate function passing in jQuery into the scope.
You’re thinking of
$(function (){
});
Hey everyone, Robb got it wrong. Let’s keep pointing it out and ridiculing him ‘cos it makes us feel all superior ”n’ crap.
Robb you idiot, how embarrassing. You stupid boy. Ha ha ha. Naa naa na naa na. 😛 😛 😛
Wow, that’s better – I feel great now.
Guys, that’s neither a “self-executing anonymous function” nor “self executing function” or “self-executing function that is run immediately”.
“annonymous self invoking function” comes closest.
That’s an immediately-invoked function expression (= IIFE).
An anonymous function can’t call or execute itself. It just gets immediately invoked …
tssss, love you all 😛
Starting from 2.0.0 you can setup a custom build that drops sizzle and you end up having a very nice wrapper around document.querySelectorAll. Check out https://raw.github.com/jquery/jquery/master/src/selector-native.js
I really think that we won’t need to drop jQuery entirely, even for mobiles, as it is more and more modularized in the future, I am confident we will be able to really extract only what we need from jQuery & get a very tiny footprint for mobile devices.
Great article I was wondering where you were going with this when I read it because it kinda of contradicted it self in some places but I am glad you wrapped it up with Stop Reading Articles That Tell You To Stop Doing Something.
Thanks again for providing a great example of what you read is not the bible it just a opinion man.
I disagree with your proposition to stop using THIS. Here is why by using this you are saving on having to define a local variable, you are also saving a round trip to get the DOM element since Jquery, or vanilla JS for that matter, has already selected an element of the DOM and has it stored on the variable THIS, THIS is already available and saves on redundancies and an extra round trip to the DOM. I could, however, get very confusing if you don’t know what THIS is at any point in your code or if you don’t organize your JS. Just my 2 cents based purely on experience….
You’re absolutely right that THIS is extremely useful; I find it helpful, too.
I think OP meant “Stop using THIS -ALL-the-time-with-no-clarification-” because, as you noted, THIS will get confusing if you don’t meticulously keep track of it. It’s also hard for anyone else to read your code and collaborate with development if you’re the only one who can keep track of your THIS. I benefited a lot from another developer who stored his contexts in VARs with appropriate names. I found that I could easily make sense of all the code and use it as an example to develop my own project.
Even when I use place-holding variables whenever I can, I still find the need to use THIS pretty often. What I’m saying is, I agree with you that THIS is useful, but I also agree with OP that place-holding variables make the code more readable.
* I don’t actually know if calling THIS would make a trip to DOM each time or not, so I didn’t address that part of your post. Thanks for pointing it out.
Thanks for sharing & you have shown the differences which gets a clear picture for us.
Stay in school? Why? The professor is teaching me about Java. He doesn’t even understand jQuery yet. Sheesh. School is costing me a fortune!
Java is a good place to start, and I one doesn´t have to know/understand jQuery to be a pro.
I hope you know that Java and JavaScript are two completely different things. Java is an extremely useful language and used in many many contexts. jQuery is (AFAIK) only run in the browser. Not at all suprising your prof doesn’t know jQuery if he’s not a front-end web-dev.
And take the following advice with a grain of salt; but if you’re trying to go into CS, expensive schooling might not be the best investment. You can get very far as self-taught, though I’d reccomend community college, or at least a structured approach reccommended by smart folks in the field you’re aspiring to be a part of.
JavaScript isn’t run only in the browser. The biggest example is node.js (https://nodejs.org/), a JavaScript runtime, mostly used in server backend.
I agree. School will only help you understand CS concepts in a structured environment, but to be successful in this field, you need to keep learning beyond school. Once you understand the concepts of CS, the languages change but the fundamental concepts don’t. Coding is not a career. Its a way of life.
You could make a fortune developing with Java. Not so much with JQuery/Javascript.
And use undescore.js 😉
lodash 😉
lodash is awesome
1) It’s not as simple as that – if you’re using user controls, partial views, master pages, or any similar concept (which I would imagine most people are), you can’t just dump scripts at the bottom, because the bottom of the markup file is not the bottom of the rendered page.
4) I worry about jQuery custom builds – yes, they work, but anytime you want to use a custom library (one of the thousands of jQuery add-ons), you have to see what jQuery features that library needs, not only in normal scenarios but also in exceptional circumstances. Using and caching the full version of jQuery from the CDN means that there’s zero bandwidth wasted after the first download, so your browser will likely have jQuery before they even visit your site. With a custom build, you’re guaranteed that they have to download your script. The only wasteful part is the execution of the script on load, but executing the jquery.js file is ridiculously fast regardless of what device you’re on.
5) Remapping $ to document.querySelector is terrible – if you take code that has this and then add jQuery to it later (which is not unreasonable), every piece of script you’ve previously written is now broken. Plus you’ll confuse yourself and other developers looking at your code, as you’re developing and in the future. If you don’t want to use jQuery, that’s fine – but don’t pretend to use it. Write standard javascript, or your own customer wrapper.
If you worry about the custom build, I wrote a some code for finding all the jQuery functions you’re using.
https://github.com/herrwalter/jqueryFunctionsFinder
Though I agree on google cdn. I used this jquery functions finder to come up with alternatives and come less dependent of jQuery.
That function finder looks pretty interesting. I’ll have to try that out sometime.
I tend to agree with your comment on item 1 — scripts at the bottom of the page isn’t necessarily for everyone. For the sites / applications I’ve developed or been involved with, I’ve often found that using a lightweight script loader, such as yepnope (included in Modernizr), to trigger the loading of resources in the HEAD rather than placing them at the bottom of the page to have comparable or better overall performance. Of course, this is in part because most of my recent projects use Modernizr anyway, so given that I’m already blocking rendering in the HEAD waiting for Modernizr to load, I might as well spin up yepnope (Modernizr.load) while I’m at it.
As for your concern about remapping $ to document.querySelector — I completely disagree. There are plenty more scripts than just jQuery that map themselves to $. ‘$’ is not strictly a jQuery pattern, and using it is not ‘pretending to use jQuery’. I think that if your code is going to use a lot of calls to document.querySelector or document.querySelectorAll, but not a lot of jQuery, then I think it makes perfect sense to use $ and $$, respectively. Turns out, I’ve seen it done plenty of times before, so doing so wouldn’t be out of line with the web development community at large, and consistency is usually a good thing.
Finally, if you write code like this, and then add jQuery to the project after the fact, none of your old code need be broken — just use jQuery.noConflict() after loading jQuery, or make sure you do your custom ‘$’ remapping after jQuery is loaded.
I suppose I can re-word my position on the $ thing. If you always use the jQuery variable instead of $, you’ll be fine using noConflict and a different meaning for $. Or if you actually wrap all of your jQuery calls inside of an anonymous function mapping $ to jQuery locally, the way plugins do, you’d be ok there too. However, in real life, the overwhelming majority of developers I’ve seen use the global $ variable for jQuery. If you are working with developers who write jQuery all day long and use $ for it, their muscle memory will use $ without thinking about it, and it will conflict, regardless of when the remapping happens.
Of course you’re right about $ being used in other libraries other than jQuery – but according to some stats (74% of statistics are made up on the spot, but I actually believe this one), more than half the web uses jQuery now – so the $ which represents jQuery is likely an order of magnitude more popular than the next most common one (MooTools?).
“1) It’s not as simple as that – if you’re using user controls, partial views, master pages, or any similar concept (which I would imagine most people are), you can’t just dump scripts at the bottom, because the bottom of the markup file is not the bottom of the rendered page.”
You can do this easily in every major framework that comes to mind….except WebForms. Actually, I’d be surprised to find that it wasn’t supported in WebForms as of ASPNet4. Stop using WebForms. The .Net world has largely moved to MVC & WebAPI. If you’re maintaining a WebForms app then you’re SOL.
It’s not just WebForms. Partial views (or partial templates) and layout pages exist in other platforms like ASP.NET MVC and Rails. If I remember, JSP has user controls, and PHP and ColdFusion have partials. I’d expect every other decent platform has the same concepts, whatever they actually call them.
There’s no “put-this-at-the-bottom-of-the-final-rendered-page” function, so dumping all of your script to the bottom of the page just before the /body tag would require some kind of placeholder. If you have a layout page, a regular view, and a partial view, and the partial has scripts that are supposed to end up at the bottom of the body (defined on the layout page), while the rest of the partial view ends up where it belongs (defined by the regular view), it’s not going to be pretty.
Joe, I agree with you that remapping document.queryselector is and using custom jquery builds is a bad idea, Your first point that it’s not as simple as that, however, is wrong. Every framework that uses either partial views, user controls, partials, … should have a way of letting you include scripts in the bottom of the page. If it doesn’t, you should find a way. Saying the framework doesn’t have support for it, is not a good excuse for litterling you HTML with javascript. ASP.NET MVC has script-sections for example. They let you add scripts to (partial) views which then get rendered on the bottom of the layout-page.
Using “this” isn’t “bad” per se. It really all depends on function scope and how your code is organized. But, you’re dead on when you advise folks to take some time and analyze when they should use jQuery. Sometimes slowing down and looking ahead makes all the difference.
While you are right that Array.slice doesn’t accept native NodeLists in IE7/8, it’s trivial to fix this (and very efficient in practice) with a simple loop:
var nodelist = document.querySelectorAll(selector)
for (var i = nodelist.length; i–; results.unshift(nodelist[i]));
One additional line of code and you get oldIE support.
Nice Article
The point No3. about the (this) was good i had few issues when i was using it.
And BTW i too had tears of joy when i started using jQuery.
About .map() – there are actually 3 versions of map() involved here:
– Array.map(), native built-in iterator for Arrays using 3 parameters (item, index, array)
– $.map(), similar to the native Array.map() method
– $().map(), which uses the same parameter sequence as $.each()
So if you have an array (and do not need to care for older IEs) you don’t even need to use jQuery.
From my experiences, jQuery is great for the UI, but not necessarily needed for business logic.
PS. $.grep() => Array.filter()
Bad article. “this” is literally one of the best things a dynamic language has. It enables proxy patterns and improves consistency. Furthermore, it makes perfect sense; the likelier case is that you don’t understand it.
Beyond that, I think “document.ready” still has a very broad use case in the async world — which is soon to be the only world. Even in offline development (e.g. Async calls to load assets etc.) there’s a case for it.
I don’t personally use jQuery at all — nada — except for work; but it is for different reasons than you listed here.
You are confused, Benny. “this” helps with closures. Dynamic languages have nothing to do with it.
I fully agree with Benny, bad article. You should only resort to aliasing “this” as a last resort.
“Stop Reading Articles That Tell You To Stop Doing Something” – I completely agree!
> Of course, there is no chaining when using the native “style” method, so item logs out “salmon” which is what the backgroundColor method returned.
backgroundColor isn’t a method, and it doesn’t return anything.
Regarding the $$ function, why would you create an array-like object with each when you could just, you know, return the array and use forEach?
Finally:
> // select item1 by id and change it’s background color to salmon
*its
Great Article, I got a lot of new things to try out in my code.
Surprised no one mentioned Zepto.js as a lightweight replacement for jQuery. It’s only 10k and has a near identical API as jQuery.
Hi Andy, I tried Zepto a few weeks ago for a mobile app development, trying to get a faster solution than jquery.
At the end, I fall in too many problems with native document querying that zepto rely on and that jquery cares and fix.
It also appeared that jQuery has a strong cache system that finally made it faster on a real use case than Zepto.
This is also why I would disagree with the 5) point since for complex manipulation (needing live creation of dom elements with their own events), I think jQuery makes the whole thing work, whereas native implementation (chrome in that case) is far from perfect, and god, such issues are really hard to check and fix 😉
As a moderate UNIX user, I believe the array GREP function here more closely resembles the typical use case of extracting lines from a document that match a search pattern, such as
cat Bayside | grep Zack
Also, Jessie’s model is incomplete:
{ firstName: “Jessie”, lastName: “Spano”, soExcited: true, soScared: true },
Hahahaha! Nice!
Totally agree with this article.
I think you mean “outcry” rather than “decry.”
Good article. Read a similar one a little bit back. Isn’t this a kind-of bad coding convention?
for ( ; i < length; ) {
items[i] = results[i];
i++;
}
I realize what it does, but wouldn't it be easier and more clear to just use a while loop?
Scripts at bottom is the worst case scenario for automation scripts development. Most of the times, page load completion is checked based on availability of a particular element on the page and since DOM is loaded, it gives incorrect status of the page load completion and cause failures as well.
I am interested in the “scripts at bottom” vs jQuery “on document ready” strategy, but I was puzzled to note that this page loads all its own scripts in the HEAD section. Perhaps this has to do with its blogging setup?
It looks as a WordPress site and is pretty easy moving the scripts at the bottom of the page using the $in_footer parameter in wp_register_script/wp_enqueue_script
Some great points in the article, but for me the key one is ‘stop using jQuery’, not to then use js, but eventually, once doc specs are finalised and all functionality is stable (user base browser / device support permitting) that CSS3 and HTML5 or newer technologies will provide all the support and functionality that jQuery does now.
Cool article. I’ll definitely stop using jQuery when I don’t need it!
This article solved some problems for me. jQuery is a big library for develop solutions faster, but isn’t all
Hey, nice article. Coding smartly is the best advice we can provide 🙂
However just a small fix, the `$(“#picture”).src` won’t work as `$(“#picture”)` returns an array.
You have either to do `$(“#picture”).get(0).src`, `$(“#picture”)[0].src` or `document.getElementById(‘picture’).src` to make this working. The caveat is you have to test the existence of the DOM query returned value, as it may not exist.
Remy Sharp gave a nice talk at jQuery UK this year about this same topic, which can be summarised as “learn the DOM, it’s almost clean now”.
Apart from #4, I can’t agree with this article. Using this is fine, understanding this is the important part. #1 Not using $(function() {}) – still would do this as a default practise.
#2 It sounds like the author hasn’t heard of underscore.js or lodash (quoted by others). This gives you _.each, _.map, _.reduce _.filter etc. and IMO read better than JQuery’s.
#3 use underscore.js and use _.bind(..) to change the context of this.
I also disagree with #5 except for large performance code. Jquery is pretty much a standard for frontend web development… why go against the grain?
For a guy who is bashing jQuery, your site sure uses a lot of jQuery plugins… anywho I wouldn’t say stop using jQuery, cause it is way easier to work with than javascript, but I would not use others people’s plugin. I would learn to write my own properly.
I would kindly suggest you actually read the article rather than just the title. If you read it, you would see that it is far from bashing jQuery but rather about better use of jQuery.
Thanks for an insightful article. I learned of this from Treehouse.com. I think the comments teach as much as the actual post!
Nice article!
Coming from the functional programming world, I think your example of .map() is a bit strange. Map is normally not used for filtering a data set, it’s used for projecting every element of a data set into a new form by applying the same function to each element. In f#, haskell and others, filtering is normally done by .filter()
Why my document ready function assignment is overwritten by _layout.cshtml default assignment?
in _layout.cshtml I have this
Operations Overview
Which is in a header bar for displaying information related to the page. In document ready function, I have
$(“#pageTheme”).text(“Hello Kitty”);
When a button is clicked and the document ready function is executed, a new routed page shows up, I can see “Hello Kitty” showing up and then back to
“Operations Overview”.
I thought the document ready function is executed after loading the page, not going back to the page again.
Please help. Thanks.
#6: Stop writing really dumb articles that are really inaccurate.
haha have to agree. Thank god I only read the headlines I could of wasted a lot of time
I remember the time when there was no programming trolls. They have a common sickness where everything is black or white. There are no grays, colors. They don’t disagree with a point of view, they start with “This sucks”, “This is bad”, “You don’t know what you are talking about”, etc.
By the way, I won’t stop using jQuery because there are many selections that require a combination of selectors. But I would love to hear for a tested library (lightweight) replacement that really works like jQuery for DOM manipulation.
I have a problem with articles that say you should stop using features built into a library, or all together stop using the library. As with anything that has any negative press around quality and efficiency – USE IT RIGHT. PHP, WordPress, jQuery, etc. all are extremely powerful, efficient, and useful when used correctly. The problem with the 3 I mention specifically is that the barrier to entry is so low (a GOOD thing) that anyone can get in there and start writing code, which usually tends to be in poor quality until that person gains some meaningful experience.
The article is good. I just don’t think it should be named “STOP USING”. The topics are important and the author gives good examples of bad and good. However, if the topic was something like “jQuery Tips” then I probably wouldn’t have viewed it, so maybe “STOP USING” was to grab attention. Also, I clicked my link from the Web Observer and expected it to be pretty good, which it is pretty good. These are important areas of jQuery and should be understood before using them just because someone said use them.
You forgot the most important point “Stop Reading Modernweb.com”
Seriously, stop using jQuery, well you lost me there and then 🙁
Thanks for the 5 things!
Thank You! I had a problem with using “this” and after using a copy of that in my code my problem solved!
How about
window.$ = document.querySelector;
instead of
window.$ = function(selector) {
return document.querySelector(selector);
};
because that doesn’t work. in old-ish browsers, you’re not allowed to alias certain methods.. that included. in current chrome – it lets me set it, but gives an Invalid Invocation when I try to use it.
the latter is used because it doesn’t change the context of how querySelector is being called – and doesn’t break things.
Hmmm….I think it is a good article
Bc css jQuery function broke my whole page.
I feel like #1 should be titled “load scripts last”. Maybe you could use “if !document.ready() throw Splosions” as a kind of assert statement?
`var that = this`
nice