Page 1

2009 Sampler

The Red Pill: Functional Programming in Javascript JazzRecord: JavaScript Databases Made Painless Using Object Literals to Organize Your Features Community News

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

for JavaScript professionals


Welcome to JSMag! Purchasing

This sampler issue of JSMag is intended to give you an idea of what JSMag is all about. We aim to bring the best JavaScript-oriented articles to you each month, with an eye toward topics you might not read about in other resources. While we will run articles that are useful to JavaScript beginners, our goal is to bring you articles that lean towards the “advanced” side of the aisle.

Each issue is available in PDF format for $4.99, and annual subscriptions are available. Visit http://jsmag.com to learn more or to purchase. Bulk licensing discounts are available for companies and user groups. We will occasionally have advertisements that we deem will be of sufficient value to the readership, but JSMag is not advertising driven. Our primary (and majority) revenue comes from the sale of the magazine.

Between a blog and a book While there are numerous blogs available, most are journals, outlining a fellow developer’s experiments with new technology. Blogs can be great for keeping up with the cutting edge, but usually don’t go deep enough in to a subject to help a large number of people. On the other end of things, technical books provide large amounts of great info, but are often outdated within weeks of publication. By providing a monthly stream of information, we’ll be bringing you content that’s more polished than most blogs, and more timely than most books.

Each JSMag PDF is DRM-free. The PDF is completely searchable, indexable and printable. Additionally, each PDF issue comes bundled with code files necessary to run any examples from the articles.

Looking for writers JSMag is always looking for writers to share their knowledge of JavaScript with our readers. Contributors are paid for their pieces, and retain copyright to any materials created. If you are interested in writing for JSMag, please email editor@jsmag.com.

The how and the why I ask all contributors to use their own voice and experience as much as possible. It’s very easy to find JavaScript code snippets without good context. It’s also very easy to find forums threads filled with academic debate devoid of code. My charge to our writers is to give both the technical “how” part coupled with the “why” from their own experiences.

Feedback We’re always looking for feedback and input from the community. Please email editor@jsmag.com with your feedback, ideas or thoughts on what we can do to improve the magazine.

Contents JazzRecord: JavaScript Databases Made Painless Nick Carter

3

The Red Pill: Functional Programming in JavaScript

Robert Fischer

9

Using Object Literals to Organize Your Features Rebecca Murphey

15

Community News

22

Matt Henry 

Technical Editors Darryl Bloch Craig Wickesser Reviewers Ryan McGrath Adam Sontag Production, Design & Cover Photo Rebecca Murphey jsmag.com twitter.com/jsmag

JSMag

2

2009 Sampler

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

Editor Michael Kimsal editor@jsmag.com


JazzRecord: JavaScript Databases Made Painless Nick Carter

This article will examine a typical usage of JazzRecord in handling the data storage/retrieval needs for a client-side wiki. We’ll see examples of finders, association loading, and a minor example of validation. But first ...

New JavaScript runtimes like Adobe AIR and Google Gears allow us to store complex data structures as local databases. JazzRecord, inspired by Rails ActiveRecord, enables developers to interact with these disparate APIs seamlessly and uniformly. This article examines the usage of JazzRecord in a demo wiki application, serving as an introduction to this versatile tool.

A Brief Tour of Jazz

Editor note: code is available in the downloaded ZIP file.

JazzRecord is full of features to make your database usage quick and painless. It includes: • Finders: JazzRecord’s finders are ported directly from ActiveRecord, and as such allow complex options to be passed in for modifying the SELECT statements that are generated and executed. Most notably, JazzRecord will pre-load associated record data from other tables, very similarly to how ActiveRecord performs.

Wide World of Jazz JazzRecord (http://www.jazzrecord.org) is a platform-independent JavaScript library for ORM (Object Relational Mapping) with SQLite. It works with any other library (such as jQuery or MooTools), via Adobe AIR and Google’s Gears project. JazzRecord simplifies dealing with database records, and eases Rails developfamiliar interface for ORM. JazzRecord is essentially a simplified port of ActiveRecord, one of the core components of Rails. As JavaScript is missing several of the features available in Ruby, some features of ActiveRecord needed to be scrapped or have

• Complex validation: JazzRecord comes with several built-in validation helper methods, which can be used to quickly build data models where storing invalid data (that would cause your application to break) is next to impossible.

alternatives created for JazzRecord. If you come from a Rails background, you’ll find the feature set of JazzRecord is very rich and you can generally quickly overcome these shortcomings using the provided features. If you don’t come from a Rails background —

• Automatic type escaping and conversion: For example, SQLite doesn’t have a true boolean type, but JazzRecord converts data you’ve ascribed as bool to a 0 or 1 for storage and returns it back to a boolean when loading it from the database.

well, you probably wouldn’t have noticed in the first place! A quick note: JazzRecord (as of version 0.7) is currently a synchronous-only library. On the horizon is the ability to work with synchronous and asynchronous environments, the first and most

JazzRecord is contained almost entirely within two JavaScript “classes,” JazzRecord.Model and JazzRecord.Record. You can create model objects directly and instantiate record objects via finders, or by calls to a model’s create() or newRecord() methods.

important of which is HTML5 (HTML5 is strictly asynchronous). This will open up JazzRecord to new versions of Appcelerator Titanium as well as Palm’s webOS, both of which are HTML5-based.

2009 Sampler

3

JSMag

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

• Save/destroy linking and unlinking: When saving (INSERTing and UPDATEing) records with JazzRecord, the library will automatically associate records which the user has indicated should be linked by placing them in the same base object. This deserves further discussion and will be covered later.

ers into JavaScript-based application development by presenting a


For a full list of features and the API, see the documentation (http://www.jazzrecord.org/docs).

<h1 id="title">JazzWiki</h1> <ul id="nav" class="clearfix"> <li><a id="home" href="#">Home</a></li> <li><a id="entryList" href="#">Entry List</a></li> <li><a id="tagList" href="#">Tag List</a></li> <li class="entrySpecific"><a id="toggle" href="#">Form Toggle</a></li> </ul> <span id="contentKiller"><a href="#">X</a></span> <div id="content"> </div>

An Earful of Jazz File Overview Our example project, JazzWiki, is a Gears-backed wiki using Markdown for formatting. For handling this we’ll use Showdown (http:// attacklab.net/showdown/), a handy little library for parsing Markdown in JavaScript. This is available in the provided project files in showdown.js. The view code for the entire application is contained in one HTML file, and the CSS is limited enough that I’ve simply entered it in the head of this file.

<div class="entrySpecific" style="float: left;"> <div id="tagLabel"> Tags: </div> <div id="tags"> </div> </div>

For simplicity’s sake — and since most everyone already knows how to use it — we’re using jQuery in this example (through the Google Ajax Libraries API) to manipulate the DOM and handle events. MooTools, Prototype, or any other library would work just as well. We also make sure to include the gears_init.js file to set up Gears’ functionality and the single file for JazzRecord, jazz_record.js.

<form id="editor"> <fieldset> <label for="editorTitle">Title:</label> <input type="text" name="title" value="" id="editorTitle"/> <label for="editorContent">Contents:</label> <textarea id="editorContent" rows="8" cols="40"></ textarea> <label for="editorTags">Tags:</label> <input type="text" name="tags" value="" id="editorTags"/> <input type="submit" value="Save" id="saveButton"/> </fieldset> </form>

Our custom JavaScript code will be split into three files: models.js, fixtures.js, jazz_wiki.js. These files cover the modeling of the database, the initialization of data, and provide a mini-library for dealing with events and the DOM in this app. We’ve also created a file called jazz_links.js, which is a jQuery plugin for rendering the links in appropriate colors (indicating existent/nonexistent/ external links) and for hijacking the links so they call library functions rather than perform their normal actions.

Listing 1: Our markup

JazzRecord Configuration and Model Setup On to the good stuff: JavaScript! First, we set up JazzRecord’s configuration variables in models.js, namely JazzRecord.debug and JazzRecord.adapter. These turn on logging when set to true and set up the library’s adapter to handle a given environment, like Adobe AIR or Google Gears. In this case, we set debug to true so we can better see what’s happening (you’d turn it off in a production app) and we set the adapter to an instantiation of JazzRecord. GearsAdapter to handle Gears, passing in a filename for the database that will store our data. (The actual location of the SQLite file is dependent on the environment in which it is run.)

JSMag

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

var Entry = new JazzRecord.Model({ table: "entries", foreignKey: "entry_id", hasAndBelongsToMany: {tags: "tags"}, columns: { wiki_name: "text", title: "text", content: "text" }, //... }); var Tag = new JazzRecord.Model({ table: "tags", foreignKey: "tag_id", hasAndBelongsToMany: {entries: "entries"}, columns: { name: "text" }, //... }

The view code is shown in Listing 1. There are five distinct sections: #title, which holds the title for a given entry in the wiki; #nav, which contains Home, Entry List, Tag List, and Form Toggle link controls; #content, which is surrounded with a black border and holds the content of a given entry; #tags, which holds the set of tag links for a given entry; and #editor, which holds the form for editing the currently active entry.

Listing 2: Entry and Tag models

4

2009 Sampler


Next, we define the two models required by our application, namely Entry and Tag (see Listing 2). These models represent the tables used by the app and their in-memory representation and, as such, define a few key pieces of data: table; foreignKey; association data such as hasAndBelongsToMany; a set of columns in a columns object literal (defined as key: "value" pairs representing column name and type, respectively); and, optionally, a set of validation functionality to be called upon at key moments during record objects’ lifetimes.

var Entry = new JazzRecord.Model({ //... validate: { atSave: function() { this.validatesUniquenessOf("wiki_name"); if(this.originalData && this.originalData.wiki_ name === "Home") if(this.wiki_name !== "Home") { // reset WikiName and flag error this.wiki_name = "Home"; this.pushError("wiki_name", "Home record's WikiName cannot be changed"); } } } });

While table and foreignKey might be obvious if you have databases experience, associations are where it gets interesting. JazzRecord defines a number of association types, including hasAndBelongsToMany, hasOne, hasMany, and belongsTo. Each of these association types denotes a given set of behaviors in terms of how records are linked to one another. Essentially, an object literal property named after one of the association types is passed into the options object of the constructor for a JazzRecord.Model. Each property inside this object literal is the name of an association property that will be populated when a record is first loaded (if data exists on the association), or via an AssociationLoader. In our example, each Tag-generated record can have a number of Entry objects associated with it as an array on the entries association property, and each Entry object can likewise host an array of Tag objects on the tags property. More on this later.

Listing 3: Validations a later date! (Again, certain operations can inherently lead to irreversible data loss.) For more info on manual migrations see http:// www.jazzrecord.org/docs/migrations#manual_migrations. These models also contain some simple validations (see Listing 3) to ensure that Entry records contain unique wiki_name values, and that Tag records contain unique name values. We also define a validation that prevents the deletion of the “home” entry. JazzRecord defines a number of different validations you can run on your record data, from uniqueness, to type validation, to regex matching and more. See http://www.jazzrecord.org/docs/model#validation.

AssociationLoaders can load data after a record has been loaded, which may prove important if you need to reach deeply nested associated data without incurring the initial hit of deep-loading finders. This is accomplished via a call to a record’s load() method, passing in the property name you wish to load as a string. For example, if an Entry record does not have its tags loaded, calling entry.load("tags") will load them.

After setting up the models for use in the app, we next set up some default data using what are known as fixtures in fixtures.js (see Listing 4), which are object literals representing data with which we populate the database tables. The composition for this fixtures object is one object literal assigned to the property name tables which consists of a number of named arrays. Each array represents a table in the database with the same name as the array, and the array’s contents represent individual records. Each index of these table arrays is an object literal with property names mimicking the column names defined in the model. In addition to the individual model-based arrays in the tables object of the fixture data, there’s optionally a mappingTables object which likewise holds row data for any mapping tables (aka “join tables”) that JazzRecord generates based on the presence of hasAndBelongsToMany properties in model definitions. Mapping tables are always named tableA_tableB, where A is the first of two remote tables (when sorted alphabetically) and B is the second.

For details on other types of associations, see http://www.jazzrecord.org/docs/model#associations and elsewhere in the online docs. More complex applications, which tend to go through many iterations of development, can make use of a more complicated functionality provided by JazzRecord called manual migrations. By default, JazzRecord will create any missing tables matching the descriptions given in the models. But if you’ve got an installed application on a user’s computer, you will want to be able to modify the schema and existing data without causing loss of important data that your users have already stored. Manual migrations allow you to perform a number of schema operations to transform the database without losing data. (Removing columns, dropping tables, and changing column types can all affect data permanently. Other schema operations leave existing data in place.) Not only do they make schema changes easy, they can also revert changes made at

2009 Sampler

After actually setting up the default data for the wiki (a few demo entries and some tags to go along with them) we call JazzRecord.migrate() which creates the tables initially and performs some behind-the-scenes magic to associate the model objects in memory with the tables in the SQLite file. After this first

5

JSMag

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

Fixture Data and Initial Load


JazzRecord.fixtures = { tables: { entries: [ {wiki_name: "home", title: "JazzWiki", content: "*This* is the **content area**. Here you will view [existing content](another_entry) and [more content] (more_content). To edit, click Edit to reveal form. Contents are Markdown code to be rendered."}, {wiki_name: "another_entry", title: "Second Demo Entry", content: "This has no content but a link to [Thyncology](http://www.thynctank.com) and a link to [Home](home)."} ], tags: [ {name: "home"}, {name: "wiki"}, {name: "demo"} ] }, mappingTables: { entries_tags: [ {entry_id: 1, tag_id: 1}, {entry_id: 1, tag_id: 2}, {entry_id: 1, tag_id: 3}, {entry_id: 2, tag_id: 3} ] } };

var JazzWiki = { converter: new Showdown.converter(), // load or create empty content, title, and tags into HTML load: function(wikiName) {}, save: function(evt) {}, toggleForm: function() {}, deleteEntry: function() {}, goHome: function(evt) {}, loadEntryList: function(evt) {}, loadTagList: function(evt) {}, loadTagPage: function(tagName) {}, renderList: function(collection, options) {}, renderListContent: function(collection, options) {} };

Listing 5: Namespaced Wiki Functions var JazzWiki = { load: function(wikiName) { this.currentEntry = Entry.findBy("wiki_name", wikiName); if(!this.currentEntry) this.currentEntry = Entry.create({wiki_name: wikiName, title: "[Untitled]", content: "[Empty]"}); //... }, //... };

Listing 4: Fixture data

Listing 6: A Finder and a Call to create

call, we look to see if any entries exist by calling Entry.count(),

load an actual record into memory. If the record exists ahead of time, all of its data (title, content, associated tags) will be loaded in memory automatically as a result of the finder.

which returns the number of rows in the associated table. If this is 0 (which it will be the first time through) we call JazzRecord. migrate() a second time, this time passing in {refresh: true} which will cause the fixtures data to be loaded. Once loaded like tion of the “home” entry via the custom validation defined on the Entry model; therefore Entry.count() will thereafter always return greater than 0.

Loading Wiki Entries

Once our record object is loaded up, we can copy the data from it into the DOM by a series of jQuery setter calls (see included source code for details). We load the data as-is into the editor textarea, and we load the Markdown-parsed data into #content by first calling this.converter.makeHtml() on it (converter was first initialized when the entire namespace was created).

Now that our tables are set up and default data is loaded, we can set up event handlers (via a call to the ever-handy $() function in the main HTML file) for the various navigation links, and then load the “home” entry as the default when the page loads. For loading this entry, we’ve defined a function goHome() in JazzWiki, a namespace we set up to store app-specific methods. The function goHome()

Loading, Styling, and Handling Wiki Tag Links

tells the app to load the home entry. See Listing 5 for a summary of

Loading the tags is a little trickier, but still achievable. We iterate over the collection of tags populated on this.currentEntry.tags and spit out a comma-delimited string into the tags field in #editor. Likewise, we spit out a string of some kind into #tags. To generate the markup that we use to populate this portion of the view, we’ve written a helper function called renderList(). This method takes

the functions defined Loading an entry in our app is handled by JazzWiki.load(), which takes a wiki_name string as its only parameter (see Listing 6). This method internally sets the namespace’s currentEntry to whatever entry is found by running a findBy("wiki_name", wikiName) to

JSMag

6

2009 Sampler

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

If a record doesn’t exist before the finder is run, we create a new one. This is accomplished via Entry.create({wiki_name: wikiName, title: wikiName, content: ""}) which creates an empty wiki entry with a name and title identical to what was passed in. JazzRecord creates a reference to the newly-created record, as well as data stored in the db.

this, the fixtures will no longer be loaded. We disallow the dele-


an array to iterate through as an options object. The options object sets things like what properties of the array indices should be used to populate which portions of the markup generated by the helper. displayProp determines which text to show in links, and link determines what property to use to build the href property of the given link. join is a string used to join together the entire list as a whole. This same helper is used elsewhere in the namespace but passed different parameters.

var JazzWiki = { //... save: function(evt) { if(evt) { evt.preventDefault(); } // grab text from editor, escape string JazzWiki.currentEntry.title = $("#editorTitle"). val(); JazzWiki.currentEntry.content = encodeURIComponent($("#editorContent").val()); JazzWiki.currentEntry.tags = [];

After populating the various editable and active portions of the view with data from the records, we focus on the interactive bits: showing all .entrySpecific-classed elements (such as #toggle and the tags list). Then we determine whether to hide or show #contentKiller, which is an “X” link used to delete entry records other than “home.” We already protect against deleting the “home” record.

var currentTags = $("#editorTags").val().split(", ");

After we’ve both loaded content and set up #contentKiller, we call on our custom jQuery plugin, jazzLinks(), for the last bit of load magic: colorizing and hijacking links.

// parse out tags, create tags as necessary, associate to entry JazzRecord.each(currentTags, function(t) { var e = Tag.findBy("name", t); if(!e) { e = Tag.create({name: t}); } JazzWiki.currentEntry.tags.push(e); });

The jQuery plugin configures each link in #content or #tags based on its href. If href begins with “tag:” it is assumed to be a link to a tag page, which should show a list of articles with a given tag assigned.

JazzWiki.currentEntry.save(); JazzWiki.load(JazzWiki.currentEntry.wiki_name); }, //... };

Depending on whether href begins with no protocol or a pseudoprotocol, it is colored differently:

Listing 7: Saving currentEntry

Wrapping Up

• Red (for nonexistent entries)

• Gray (for external content, launched in a new window) To determine what color to paint an entry link, we utilize JazzRecord finders again. If Entry.findBy("wiki_name", href) returns something, that record must exist, so it is an .existentLink, and is colored green. If, however, the finder returns nothing, the link’s class is set to .nonexistentLink and colored red. Regardless, both varieties of in-wiki links have their click handler set to JazzWiki. load(href), which when triggered would begin the whole scenario over again. If the link has “http://” in it, it is assumed to be an .offsiteLink and is given that class, which colors it gray. Its click event is overridden to pop the link in an external window.

JazzRecord is smart enough to know what data was originally associated with a record on load, compare it to the data associated on save, and perform updates as needed, adding or removing association data in the database. Manually mucking about with individual foreignKeys is rarely necessary.

Saving entries and tags, deleting entries, and displaying the Tag List and Entry List pages are the last big pieces of the puzzle. Let’s cover them quickly.

At the end of JazzWiki.save(), we again call JazzWiki.load(), this time to load the data we just wrote to the database into the rendered view. This allows for all sorts of nice formatting using Markdown to take immediate effect.

Saving an entry is as simple as copying form data back into the currentEntry stored on the namespace, which happens to already be an existing record object. JazzRecord defines a handy save() method, which when called performs any required validations and (if these pass) INSERTs or UPDATEs records in corresponding database table. We’ll delay calling this until we’ve dealt with entries, however.

2009 Sampler

Deleting entries is as simple as calling destroy() on a record object. The #contentKiller link has its click event assigned to

7

JSMag

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

Saving an entry’s tags is, again, slightly more complex. First we reset the this.currentEntry.tags in case we’ve removed any tags from the entry. We then split the tags on the comma, and one by one search for tags with those names. In each case, if the tag doesn’t yet exist we create it, and then we add the tag record to the association array this.currentEntry.tags. Once we’re done populating this association array with the current tags (if any), we call save() on the entry record object. In addition to saving data to the “entries” table in the database this also saves the associated tags and links them appropriately by inserting records in the mapping table. See Listing 7 for this code sample.

• Green (for existent entries and tag page links)


to be destroyed when they themselves are destroyed. Currently, obtaining this functionality with JazzRecord is somewhat cumbersome. The second, async, is far more complicated, and is the first major piece of brand new JazzRecord code in several months. The current HTML5 spec, which is seeing production use in Appcelerator Titanium, Palm webOS, and the latest builds of Safari, is asynconly. Asynchronous API forces the application (and any libraries built on it) to use a series of callbacks to accomplish what might normally be done in a few lines of procedural code. The upshot is that JazzRecord finders and other methods will soon take callbacks (when used asynchronously) to execute upon building the complex record objects we’ve discussed in this article.

JazzWiki.deleteEntry() when visible, which calls destroy() on the currentEntry record, thereby removing the entry record from the database. After destroying an entry, we call JazzWiki. load("home"). To display Entry List and Tag List views, we make use of the previously mentioned renderList() helper method to generate a view’s content based on a number of records loaded from the database. These records are loaded using the Entry.all() and Tag.all() methods, respectively. Once the array of entries or tags is loaded, we call JazzWiki.renderList(), passing in the collection, as well as some minor formatting details. The Tags List page in particular loads all of its links with a “link:” prefix, and so each of these links individually loads a “tag page” which is a list of all entries associated with the given tag.

Should you find a bug in JazzRecord, it’s recommended that you submit a failing JSSpec test demonstrating the problem. Including JSSpec tests allows the development team to more easily diagnose and correct the problem without relying on the imprecision of the written word. JSSpec (http://jania.pe.kr/aw/moin.cgi/JSSpec) is a user-friendly test spec library, which JazzRecord uses to ensure that behaviors are maintained correctly from version to version. When submitting failing tests, include at a minimum one .js file with whatever tests are failing. Feel free to send a zip file of whatever related code is appropriate, such as model definitions or migrations run prior to this test. Tests can be submitted via email to thynctank@thynctank.com.

Jazz Summation That’s a lot of features packed into 72 kb, and we haven’t discussed all of it. We’ve quickly covered a lot of ground and you’d do well to look over the online docs and submit any questions or comments via the Google Group (http://groups.google.com/group/jazzrecord). Some ideas for expanding on this article’s project: • WikiNamespaces: Allow a top-level grouping of potentially like-named entries. This could easily be accomplished by storing entries with wiki_name of the concatenated namespace__entry_name.

References • http://jazzrecord.org – JazzRecord home page

• Running on AIR: With a few minor changes (setting JazzRecord.adapter to an instance of JazzRecord.AirAdapter, including AIRAliases.js in index.html, and building an appropriate application.xml file), the app should run almost unchanged in Adobe AIR, which demonstrates JazzRecord’s versatility and portability.

• http://attacklab.net/showdown/ – Showdown home page

Nick Carter is a Ruby on Rails engineer for RideCharge, where he specializes in front end and JavaScript. In his spare time he pretends to work on projects like JazzRecord and forthcoming JazzFusion, relying on former shoemaker’s elves to do the actual work. He’s been pretending to work now for five years professionally, and is enjoying it immensely. He occasionally finds time to sequence music in Ableton Live or get in a game or two on his Wii, but the elves have him bested there as well. This is his first article.

Upcoming versions of JazzRecord will have even more features; some of them mere conveniences and some of them huge chunks of code. The two biggest planned features include “specified cascading destroy” and asynchronous everywhere. The first of these will allow you to predetermine which, if any, records cause associated records

JSMag

8

2009 Sampler

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

• http://jania.pe.kr/aw/moin.cgi/JSSpec – JSSpec home page


The Red Pill Functional Programming in JavaScript

Robert Fischer

Functions are the basic building block of JavaScriptâ&#x20AC;&#x2122;s structure. This article will provide a brief introduction to some key ideas of functional programming in JavaScript, as well as demonstrate some of the lesser-known features of JavaScript functions. After reading this article, the reader will be able to manipulate functions in a much more direct way, including writing their own higher-order functions.

function funk(who, what) { print(who + "'s " + what + " has got the funk!"); } funk('Robert', 'code'); funk("Joe", 'towel'); // This prints out: // Robert's code has got the funk! // Joe's towel has got the funk!

Listing 1: The Basic Function Call

The average JavaScript programmer routinely overlooks one of the most powerful features of the language: function manipulation. Functions are used throughout JavaScript, including forming the basis of the object model. The libraries/frameworks provided to JavaScript regularly utilize anonymous functions in the form of callbacks: they look like function() { alert("Done!") }. These hooks have much more power than most people realize, because each method, function definition, and callback opportunity can change the execution of the application at the most basic level.

var myFunk = function(who, what) { print(who + "'s " + what + " has the funk!"); }; myFunk('Robert', 'code'); // This prints out: // Robert's code has the funk!

Listing 2: Function in a Box

Before we set out, a warning is probably in order. Like most things in JavaScript, the user is given all the power they want (and possibly more). As will be demonstrated, there are very few safety checks in JavaScript function calls, which can be both a blessing and a curse. This makes the re-writing and function mangling possibilities in JavaScript effectively endless, but this looseness can also make bugs tricky to track down.

function doIt(it) { it(); } doIt(function() { print("Sneaky!"); });

Basics of Functions

The body of a function (anonymous or otherwise) can refer to variables defined outside of that body, as demonstrated in Listing 4. This capturing of the surrounding variables is called enclosing its scope, and so the function is said to be a closure. Since normal JavaScript functions can refer to their outside scope, they are technically closures, but the word closure is often wrongly used to mean the same thing as anonymous function.

Even an elementary JavaScript developer is familiar with defining and executing the basic function call, as demonstrated in Listing 1. The name of a function, however, is purely optional: it is valid JavaScript to leave out the funk from the example above. Such a function is called an anonymous function, and is usually assigned to a variable (as in Listing 2) or passed directly into another function (Listing 3). When a variable references an anonymous function, the variable can be called as if it were a function â&#x20AC;&#x201C; so storing a function into the it variable means that it() calls the stored function.

2009 Sampler

9

JSMag

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

Listing 3: Function Without a Box


is nothing particularly tricky to implement a callback: it’s simply a function call at a particular point. In Listing 6, before and after are both callbacks, executed before and after the printing, respectively.

var iExist = true; function checkExist() { return iExist; } var anonCheckExist = function() { return iExist; };

function printWithEvents(value, before, after) { before(); print(value); after(); } printWithEvents("Print me!", function() { print("Before the print."); }, function() { print("After the print."); } ); // This prints out: // Before the print. // Print me! // After the print.

Listing 4: Functions as Closures Depending on what other languages you know, it may surprise you that this closure behavior in JavaScript captures the variables in the surrounding scope, not the values. This is a common source of bugs, and something to guard against: if a function refers to a variable, and that variable is later assigned a new value, then the new value is used when that function is executed. For a demonstrating of that, see Listing 5. In that listing, “But this is printed out” makes it to the screen, even though variable is set to “Initial value” at the point when “toDo” is declared.

Listing 6: Callback Pattern As shown in Listing 2 and Listing 6, an anonymous function can be executed by another function. But there is no reason we must limit ourselves to calling that function only once: the function can be called many times (as in Listing 7), and even passed different arguments each time it is called (as in Listing 8).

var variable = "Initial value"; var toDo = function() { print(variable); }; variable = "But this is printed out"; toDo(); // This prints out: // But this is printed out

function threeTimes(it) { it(); it(); it(); } threeTimes(function() { print("This was run."); }); // This prints out: // This was run. // This was run. // This was run.

Listing 5: Function Carries Its Scope With It At this point, we have reached the proficiency of most hobbyist JavaScript developers and many professionals. Even this basic level of functionality provides a lot of power to the JavaScript language. The real power and fun of functions, however, come when we start to consider higher-order functions.

Up to this point, our higher-order functions have simply consumed other functions; they accepted functions as arguments and called them at the appropriate time and with the appropriate arguments. Yet functions are simply values, and so can be returned. Listing 9 demonstrates how this works in JavaScript at its most basic level: the printer function takes an argument, and returns a function that prints out a common prefix followed by that argument. The printer function is then used to generate the before and after callbacks for the printWithEvents function we saw in Listing 6.

Higher-Order Functions A function that works on another function is called a higher-order function. We already saw one of these before: the doIt function defined in Listing 2. When working with higher-order functions, the idea is to build the One Function to Rule Them All: instead of applying series of functions to data in order to get the intended result, the functions themselves are modified until a single function call is defined that can turn the input into the intended result. This style of programming is called functional programming due to its emphasis on function manipulation, and JavaScript provides solid support for it. The most familiar use of higher-order functions for novice JavaScript developers is callbacks. The idea with a callback is to pass in an anonymous function which is executed in a particular circumstance: for instance, the jQuery and Prototype frameworks both use callbacks as a key part of their AJAX handling. Yet there

JSMag

10

2009 Sampler

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

Listing 7: Function That Takes a Function


function threeTimesCounting(it) { it("1st"); it("2nd"); it("3rd"); } threeTimesCounting(function(val) { print("This is the " + val + " time being run"); }); // This prints out: // This is the 1st time being run // This is the 2nd time being run // This is the 3rd time being run

/* 1 */ function prefixPrinter(prefix) { /* 2 */ var label = ", currently on : "; /* 3 */ return function(arg) { print(prefix + label + arg); }; /* 4 */ } /* 5 */ function oneToThreeTimes(it) { /* 6 */ it(1); it(2); it(3); /* 7 */ } /* 8 */ var robertIsCounting = "Robert is counting"; /* 9 */ oneToThreeTimes(prefixPrinter(robertIsCountin g)); // This prints out: // Robert is counting, currently on : 1 // Robert is counting, currently on : 2 // Robert is counting, currently on : 3

Listing 8: Function That Takes a Function and Calls It With An Argument This technique demonstrates a wild new way to meta-program: functions that can generate other functions. These functions are called generators or template functions.

Listing 10: Mix and Match Scopes By this point, it should be clear that working with functions at a higher level will require a unique set of techniques and tools. Our code examples so far have been painfully unabstracted; the most obvious is that our higher-order functions have hard-coded the number of arguments required, which significantly reduces flexibility. This is where the flexibility of JavaScript comes in.

function printer(arg) { return function() { print("This is some common prefix: " + arg); }; } var beforePrinter = printer("Before the run."); var afterPrinter = printer("After the run."); printWithEvents("Print me!", beforePrinter, afterPrinter); // This prints out: // This is some common prefix: Before the run. // Print me! // This is some common prefix: After the run.

Functions as Objects Although its higher-order function standard library is generally limited, JavaScript does provide some built-in higher order tools. These tools are attached to the Function class, which all functions implement: see Listing 11 for proof. Two of the most straightforward tools in the class are the name and length properties, which return the name of the function and the number of declared arguments. These are demonstrated in Listing 12.

Listing 9: A Function Returning a Function to Remove Duplicate Code In Listing 9, the generators were used to extract common code in our callbacks. Generators can als be used to mix and match different variables from different scopes. To see how this works, see Listing 10: due to the complexity of that code listing, inline comments are provided on the left to number the lines.

function nop() { /* Do nothing */ } print(typeof(nop)); print(typeof(function() { /* Do nothing */ })); // This prints out: // function // function

Listing 10 is fairly sophisticated, so let’s take it piece by piece.

Although the name and length of the function are useful, the key higher order tools JavaScript provides are the call and apply methods. Both of these methods execute the function, but call expects the arguments for the function listed out directly, while apply expects the arguments for the function as a array. In both the call and apply methods, the first argument is the value to assign to this inside of the function – this first argument is a way to implement some very advanced techniques with objects, including hijacking a method off of one object for another (as we will see

• The function oneToThreeTimes takes a function, and calls it three times: once with the argument 1, once with the argument 2, and once with the argument 3 (all on line 6). • On line 9, we use prefixPrinter to generate the function that is passed into oneToThreeTimes. • By the time code execution reaches the print in line 3, we have distinct variables from three distinct scopes, a feat made possible by the power of higher order functions.

2009 Sampler

11

JSMag

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

Listing 11: Proving the Type of Functions and Anonymous Functions

• The generator function prefixPrinter defined on lines 1 through 4 takes a prefix as an argument. On line 3, it returns a function that prints the prefix (prefix), followed by label (label), followed by whatever argument is provided (arg).


below). If left as null, the this variable is set to the “global” object, which represents the top level of the JavaScript program. For a basic example of the call and apply methods, see Listing 13.

tract out all elements of arguments beginning with the one at index 0. (Also note that the value of printManyArgs.length is 0, since length provides the number of declared arguments.)

function printArgCount(func) { print(func.name + " expects " + func.length + " arguments"); } printArgCount(add); // prints "add expects 2 arguments" printArgCount(function(foo,bar,baz) { }); // prints " expects 3 arguments"

threeArgs.call(null, 1,2,3,4); threeArgs.apply(null, [1,2,3,4]); threeArgs(1,2,3,4,5); threeArgs(1,2); // This prints out: // this[[object global]] arg1[1] // this[[object global]] arg1[1] // this[[object global]] arg1[1] // this[[object global]] arg1[1] // arg3[undefined]

Listing 12: Determining the Number of Arguments for a Function

Listing 14: Calling a 3-Argument Function with 2,4, or 5 Arguments

function threeArgs(arg1, arg2, arg3) { print("this[" + this + "] arg1[" + arg1 + "] arg2[" + arg2 + "] arg3[" + arg3 + "]"); } threeArgs.call(null, 1, 2, 3); threeArgs.apply(null, [1, 2, 3]); threeArgs.call(0, 1, 2, 3); threeArgs.apply(0, [1, 2, 3]); // This prints out: // this[[object global]] arg1[1] arg2[2] arg3[3] // this[[object global]] arg1[1] arg2[2] arg3[3] // this[0] arg1[1] arg2[2] arg3[3] // this[0] arg1[1] arg2[2] arg3[3]

function printManyArgs() { var args = [].splice.call(arguments, 0); print(args.join(" ")); } printManyArgs("Robert", "is", "being", "sneaky");

Listing 15: Explicit Arguments Access Unfortunately, that is about the extent of the higher-order function utilities provided by the standard library of JavaScript. In the next section, we will create own useful higher-order function utilities so that we can work with functions at a more abstract level.

Listing 13: Call vs. Apply Static typing afficianadoes may be somewhat dismayed to know that there are no bounds checks on either call or apply: this is one of the points where JavaScript sacrifices safety in favor of flexibility. The reason is because there are no bounds checking on any functions at all in JavaScript – no matter what the method may be apparently declared to handle, the function may be called with as many or as few arguments as the user desires. This kind of wonton disregard for the API is demonstrated in Listing 14.

The most basic higher-order function utility is called curry. Basically, all curry does is fix the first argument of a function and leave the rest of the arguments open to be set later. This is useful because it can change a function that takes two or three arguments into a function that takes no arguments, which is what is expected for callbacks. It can also be used to generate a specific form of a more general-case function, such as the addTwo specification of add demonstrated in Listing 16. In that listing, the same multiple-scope generator trick we saw back in Listing 10 is used to store the first argument to a function, leaving the second argument open to be specified at a later time. This curry has a number of striking limitations, though. For one thing, it only works on functions with two arguments. For another, it can only curry one variable at a time. Although this is theoretically acceptable (indeed, it’s the basis of an entire computational theory called lambda calculus), it is inefficient and verbose. A better solution would be to “curry” multiple arguments onto functions with arbitrary argument lengths. A “curry” of multiple arguments is technically called partial function application, although that is a pretty long method name, so we’ll stick to curry. A generic curry is implemented in listing 17.

12

2009 Sampler

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

Higher-Order Function Utility: Curry

As seen in Listing 14, unspecified arguments are left as an undefined value. It seems as though extra arguments are simply disregarded, but this is not true: they can be accessed through an “array-like” implicit local variable called arguments. By accessing this variable, even unnamed arguments in the functional call can be used in JavaScript. Listing 15 demonstrates that kind of function, as well as a hack around a higher-order JavaScript annoyance: the “array-like” arguments variable isn’t very array-like at all, so to do anything more than indexing into arguments, it needs to be converted to an array. Although both Prototype and jQuery offer an array conversion utility (probably for precisely this reason), the native idiom to go from arguments to an array is to hijack splice. Remember that the first argument to call specifies the value of this, so by passing arguments in there, we can get splice to ex-

JSMag

arg2[2] arg3[3] arg2[2] arg3[3] arg2[2] arg3[3] arg2[2]


function curryBinary(func, value) return function(arg) { return func(value, arg); } } function add(left, right) { return left + right; } var addTwo = curryBinary(add, 2); print(addTwo(1)); // prints print(addTwo(2)); // prints print(addTwo(3)); // prints

{

function curry() { var myThis = this; var func = arguments[0]; var expected_args = func.length; var args = [].splice.call(arguments, 1); return function() { var myArgs = [].concat(args); myArgs = myArgs.concat([].splice.call(arguments, 0)); if(expected_args <= myArgs.length) { return func.apply(myThis, myArgs); } else { return curry(func, myArgs); } } } var addTwoClean = curry(add, 2); print(addTwoClean(1)); // prints 3 print(addTwoClean(2)); // prints 4 print(addTwoClean(3)); // prints 5 var addTwoAndOne = curry(addTwoClean, 1); print(addTwoAndOne()); // prints 3

3 4 5

Listing 16: Basic Currying There is less going on in Listing 17 than the number of lines would imply. Basically, what curry does is store off the current value of this, the function being curried (arguments[0]), the expected number of arguments for the function (func.length), and the arguments that were passed in (args). It then generates a function, which takes in additional arguments. If the total number of arguments equal or exceed the number of arguments expected, func is executed with the total arguments and the original this. If the number of arguments is still less than the number expected, the new arguments are curried into the front as well. Most of the additional noise is to prevent values from bleeding over between different executions (a common problem with imperative languages when performing functional programming stunts), and dealing with the â&#x20AC;&#x153;array-likeâ&#x20AC;? (but not array) nature of arguments.

Listing 17: Generic Curry function divide(numerator, denominator) { return numerator / denominator; } function flipTwoArgs(func) { return function(first,second) { return func(second,first); }; } function divideBy(denominator) { return curry(flipTwoArgs(divide), denominator); } var divideByTwo = divideBy(2); print("Divide 2 by 2:" + divideByTwo(2)); // prints 1 print("Divide 4 by 2:" + divideByTwo(4)); // prints 2 print("Divide 6 by 2:" + divideByTwo(6)); // prints 3

Higher-Order Function Utility: Flip A major apparent limitation of curry is that can only set the first argument. Yet a little higher order magic can quickly solve this problem. Recall that the functional programming mantra is to make the function work with data (not the other way around): if the arguments are in the wrong order, then why not simply change the order of the arguments?

Listing 18: Changing Argument Order

This trick is a common one in functional programming, and is called flip. It is most commonly used in conjunction with curry, such as in Listing 18.

2009 Sampler

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

Again, we have a situation where it is very easy to implement the higher-order function when the argument length is only two. In actuality, though, flip is very easy in the abstracted case, as well: after all, we already have an array of the arguments, and flipping is simply swapping the first two arguments in that array. An implementation of the abstracted implementation, along with a more involved demonstration of flip and curry, is in Listing 19.

13

JSMag


For a ready-made set of higher-order utilities, see the Functional JavaScript library at http://osteele.com/sources/JavaScript/ functional/.

function flipFirstTwoArgs(func) { return function() { var tmp = arguments[0]; arguments[0] = arguments[1]; arguments[1] = tmp; return func.apply(this, arguments); } } function divideAndAdd(numerator, denominator, additive) { return (numerator/denominator)+additive; } var divideByTwoAddThree = curry(flipFirstTwoArgs( divideAndAdd), 2); divideByTwoAddThree = curry(flipFirstTwoArgs( divideByTwoAddThree), 3); print(divideByTwoAddThree(2)); // prints 4 print(divideByTwoAddThree(4)); // prints 5 print(divideByTwoAddThree(6)); // prints 6

function fold(collection, func, initial) { var args = [].splice.call(collection, 0); var current = initial; for(var i = 0; i < args.length; i++) { current = func(current, args[i]); } return current; } function sum() { return fold(arguments, function(a,b) { return a + b }, 0); } print(sum(1,2,3,4,5)); // prints 15

Listing 19: Changing Argument Order in the General Case

function findAll(collection, test) { var doCheck = function(found,toCheck) { if(test(toCheck)) { found.push(toCheck); } return found; }; return fold(collection, doCheck, []); } print(findAll([1,2,3,4,5], function(it) { return it % 2 == 0; })); // prints 2,4

Higher-Order Function Utility: Fold (Left) Brian Hurt (who blogs with the author at Enfranchised Mind) likes to say that if he could only take one higher-order function to a desert island with him, he would take fold. Fold is a strange beast, even among higher-order functions: it takes a collection, a function, and an initial value. Fold then rolls its way through the collection with a running value: on each element, it executes the function with the current running value and the current element, and takes the result to be the new running value. While this seems complicated and somewhat arbitrary, it is actually incredibly powerful. Once fold is in a programmer’s repertoire, that programmer will never need to iterate over a list again. Furthermore, every other collection operation method can be shown to be a special case of fold.

Robert Fischer is a web application architect, technical leader, and trainer who consults independently as Smokejumper Consulting. He specializes in functional programming and web application persistence layers, and his fondness for programming language theory borders on the unhealthy. His open source projects include JConch (a Java concurrency library), Autobase (a Grails database migration plugin), and set of Perl utilities for text-based ciphers. He currently resides in Durham, North Carolina, and is enrolled part-time in graduate school at Duke University. His most recent business project is Groovy and Grails training in conjunction with GroovyMag.

Fold in JavaScript, along with some examples, is demonstrated in Listing 20. This particular version of fold moves from the beginning of the list to the end and is referred to as a fold left, under the Greco-Latin assumption that the beginning of the list is at the left and the function “moves” to the right. The version of fold that moves from the end of the list to the beginning is referred to as a fold right.

Conclusion The power of higher order functions cannot be understaded, and JavaScript provides some basic capabilities to leverage them. The general succinctness and power of JavaScript really shines at this higher level, although there are a few rough edges, as noted.

JSMag

14

2009 Sampler

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

Listing 20: Fold Left


Using Object Literals to Organize Your Features Rebecca Murphey

When you move beyond simple snippets of jQuery and start

var myObjectLiteral = { myBehavior1 : function() { /* do something */ },

developing more complex user interactions, your code can quickly become unwieldy and difficult to debug. This article shows you how to start thinking about these interactions in terms of the bits of behavior the feature comprises, using the object literal pattern.

myBehavior2 : function() { /* do something else */ } };

In the past few years, JavaScript libraries have given beginning developers the ability to add elaborate interactions to their sites. Some, like jQuery, have a syntax so simple that people with zero

Listing 1

programming experience can quickly add bells and whistles to their pages.

As an artificially simplistic example, suppose you had the jQuery shown in Listing 2 for showing and hiding content when a list item was clicked.

Adding all those bells and whistles, even some pretty elaborate ones, seems to be just a few Google searches away. A copy here, a paste there, a plugin or a few dozen lines of custom code — the cliBut wait. Now the requirements have changed. Now the thing that needed to work for three elements needs to work for ten. Now your code needs to be reused for a slightly different application where all the IDs are different. We’ve all seen the snippets that make jQuery (and other libraries) look dead-simple. What those snippets leave out — and hey, they’re just snippets, right? — is how to design your code when your needs go beyond dropping in a plugin or doing some show() and hide().

Listing 2

Introducing the Object Literal pattern

Simple enough, and yet even in this example there are several things you might want to change later — for example, the way you determine the URL for loading the content, the destination of the loaded content, or the show and hide behavior.

The object literal pattern offers a way to organize code by the behaviors it comprises. It’s also a means to keep your code from “polluting the global namespace,” which is a good practice for all projects and imperative for larger ones. It forces you to think at the

An object literal representation of the feature cleanly separates these aspects. It might look like Listing 3.

outset about what your code will do and what pieces need to be in place in order for you to do it. An object literal is a way to encapsulate related behaviors, as shown in Listing 1.

2009 Sampler

15

JSMag

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

$(document).ready(function() { $('#myFeature li'). append('<div/>'). each(function() { $(this).find('div'). load('foo.php?item=' + $(this).attr('id')); }). click(function() { $(this).find('div').show(); $(this).siblings().find('div').hide(); }); });

ent is duly impressed, and you’re adding jQuery to your resume.


An in-depth example

var myFeature = { config : { $wrapper : $('#myFeature'), container : 'div', urlBase : 'foo.php?item=' },

Our mission will be to create a UI element that features multiple pieces of content divided into several sections. Clicking on a section will show a list of items in the section; clicking on an item in the left nav will show the item in the content area. Whenever a section is shown, the first item in the section should be shown. The first section should be shown when the page loads.

init : function(config) { $.extend(myFeature.config, config); myFeature.config.$wrapper.find('li'). each(function() { myFeature.getContent($(this)); }). click(function() { myFeature.showContent($(this)); }); },

It will look something like Figure 1.

Step 1: Crafting the HTML Writing good semantic HTML is a crucial prerequisite to writing good JavaScript, so let’s start by thinking about what the HTML for something like this might look like. The HTML should: • Make sense (and work) when JavaScript isn’t available.

buildUrl : function($li) { return myFeature.config.urlBase + $li.attr('id'); },

• Provide a predictable DOM to which we can attach JavaScript. • Avoid unnecessary IDs and classes (and you might be surprised by how few are necessary).

getContent : function($li) { $li.append(myFeature.config.container); var url = myFeature.buildUrl($li); $li.find(myFeature.config.container).load(url); },

With those guidelines in mind, we’ll start with the HTML in Listing 4. Note that we haven’t included any markup to display the section navigation or the item navigation; those pieces will be added by jQuery since they will only work with jQuery; non-JavaScript users will get nice semantic markup. (If there’s anything surprising or confusing in that HTML, now would be a good time to read up on POSH (plain-old semantic HTML) and progressive enhancement.)

showContent : function($li) { $li.find('div').show(); myFeature.hideContent($li.siblings()); }, hideContent : function($elements) { $elements.find('div').hide(); } };

<div id="myFeature"> <ul class="sections"> <li> <h2><a href="/section/1">Section 1</a></h2> <ul> <li> <h3><a href="/section/1/content/1">Section 1 Title 1</a></h3> <p>The excerpt content for Content Item 1</p> </li>

$(document).ready(function() { myFeature.init(); });

Listing 3 Because the initial example was incredibly simplistic, the object literal incarnation is longer. Truth be told, the object literal method generally won’t save you lines of code. What it will save is headaches. By using an object literal, we’ve broken our code into its logical parts, making it easy to locate the things we might want to change down the road. We’ve made our feature extendable, by providing the ability to pass in overrides to the default configuration. And, we’ve done some limited self-documentation — it’s easy to see at a glance what the feature does. As your needs grow beyond the simplicity of this example the benefits of the structure will become clearer, as you’ll see below.

</ul> </li> <!-- one <li> for each section --> </ul> </div>

Listing 4: Full version at http://www.rebeccamurphey.com/jsmag/ object-literal/code-examples/object-literal-html.html

Note: For an excellent primer on objects, properties, and methods, check out Object-Oriented JavaScript: Create scalable, reusable highquality JavaScript applications and libraries by Stoyan Stefanov. You may also want to read up on JSON (JavaScript Object Notation).

JSMag

16

2009 Sampler

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

<!-- one <li> for each content item -->


var myFeature = { 'config' : { }, 'init' : function() { }, 'buildSectionNav' : function() { }, 'buildItemNav' : function() { }, 'showSection' : function() { }, 'showContentItem' : function() { } };

Figure 1 Listing 5 'config' : { // default container is #myFeature 'container' : $('#myFeature') },

Step 2: Scaffolding the Object My first step in creating an object for a feature is to create “stubs” within the object. Stubs are basically placeholders; they’re the outline for the feature we’re going to build. Our object will have the following methods:

'init' : function(config) { // provide for custom configuration via init() if (config && typeof(config) == 'object') { $.extend(myFeature.config, config); }

• myFeature.init() will run on $(document).ready(). It will turn the semantic HTML we start with into a JavaScript-enabled user interface. • myFeature.buildSectionNav() will be called by myFeature. init(). It will take a jQuery object that contains all of the sections from the semantic HTML and use those sections to build the top navigation. It will bind the click handlers to the top navigation items so that clicking on them will show the appropriate section.

// create and/or cache some DOM elements // we'll want to use throughout the code myFeature.$container = myFeature.config.container;

• myFeature.buildItemNav() will be called by myFeature. showSection(). It will take a jQuery object that contains all of the items associated with the section from the semantic HTML, and use them to build the side navigation. It will bind the click handlers to the side navigation items so that clicking on them will show the appropriate content.

myFeature.$section_nav = $('<ul/>'). attr('id','section_nav'). prependTo(myFeature.$container);

• myFeature.showSection() will be called when the user clicks on an item in the top navigation. It will use the navigation item that’s clicked on to figure out which section to show from the semantic HTML.

myFeature.$content = $('<div/>'). attr('id','content'). insertAfter(myFeature.$item_nav);

myFeature.$sections = myFeature.$container. // only select immediate children! find('ul.sections > li');

myFeature.$item_nav = $('<ul/>'). attr('id','item_nav'). insertAfter(myFeature.$section_nav);

• myFeature.showContentItem() will be called when the user clicks on an item in the side navigation. It will use the navigation item that’s clicked on to figure out which content item to show from the semantic HTML.

// build the section-level nav and // "click" the first item myFeature.buildSectionNav(myFeature.$sections); myFeature.$section_nav.find('li:first').click(); 1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

// hide the plain HTML from sight myFeature.$container.find('ul.sections').hide();

We’ll also make room for a configuration property, myFeature. config, which will be a single location for setting default values rather than scattering them throughout the code. We’ll include the ability to override the defaults when we define the myFeature. init() method (see Listing 5).

// make a note that the initialization // is complete; we don't strictly need this // for this iteration, but it can come in handy myFeature.initialized = true;

}

Listing 6

2009 Sampler

17

JSMag


'buildSectionNav' : function($sections) {

'buildItemNav' : function($items) {

// iterate over the provided list of sections $sections.each(function() {

// iterate over the provided list of items $items.each(function() {

// get the section var $section = $(this);

// get the item var $item = $(this);

// create an <li> element // for the section navigation $('<li/>').

// create an <li> element for the item navigation $('<li/>').

// use the text of the first h3 // in the item as the text for the // item navigation text($item.find('h3:first').text()).

// use the text of the first h2 // in the section as the text for // the section navigation text($section.find('h2:first').text()). // add the <li> to the section navigation appendTo(myFeature.$section_nav).

// use data() to store a reference // to the original section on the // newly-created <li> data('section', $section).

// use data() to store a reference // to the original item on the // newly-created <li> data('item', $item).

});

// bind the click behavior // to the newly created <li> // so it will show the section click(myFeature.showSection);

// bind the click behavior // to the newly created <li> // so it will show the content item click(myFeature.showContentItem);

// add the <li> to the item navigation appendTo(myFeature.$item_nav).

}); } }

Listing 7

Listing 8

Step 3: The Code

Step 4: Changing Requirements

Once we’ve built this skeleton, it’s time to start coding. Let’s start by setting up a simple myFeature.config object and writing the myFeature.init() method, as shown in Listing 6.

No project is complete without some last-minute change in the requirements, right? Here’s where the object literal approach really shines by making it quick and fairly painless to implement lastminute changes.

Next we’ll create the myFeature.buildSectionNav() method, as shown in Listing 7. Next we’ll create the myFeature.buildItemNav() method, as shown in Listing 8.

Do you find the simple show/hide of the content area boring? See Listing 11.

Finally, we’ll write the methods for showing sections and content items, as shown in Listing 9.

Do you need more flexibility? There’s a lot more you can configure (and therefore override) if you really want to make this flexible. (See Listing 12.) For example, you can use myFeature.config to specify how to find and process the title text for each item in the left nav. Once you’ve added defaults to the config object, you can override them when you call myFeature.init():

All that’s left to do is to call the myFeature.init() method: $(document).ready(myFeature.init);

You can see the whole thing (including a little CSS to make it presentable) at: http://www.rebeccamurphey.com/jsmag/object-literal/. The JavaScript is at http://www.rebeccamurphey.com/jsmag/objectliteral/js/object-literal.js.

JSMag

$(document).ready(function() { myFeature.init({ 'itemNavSelector' : 'h2' }); });

18

2009 Sampler

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

What if we need to get the content item excerpts via AJAX instead of from the HTML? Assuming the backend is set up to handle it, try the code in Listing 10.


'showSection' : function() {

var myFeature = {

// capture the <li> that was clicked on var $li = $(this);

'config' : { 'container' : $('#myFeature'),

// clear out the left nav and the content area myFeature.$item_nav.empty(); myFeature.$content.empty();

// configurable function for getting // a URL for loading item content 'getItemURL' : function($item) { return $item.find('a:first').attr('href'); }

// get the jQuery section object from the original HTML, // which we stored using data() during myFeature. buildSectionNav() var $section = $li.data('section');

}, 'init' : function(config) { // stays the same },

// mark the clicked <li> as current // and remove the current marker from its siblings $li.addClass('current'). siblings().removeClass('current');

'buildSectionNav' : function($sections) { // stays the same },

// find all of the items related to the section var $items = $section.find('ul li');

'buildItemNav' : function($items) { // stays the same },

// build the item nav for the section myFeature.buildItemNav($items); // "click" on the first <li> in the section's item nav myFeature.$item_nav.find('li:first').click();

'showSection' : function() { // stays the same },

},

'showContentItem' : function() {

'showContentItem' : function() {

var $li = $(this); $li.addClass('current'). siblings().removeClass('current');

var $li = $(this); // mark the clicked <li> as current // and remove the current marker from its siblings $li.addClass('current'). siblings().removeClass('current');

var $item = $li.data('item'); var url = myFeature.getItemURL($item); // myFeature.$content.html($item.html()); myFeature.$content.load(url);

// get the jQuery item object from the orignial HTML, // which we stored using data() during // myFeature.buldContentNav() var $item = $li.data('item'); // use the item's HTML to populate // the content area myFeature.$content.html($item.html());

} };

Listing 10 1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

}

Listing 9

2009 Sampler

19

JSMag


var myFeature = {

var myFeature = { 'config' : { 'container' : $('#myFeature'),

'config' : { 'container' : $('#myFeature'),

// configurable fadeIn and fadeOut speeds 'fadeOutSpeed' : 300, 'fadeInSpeed' : 300 },

// specify the default selector // for finding the text to use // for each item in the item nav 'itemNavSelector' : 'h3',

'buildSectionNav' : function($sections) { // stays the same },

// specify a default callback // for "processing" the jQuery object // returned by the itemNavText selector 'itemNavProcessor' : function($selection) { return 'Preview of ' + $selection.eq(0).text(); } },

'buildItemNav' : function($items) { // stays the same },

'init' : function(config) { // stays the same },

'showSection' : function() { // stays the same },

'buildSectionNav' : function($sections) { // stays the same },

'showContentItem' : function() {

'buildItemNav' : function($items) {

var $li = $(this); $li.addClass('current'). siblings().removeClass('current');

$items.each(function() { var $item = $(this);

'init' : function(config) { // stays the same },

// use the selector and processor // from the config // to get the text for each item nav var myText = myFeature.config.itemNavProcessor( $item.find(myFeature.config.itemNavSelector) );

var $item = $li.data('item'); // myFeature.$content.html($item.html()); myFeature.$content.fadeOut( myFeature.config.fadeOutSpeed, function() { myFeature.$content.html($item.html()).fadeIn( myFeature.config.fadeInSpeed ); } );

$('<li/>'). // use the new variable // as the text for the nav item text(myText). appendTo(myFeature.$item_nav). data('item', $item). click(myFeature.showContentItem); }); },

} };

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

'showSection' : function() { // stays the same },

Listing 11

'showContentItem' : function() { // stays the same } };

Listing 12

JSMag

20

2009 Sampler


Beyond the scope of this article (but also interesting to contemplate

• More on the jQuery data() method: http://docs.jquery.com/ Data

and much easier with the object literal pattern) is this: making the back button retrace your path through the tabs using the jQuery history plugin. I leave it as an exercise for the reader.

• More praise for the object literal pattern: http://www.wait-tilli.com/2006/02/16/show-love-to-the-object-literal/

Conclusion

• The jQuery History plugin: http://www.mikage.to/jquery/ jquery_history.html

If you’ve stepped through the code examples in this column, you

• An interesting application of the object literal pattern for architecting code for multiple page types: http://paulirish. com/2009/markup-based-unobtrusive-comprehensive-domready-execution/

should have a basic understanding of the object literal pattern and how it might prove useful to you as you develop more complex features and interactions. You also have access to some code that you can use to build on this basic foundation.

• Even more about the benefits of object literals: http://www. dustindiaz.com/json-for-the-masses/

I encourage you to give this pattern a try the next time you find yourself writing more than a few lines of JavaScript — it forces you

• More on POSH (Plain Old Semantic HTML) http://www.456bereastreet.com/archive/200711/ posh_plain_old_semantic_html/

to think through the elements and behaviors that make up a complex feature or interaction. Once you become proficient, it provides a sturdy foundation for extending and reusing your code.

Rebecca Murphey is a consultant specializing in front-end architecture, including HTML, CSS and jQuery. You can reach her at rebecca@rebeccamurphey.com, find her on Twitter @rmurphey, or visit her website at http://www.rebeccamurphey.com.

Learn More • Object-Oriented JavaScript: Create scalable, reusable high-qual-

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

ity JavaScript applications and libraries by Stoyan Stefanov

2009 Sampler

21

JSMag


JavaScript Community News Matt Henry

JSUnitTest, newjs, JavaScript Autotest

This was an amazing month for JavaScript unit testing. There’s a couple of new unit testing utilities out that really raised the bar, which we’ll go over in depth. We’ve also gotten some excellent insights into performance, as well as a few new toys for mobile application developers and Mac users.

Yes, the JavaScript unit testing library market is starting to get crowded, but there is a new contender, and it’s one worth checking out. JSUnitTest (not to be confused with JSUnit — see what I mean about the market being crowded?) is a brand new testing library created by Dr. Nic Williams. Dr. Nic is a heavyweight in the Ruby community, but he is making a very strong first showing in the JavaScript world with this new testing utility, and a couple of extremely useful companion libraries.

Test Swarm John Resig, the author of jQuery (and Dromaeo, and FireUnit, and ...), is in the process of creating a new JavaScript testing utility he’s calling Test Swarm (http://testswarm.com/). The motivation for the project came from the difficulty of having to run jQuery’s large test suite in multiple environments before and after every commit. The problem of scaling the heavily time- and resource-intensive process caused Resig to consider ways to distribute the testing workload, and that is precisely what Test Swarm does.

JSUnitTest (http://jsunittest.com/) is an adaptation of Prototype’s unittest.js that has been decoupled from Prototype. It isn’t remarkably different from several of the other JavaScript unit testing frameworks out there, but it does have a nice display for your test results, and it’s library agnostic.

As if that weren’t enough, Dr. Nic has also made a really slick JavaScript port of Autotest. Autotest (part of the ZenTest library) is a staple of my Ruby development workflow, and I’ve long lamented the lack of a similar tool for JavaScript. Autotest works by running in the background while you’re doing your development, and then running your whole test suite whenever you save a change to your source code so you can immediately see the effect that that change had on your application’s functionality (provided you have sufficient test coverage, of course). It’s an invaluable tool, and one that I’m thrilled to see being ported to JavaScript. The JavaScript version works in essentially the same way as its Ruby cousin, except the test results are reported in a browser window rather than in the terminal (or a Growl notification). Dr. Nic says that it works best in Safari

Currently, the only data Test Swarm collects from client machines is the user agent (along with test results, obviously), but Resig is planning to start gathering other useful data about the platforms that will be running the tests, so there is a great deal to look forward to. As I write this, Test Swarm remains in pre-alpha, but Resig should be contacting alpha testing volunteers any day now (possibly even before this publication goes to press). Hopefully, the JavaScript community at large will be benefitting from crowdsourcing their unit tests with Test Swarm in the very near future.

JSMag

22

2009 Sampler

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

But wait, there’s more! Newjs (http://newjs.rubyforge.org/) is a tool that gives you Rails-like code generation for your JavaScript unit tests. When you start a new project, running newjs will automatically generate a test harness (using JSUnitTest) along with basic HTML pages that will serve as fixtures for your tests. Additionally, it includes tools to quickly package your code and make it available for others (on Rubyforge).

The way it works is that you will have your test suite on a server somewhere, and give Test Swarm the URL for your test runner. Test Swarm will then run your tests on a variety of client machines and then aggregate and report the results. Users will be able to opt in to making their machines available to run as Test Swarm clients in much the same way as they can with the Folding@Home or SETI@Home projects. So in addition to donating some cycles from your main development box, you can also help out by setting up the Test Swarm client on that old Win2k machine you have gathering dust above the garage.


PhoneGap

at the moment, but it’s meant to support all modern browsers. You can read much more about how it works here: http://drnicwilliams. com/2008/01/04/autotesting-JavaScript-in-rails/.

PhoneGap (http://phonegap.com/) is a new project from Nitobi (http://www.nitobi.com/) that allows web developers to build mobile applications with HTML, CSS, and JavaScript. PhoneGap works by passing through phone APIs into a browser view so that they can be accessed via JavaScript. This allows web developers to write mobile applications without touching a single line of proprietary, platform-specific code. Currently, the iPhone has the widest range of APIs exposed via PhoneGap, but Android and Blackberry are also supported to varying degrees. Ideally, as the project matures, it can become be a write once, run anywhere framework for mobile application development that uses only open web technologies. We can certainly all be encouraged by how far down that road the folks at Nitobi have already gone.

Now how much would you pay?

Reflows and Repaints are Killing Your Performance Does the performance of your DOM-manipulating code totally suck? Maybe it’s because of your CSS. Nicole Sullivan (aka Stubbornella) has written a detailed (and well researched & sourced) blog post on the dramatic performance hit your scripts can see when they cause a repaint or reflow (http://www.stubbornella.org/content/2009/03/27/reflows-repaints-css-performance-making-yourJavaScript-slow/), and how you can mitigate that somewhat with some careful front-end engineering.

JSTalk

Here are some of the nuggets that are more directly relevant to JavaScript developers:

Okay, one last Apple tidbit: Gus Mueller from Flying Meat Software (makers of VoodooPad and Acorn) has created JSTalk, a bridge between JavaScript and Cocoa that gives you an AppleScript-like programming interface for your Mac software, but one that allows you to use JavaScript to work your OSX magic. What is interesting about JSTalk when compared with other Cocoa bridges is that it allows you to write as much or as little Objective-C as you would like (which for me is none at all).

• In animations, speed should trump smoothness. Sullivan suggests animating elements in bigger increments, for instance 3px at a time rather than 1px at a time. While the effect might not appear as smooth, it won’t cause a CPU spike on the client machine that is doing the rendering, which would likely cause the animation to jump.

Check out Gus’s description of the project on his blog (http://gusmueller.com/blog/archives/2009/03/introducing_jstalk__an_alternative_to_applescript.html), and then grab the code from Github (http://github.com/ccgus/jstalk/tree/master).

• Add/remove classes as far down in the DOM as possible. As conscientious JavaScript developers, I’m sure that you’re all styling your dynamic objects by adding and removing classes that pull in CSS from external stylesheets and not by applying styles inline (and if you’re not, Sullivan suggests you start). But even doing that, you still need to be mindful of exactly which elements you’re manipulating the class of. Sullivan advises that you apply classes as far down in the DOM as possible. Changing classes causes a costly reflow, so the fewer elements that have to be involved in that reflow, the less of a performance drag you’ll incur.

Matt Henry is a Web Developer based in Durham, NC. He is passionate about standards-driven development with HTML, CSS and JavaScript on the front-end, and Ruby on the backend (Rails, Merb, Sinatra—it’s all good). He works with a great team at hesketh.com/ inc, and otherwise he’s at home with his fiancee Staci, and their two Schnauzers.

1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

There’s plenty more information in Sullivan’s blog post, and there are a ton of useful links to give you all of the background you’ll need on reflows and repaints in order to carefully evaluate the impact that they’re having on your JavaScript performance.

2009 Sampler

23

JSMag


1 copy licensed to katienazarova@gmail.com 07/16/2013 05:36:47 AM

/ for JavaScript professionals


Jsmag js0  
Advertisement
Read more
Read more
Similar to
Popular now
Just for you