Archive for the ‘javascript’ Category

What is a closure in JavaScript?

Monday, January 3rd, 2011

Intro

There have been many attempts to answer this question in a succinct way, but I haven’t really been satisfied by them. Here’s my attempt at a (relatively) concise explanation.

This is adapted from a reply I posted on reddit which people seemed to have found useful.

Broad definition

Normally when people talk about closures in JavaScript, they’re talking about methods and properties that outlive the scope of their original function (more on that in a second), but actually the definition is a bit broader. A closure is how a function “closes over” (Crockford) its variables and creates a different scope for them out of the way of the global [window] scope. So an understanding of closures will require some understanding of scope, which is definitely a common stumbling block in first learning JavaScript.

Essentially, closures make this possible:

var a = 1;
function(){
  var a = 2;
  a; // 2 (functional scope)
};
a;  // 1 (global scope)

Variables that survive after function execution

But when people get excited about closures, they’re not really talking about the example above, but about the ability for functional variables to outlive their original functional scope:

var b = function() {
  var myPrivateVar = 'Foo';
  var myPublicVar = 'Bar';

  return myPublicVar;
};

b();  // 'Bar'
myPrivateVar;  // ERROR (not defined, because it was only defined in functional scope and is trying to be accessed from the global [window] scope)
myPublicVar;   // ERROR (not defined)

But note that the original method name (myPublicVar) isn’t available – but the value IS available from what we exposed to the global scope through the variable ‘b’.

Closures and the Module Pattern

How is this useful? This turns out to be the foundation for the Module Pattern in JavaScript – the building block of modern JavaScript applications. They’re in essence a glorified version of the block of code above, with the purpose of hiding the function’s private variables (this comes by default when declaring variables with the ‘var’ keyword in functions), and exposing public variables. And note that because functions are first class in JavaScript, those variables can even be references to functions themselves!

So in essence this is the module pattern, with both private and public properties and methods:

var myAPI = (function() {
  var privateProperty = 'Foo';
  var publicProperty = 'Bar';

  var privateMethod = function() {
    alert('I can only be executed from the scope of myAPI');
  };

  var publicMethod = function() {
    alert('I am publicly accessible (through the global scope) because a reference to publicMethod is returned by myAPI');
  };

  // set up an object whose own property names (on the left) match the references to the internal, functionally-scoped methods (on the right)
  var publicStuff = {
    publicProperty: publicProperty,
    publicMethod: publicMethod
  };

  // return our public object (myAPI is now equal to this object)
  return publicStuff;
})();   // immediately execute myAPI as a function, which returns an object that contains pointers to stuff in myAPI, which is exposed through myAPI.x, myAPI.y, etc

By the time we reach the last line of the above script, the function has stopped executing, but some original pieces of the function still live on! Because some references to functional variables were returned by the function, we can now access these through the “namespace” myAPI:

myAPI.publicProperty;  // 'Bar'
myAPI.publicMethod(); // (alert: 'I am publicly accessible'...)

But those variables that were not exposed are of course not accessible:

myAPI.privateProperty;  // error (not defined)
myAPI.privateMethod(); // error (not defined)

Access to unexposed variables

Exposed public methods still have the context of the original function, meaning that they have access to all the function’s variables, public and private:

var myAPI = (function(){
  var privateProperty = 'Foo';

  var publicFunction = function() {
    // this function has access to privateProperty because it's in the same scope, even after the main function stops executing!
    return privateProperty;
  };

  // create a new object and return it
  return {
    publicFunction: publicFunction
  };
})();

privateProperty;         // ERROR (not defined)
myAPI.publicFunction();  // 'Foo'

There’s definitely more to be said here, but hopefully this helps!

What happens when we serve JavaScript with random MIME types?

Monday, November 1st, 2010

Introduction

When people started to learn about the HTML5 doctype, they kind of freaked out a little, not knowing how older browsers would handle it. A post by Dustin Diaz prompted me to test out how pages rendered (in QuirksMode or Standards Mode) with a little help from document.compatMode, and I found that surprisingly every browser rendered in Standards Mode with the new doctype. In other words, no need to worry!

There’s another welcome simplification (along with others): the “type” attribute is no longer necessary on script tags:

The type attribute gives the language of the script or format of the data. If the attribute is present, its value must be a valid MIME type. The charset parameter must not be specified. The default, which is used if the attribute is absent, is “text/javascript”. -W3C HTML5 spec

Which means that this is all that’s required now:

<script src="script.js"></script>

But how do older browsers handle this? Also, what if we send some crazy Content-Type back in the response header? To make matters more confusing, I noticed that different CDNs send back different Content-Types: YUI and jQuery‘s CDNs send back “application/x-javascript” whereas Google’s CDN serving jQuery sends back “text/javascript; charset=UTF-8″.

So does it really matter what the Content-Type is? Let’s find out!

Setting up the tests

The test is fairly simple: I have six JavaScript files that all write to the DOM when they’re executed successfully. Each of these files has a different file extension (js.one, js.two, js.three, etc) and each is served with an extension determined by the .htaccess file, which is in the same directory, and contains this bit of magic:

AddType text/javascript .one
AddType application/x-javascript .two
AddType application/javascript .three
AddType text/ecmascript .four
AddType text/jscript .five
AddType text/foo .six

My index.html contains a little helper utility for each of these scripts to use:

var TEST = {
  node: document.body,
  addMessage: function(message) {
    var p = document.createElement('p');
    p.innerHTML = message;
    this.node.appendChild(p);
  }
}

TEST.addMessage() is simply a glorified document.write. As each of the six scripts is run, they’ll write out a message to the page essentially saying “I’m here! It worked!”.

Results

All the browsers I tested worked better than expected. It turns out that Content-Type doesn’t even matter. I made up my own content type “text/foo”, served the file successfully, and it still executed as JavaScript!

I tried all the major A-grade browsers (yes, including IE6-8), plus other random browsers through Browsershots.org.

One thing I still need to try is IE9, which Paul Irish said may not work. I’ll give it a test… soon.

Additional test #1: playing with the “type” attribute

Instead of messing around with the MIME type sent back in the response header, what happens when we mess around with the “type” attribute on the script tag? For instance:

<script type="text/foo"></script>

Using the same testing technique as above, I found these results to be more pronounced. Browsers were more picky. For instance, Chrome and Safari ran all the content types successfully except my made-up “text/foo”. Firefox was even more picky, choosing not to recognize the type “text/jscript”. I’d imagine there’s similar results with other browsers such as IE.

…But none of that really matters now! Simply omit the type attribute and everything seems to work fine (except possibly not in IE9?).

Additional test #2: content type and caching

Philip Tellis wanted to know if Content-Type had any bearing on how the browser caches data. For instance, if something previously requested has the same filename but a different content type, is there a cache hit (304 code returned) or miss?

In the first test I made a page that requested a file. Then in a not-too-fancy way I changed the content type through .htaccess on the fly and made another request. A 304 code was returned even with the new content type, so it was clear that this traditional caching method wasn’t affected.

In my second test I instead changed the “type” attribute on the script tag itself (in the HTML). The file was still cached normally, even after the type changed.

I only tested in Chrome, Safari, and Firefox, so the story might be different in IE. Anyhow, this is an edge case anyway and more of a test out of curiosity! It seems the way browsers handle caching in these instances is truly RESTful, that is, the current state of the file is determined entirely by the filename.

JavaScript links from last week (September 26)

Tuesday, October 5th, 2010

JavaScript Asteroids – blow up any webpage with this bookmarklet!

JS1k contest – and the winner

PromoteJS – Google bombing with a good intent. Better links to JavaScript documentation!

Async and defer attributes for Script tags added to WebKit

Evercookie – uses devious ways to try to track users. Hmm, this one is questionable. Please use it for good, not evil.. :/

JSPerf.com – not really new news, but a nice quick way to test algorithm performance in JavaScript

yepnope.js – a wrapper around LABjs Script Loader to save bandwidth by only loading needed components. Think of JSON – there’s no reason to send this down the wire if the browser supports this natively.

Classlist in Firefox 3.6 – for easier manipulation of classes on elements. And it just landed a patch in WebKit!

QuirksBlog: Click event delegation on the iPhone and an update

Chrome Speak To Site; Give any input the power to listen to you – support for input type=speech (supported by WebKit)

embedJS – selective JS for embedded devices (mobile, TV, etc.) based on capabilities.

JS Console for iOS – native JS console built by Remy Sharp.

Joyent Node SmartMachine – API for node.js?

Slides: Pushing browsers to the limit (Ben Firshman) – by the creator of Virtual NES – all in JavaScript!

Release the Kraken – Mozilla releases its Kraken JavaScript benchmark, analogue to WebKit’s SunSpider

Server side console.log

Wednesday, September 15th, 2010

The problem

On the desktop we’re quite privileged to have nice debugging tools such as Firebug and Web Inspector in Webkit-based browsers. But when it comes to mobile, debugging JavaScript with console.log isn’t quite as easy.

Probably the best available tool on mobile at the moment is mobile Safari’s console, which looks like the following when enabled (Settings -> Safari -> Developer -> Debug Console):

Mobile Safari's debug console

On the left you can see the debug console displayed above the document itself, and on the right is an example of what you might see after outputting an object or a string of text to console.log. It’s the best debugging tool on mobile, but it’s not without its issues.

The first issue is that the debug console is taking up space in the screen and interfering with how an actual user would view the website. I could image this could become particularly annoying when trying to develop a web app in the style of the new YouTube mobile, which doesn’t function like a traditional webpage at all, and relies on the screen being a certain height in order to display its content.

The second issue is that you can’t see the contents of JavaScript Objects. We’re a bit spoiled being able to see a tree view of objects on the latest browsers with the latest debugging tools, and therefore it makes the experience on mobile Safari less than adequate. When we type console.log(navigator) all we can see on mobile Safari is [object Navigator], which leaves something to be desired.

So what about Android? Google offers something called Android Debug Bridge, which is a client-server debugging solution that can be used either for web or application development. As such, when you view the messages the devices sends to the server, the vast majority of messages will be messages about low-level operations, stuff we usually don’t care much about when developing with JavaScript. The workaround for this is to grep for “console” on the command line, which will only display the messages we’re interested in.

The solution: server side console.log!

Why not just send the contents of your console message to a server, and have it log it? The concept is pretty simple:

  1. Create a log function that sends an XHR to a server.
  2. Have the server process the request and log the message to a file.
  3. Tail the end of the file on the command line to see the latest messages.

The implementation is pretty simple. In JavaScript we have this code:

(function(){

// define console if not already defined
console || (console = {});

// new toFile method
console.toFile = function(log) {
  // variable declarations
  var http, url, params;

  // might as well use the traditional console.log() as well
  console.log(log);

  // ajax request
  http = new XMLHttpRequest();
  url = "//example.com/log.php";
  params = "log=" + Date.now() + ' ' + escape(sanitize(log));
  http.open("POST", url, true);
  http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
  http.send(params);
}

// do something special if txt is an object
var sanitize = function(txt) {
  var output, x;

  if(typeof txt == 'object') {
    // create a new object to get around circular references
    output = {};
    for(x in txt) {
        // type conversion of each element to a string
        output[x] = txt[x] + '';
    }
    output = JSON.stringify(output, null, 2);
  } else {
    output = txt;
  }

  return output;
}

})();

In summary, the above code adds a new method to the console object called toFile, which simply takes the inputted data and sends it to the specified URL. The only bit of trickery here is the function sanitize, which detects if the message being passed in is an object. If it is, it copies it to a new object containing only strings (which gets around JSON “circular reference” errors) and runs JSON.stringify() on it, which lets us peek into its contents one level deep.

The server side PHP code to make this work is even simpler:

// log.php
<?php

// take advantage of error_log to log the message to the file console.log
@error_log($_POST['log'] . "\n", 3, 'console.log');

?>

On the server, we log in with terminal, navigate to the directory containing the file console.log, and simply tail the end of the file, which shows live updates as new messages are added to the end of the file:

tail -f console.log

Example

Once we have the above code in place, using the console is very simple:

console.toFile('hello world!');
console.toFile(navigator);

After running this code, you should see this pop up on your terminal:

1284574866900 hello world!
1284575008914 {
  "geolocation": "[object Geolocation]",
  "standalone": "false",
  "cookieEnabled": "true",
  "language": "en-us",
  "productSub": "20030107",
  "product": "Gecko",
  "appCodeName": "Mozilla",
  "mimeTypes": "[object MimeTypeArray]",
  "vendorSub": "",
  "vendor": "Apple Computer, Inc.",
  "platform": "iPhone",
  "appName": "Netscape",
  "appVersion": "5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7",
  "userAgent": "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_1 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8B117 Safari/6531.22.7",
  "plugins": "[object PluginArray]",
  "onLine": "true",
  "javaEnabled": "function javaEnabled() {\n    [native code]\n}",
  "getStorageUpdates": "function getStorageUpdates() {\n    [native code]\n}",
  "registerProtocolHandler": "function registerProtocolHandler() {\n    [native code]\n}",
  "registerContentHandler": "function registerContentHandler() {\n    [native code]\n}"
}

Sweet! Now we can easily see console messages from actual devices. You can potentially use this code to log Events as they occur (on click or touch interactions) and view the actual x/y coordinate values as they’re being detected on the device!

Related

Alex Kessinger implemented a similar concept with node.js running locally

Update

It turns out that Joe Hewitt did this before me with his “Firebug for iPhone”. I have no idea why it took me so long to find this!

Video: John Resig – Testing, Performance Analysis, and jQuery 1.4

Monday, December 21st, 2009

In case you hadn’t seen it yet, John Resig was kind enough to stop by Yahoo! for the December Bayjax meetup. Here’s the video:

Usually developers are more interested in just getting the dang code to work, and as a result actual the testing and maintenance of JavaScript isn’t talked about too much, so I’m sure this will be new territory for many developers. And since it’s John Resig speaking, there was of course a bit about using TestSwarm, a testing distributed framework-agnostic automated testing tool (that’s a mouthful!).

Included in the talk are good things to note while testing, such as the fact unless you’re running Firefox or Chrome on Windows, all test times have a margin of error of up to 15ms (not to be confused with PPK’s observation of the delay between JavaScript computation and browser rendering).

(via YUIBlog)