A couple of months ago, I was on a “Update All The Things” spree with my websites. In one of them, the blog I have for my Volvo 1800S, I’m using a purchased theme that I’ve left pretty much alone. It’s fine as far as it goes, a bit inefficient, but it did serve as a basis for my articles here on speeding up web pages (1, 2, 3). After I had written those it was time to fix the problems with the theme.
Plan A was to upgrade it to the developer’s latest version. Except it was no longer available. (The developer had dropped it, essentially, for a more complete WordPress theme instead. Oh well.) Since I had all the (non-minified) source files, it was onto plan B instead.
Plan B involved me updating the whole shebang myself. Hey, it’s only JavaScript, right? First was to move off jQuery 1.8.2 (eek!) to the latest, 1.11.3. And, BOOM, the slideshow on the main page stopped. OK, I was starting to get the picture. It was obviously time to refresh all the other open-source libraries the theme was using, drop those my site wasn’t, and fix the theme-specific JavaScript as well. I also set into place a simple build process to minify and concatenate the script files. After a few hours work it was all done.
Anyway, during all this work I came across a bit of code from the theme developer that gave me pause and caused me to do a bit of research into jQuery.
Here’s the Julian-modified code in question:
// if the document is smaller than the viewport, force the footer to
// the bottom of the viewport.
(function ($) {
"use strict";
$.fn.extend({
fixfooter: function () {
var fix = $(this).appendTo("div#content");
$.extend({
refixfooter: function () {
var
documentHeight = $(document.body).height() - fix.height(),
windowHeight = $(window).height();
if (documentHeight < windowHeight) {
fix.height(windowHeight - documentHeight);
}
}
});
$.refixfooter();
$(window).bind("load resize scroll", $.refixfooter);
}
});
}(jQuery));
And it is called later on like this:
$("div#fix-footer").fixfooter();
All it does is to ensure that the footer of the HTML document (it has the id “fix-footer”) is forced to the bottom of the viewport, should the document be smaller in height than the viewport height. And it makes sure that this behavior survives resizing the browser window, zooming, and scrolling . Nothing too contentious. But…
Look again. There are two calls to a function called extend
here: the first on the fn
property of the jQuery
function, and second on jQuery
itself. What’s the difference?
Here’s the declaration of extend
:
jQuery.extend = jQuery.fn.extend = function() { … };
So it is the very same function. (In this form, it essentially adds the properties of the parameter object to the object calling extend
. It, ahem, extends it.) What about fn
?
jQuery.fn = jQuery.prototype = { … };
As you can see, fn
is just an alias for the jQuery prototype object.
(Aside: the jQuery function itself, the one that gets used when you call it on a selector, like the one on “#fix-footer” above, looks like this:
jQuery = function( selector, context ) {
return new jQuery.fn.init(selector, context);
},
and, as you can see, all it does is to create a new jQuery object and return it. All of the properties that have been added to the jQuery prototype will then be available to the newly created jQuery object that wraps that selector. And, yes, I know the code declaration is self-referencing.)
So, in the end, the fixfooter
function is added to the jQuery prototype, so it is available to all jQuery objects. The refixfooter
function is not. It is only available on that one and only instance of jQuery, the global one, the function we all call to wrap selectors and the like.
Of course, there is no earthly reason why refixfooter
was added to the jQuery function at all. It can quite easily be declared inside that fixfooter
function and be available as part of the closure:
$.fn.extend({
fixfooter: function() {
var
fix = $(this).appendTo("div#content"),
refixfooter = function() {
var
documentHeight = $(document.body).height() - fix.height(),
windowHeight = $(window).height();
if (documentHeight < windowHeight) {
fix.height(windowHeight - documentHeight);
}
};
refixfooter();
$(window).bind("load resize scroll", refixfooter);
}
});
Mind you, if it had been coded that way in the first place, I wouldn’t have gone down this particular rabbit hole.
No Responses
Feel free to add a comment...
Leave a response
Note: some MarkDown is allowed, but HTML is not. Expand to show what's available.
_emphasis_
**strong**
[text](url)
`IEnumerable`
* an item
1. an item
> Now is the time...
Preview of response