flannel 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +2 -1
- data/VERSION.yml +3 -2
- data/features/feed.feature +10 -0
- data/features/fixtures/devlicious.rss +959 -0
- data/features/fixtures/feed.flannel +3 -0
- data/features/fixtures/feed.out +31 -0
- data/features/fixtures/rubyyot.rss +29 -0
- data/features/fixtures/{wiki_links_for_lamdba.flannel → wiki_links_for_lambda.flannel} +0 -0
- data/features/step_definitions/flannel_steps.rb +9 -0
- data/flannel.gemspec +17 -6
- data/lib/feed_parser.rb +42 -0
- data/lib/shears.rb +4 -2
- data/lib/square.rb +1 -1
- data/lib/stripe.rb +13 -3
- data/test/feed_parser_test.rb +74 -0
- data/test/shears_test.rb +7 -0
- metadata +22 -4
data/Rakefile
CHANGED
@@ -11,7 +11,8 @@ begin
|
|
11
11
|
gem.homepage = "http://github.com/rubyyot/flannel"
|
12
12
|
gem.authors = ["Jamal Hansen"]
|
13
13
|
gem.rubyforge_project = "flannel"
|
14
|
-
gem.
|
14
|
+
gem.add_dependency 'Hpricot'
|
15
|
+
gem.add_development_dependency ['technicalpickles-shoulda', 'mocha']
|
15
16
|
|
16
17
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
17
18
|
end
|
data/VERSION.yml
CHANGED
@@ -0,0 +1,10 @@
|
|
1
|
+
Feature: Feed conversion
|
2
|
+
In order to insert "live" links from rss feeds
|
3
|
+
A user of Flannel
|
4
|
+
Will quilt feed text markup
|
5
|
+
|
6
|
+
Scenario: Inserting links from an rss feed
|
7
|
+
Given input of "feed" text
|
8
|
+
And the necessary feeds
|
9
|
+
When I quilt it with flannel
|
10
|
+
Then valid html should be produced
|
@@ -0,0 +1,959 @@
|
|
1
|
+
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Sergio Pereira : JavaScript-Demystified</title><link>http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript-Demystified/default.aspx</link><description>Tags: JavaScript-Demystified</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP1 (Build: 31106.3070)</generator><item><title>JavaScript and its love for zeroes</title><link>http://devlicio.us/blogs/sergio_pereira/archive/2009/09/19/javascript-and-its-love-for-zeroes.aspx</link><pubDate>Sat, 19 Sep 2009 13:54:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:51520</guid><dc:creator>sergiopereira</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/sergio_pereira/rsscomments.aspx?PostID=51520</wfw:commentRss><comments>http://devlicio.us/blogs/sergio_pereira/archive/2009/09/19/javascript-and-its-love-for-zeroes.aspx#comments</comments><description><div class="note">
|
2
|
+
This post is part of a series called <a href="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript-Demystified/default.aspx">
|
3
|
+
JavaScript Demystified</a>.
|
4
|
+
</div>
|
5
|
+
|
6
|
+
<p>Answer quick. Do you know what date is being created here?</p>
|
7
|
+
<pre name="code" class="js:nogutter">var year = &#39;2009&#39;, month = &#39;09&#39;, day = &#39;01&#39;;
|
8
|
+
var date = new Date(
|
9
|
+
parseInt(year),
|
10
|
+
parseInt(month),
|
11
|
+
parseInt(day)
|
12
|
+
); </pre>
|
13
|
+
|
14
|
+
<p>
|
15
|
+
At first glance, it wouldn&#39;t surprising that someone guesseed <i>September 1<sup>st</sup> 2009</i>.
|
16
|
+
However, I&#39;d not be writing this post if that was the correct answer, right?
|
17
|
+
</p>
|
18
|
+
<p>
|
19
|
+
There&#39;s an interesting and tricky thing with the JavaScript <code>parseInt</code> function: it
|
20
|
+
can parse strings with a numeric value in the decimal radix, but also in other radices. See the
|
21
|
+
following examples.
|
22
|
+
</p>
|
23
|
+
|
24
|
+
<pre name="code" class="js:nogutter">//passing the radix explicitly
|
25
|
+
parseInt(&#39;1011&#39;, 10); // ==&gt; 1011
|
26
|
+
parseInt(&#39;1011&#39;, 2); // ==&gt; 11
|
27
|
+
parseInt(&#39;1011&#39;, 8); // ==&gt; 521
|
28
|
+
parseInt(&#39;1011&#39;, 16); // ==&gt; 4113
|
29
|
+
</pre>
|
30
|
+
|
31
|
+
<p>Maybe you thought that if you didn&#39;t pass the radix, then it would default to 10 because
|
32
|
+
it&#39;s the obvious behavior. Well, no. In JavaScript the default behavior is to try to
|
33
|
+
identify one of the literal formats and interpret that. So here&#39;s that in action:</p>
|
34
|
+
|
35
|
+
<pre name="code" class="js:nogutter">//leaving JavaScript on its own
|
36
|
+
parseInt(&#39;1011&#39;); // ==&gt; 1011 (decimal literal)
|
37
|
+
parseInt(&#39;0x12&#39;); // ==&gt; 18 (hexadecimal literal)
|
38
|
+
parseInt(&#39;0511&#39;); // ==&gt; 329 (octal literal)
|
39
|
+
parseInt(&#39;0182&#39;); // ==&gt; 1 (whaaaa?!?!)
|
40
|
+
</pre>
|
41
|
+
|
42
|
+
<img src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/sergio_5F00_pereira.2009.09/js_2D00_newyear.png" align="left" alt="" />
|
43
|
+
|
44
|
+
<p>
|
45
|
+
If you are familiar with the literal notation for integer numbers in JavaScript,
|
46
|
+
and after I explained the default behavior of <code>parseInt</code>, then
|
47
|
+
you probaly understood the results shown above. Well, maybe the last one deserves
|
48
|
+
some comments.
|
49
|
+
</p>
|
50
|
+
<p>
|
51
|
+
When JavaScript is parsing the string, if it finds a digit (number or alpha) that is invalid
|
52
|
+
in the chosen radix, it stops right there and parses only the portion of the string that
|
53
|
+
comes before that digit. So, since we started <code>&#39;0182&#39;</code> with a leading zero, the
|
54
|
+
octal radix is assumed. Then, because <b>8</b> is not a valid octal digit, only <code>&#39;01&#39;</code>
|
55
|
+
will be parsed, which becomes <b>1</b>.
|
56
|
+
</p>
|
57
|
+
|
58
|
+
<div class="note"><span class="legend">Tip #1:</span>
|
59
|
+
If there&#39;s any chance the string value you plan to parse into an integer number has
|
60
|
+
a leading zero (or a less likely <b>0x</b>,) then be safe and pass the radix parameter
|
61
|
+
to your <code>parseInt</code> call. If you&#39;re extra paranoid, then always pass the radix.
|
62
|
+
</div>
|
63
|
+
|
64
|
+
|
65
|
+
<h3>Back to our original question</h3>
|
66
|
+
|
67
|
+
<p>Armed with the clarification made above, we can expand our example like this:</p>
|
68
|
+
<pre name="code" class="js:nogutter">//given:
|
69
|
+
var year = &#39;2009&#39;, month = &#39;09&#39;, day = &#39;01&#39;;
|
70
|
+
// then the following statement:
|
71
|
+
var date = new Date(
|
72
|
+
parseInt(year),
|
73
|
+
parseInt(month),
|
74
|
+
parseInt(day)
|
75
|
+
);
|
76
|
+
//...is equivalent to:
|
77
|
+
var date = new Date(
|
78
|
+
2009,
|
79
|
+
0, // ===&gt; oopsie
|
80
|
+
1
|
81
|
+
); </pre>
|
82
|
+
|
83
|
+
<p>Hmmm, a zero in the month parameter. Will we have an error here? No, here comes the second potential surprise of this post.</p>
|
84
|
+
|
85
|
+
<div class="note"><span class="legend">Tip #2:</span>
|
86
|
+
When creating a new date using <code>new Date(year, month, day)</code>, the <code>month</code>
|
87
|
+
parameter, and <b>only</b> the month parameter is zero-based (0 to 11).
|
88
|
+
</div>
|
89
|
+
|
90
|
+
<p>So, in case the tips and the picture in this text were not enough to help you guessing the
|
91
|
+
date being created, here goes another completely gratuitous one with the answer.
|
92
|
+
|
93
|
+
<p><img src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/sergio_5F00_pereira.2009.09/js_2D00_newyear2.png" alt="" /></p>
|
94
|
+
<div style="clear:both;"></div><img src="http://devlicio.us/aggbug.aspx?PostID=51520" width="1" height="1"></description><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/Development/default.aspx">Development</category><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/Tips-and-Tricks/default.aspx">Tips-and-Tricks</category><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript/default.aspx">JavaScript</category><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript-Demystified/default.aspx">JavaScript-Demystified</category></item><item><title>JavaScript: Not your father's inheritance model - Part 2</title><link>http://devlicio.us/blogs/sergio_pereira/archive/2009/06/12/javascript-not-your-father-s-inheritance-model-part-2.aspx</link><pubDate>Fri, 12 Jun 2009 23:26:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:47885</guid><dc:creator>sergiopereira</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/sergio_pereira/rsscomments.aspx?PostID=47885</wfw:commentRss><comments>http://devlicio.us/blogs/sergio_pereira/archive/2009/06/12/javascript-not-your-father-s-inheritance-model-part-2.aspx#comments</comments><description><div class="note">
|
95
|
+
This post is part of a series called <a href="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript-Demystified/default.aspx">
|
96
|
+
JavaScript Demystified</a>.
|
97
|
+
</div>
|
98
|
+
|
99
|
+
<p><i>This particular chapter is further divided in two parts. Read <a href="http://devlicio.us/blogs/sergio_pereira/archive/2009/06/12/javascript-not-your-father-s-inheritance-model-part-1.aspx">Part 1</a>.</i></p>
|
100
|
+
|
101
|
+
|
102
|
+
|
103
|
+
|
104
|
+
<h3>Build your own hierarchy</h3>
|
105
|
+
|
106
|
+
<p>Let&#39;s pretend we are building some scripts that deal with musical instruments. We could define our own <code>Guitar</code> <strike>class</strike> type like this:
|
107
|
+
</p>
|
108
|
+
|
109
|
+
<pre name="code" class="js:nogutter">//The constructor
|
110
|
+
function Guitar(brand, model) {
|
111
|
+
this.brand = brand;
|
112
|
+
this.model = model;
|
113
|
+
this.strings = [&#39;E&#39;, &#39;A&#39;, &#39;D&#39;, &#39;G&#39;, &#39;B&#39;, &#39;e&#39;];
|
114
|
+
}
|
115
|
+
|
116
|
+
//Instance methods
|
117
|
+
Guitar.prototype = {
|
118
|
+
play: function (chord) {
|
119
|
+
alert(&#39;Playing &#39; + chord);
|
120
|
+
},
|
121
|
+
toString: function () {
|
122
|
+
return &#39;(Guitar: &#39; +
|
123
|
+
this.brand + &#39; &#39; +
|
124
|
+
this.model + &#39;)&#39;;
|
125
|
+
}
|
126
|
+
};
|
127
|
+
|
128
|
+
var guitar1 = new Guitar(&#39;Gibson&#39;, &#39;Les Paul&#39;);</pre>
|
129
|
+
|
130
|
+
<p>What may not be apparent by just looking at the code for the first time is that <code>guitar1</code>&#39;s Prototype will be <code>Guitar.prototype</code>, which means that <code>guitar1</code> inherits from <code>Guitar.prototype</code>. Also <code>guitar1.constructor === Guitar</code>.
|
131
|
+
</p>
|
132
|
+
|
133
|
+
<p>When the last line in the above example is executed, the JavaScript runtime will take care of initializing a new object that has <code>Guitar.prototype</code> as its Prototype and makes its <code>constructor</code> property point to the <code>Guitar</code> function.
|
134
|
+
</p>
|
135
|
+
|
136
|
+
<p>But what if we want to create a different type of guitars and still reuse the existing <code>Guitar</code> type. We could do this:
|
137
|
+
</p>
|
138
|
+
|
139
|
+
<pre name="code" class="js:nogutter">function BassGuitar(brand, model) {
|
140
|
+
//call the constructor of our base type
|
141
|
+
Guitar.apply(this, [brand, model] );
|
142
|
+
//change or add anything we wish
|
143
|
+
this.strings = [&#39;E&#39;, &#39;A&#39;, &#39;D&#39;, &#39;G&#39;];
|
144
|
+
}
|
145
|
+
|
146
|
+
//Copy the Prototype of our base type
|
147
|
+
BassGuitar.prototype = Object.create(Guitar.prototype);
|
148
|
+
|
149
|
+
//Override whatever we want:
|
150
|
+
BassGuitar.prototype.toString = function () {
|
151
|
+
return &#39;(BassGuitar: &#39; +
|
152
|
+
this.brand + &#39; &#39; +
|
153
|
+
this.model + &#39;)&#39;;
|
154
|
+
};
|
155
|
+
|
156
|
+
var bass1 = new BassGuitar(&#39;Peavey&#39;, &#39;Cirrus&#39;);
|
157
|
+
bass1.toString(); //=&gt; &#39;(BassGuitar: Peavey Cirrus)&#39;
|
158
|
+
alert(bass1.strings); //=&gt; [ &#39;E&#39;, &#39;A&#39;, &#39;D&#39;, &#39;G&#39; ]</pre>
|
159
|
+
|
160
|
+
<p style="text-align:center;"><img src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/sergio_5F00_pereira.2009.06/js_5F00_inh_5F00_5.png" alt="" /></p>
|
161
|
+
|
162
|
+
|
163
|
+
<p><b>But there&#39;s a problem with the above code.</b> There isn&#39;t a method <code>Object.create()</code>. Yeah, that&#39;s one of the design omissions in JavaScript. Any prototype-based language needs an easy way to let use create objects from other objects.
|
164
|
+
</p>
|
165
|
+
|
166
|
+
<p>Thankfully JavaScript is also dynamically typed, so we can add that function ourselves. Here I&#39;m borrowing from <a href="http://javascript.crockford.com/prototypal.html">Douglas Crockford</a>.
|
167
|
+
</p>
|
168
|
+
|
169
|
+
<pre name="code" class="js:nogutter">//add this to the very beginning of your scripts
|
170
|
+
if (typeof Object.create !== &#39;function&#39;) {
|
171
|
+
Object.create = function (o) {
|
172
|
+
function F() {}
|
173
|
+
F.prototype = o;
|
174
|
+
return new F();
|
175
|
+
};
|
176
|
+
}</pre>
|
177
|
+
|
178
|
+
<p>I&#39;ll leave the interpretation of the above function as an exercise to the reader. Once you understand what it is doing you will have mastered prototypes and constructors.
|
179
|
+
</p>
|
180
|
+
|
181
|
+
<h3>Handy Prototype tricks</h3>
|
182
|
+
|
183
|
+
<p>Knowing what we know now and once again leveraging JavaScript&#39;s dynamism we can fix one of the things that has always annoyed me in JavaScript: the lack of a <code>trim()</code> method on strings.
|
184
|
+
</p>
|
185
|
+
|
186
|
+
<pre name="code" class="js:nogutter">String.prototype.trim = function () {
|
187
|
+
return this.replace( /^\s*(\S*(\s+\S+)*)\s*$/, &quot;$1&quot;);
|
188
|
+
};
|
189
|
+
var text = &#39; some user-entered value &#39;;
|
190
|
+
alert( text.trim() ); // =&gt; &#39;some user-entered value&#39;</pre>
|
191
|
+
|
192
|
+
<p>How about an easy way to pad numbers with zeroes?
|
193
|
+
</p>
|
194
|
+
|
195
|
+
<pre name="code" class="js:nogutter">Number.prototype.padLeft = function (width) {
|
196
|
+
var text = this.toString();
|
197
|
+
for(; text.length &lt; width; ){
|
198
|
+
text = &#39;0&#39; + text;
|
199
|
+
}
|
200
|
+
return text;
|
201
|
+
};
|
202
|
+
|
203
|
+
var num = 1234;
|
204
|
+
alert(num.padLeft(6)); // =&gt; 001234</pre>
|
205
|
+
|
206
|
+
|
207
|
+
<h3>Why do I need to know all this stuff?</h3>
|
208
|
+
|
209
|
+
<p>Well, you don&#39;t. But why even bother writing JavaScript code if you&#39;re not willing to learn how it works? </p>
|
210
|
+
|
211
|
+
<p>As we have been seeing during this series, JavaScript bears only some syntax similarities with C# or Java. Underneath the surface it has been designed very differently. The web is riddled with attempts to mimic class-based inheritance in JavaScript only because programmers don&#39;t want to learn and leverage prototype-based logic.</p>
|
212
|
+
|
213
|
+
<p>My humble advice is that you will feel happier and smarter if you chose to learn how to use the language as it was intended.</p>
|
214
|
+
|
215
|
+
<div style="clear:both;"></div><img src="http://devlicio.us/aggbug.aspx?PostID=47885" width="1" height="1"></description><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/Series/default.aspx">Series</category><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript/default.aspx">JavaScript</category><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript-Demystified/default.aspx">JavaScript-Demystified</category></item><item><title>JavaScript: Not your father's inheritance model - Part 1</title><link>http://devlicio.us/blogs/sergio_pereira/archive/2009/06/12/javascript-not-your-father-s-inheritance-model-part-1.aspx</link><pubDate>Fri, 12 Jun 2009 23:03:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:47882</guid><dc:creator>sergiopereira</dc:creator><slash:comments>9</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/sergio_pereira/rsscomments.aspx?PostID=47882</wfw:commentRss><comments>http://devlicio.us/blogs/sergio_pereira/archive/2009/06/12/javascript-not-your-father-s-inheritance-model-part-1.aspx#comments</comments><description><div class="note">
|
216
|
+
This post is part of a series called <a href="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript-Demystified/default.aspx">
|
217
|
+
JavaScript Demystified</a>.
|
218
|
+
</div>
|
219
|
+
|
220
|
+
<p><i>This particular chapter is further divided in two parts. Read <a href="http://devlicio.us/blogs/sergio_pereira/archive/2009/06/12/javascript-not-your-father-s-inheritance-model-part-2.aspx">Part 2</a>.</i></p>
|
221
|
+
|
222
|
+
|
223
|
+
|
224
|
+
<p>In a previous installment in this series we saw how we could create constructor functions in JavaScript. Back then I just mentioned that we don&#39;t have classes in JavaScript and that there&#39;s this weird <code>prototype</code> property in every object.
|
225
|
+
</p>
|
226
|
+
|
227
|
+
<p>Let&#39;s dig into those concepts a little more and try to understand how inheritance is achieved in JavaScript.
|
228
|
+
</p>
|
229
|
+
|
230
|
+
<h3>Inheritance as we often know it</h3>
|
231
|
+
|
232
|
+
<p>For myself and probably the majority of you reading this blog, inheritance in an Object Oriented programming language is directly associated with the concept of classes.
|
233
|
+
</p>
|
234
|
+
|
235
|
+
<p>When we work with C#, VB, Java, Ruby, and many other popular programming languages, each of our objects is of some type, which is represented by a class. Our objects automatically inherit functionality from their associated class often called base or super class, and any other classes that the base class itself is associated with (i.e. derives from.)
|
236
|
+
</p>
|
237
|
+
<p>That&#39;s nothing new to you, I&#39;m sure. I&#39;m just re-hashing that in the previous paragraph to make a comparison later. Let&#39;s call this model class-based inheritance.
|
238
|
+
</p>
|
239
|
+
|
240
|
+
|
241
|
+
<h3>That&#39;s not the end of the story</h3>
|
242
|
+
|
243
|
+
<p>This may come as a surprise to some people, but class-based inheritance is not the only way to obtain Object Oriented inheritance (by saying Object Oriented I automatically excluded those of you that thought Copy/Paste Inheritance was one of them.)
|
244
|
+
</p>
|
245
|
+
|
246
|
+
<p>It just so happens that the JavaScript language designers chose another inheritance model. And they are not alone in that choice. By opting for a <a href="http://en.wikipedia.org/wiki/Prototype-based_programming">prototype-based inheritance model</a> , JavaScript joined the ranks of other programming languages such as <a href="http://selflanguage.org/">Self</a> , <a href="http://www.lua.org/">Lua</a> , and <a href="http://prog.vub.ac.be/research/agora/">Agora</a>.
|
247
|
+
</p>
|
248
|
+
|
249
|
+
|
250
|
+
<h3>The prototype is the king</h3>
|
251
|
+
|
252
|
+
<p>Objects in JavaScript don&#39;t inherit from classes; they inherit straight from other objects. The object they inherit from is called their Prototype (I&#39;m using a capital P here to avoid confusion down the line.) The object&#39;s Prototype is assigned right at construction time.
|
253
|
+
</p>
|
254
|
+
|
255
|
+
<p>You may be intrigued and say: But when I create my objects I don&#39;t remember specifying any Prototype stuff. What gives?
|
256
|
+
</p>
|
257
|
+
|
258
|
+
<p>Let&#39;s see what happens then. When you create a plain Object using either of the following syntaxes
|
259
|
+
</p>
|
260
|
+
|
261
|
+
<pre name="code" class="js:nogutter">var obj1 = new Object();
|
262
|
+
obj1.name = &#39;box&#39;
|
263
|
+
//or
|
264
|
+
var obj2 = { name: &#39;door&#39; };
|
265
|
+
</pre>
|
266
|
+
|
267
|
+
<p>JavaScript will automatically assign a Prototype to each of these objects. This prototype will be <code>Object.prototype</code>.
|
268
|
+
</p>
|
269
|
+
|
270
|
+
<p style="text-align:center;"><img src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/sergio_5F00_pereira.2009.06/js_5F00_inh_5F00_1.png" alt="" /></p>
|
271
|
+
|
272
|
+
<p>Similarly, let&#39;s see what happens with a few of the other object types in JavaScript.
|
273
|
+
</p>
|
274
|
+
|
275
|
+
<p style="text-align:center;"><img src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/sergio_5F00_pereira.2009.06/js_5F00_inh_5F00_2.png" alt="" /></p>
|
276
|
+
|
277
|
+
<p>The Prototype objects is how every object in JavaScript is born with inherited functionality. For example, the <code>substring()</code> method that every <code>String</code> object has is a method defined in the object <code>String.Prototype</code>.
|
278
|
+
</p>
|
279
|
+
|
280
|
+
<p style="text-align:center;"><img src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/sergio_5F00_pereira.2009.06/js_5F00_inh_5F00_3.png" alt="" /></p>
|
281
|
+
|
282
|
+
<p>The prototype objects themselves also inherit from <code>Object.prototype</code>, that&#39;s how every object of any type has a <code>toString()</code> method.
|
283
|
+
</p>
|
284
|
+
|
285
|
+
<p style="text-align:center;"><img src="http://devlicio.us/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/sergio_5F00_pereira.2009.06/js_5F00_inh_5F00_4.png" alt="" /></p>
|
286
|
+
|
287
|
+
<p>When you try to access <code>1234.constructor</code>, as an example, the runtime will look for a <code>constructor</code> property on our object (the number 1234). It doesn&#39;t have one so the next step taken is to check if that object&#39;s Prototype has it. The Prototype for 1234 is <code>Number.prototype</code> and it doesn&#39;t have that property either. The runtime then looks on the Prototype of <code>Number.prototype</code>, which is <code>Object.prototype</code>. That last object does have a <code>constructor</code> property, so that is returned. If it didn&#39;t, <code>undefined</code> would have been returned instead.
|
288
|
+
</p>
|
289
|
+
|
290
|
+
<p>In <a href="http://devlicio.us/blogs/sergio_pereira/archive/2009/06/12/javascript-not-your-father-s-inheritance-model-part-2.aspx">Part 2</a> we will see how to create our own Prototypes.
|
291
|
+
</p><div style="clear:both;"></div><img src="http://devlicio.us/aggbug.aspx?PostID=47882" width="1" height="1"></description><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/Series/default.aspx">Series</category><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript/default.aspx">JavaScript</category><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript-Demystified/default.aspx">JavaScript-Demystified</category></item><item><title>JavaScript: Avoid the Evil eval</title><link>http://devlicio.us/blogs/sergio_pereira/archive/2009/03/31/javascript-avoid-the-evil-eval.aspx</link><pubDate>Tue, 31 Mar 2009 22:23:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:45311</guid><dc:creator>sergiopereira</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/sergio_pereira/rsscomments.aspx?PostID=45311</wfw:commentRss><comments>http://devlicio.us/blogs/sergio_pereira/archive/2009/03/31/javascript-avoid-the-evil-eval.aspx#comments</comments><description><div class="note">
|
292
|
+
This post is part of a series called <a href="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript-Demystified/default.aspx">JavaScript Demystified</a>.
|
293
|
+
</div>
|
294
|
+
<p>
|
295
|
+
I&#39;m pretty sure by now you have heard at least once that <a href="http://blogs.msdn.com/ericlippert/archive/2003/11/01/53329.aspx"><code>eval</code> is evil</a>. Some
|
296
|
+
nuggets from Eric Lippert&#39;s post:
|
297
|
+
</p>
|
298
|
+
|
299
|
+
<blockquote>if you are considering using eval then there is probably a better way</blockquote>
|
300
|
+
<blockquote>People, eval starts a compiler.</blockquote>
|
301
|
+
|
302
|
+
<p>
|
303
|
+
I&#39;m also pretty sure I don&#39;t need to tell you that anytime you have an explicit <code>eval()</code> in your
|
304
|
+
code, there&#39;s a good chance it&#39;s there because
|
305
|
+
<a href="http://devlicio.us/blogs/sergio_pereira/archive/2008/05/03/give-javascript-a-chance.aspx">you&#39;re not taking JavaScript seriously</a> yet.
|
306
|
+
</p>
|
307
|
+
<pre name="code" class="js">//mandatory square brackets notation example
|
308
|
+
//------------------------------------------
|
309
|
+
var myObject = new MyObject();
|
310
|
+
var prop1 = eval( &#39;myObject.&#39; + somePropertyName ); // BAD!
|
311
|
+
var prop2 = myObject[ somePropertyName ]; // Better</pre>
|
312
|
+
|
313
|
+
<h3>That&#39;s not the end of all <code>eval()</code></h3>
|
314
|
+
<p>
|
315
|
+
At this point some people might be feeling relieved: <i>&quot;Phew! That was
|
316
|
+
easier than it sounded. Getting rid of eval is a piece of cake.&quot;</i> Well,
|
317
|
+
I&#39;m not going to say it&#39;s significantly harder than that, but we&#39;re not
|
318
|
+
done prunning <code>eval()</code> from our code just yet.
|
319
|
+
</p>
|
320
|
+
<p>
|
321
|
+
You see, <code>eval()</code> is like that coward opponent that sneaks in the
|
322
|
+
dark to attack you from behind. Let&#39;s find some of <code>eval</code>&#39;s
|
323
|
+
favorite hiding places.
|
324
|
+
</p>
|
325
|
+
|
326
|
+
<h3>There&#39;s a time when you need a timer</h3>
|
327
|
+
<p>
|
328
|
+
Two very popular JavaScript functions used to create timers are <code>setTimeout()</code> and
|
329
|
+
<code>setInterval()</code>. Here&#39;s how you still find code being written to use them.
|
330
|
+
</p>
|
331
|
+
<pre name="code" class="js">function doSomething(someValue){
|
332
|
+
//...
|
333
|
+
}
|
334
|
+
|
335
|
+
setTimeout(&quot;doSomething(&#39;3 seconds elapsed. Time is up.&#39;);&quot;, 3000);</pre>
|
336
|
+
|
337
|
+
|
338
|
+
<p>
|
339
|
+
As it turns out, this is just another occurrence of <code>eval()</code> revealing
|
340
|
+
how incompetent we can still be in this programming language. Here&#39;s
|
341
|
+
a better way to write that code.
|
342
|
+
</p>
|
343
|
+
<pre name="code" class="js">setTimeout( function(){
|
344
|
+
doSomething(&#39;3 seconds elapsed. Time is up.&#39;);
|
345
|
+
},
|
346
|
+
3000);</pre>
|
347
|
+
|
348
|
+
<h3>Thank God I didn&#39;t know functions had constructors</h3>
|
349
|
+
<p>
|
350
|
+
The other secret place that <code>eval()</code> likes to hang out is
|
351
|
+
in the <code>Function</code> constructor. Fortunately this isn&#39;t exactly a
|
352
|
+
popular way of creating functions. I&#39;ll say it: I didn&#39;t even know about
|
353
|
+
this constructor until less than a couple of years ago.
|
354
|
+
</p>
|
355
|
+
<p>
|
356
|
+
So, in case you don&#39;t know what I&#39;m talking about here, I&#39;ll show you
|
357
|
+
how to use the function constructor just to imemdiately tell you to not do it.
|
358
|
+
</p>
|
359
|
+
|
360
|
+
<pre name="code" class="js">var sum = new Function(&#39;op1&#39;, &#39;op2&#39;, &#39;return op1 + op2;&#39;);
|
361
|
+
var result = sum(10, 20); // ==&gt; 30</pre>
|
362
|
+
|
363
|
+
<p>
|
364
|
+
The above code is roughly equivalent to the explicit <code>eval()</code> usage below.
|
365
|
+
</p>
|
366
|
+
<pre name="code" class="js">eval(&quot;var sum = function (op1, op2) { return op1 + op2; }&quot;);
|
367
|
+
var result = sum(10, 20); // ==&gt; 30</pre>
|
368
|
+
<p>
|
369
|
+
We don&#39;t come up with the need to use the function constructor often, but I&#39;ll
|
370
|
+
admit that when we do, it&#39;s usually hard to replace it with another way that
|
371
|
+
doesn&#39;t use <code>eval()</code>.
|
372
|
+
</p>
|
373
|
+
|
374
|
+
<div class="note"><span class="legend">Minor update:</span>
|
375
|
+
I was doing some snooping around with Firebug and Reflector and found that WebUIValidation.js (embedded in System.Web.dll)
|
376
|
+
does use <code>eval()</code> in some ways that I just pointed out to be unnecessary. If that is of any comfort to anyone
|
377
|
+
that has done the same in the past, there you have probably the largest deployment of misused <code>eval()</code> I know of.
|
378
|
+
</div><div style="clear:both;"></div><img src="http://devlicio.us/aggbug.aspx?PostID=45311" width="1" height="1"></description><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/Series/default.aspx">Series</category><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript/default.aspx">JavaScript</category><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript-Demystified/default.aspx">JavaScript-Demystified</category></item><item><title>JavaScript, inner functions and private members</title><link>http://devlicio.us/blogs/sergio_pereira/archive/2009/02/24/javascript-inner-functions-and-private-members.aspx</link><pubDate>Tue, 24 Feb 2009 14:31:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:44569</guid><dc:creator>sergiopereira</dc:creator><slash:comments>15</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/sergio_pereira/rsscomments.aspx?PostID=44569</wfw:commentRss><comments>http://devlicio.us/blogs/sergio_pereira/archive/2009/02/24/javascript-inner-functions-and-private-members.aspx#comments</comments><description><div class="note">
|
379
|
+
This post is part of a series called <a href="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript-Demystified/default.aspx">JavaScript Demystified</a>.
|
380
|
+
</div>
|
381
|
+
|
382
|
+
<p>
|
383
|
+
In <a href="http://devlicio.us/blogs/sergio_pereira/archive/2009/02/23/javascript-time-to-grok-closures.aspx">our last installment</a> in this short JavaScript series we
|
384
|
+
took a look at closures. In some of the examples, we saw functions being
|
385
|
+
declared (and returned) inside other functions. The capability of declaring
|
386
|
+
a function inside another one is not common to all languages &mdash; C#
|
387
|
+
only added this ability in version 2.0, via anonymous delegates.
|
388
|
+
</p>
|
389
|
+
|
390
|
+
<p>
|
391
|
+
Here&#39;s an example of inner functions in use.
|
392
|
+
</p>
|
393
|
+
|
394
|
+
<pre name="code" class="js">function printPriceLong(name, price, quantity, currency) {
|
395
|
+
var formatCurrency = function(value) {
|
396
|
+
return value + &#39; &#39; + currency;
|
397
|
+
};
|
398
|
+
return &#39;Item: &#39; + name + &#39;\n&#39; +
|
399
|
+
&#39;Unit price: &#39; + formatCurrency(price) + &#39;\n&#39; +
|
400
|
+
&#39;Quantity: &#39; + quantity + &#39;\n&#39; +
|
401
|
+
&#39;TOTAL: &#39; + formatCurrency(price * quantity);
|
402
|
+
}
|
403
|
+
|
404
|
+
alert( printPriceLong(&#39;100g Toblerone bar&#39;, 2.09, 3, &#39;USD&#39;) );
|
405
|
+
/* =&gt;
|
406
|
+
Item: 100g Toblerone bar
|
407
|
+
Unit price: 2.09 USD
|
408
|
+
Quantity: 3
|
409
|
+
TOTAL: 6.27 USD
|
410
|
+
*/</pre>
|
411
|
+
|
412
|
+
<p>
|
413
|
+
If we try to call <code>formatCurrency</code> from anywhere outside
|
414
|
+
of <code>printPriceLong</code> we are going to cause an error because
|
415
|
+
<code>formatCurrency</code> is scoped only inside its parent function.
|
416
|
+
</p>
|
417
|
+
<p>
|
418
|
+
In this example we can also see closures in action once again. The
|
419
|
+
<code>currency</code> value is referenced inside <code>formatCurrency</code>
|
420
|
+
but it&#39;s declared in it&#39;s parent. It&#39;s a short-lived closure, mind you,
|
421
|
+
because we are not returning that inner function. It&#39;s discarded as soon
|
422
|
+
as the parent function exits.
|
423
|
+
</p>
|
424
|
+
|
425
|
+
|
426
|
+
<h3>Who said JavaScript objects can&#39;t have private members?</h3>
|
427
|
+
|
428
|
+
<p>
|
429
|
+
Developers sometimes get upset when they realize that anyone has
|
430
|
+
read and write access to the fields and methods of their JavaScript objects.
|
431
|
+
Most of us are used to work with languages that allow us to declare
|
432
|
+
some of our object&#39;s members out of reach for the calling code. We
|
433
|
+
say that these members are private and we don&#39;t want anyone changing
|
434
|
+
or even seeing them.
|
435
|
+
</p>
|
436
|
+
|
437
|
+
<p>
|
438
|
+
Well, this is not exactly true. If you must have private members in
|
439
|
+
your JavaScript objects, you can. Inner functions and closures will
|
440
|
+
come to our rescue.
|
441
|
+
</p>
|
442
|
+
|
443
|
+
<p>
|
444
|
+
Let&#39;s build on our previous example. Let&#39;s create an <code>OrderItem</code>
|
445
|
+
object that will hold those values (name, price, etc.) Let&#39;s assume we
|
446
|
+
do not want anyone changing the object&#39;s price without changing the
|
447
|
+
currency at the same time (to ensure some level of consistency.) We
|
448
|
+
could code our object like this:
|
449
|
+
</p>
|
450
|
+
|
451
|
+
<pre name="code" class="js">function OrderItem(productName, price, quantity, currency) {
|
452
|
+
//regular properties
|
453
|
+
this.name = productName;
|
454
|
+
this.quantity = quantity;
|
455
|
+
|
456
|
+
//read accessors
|
457
|
+
this.getCurrency = function(){ return currency; };
|
458
|
+
this.getPrice = function(){ return price; };
|
459
|
+
//write accessor
|
460
|
+
this.setPrice = function(newPrice, newCurrency){
|
461
|
+
if(typeof price !== &#39;number&#39; || price &lt; 0){
|
462
|
+
throw { message:&#39;invalid price&#39; };
|
463
|
+
}
|
464
|
+
if(typeof newCurrency !== &#39;string&#39;){
|
465
|
+
throw { message:&#39;invalid currency&#39; };
|
466
|
+
}
|
467
|
+
price = newPrice;
|
468
|
+
currency = newCurrency;
|
469
|
+
};
|
470
|
+
|
471
|
+
//a private function
|
472
|
+
var formatCurrency = function(value) {
|
473
|
+
return value + &#39; &#39; + currency;
|
474
|
+
};
|
475
|
+
|
476
|
+
//methods that need private members
|
477
|
+
this.getUnitPriceString = function(){
|
478
|
+
return formatCurrency(price);
|
479
|
+
};
|
480
|
+
this.getTotalPriceString = function(){
|
481
|
+
return formatCurrency(price * quantity);
|
482
|
+
};
|
483
|
+
}
|
484
|
+
|
485
|
+
OrderItem.prototype = {
|
486
|
+
//overriding the string representation of the object
|
487
|
+
toString: function(){
|
488
|
+
return &#39;Item: &#39; + this.name + &#39;\n&#39; +
|
489
|
+
&#39;Unit price: &#39; + this.getUnitPriceString() + &#39;\n&#39; +
|
490
|
+
&#39;Quantity: &#39; + this.quantity + &#39;\n&#39; +
|
491
|
+
&#39;TOTAL: &#39; + this.getTotalPriceString();
|
492
|
+
}
|
493
|
+
};</pre>
|
494
|
+
|
495
|
+
<p>
|
496
|
+
That seems a bit long, but hopefully we can understand what&#39;s going on here.
|
497
|
+
We are letting <code>name</code> and <code>quantity</code> be regular
|
498
|
+
read/write properties but we never defined properties for <code>price</code>
|
499
|
+
or <code>currency</code>. We made those two values accessible via the
|
500
|
+
<code>getPrice</code> and <code>getCurrency</code> methods, respectively.
|
501
|
+
</p>
|
502
|
+
|
503
|
+
<p>
|
504
|
+
The trick here is that both <code>getPrice</code>
|
505
|
+
and <code>getCurrency</code> are defined inside our constructor
|
506
|
+
function so they have access to the local variables <code>price</code>
|
507
|
+
and <code>currency</code>. They have access to these variables even
|
508
|
+
after the constructor returns (thank you closures.)
|
509
|
+
</p>
|
510
|
+
|
511
|
+
<p>
|
512
|
+
The same can be said for the <code>setPrice</code> method. We
|
513
|
+
will use this method when we need to change the object&#39;s price.
|
514
|
+
It will force us to also provide a currency.
|
515
|
+
</p>
|
516
|
+
|
517
|
+
<p>
|
518
|
+
I&#39;ll leave the explanation of the methods <code>getUnitPriceString</code>
|
519
|
+
and <code>getTotalPriceString</code> as an exercise for you.
|
520
|
+
</p>
|
521
|
+
|
522
|
+
<p>
|
523
|
+
Let&#39;s instantiate one of these objects and see it in action.
|
524
|
+
</p>
|
525
|
+
|
526
|
+
<pre name="code" class="js:nogutter">var item = new OrderItem(&#39;100g Toblerone bar&#39;, 2.09, 3, &#39;USD&#39;);
|
527
|
+
//public methods:
|
528
|
+
alert( item.getUnitPriceString() );
|
529
|
+
// =&gt; &#39;2.09 USD&#39;
|
530
|
+
alert( item.getTotalPriceString() );
|
531
|
+
// =&gt; &#39;6.27 USD&#39;
|
532
|
+
alert(item); //this will use the toString() method
|
533
|
+
/* =&gt;
|
534
|
+
Item: 100g Toblerone bar
|
535
|
+
Unit price: 2.09 USD
|
536
|
+
Quantity: 3
|
537
|
+
TOTAL: 6.27 USD
|
538
|
+
*/
|
539
|
+
|
540
|
+
//changing private fields
|
541
|
+
item.setPrice(1.11, &#39;EUR&#39;);
|
542
|
+
alert( item );
|
543
|
+
/* =&gt;
|
544
|
+
Item: 100g Toblerone bar
|
545
|
+
Unit price: 1.11 EUR &lt;-- it worked!
|
546
|
+
Quantity: 3
|
547
|
+
TOTAL: 3.33 EUR
|
548
|
+
*/
|
549
|
+
|
550
|
+
//proving that price is not a field
|
551
|
+
item.price = &#39;5.00&#39;;
|
552
|
+
alert( item.getUnitPriceString() );
|
553
|
+
// =&gt; &#39;1.11 EUR&#39; &lt;-- Gotcha, smart pants!
|
554
|
+
|
555
|
+
item.setPrice(2);
|
556
|
+
//ERROR: message = &#39;invalid currency&#39;
|
557
|
+
alert( item.formatCurrency(1.23) );
|
558
|
+
//ERROR: item.formatCurrency is not a function</pre>
|
559
|
+
|
560
|
+
<h3>And what am I supposed to do with this information?</h3>
|
561
|
+
|
562
|
+
<p>
|
563
|
+
I have yet to find the need to use private members in my
|
564
|
+
JavaScript objects. Maybe that&#39;s because I am not shipping
|
565
|
+
any JavaScript library with complex enough objects.
|
566
|
+
</p>
|
567
|
+
<p>
|
568
|
+
I think it&#39;s nice to know that you can create those off-limits
|
569
|
+
values in your object. Hopefully when the need for such thing
|
570
|
+
arises, we won&#39;t just say <i>Oh, no! Can&#39;t do that!</i>.
|
571
|
+
</p>
|
572
|
+
<p>
|
573
|
+
What about you? Have you found a use for private members in
|
574
|
+
your JavaScript code? How did you get around or implemented it?
|
575
|
+
</p><div style="clear:both;"></div><img src="http://devlicio.us/aggbug.aspx?PostID=44569" width="1" height="1"></description><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/Series/default.aspx">Series</category><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript/default.aspx">JavaScript</category><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript-Demystified/default.aspx">JavaScript-Demystified</category></item><item><title>JavaScript, time to grok closures</title><link>http://devlicio.us/blogs/sergio_pereira/archive/2009/02/23/javascript-time-to-grok-closures.aspx</link><pubDate>Mon, 23 Feb 2009 13:28:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:44499</guid><dc:creator>sergiopereira</dc:creator><slash:comments>18</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/sergio_pereira/rsscomments.aspx?PostID=44499</wfw:commentRss><comments>http://devlicio.us/blogs/sergio_pereira/archive/2009/02/23/javascript-time-to-grok-closures.aspx#comments</comments><description><div class="note">
|
576
|
+
This post is part of a series called <a href="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript-Demystified/default.aspx">JavaScript Demystified</a>.
|
577
|
+
</div>
|
578
|
+
|
579
|
+
<p>
|
580
|
+
When I wrote about <a href="http://devlicio.us/blogs/sergio_pereira/archive/2009/02/09/javascript-5-ways-to-call-a-function.aspx">functions in JavaScript</a> I mentioned that
|
581
|
+
functions are more than just a block of code:
|
582
|
+
</p>
|
583
|
+
<blockquote>
|
584
|
+
<code>Function</code> is a standard data type in JavaScript, an object indeed; you can pass them around and copy them.
|
585
|
+
</blockquote>
|
586
|
+
|
587
|
+
<p>
|
588
|
+
Let&#39;s take a look at this small sample of a function that creates
|
589
|
+
and returns another function. The returned function accepts one
|
590
|
+
string argument and returns another string repeating the argument a number of times.
|
591
|
+
</p>
|
592
|
+
|
593
|
+
<pre name="code" class="js">function makeRepeater(times){
|
594
|
+
return function(text){
|
595
|
+
var message = &#39;&#39;;
|
596
|
+
for (var i=0; i &lt; times; i++) {
|
597
|
+
message += text + &#39; &#39;;
|
598
|
+
}
|
599
|
+
return message;
|
600
|
+
};
|
601
|
+
}</pre>
|
602
|
+
|
603
|
+
<p>
|
604
|
+
Let&#39;s now write some code that uses that function.
|
605
|
+
</p>
|
606
|
+
|
607
|
+
<pre name="code" class="js">var threeTimes = makeRepeater(3);
|
608
|
+
var fourTimes = makeRepeater(4);
|
609
|
+
alert( threeTimes(&#39;hi&#39;) );
|
610
|
+
// =&gt; &#39;hi hi hi &#39;
|
611
|
+
alert( fourTimes(&#39;hi&#39;) );
|
612
|
+
// =&gt; &#39;hi hi hi hi &#39;</pre>
|
613
|
+
|
614
|
+
<p>
|
615
|
+
Nothing spectacular, right? But look closely. The function returned by
|
616
|
+
<code>makeRepeater</code> contains a reference to <code>times</code>,
|
617
|
+
which is a local variable of <code>makeRepeater</code>. When we call
|
618
|
+
<code>threeTimes</code> or <code>fourTimes</code> the
|
619
|
+
<code>makeRepeater</code> call has already returned and <code>times</code>
|
620
|
+
should be out of scope. Or should it?
|
621
|
+
</p>
|
622
|
+
|
623
|
+
<h3>Extra life for your local scope</h3>
|
624
|
+
|
625
|
+
<p>
|
626
|
+
You may try to argue and say that the <code>times</code> inside
|
627
|
+
<code>threeTimes</code> is not a <i>reference</i> to the
|
628
|
+
<code>times</code> from <code>makeRepeater</code>, but just
|
629
|
+
a <i>copy</i> of that value. Well, sadly I&#39;ll have to prove you wrong. Let&#39;s
|
630
|
+
modify our code just a little.
|
631
|
+
</p>
|
632
|
+
|
633
|
+
<pre name="code" class="js">var times;
|
634
|
+
function makeRepeater(){
|
635
|
+
return function(text){
|
636
|
+
var message = &#39;&#39;;
|
637
|
+
for (var i=0; i &lt; times; i++) {
|
638
|
+
message += text + &#39; &#39;;
|
639
|
+
}
|
640
|
+
return message;
|
641
|
+
};
|
642
|
+
}
|
643
|
+
|
644
|
+
times = 3;
|
645
|
+
var threeTimes = makeRepeater();
|
646
|
+
times = 4;
|
647
|
+
var fourTimes = makeRepeater();
|
648
|
+
alert( threeTimes(&#39;hi&#39;) );
|
649
|
+
// =&gt; &#39;hi hi hi hi &#39; ---&gt; What?!?!
|
650
|
+
alert( fourTimes(&#39;hi&#39;) );
|
651
|
+
// =&gt; &#39;hi hi hi hi &#39;</pre>
|
652
|
+
|
653
|
+
<p>
|
654
|
+
If it&#39;s not clear yet, let me write it down for you. The returned function
|
655
|
+
really keeps a reference to any outside values it will need when invoked.
|
656
|
+
In our original example, it kept a reference to the <code>times</code>
|
657
|
+
local variable at the time it was produced. If we had created other
|
658
|
+
local variables inside <code>makeRepeater</code> they would also become
|
659
|
+
available inside the returned function. In other words, all the scope
|
660
|
+
created during the call to <code>makeRepeater</code> will be preserved
|
661
|
+
for the returned function. This happens when the returned (or inner)
|
662
|
+
function has a reference to anything defined in the parent (or outer)
|
663
|
+
function, i.e. the parent local scope. When this happens, we say that a
|
664
|
+
<a href="http://en.wikipedia.org/wiki/Closure_(computer_science)">closure</a>
|
665
|
+
has been created.
|
666
|
+
</p>
|
667
|
+
|
668
|
+
<h3>Closures can be tricky</h3>
|
669
|
+
|
670
|
+
<p>
|
671
|
+
It&#39;s important to understand the mechanics of closures to avoid
|
672
|
+
subtle bugs in our code. Look at this piece of code, adapted from
|
673
|
+
a real bug I had to fix.
|
674
|
+
</p>
|
675
|
+
|
676
|
+
<pre name="code" class="js">&lt;input type=&quot;button&quot; value=&quot;Button 1&quot; id=&quot;btn1&quot;&gt;
|
677
|
+
&lt;input type=&quot;button&quot; value=&quot;Button 2&quot; id=&quot;btn2&quot;&gt;
|
678
|
+
&lt;input type=&quot;button&quot; value=&quot;Button 3&quot; id=&quot;btn3&quot;&gt;
|
679
|
+
|
680
|
+
&lt;script type=&quot;text/javascript&quot;&gt;
|
681
|
+
function createEventHandlers(){
|
682
|
+
var btn;
|
683
|
+
for(var i=1; i &lt;= 3; i++){
|
684
|
+
btn = document.getElementById(&#39;btn&#39; + i);
|
685
|
+
btn.onclick = function(){
|
686
|
+
alert(&#39;Clicked button #&#39; + i);
|
687
|
+
}
|
688
|
+
}
|
689
|
+
}
|
690
|
+
createEventHandlers();
|
691
|
+
&lt;/script&gt;</pre>
|
692
|
+
|
693
|
+
<p>
|
694
|
+
If you put this code in a page and click the three buttons you will see
|
695
|
+
that all of them will show the message &quot;Clicked button #4&quot;. Armed with
|
696
|
+
our understanding of closures we can immediately understand that this
|
697
|
+
bug is being caused by that reference to <code>i</code> used inside
|
698
|
+
the event handler. We can fix that.
|
699
|
+
</p>
|
700
|
+
|
701
|
+
<pre name="code" class="js">function createEventHandlers(){
|
702
|
+
var btn;
|
703
|
+
for(var i=1; i &lt;= 3; i++){
|
704
|
+
btn = document.getElementById(&#39;btn&#39; + i);
|
705
|
+
btn.onclick = createOneHandler(i);
|
706
|
+
}
|
707
|
+
}
|
708
|
+
|
709
|
+
function createOneHandler(number){
|
710
|
+
return function() {
|
711
|
+
alert(&#39;Clicked button #&#39; + number);
|
712
|
+
}
|
713
|
+
}</pre>
|
714
|
+
|
715
|
+
<p>
|
716
|
+
The above code works because we are not creating functions inside
|
717
|
+
the <code>for</code> loop, hence not producing closures on the same local scope.
|
718
|
+
There is a different set of closures being produced by
|
719
|
+
<code>createOneHandler</code>, but those are not pointing to the same
|
720
|
+
parent scope. Each of these three new closures contain a different
|
721
|
+
scope, created by each call to <code>createOneHandler</code>
|
722
|
+
</p>
|
723
|
+
|
724
|
+
<h3>Closing thoughts</h3>
|
725
|
+
|
726
|
+
<p>
|
727
|
+
Closures, of course, are not an exclusive feature of JavaScript. It&#39;s
|
728
|
+
a very important trait of functional languages. Even in C#, when
|
729
|
+
we use lambdas, closures are created &mdash; many times without us
|
730
|
+
noticing.
|
731
|
+
</p>
|
732
|
+
<p>
|
733
|
+
The key to properly using closures in our code is to pay attention
|
734
|
+
to locally scoped values from the outer function being used in the
|
735
|
+
body of the inner function. Most of the times this will work as
|
736
|
+
intended by the developer but, when it doesn&#39;t, stop and check
|
737
|
+
if more than one closure is sharing the same local scope or if
|
738
|
+
these local values are changing between the inner function
|
739
|
+
creation and its invocation.
|
740
|
+
</p>
|
741
|
+
|
742
|
+
<div style="clear:both;"></div><img src="http://devlicio.us/aggbug.aspx?PostID=44499" width="1" height="1"></description><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/Series/default.aspx">Series</category><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript/default.aspx">JavaScript</category><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript-Demystified/default.aspx">JavaScript-Demystified</category></item><item><title>JavaScript, 5 ways to call a function</title><link>http://devlicio.us/blogs/sergio_pereira/archive/2009/02/09/javascript-5-ways-to-call-a-function.aspx</link><pubDate>Mon, 09 Feb 2009 06:03:00 GMT</pubDate><guid isPermaLink="false">40756a8b-6212-4073-9d98-6c26781577de:44041</guid><dc:creator>sergiopereira</dc:creator><slash:comments>25</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://devlicio.us/blogs/sergio_pereira/rsscomments.aspx?PostID=44041</wfw:commentRss><comments>http://devlicio.us/blogs/sergio_pereira/archive/2009/02/09/javascript-5-ways-to-call-a-function.aspx#comments</comments><description><div class="note">
|
743
|
+
This post is part of a series called <a href="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript-Demystified/default.aspx">JavaScript Demystified</a>.
|
744
|
+
</div>
|
745
|
+
|
746
|
+
<p>
|
747
|
+
Time after time I find JavaScript code that has bugs caused by lack of proper understanding of how functions work in JavaScript (a lot of that code has been written by me, by the way.) JavaScript has functional programming characteristics, and that can get in our way until we decide to face and learn it.
|
748
|
+
</p>
|
749
|
+
|
750
|
+
<p>
|
751
|
+
For starters, let&#39;s examine five ways to invoke a function. On the surface we might be tempted to think that functions work exactly like C#, but we will see that there are important differences and ignoring them will undoubtedly result in hard to track bugs.
|
752
|
+
</p>
|
753
|
+
|
754
|
+
<p>
|
755
|
+
Let&#39;s first create a simple function that we will be using through the rest of this post. This function will just return an array with the current value of <code>this</code> and the two supplied arguments.
|
756
|
+
</p>
|
757
|
+
|
758
|
+
|
759
|
+
<pre name="code" class="js:nogutter">&lt;script type=&quot;text/javascript&quot;&gt;
|
760
|
+
function makeArray(arg1, arg2){
|
761
|
+
return [ this, arg1, arg2 ];
|
762
|
+
}
|
763
|
+
&lt;/script&gt;</pre>
|
764
|
+
|
765
|
+
<h3>Most common way, unfortunately, global function calls</h3>
|
766
|
+
|
767
|
+
|
768
|
+
<p>
|
769
|
+
When we are learning JavaScript we learn how to define functions using the syntax used in the example above. We learn that it&#39;s also very easy to call that function &mdash; all we need to do is:
|
770
|
+
</p>
|
771
|
+
|
772
|
+
|
773
|
+
<pre name="code" class="js:nogutter">makeArray(&#39;one&#39;, &#39;two&#39;);
|
774
|
+
// =&gt; [ window, &#39;one&#39;, &#39;two&#39; ]</pre>
|
775
|
+
|
776
|
+
|
777
|
+
<p>
|
778
|
+
Wait a minute. What&#39;s that <code>window</code> object doing there? Why is it the value of <code>this</code>? If you haven&#39;t stopped to think about it, please stay with me here.
|
779
|
+
</p>
|
780
|
+
|
781
|
+
<p>
|
782
|
+
In JavaScript, and I&#39;m not talking specifically about the browser here, there&#39;s a default/global object. It&#39;s as if every code that we write which seems to be just &quot;loose&quot; inside your script (i.e. outside of any object declaration) is actually being written in the context of that global object. In our case, that <code>makeArray</code> function isn&#39;t just a loose &quot;global&quot; function, it&#39;s a method of the global object. Bringing ourselves back to the browser, the global object is mapped to the <code>window</code> object in this environment. Let&#39;s prove that.
|
783
|
+
</p>
|
784
|
+
|
785
|
+
|
786
|
+
<pre name="code" class="js:nogutter">alert( typeof window.methodThatDoesntExist );
|
787
|
+
// =&gt; undefined
|
788
|
+
alert( typeof window.makeArray);
|
789
|
+
// =&gt; function</pre>
|
790
|
+
|
791
|
+
|
792
|
+
<p>
|
793
|
+
What all this means is that calling <code>makeArray</code> like we did before is the same as calling as follows.
|
794
|
+
</p>
|
795
|
+
|
796
|
+
|
797
|
+
<pre name="code" class="js:nogutter">window.makeArray(&#39;one&#39;, &#39;two&#39;);
|
798
|
+
// =&gt; [ window, &#39;one&#39;, &#39;two&#39; ]</pre>
|
799
|
+
|
800
|
+
|
801
|
+
<p>
|
802
|
+
I say it&#39;s unfortunate that this is the most common way because it leads us to declare our functions globally by default. And we all know that global members are not exactly the best practice in software programming. This is especially true in JavaScript. Avoid globals in JavaScript, you won&#39;t regret it.
|
803
|
+
</p>
|
804
|
+
|
805
|
+
<div class="note">
|
806
|
+
<span class="legend"><b>JavaScript function invocation rule #1</b></span>
|
807
|
+
In a function called directly without an explicit owner object, like <code>myFunction()</code>, causes the value of <code>this</code> to be the default object (<code>window</code> in the browser).
|
808
|
+
</div>
|
809
|
+
|
810
|
+
<h3>Method call</h3>
|
811
|
+
|
812
|
+
<p>
|
813
|
+
Let&#39;s now create a small object and use the <code>makeArray</code> function as one of its methods. We will declare the object using the literal notation. Let&#39;s also call this method.
|
814
|
+
</p>
|
815
|
+
|
816
|
+
|
817
|
+
<pre name="code" class="js:nogutter">//creating the object
|
818
|
+
var arrayMaker = {
|
819
|
+
someProperty: &#39;some value here&#39;,
|
820
|
+
make: makeArray
|
821
|
+
};
|
822
|
+
|
823
|
+
//invoke the make() method
|
824
|
+
arrayMaker.make(&#39;one&#39;, &#39;two&#39;);
|
825
|
+
// =&gt; [ arrayMaker, &#39;one&#39;, &#39;two&#39; ]
|
826
|
+
// alternative syntax, using square brackets
|
827
|
+
arrayMaker[&#39;make&#39;](&#39;one&#39;, &#39;two&#39;);
|
828
|
+
// =&gt; [ arrayMaker, &#39;one&#39;, &#39;two&#39; ]</pre>
|
829
|
+
|
830
|
+
|
831
|
+
<p>
|
832
|
+
See the difference here? The value of <code>this</code> became the object itself. You may be wondering why isn&#39;t it still <code>window</code> since that&#39;s how the original function had been defined. Well, that&#39;s just the way functions are passed around in JavaScript. <code>Function</code> is a standard data type in JavaScript, an object indeed; you can pass them around and copy them. It&#39;s as if the entire function with argument list and body was copied and assigned to make in <code>arrayMaker</code>. It&#39;s just like defining <code>arrayMaker</code> like this:
|
833
|
+
</p>
|
834
|
+
|
835
|
+
|
836
|
+
<pre name="code" class="js:nogutter">var arrayMaker = {
|
837
|
+
someProperty: &#39;some value here&#39;,
|
838
|
+
make: function (arg1, arg2) {
|
839
|
+
return [ this, arg1, arg2 ];
|
840
|
+
}
|
841
|
+
};</pre>
|
842
|
+
|
843
|
+
<div class="note">
|
844
|
+
<span class="legend"><b>JavaScript function invocation rule #2</b></span>
|
845
|
+
In a function called using the method invocation syntax, like <code>obj.myFunction()</code> or <code>obj[&#39;myFunction&#39;]()</code>, causes the value of <code>this</code> to be <code>obj</code>.
|
846
|
+
</div>
|
847
|
+
|
848
|
+
|
849
|
+
<p>
|
850
|
+
This is a major source of bugs in event handling code. Look at these examples.
|
851
|
+
</p>
|
852
|
+
|
853
|
+
|
854
|
+
<pre name="code" class="js:nogutter">&lt;input type=&quot;button&quot; value=&quot;Button 1&quot; id=&quot;btn1&quot; /&gt;
|
855
|
+
&lt;input type=&quot;button&quot; value=&quot;Button 2&quot; id=&quot;btn2&quot; /&gt;
|
856
|
+
&lt;input type=&quot;button&quot; value=&quot;Button 3&quot; id=&quot;btn3&quot; onclick=&quot;buttonClicked();&quot;/&gt;
|
857
|
+
|
858
|
+
&lt;script type=&quot;text/javascript&quot;&gt;
|
859
|
+
function buttonClicked(){
|
860
|
+
var text = (this === window) ? &#39;window&#39; : this.id;
|
861
|
+
alert( text );
|
862
|
+
}
|
863
|
+
var button1 = document.getElementById(&#39;btn1&#39;);
|
864
|
+
var button2 = document.getElementById(&#39;btn2&#39;);
|
865
|
+
|
866
|
+
button1.onclick = buttonClicked;
|
867
|
+
button2.onclick = function(){ buttonClicked(); };
|
868
|
+
&lt;/script&gt;</pre>
|
869
|
+
|
870
|
+
|
871
|
+
<p>
|
872
|
+
Clicking the first button will display <i>&quot;btn1&quot;</i> because it&#39;s a method invocation and <code>this</code> will be assigned the owner object (the button input element.) Clicking the second button will display <i>&quot;window&quot;</i> because <code>buttonClicked</code> is being called directly (i.e. not like <code>obj.buttonClicked()</code>.) This is the same thing that happens when we assign the event handler directly in the element&#39;s tag, as we have done for the third button. Clicking the third button does the same of the second button.
|
873
|
+
</p>
|
874
|
+
|
875
|
+
<p>
|
876
|
+
That&#39;s another advantage of using a library like jQuery. When defining event handlers in jQuery, the library will take care of overriding the value of <code>this</code> and make sure it contains a reference to the element that was the source of the event.
|
877
|
+
</p>
|
878
|
+
|
879
|
+
<pre name="code" class="js:nogutter">//using jQuery
|
880
|
+
$(&#39;#btn1&#39;).click( function() {
|
881
|
+
alert( this.id ); // jQuery ensures &#39;this&#39; will be the button
|
882
|
+
});</pre>
|
883
|
+
|
884
|
+
<p>
|
885
|
+
How does jQuery override the value of <code>this</code>? Keep reading.
|
886
|
+
</p>
|
887
|
+
|
888
|
+
<h3>Two more: <code>apply()</code> and <code>call()</code></h3>
|
889
|
+
|
890
|
+
<p>
|
891
|
+
The more you leverage functions in JavaScript, the more you find yourself passing functions around and needing to invoke them in different contexts. Just like jQuery does in the event handler functions, you&#39;ll often need to override the value of <code>this</code>. Remember I told you functions are objects in JavaScript? Functions have predefined methods, two of them are <code>apply()</code> and <code>call()</code>. We can use them to do precisely that kind of overriding.
|
892
|
+
</p>
|
893
|
+
|
894
|
+
<pre name="code" class="js:nogutter">var gasGuzzler = { year: 2008, model: &#39;Dodge Bailout&#39; };
|
895
|
+
makeArray.apply( gasGuzzler, [ &#39;one&#39;, &#39;two&#39; ] );
|
896
|
+
// =&gt; [ gasGuzzler, &#39;one&#39; , &#39;two&#39; ]
|
897
|
+
makeArray.call( gasGuzzler, &#39;one&#39;, &#39;two&#39; );
|
898
|
+
// =&gt; [ gasGuzzler, &#39;one&#39; , &#39;two&#39; ]</pre>
|
899
|
+
|
900
|
+
|
901
|
+
<p>
|
902
|
+
The two methods are similar. The first parameter will override <code>this</code>. They differ on the subsequent arguments. <code>Function.apply()</code> takes an array of values that will be passed as arguments to the function and <code>Function.call()</code> takes the same arguments separately. In practice I believe you&#39;ll find that <code>apply()</code> is more convenient in most cases.
|
903
|
+
</p>
|
904
|
+
|
905
|
+
<div class="note">
|
906
|
+
<span class="legend"><b>JavaScript function invocation rule #3</b></span>
|
907
|
+
If we want to override the value of <code>this</code> without copying the function to another object, we can use <code>myFunction.apply( obj )</code> or <code>myFunction.call( obj )</code>.
|
908
|
+
</div>
|
909
|
+
|
910
|
+
<h3>Constructors</h3>
|
911
|
+
|
912
|
+
<p>
|
913
|
+
I won&#39;t delve into the details of defining types in JavaScript but at minimum we should be aware that there aren&#39;t classes in JavaScript and that any custom type needs a constructor function. It&#39;s also a good idea to define the methods of your type using the <code>prototype</code> object, which is a property of the constructor function. Let&#39;s create a small type.
|
914
|
+
</p>
|
915
|
+
|
916
|
+
|
917
|
+
<pre name="code" class="js:nogutter">//declaring the constructor
|
918
|
+
function ArrayMaker(arg1, arg2) {
|
919
|
+
this.someProperty = &#39;whatever&#39;;
|
920
|
+
this.theArray = [ this, arg1, arg2 ];
|
921
|
+
}
|
922
|
+
// declaring instance methods
|
923
|
+
ArrayMaker.prototype = {
|
924
|
+
someMethod: function () {
|
925
|
+
alert( &#39;someMethod called&#39;);
|
926
|
+
},
|
927
|
+
getArray: function () {
|
928
|
+
return this.theArray;
|
929
|
+
}
|
930
|
+
};
|
931
|
+
|
932
|
+
var am = new ArrayMaker( &#39;one&#39;, &#39;two&#39; );
|
933
|
+
var other = new ArrayMaker( &#39;first&#39;, &#39;second&#39; );
|
934
|
+
|
935
|
+
am.getArray();
|
936
|
+
// =&gt; [ am, &#39;one&#39; , &#39;two&#39; ]</pre>
|
937
|
+
|
938
|
+
|
939
|
+
<p>
|
940
|
+
What&#39;s very important to note here is the presence of the <code>new</code> operator before the function call. Without that your function will just be called like a global function and those properties that we are creating would be created on the global object (<code>window</code>.) And you don&#39;t want to do that. Another issue is that, because you typically don&#39;t have an explicit return value in your constructor function, you&#39;ll end up assigning <code>undefined</code> to some variable if you forget to use <code>new</code>. For these reasons it&#39;s a good convention to name your constructor functions starting with an upper case character. This should serve as a reminder to put the <code>new</code> operator before the call.
|
941
|
+
</p>
|
942
|
+
|
943
|
+
<p>
|
944
|
+
With that taken care of, the code inside the constructor is very similar to any constructor you probably have written in other languages. The value of <code>this</code> will be the new object that you are trying to initialize.
|
945
|
+
</p>
|
946
|
+
|
947
|
+
<div class="note">
|
948
|
+
<span class="legend"><b>JavaScript function invocation rule #4</b></span>
|
949
|
+
When used as a constructor, like <code>new MyFunction()</code>, the value of <code>this</code> will be a brand new object provided by the JavaScript runtime. If we don&#39;t explictly return anything from that function, <code>this</code> will be considered its return value.
|
950
|
+
</div>
|
951
|
+
|
952
|
+
<h3>It&#39;s a wrap</h3>
|
953
|
+
|
954
|
+
<p>
|
955
|
+
I hope understanding the differences between the invocation styles help you keeping bugs out of your JavaScript code. Some of these bugs can be very tricky do identify and making sure you always know what the value of <code>this</code> will be is a good start to avoiding them in the first place.
|
956
|
+
</p>
|
957
|
+
|
958
|
+
|
959
|
+
<div style="clear:both;"></div><img src="http://devlicio.us/aggbug.aspx?PostID=44041" width="1" height="1"></description><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/Series/default.aspx">Series</category><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript/default.aspx">JavaScript</category><category domain="http://devlicio.us/blogs/sergio_pereira/archive/tags/JavaScript-Demystified/default.aspx">JavaScript-Demystified</category></item></channel></rss>
|