Skip to content

Commit 486113a

Browse files
committed
Merge branch 'master' of github.com:jquery/web-learn-jquery-com
* 'master' of github.com:jquery/web-learn-jquery-com: cleanup cleanup, adding missing link changed title attr on jquery-basics files to jquery-basics, some start on jquery-core code org concepts md tags for perf items perf nuggets
2 parents 5ba6778 + 3f60ffb commit 486113a

23 files changed

+773
-10
lines changed

content/code-organization/concepts.md

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
---
2+
chapter : Code Organization
3+
section: 0
4+
title: Code Organization Concepts
5+
attribution: $jQuery Fundamentals
6+
---
7+
8+
When you move beyond adding simple enhancements to your website with jQuery and
9+
start developing full-blown client-side applications, you need to consider how
10+
to organize your code. In this chapter, we'll take a look at various code
11+
organization patterns you can use in your jQuery application and explore the
12+
RequireJS dependency management and build system.
13+
14+
## Key Concepts
15+
16+
Before we jump into code organization patterns, it's important to understand
17+
some concepts that are common to all good code organization patterns.
18+
19+
- Your code should be divided into units of functionality — modules, services,
20+
etc. Avoid the temptation to have all of your code in one huge
21+
`$(document).ready()` block. This concept, loosely, is known as
22+
encapsulation.
23+
- Don't repeat yourself. Identify similarities among pieces of functionality,
24+
and use inheritance techniques to avoid repetitive code.
25+
- Despite jQuery's DOM-centric nature, JavaScript applications are not all
26+
about the DOM. Remember that not all pieces of functionality need to — or
27+
should — have a DOM representation.
28+
- Units of functionality should be [loosely
29+
coupled](http://en.wikipedia.org/wiki/Loose_coupling) -- a unit of
30+
functionality should be able to exist on its own, and communication between
31+
units should be handled via a messaging system such as custom events or
32+
pub/sub. Stay away from direct communication between units of functionality
33+
whenever possible.
34+
35+
The concept of loose coupling can be especially troublesome to developers
36+
making their first foray into complex applications, so be mindful of this as
37+
you're getting started.
38+
39+
## Encapsulation
40+
41+
The first step to code organization is separating pieces of your application
42+
into distinct pieces; sometimes, even just this effort is sufficient to lend
43+
44+
### The Object Literal
45+
46+
An object literal is perhaps the simplest way to encapsulate related code. It
47+
doesn't offer any privacy for properties or methods, but it's useful for
48+
eliminating anonymous functions from your code, centralizing configuration
49+
options, and easing the path to reuse and refactoring.
50+
51+
<div class="example" markdown="1">
52+
An object literal
53+
54+
var myFeature = {
55+
myProperty : 'hello',
56+
57+
myMethod : function() {
58+
console.log(myFeature.myProperty);
59+
},
60+
61+
init : function(settings) {
62+
myFeature.settings = settings;
63+
},
64+
65+
readSettings : function() {
66+
console.log(myFeature.settings);
67+
}
68+
};
69+
70+
myFeature.myProperty; // 'hello'
71+
myFeature.myMethod(); // logs 'hello'
72+
myFeature.init({ foo : 'bar' });
73+
myFeature.readSettings(); // logs { foo : 'bar' }
74+
</div>
75+
76+
The object literal above is simply an object assigned to a variable. The object
77+
has one property and several methods. All of the properties and methods are
78+
public, so any part of your application can see the properties and call methods
79+
on the object. While there is an init method, there's nothing requiring that it
80+
be called before the object is functional.
81+
82+
How would we apply this pattern to jQuery code? Let's say that we had this code
83+
written in the traditional jQuery style:
84+
85+
// clicking on a list item loads some content
86+
// using the list item's ID and hides content
87+
// in sibling list items
88+
$(document).ready(function() {
89+
$('#myFeature li')
90+
.append('<div/>')
91+
.click(function() {
92+
var $this = $(this);
93+
var $div = $this.find('div');
94+
$div.load('foo.php?item=' +
95+
$this.attr('id'),
96+
function() {
97+
$div.show();
98+
$this.siblings()
99+
.find('div').hide();
100+
}
101+
);
102+
});
103+
});
104+
105+
If this were the extent of our application, leaving it as-is would be fine. On
106+
the other hand, if this was a piece of a larger application, we'd do well to
107+
keep this functionality separate from unrelated functionality. We might also
108+
want to move the URL out of the code and into a configuration area. Finally, we
109+
might want to break up the chain to make it easier to modify pieces of the
110+
functionality later.
111+
112+
<div class="example" markdown="1">
113+
Using an object literal for a jQuery feature
114+
115+
var myFeature = {
116+
init : function(settings) {
117+
myFeature.config = {
118+
$items : $('#myFeature li'),
119+
$container : $('<div class="container"></div>'),
120+
urlBase : '/foo.php?item='
121+
};
122+
123+
// allow overriding the default config
124+
$.extend(myFeature.config, settings);
125+
126+
myFeature.setup();
127+
},
128+
129+
setup : function() {
130+
myFeature.config.$items
131+
.each(myFeature.createContainer)
132+
.click(myFeature.showItem);
133+
},
134+
135+
createContainer : function() {
136+
var $i = $(this),
137+
$c = myFeature.config.$container.clone()
138+
.appendTo($i);
139+
140+
$i.data('container', $c);
141+
},
142+
143+
buildUrl : function() {
144+
return myFeature.config.urlBase +
145+
myFeature.$currentItem.attr('id');
146+
},
147+
148+
showItem : function() {
149+
var myFeature.$currentItem = $(this);
150+
myFeature.getContent(myFeature.showContent);
151+
},
152+
153+
getContent : function(callback) {
154+
var url = myFeature.buildUrl();
155+
myFeature.$currentItem
156+
.data('container').load(url, callback);
157+
},
158+
159+
showContent : function() {
160+
myFeature.$currentItem
161+
.data('container').show();
162+
myFeature.hideContent();
163+
},
164+
165+
hideContent : function() {
166+
myFeature.$currentItem.siblings()
167+
.each(function() {
168+
$(this).data('container').hide();
169+
});
170+
}
171+
};
172+
173+
$(document).ready(myFeature.init);
174+
</div>
175+
176+
The first thing you'll notice is that this approach is obviously far longer
177+
than the original -- again, if this were the extent of our application, using an
178+
object literal would likely be overkill. Assuming it's not the extent of our
179+
application, though, we've gained several things:
180+
181+
- We've broken our feature up into tiny methods. In the future, if we want to
182+
change how content is shown, it's clear where to change it. In the original
183+
code, this step is much harder to locate.
184+
- We've eliminated the use of anonymous functions.
185+
- We've moved configuration options out of the body of the code and put them in
186+
a central location.
187+
- We've eliminated the constraints of the chain, making the code easier to
188+
refactor, remix, and rearrange.
189+
190+
For non-trivial features, object literals are a clear improvement over a long
191+
stretch of code stuffed in a `$(document).ready()` block, as they get us
192+
thinking about the pieces of our functionality. However, they aren't a whole
193+
lot more advanced than simply having a bunch of function declarations inside of
194+
that `$(document).ready()` block.
195+
196+
### The Module Pattern
197+
198+
The module pattern overcomes some of the limitations of the object literal,
199+
offering privacy for variables and functions while exposing a public API if
200+
desired.
201+
202+
<div class="example" markdown="1">
203+
The module pattern
204+
205+
var feature =(function() {
206+
207+
// private variables and functions
208+
var privateThing = 'secret',
209+
publicThing = 'not secret',
210+
211+
changePrivateThing = function() {
212+
privateThing = 'super secret';
213+
},
214+
215+
sayPrivateThing = function() {
216+
console.log(privateThing);
217+
changePrivateThing();
218+
};
219+
220+
// public API
221+
return {
222+
publicThing : publicThing,
223+
sayPrivateThing : sayPrivateThing
224+
}
225+
226+
})();
227+
228+
feature.publicThing; // 'not secret'
229+
230+
feature.sayPrivateThing();
231+
// logs 'secret' and changes the value
232+
// of privateThing
233+
</div>
234+
235+
In the example above, we self-execute an anonymous function that returns an
236+
object. Inside of the function, we define some variables. Because the variables
237+
are defined inside of the function, we don't have access to them outside of the
238+
function unless we put them in the return object. This means that no code
239+
outside of the function has access to the `privateThing` variable or to the
240+
`changePrivateThing` function. However, `sayPrivateThing` does have access to
241+
`privateThing` and `changePrivateThing`, because both were defined in the same
242+
scope as `sayPrivateThing`.
243+
244+
This pattern is powerful because, as you can gather from the variable names, it
245+
can give you private variables and functions while exposing a limited API
246+
consisting of the returned object's properties and methods.
247+
248+
Below is a revised version of the previous example, showing how we could create
249+
the same feature using the module pattern while only exposing one public method
250+
of the module, `showItemByIndex()`.
251+
252+
<div class="example" markdown="1">
253+
Using the module pattern for a jQuery feature
254+
255+
$(document).ready(function() {
256+
var feature = (function() {
257+
var $items = $('#myFeature li'),
258+
$container = $('<div class="container"></div>'),
259+
$currentItem,
260+
261+
urlBase = '/foo.php?item=',
262+
263+
createContainer = function() {
264+
var $i = $(this),
265+
$c = $container.clone().appendTo($i);
266+
267+
$i.data('container', $c);
268+
},
269+
270+
buildUrl = function() {
271+
return urlBase + $currentItem.attr('id');
272+
},
273+
274+
showItem = function() {
275+
var $currentItem = $(this);
276+
getContent(showContent);
277+
},
278+
279+
showItemByIndex = function(idx) {
280+
$.proxy(showItem, $items.get(idx));
281+
},
282+
283+
getContent = function(callback) {
284+
$currentItem.data('container').load(buildUrl(), callback);
285+
},
286+
287+
showContent = function() {
288+
$currentItem.data('container').show();
289+
hideContent();
290+
},
291+
292+
hideContent = function() {
293+
$currentItem.siblings()
294+
.each(function() {
295+
$(this).data('container').hide();
296+
});
297+
};
298+
299+
$items
300+
.each(createContainer)
301+
.click(showItem);
302+
303+
return { showItemByIndex : showItemByIndex };
304+
})();
305+
306+
feature.showItemByIndex(0);
307+
});
308+
</div>

content/jquery-fundamentals/jquery-basics/attributes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
chapter : jqfundamentals
2+
chapter : jquery-basics
33
section : 4
44
title : Attributes
55
attribution: jQuery Fundamentals

content/jquery-fundamentals/jquery-basics/css-styling-dimensions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
chapter : jqfundamentals
2+
chapter : jquery-basics
33
section : 3
44
title : CSS, Styling, & Dimensions
55
attribution: jQuery Fundamentals

content/jquery-fundamentals/jquery-basics/document-ready.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
chapter : jqfundamentals
2+
chapter : jquery-basics
33
section : 1
44
title : $(document).ready()
55
attribution: jQuery Fundamentals

content/jquery-fundamentals/jquery-basics/exercises.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
chapter : jqfundamentals
2+
chapter : jquery-basics
33
section : 7
44
title : Exercises
55
attribution: jQuery Fundamentals

content/jquery-fundamentals/jquery-basics/manipulating-elements.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
chapter : jqfundamentals
2+
chapter : jquery-basics
33
section : 6
44
title : Manipulating Elements
55
attribution: jQuery Fundamentals

content/jquery-fundamentals/jquery-basics/selecting-elements.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
---
2-
chapter : "jqfundamentals"
3-
section : "2"
4-
title : "Selecting Elements"
2+
chapter : jquery-basics
3+
section : 2
4+
title : Selecting Elements
5+
attribution: jQuery Fundamentals
56
---
67
## Selecting Elements
78

content/jquery-fundamentals/jquery-basics/traversing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
chapter : "qfundamentals
2+
chapter : jquery-basics
33
section : 5
44
title : Traversing
55
attribution: jQuery Fundamentals

content/jquery-fundamentals/jquery-basics/working-with-selections.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
---
2-
chapter : jqfundamentals
2+
chapter : jquery-basics
33
section : 3
44
title : Working with Selections
55
attribution: jQuery Fundamentals
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
---
2+
chapter : jquery-core
3+
section : 1
4+
title : $ vs $()
5+
attribution: jQuery Fundamentals
6+
---
7+
## $ vs $()
8+
9+
Until now, we’ve been dealing entirely with methods that are called on a jQuery object. For example:
10+
11+
<div class="example" markdown="1">
12+
$('h1').remove();
13+
</div>
14+
15+
Most jQuery methods are called on jQuery objects as shown above;
16+
these methods are said to be part of the `$.fn` namespace, or the “jQuery prototype,” and are best thought of as jQuery object methods.
17+
18+
However, there are several methods that do not act on a selection;
19+
these methods are said to be part of the jQuery namespace, and are best thought of as core jQuery methods.
20+
21+
This distinction can be incredibly confusing to new jQuery users. Here’s what you need to remember:
22+
23+
* Methods called on jQuery selections are in the `$.fn` namespace, and automatically receive and return the selection as this.
24+
* Methods in the $ namespace are generally utility-type methods, and do not work with selections; they are not automatically passed any arguments, and their return value will vary.
25+
26+
There are a few cases where object methods and core methods have the same names, such as `$.each` and `$.fn.each`. In these cases, be extremely careful when reading the documentation that you are exploring the correct method.

0 commit comments

Comments
 (0)