Saturday, October 19, 2013

Closures, javascript and how

From the wiki article, a closure (computer science) is a function or reference to a function together with a referencing environment-- a table storing a reference to each of the non-local variables of that function.  

Closure-like constructs include callbacks and as such, are important in asynchronous programming.  Here is a simple example in PHP that uses a closure as a callback to compute the total price of a shopping cart by defining a reference table for the callback function and including variables tax and total:

<?php
// SOURCE: http://php.net/manual/en/functions.anonymous.php
// A basic shopping cart which contains a list of added products
// and the quantity of each product. Includes a method which
// calculates the total price of the items in the cart using a
// closure as a callback.
class Cart
{
const PRICE_BUTTER = 1.00;
const PRICE_MILK = 3.00;
const PRICE_EGGS = 6.95;
protected $products = array();
public function add($product, $quantity)
{
$this->products[$product] = $quantity;
}
public function getQuantity($product)
{
return isset($this->products[$product]) ? $this->products[$product] :
FALSE;
}
public function getTotal($tax)
{
$total = 0.00;
$callback =
function ($quantity, $product) use ($tax, &$total)
{
$pricePerItem = constant(__CLASS__ . "::PRICE_" .
strtoupper($product));
$total += ($pricePerItem * $quantity) * ($tax + 1.0);
};
array_walk($this->products, $callback);
return round($total, 2);
}
}
$my_cart = new Cart;
// Add some items to the cart
$my_cart->add('butter', 1);
$my_cart->add('milk', 3);
$my_cart->add('eggs', 6);
// Print the total with a 5% sales tax.
print $my_cart->getTotal(0.05) . "\n";
// The result is 54.29
?>


The concept of closures in javascript is important to understand because you might not even know you're using it.  If you write in coffee-script classes or do classical inheritance patterns in vanilla javascript or even write callbacks in general for asynchronous programming, you are probably using closures.  The following example is a starting point for classical inheritance in javascript.  This shows how to hide private variables.  It doesn't use "new" but the pattern is very similar.


function car() {
// Private Variable
var val = {
make : "generic",
model : "generic",
color : "generic"
};
// "new" instance
return {
setMake: function(newMake) {
make = newMake || "generic";
val.make = make;
},
getMake: function() {
return val.make;
},
setModel: function(newModel) {
model = newModel || "generic";
val.model = model;
},
getModel: function() {
return val.model;
},
setColor: function(newColor) {
color = newColor || "generic";
val.color = color;
},
getColor: function() {
return val.color;
},
self: function() {
return val;
}
}
}
// Create our instances
var juke1 = car();
var juke2 = car();
// Set make
juke1.setMake("nissan");
juke2.setMake("nissan");
// Set model
juke1.setModel("juke");
juke2.setModel("juke");
// Set color
juke1.setColor("red");
juke2.setColor("black");
// Cannot get private variable, cool!
juke1.val // undefined
juke2.val // undefined
// Use getter for access to private data
juke1.self() // Object {make: "nissan", model: "juke", color: "red"}
juke2.self() // Object {make: "nissan", model: "juke", color: "black"}
view raw carClass.js hosted with ❤ by GitHub

According to Effective Javascript: 68 Specific Ways To Harness The Power of Javascript, there are three essential facts regarding closures:
  • JavaScript allows you to refer to variables that were defined outside of the current function
  • Functions can refer to variables defined in outer functions even after those outer functions have returned
  • Closures can update values of outer variables

Knowing this, we can do some fun stuff in Node.JS with asynchronous programming.  With closures, we can pull a document collection from a NoSQL database, manipulate the results, and push it to an array stored via closure in the parent scope.

require './nosql'
require 'async'
# new results array. this will be available via closure
results = []
# Start the NoSQL connection
nosql.connect ()->
# Get the collection pointer
collection = nosql.getCollection 'collection'
# Find the documents
collection.find {}, (documents)->
# Create our iterator fn to be consumed by the async library
eachDocument = (doc, cb)->
# Do something to doc; add/remove/modify variables.
# Push it to the results array that is in a
# parent scope and available via closure.
results.push doc
async.forEach documents, eachDocument, ()->
# At this point, we have finished getting and dealing with documents.
# We can close the db and deal with the results.
nosql.close()
# If we were writing this in an express route, use res.send
res.send { success: true, results: results }


Hopefully you will use closures to your advantage, especially when developing in javascript, be it server side or client side or even in the database (Postgres with v8).


No comments:

Post a Comment