<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Emmett Pickerel&#039;s</title>
	<atom:link href="http://docsplendid.com/feed" rel="self" type="application/rss+xml" />
	<link>http://docsplendid.com</link>
	<description>Adventures in Javascript</description>
	<lastBuildDate>Fri, 28 Sep 2012 02:07:20 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>The future of nugget functionality</title>
		<link>http://docsplendid.com/archives/202</link>
		<comments>http://docsplendid.com/archives/202#comments</comments>
		<pubDate>Fri, 28 Sep 2012 02:07:20 +0000</pubDate>
		<dc:creator>Doc Splendid</dc:creator>
				<category><![CDATA[Frontend]]></category>

		<guid isPermaLink="false">http://docsplendid.com/?p=202</guid>
		<description><![CDATA[I&#8217;ve spent some of today updating my &#8220;jQuery plugin&#8221;, doWhen, with the added help of a splendid chap and coworker, name of Erin Swenson-Healy. He adapted it to be more AMD friendly, and I expounded upon that. Basically, now, using &#8230; <a href="http://docsplendid.com/archives/202">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>I&#8217;ve spent some of today updating my &#8220;jQuery plugin&#8221;, doWhen, with the added help of a splendid chap and coworker, name of <a href="https://github.com/hippipp">Erin Swenson-Healy</a>. He adapted it to be more <a href="https://github.com/amdjs/amdjs-api/wiki/AMD">AMD</a> friendly, and I expounded upon that. Basically, now, using requirejs, we can simply say in a given file:</p>
<pre class="code">define(["doWhen"],
function(doWhen){
  doWhen(....);
});</pre>
<p>Which means for our purposes, it&#8217;s not really a jQuery plugin. And, realistically, it&#8217;s not. It&#8217;s just a tiny nugget of functionality we want to pull in. All it uses from jQuery is a flat <code>extend</code>, and that is easily replaceable (as it already is in the &#8220;plain&#8221; version).</p>
<p>However, not everybody will consume doWhen through AMD or a similar method. And not everybody who doesn&#8217;t necessarily uses jQuery. But I need *somewhere* to attach it to, if AMD or equivalent is not defined.</p>
<p>So, I&#8217;m thinking of ditching the jQuery requirement entirely. The &#8220;plain&#8221; version would be the only one. If AMD or something like it is present, it would define according to that pattern. If jQuery, underscore, or another common library is present, it would attach to one or more of those for more traditional use, defaulting perhaps to the global object if none are present?</p>
]]></content:encoded>
			<wfw:commentRss>http://docsplendid.com/archives/202/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>doWhen</title>
		<link>http://docsplendid.com/archives/198</link>
		<comments>http://docsplendid.com/archives/198#comments</comments>
		<pubDate>Tue, 27 Mar 2012 03:39:40 +0000</pubDate>
		<dc:creator>Doc Splendid</dc:creator>
				<category><![CDATA[Frontend]]></category>

		<guid isPermaLink="false">http://docsplendid.com/?p=198</guid>
		<description><![CDATA[It occurs to me that I have neglected to post about the most bloody useful utility I&#8217;ve ever written: doWhen While the main version is a jQuery plugin, I find myself using the non-jQuery version more often, so that&#8217;s the &#8230; <a href="http://docsplendid.com/archives/198">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>It occurs to me that I have neglected to post about the most bloody useful utility I&#8217;ve ever written: <a href="http://www.github.com/epickerel/dowhen" target="_blank"><code>doWhen</code></a></strong></p>
<p>While the main version is a jQuery plugin, I find myself using the non-jQuery version more often, so that&#8217;s the one I&#8217;ll describe here.</p>
<p>What <code>doWhen</code> does is allow you to create a single &#8220;virtual event&#8221; in the form of a test function which, when it returns <code>true</code>, runs a callback function.</p>
<p>Let&#8217;s say we were loading a library and wanted a quick way to do something when the library is ready:</p>
<pre class="code"><code>&lt;script type="text/javascript">
var global = (function(){return this;}());
Event.doWhen(function(){
  return !!global.jQuery;
}, function(){
  alert('jQuery loaded!');
});
&lt;/script>
&lt;script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.min.js">&lt;/script></code></pre>
<p>The <code>!!</code> ensures the result is a <code>boolean</code>. Every 100 milliseconds (configurable), it will run the first function. The first time that function returns <code>true</code>, it runs the second function.</p>
<p>I use this extremely frequently, even in wee code snippets, thanks to the tiny footprint (about 1/3kB minified).</p>
<p>See the <a href="http://www.github.com/epickerel/dowhen" target="_blank">github page</a> for options.</p>
<p>Open question: is Event the place to put this? Keep in mind this isn&#8217;t extending the object&#8217;s prototype, so shouldn&#8217;t cause conflicts in other code.</p>
<p>I am considering whether there&#8217;s a need for an ajax capable one which periodically checks a remote state.</p>
]]></content:encoded>
			<wfw:commentRss>http://docsplendid.com/archives/198/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Javascript programming in a nutshell</title>
		<link>http://docsplendid.com/archives/191</link>
		<comments>http://docsplendid.com/archives/191#comments</comments>
		<pubDate>Thu, 23 Feb 2012 14:54:59 +0000</pubDate>
		<dc:creator>Doc Splendid</dc:creator>
				<category><![CDATA[Frontend]]></category>

		<guid isPermaLink="false">http://docsplendid.com/?p=191</guid>
		<description><![CDATA[]]></description>
				<content:encoded><![CDATA[<div id="attachment_192" class="wp-caption alignnone" style="width: 970px"><a href="http://docsplendid.com/wp-content/uploads/2012/02/jsdevelopers.jpg"><img src="http://docsplendid.com/wp-content/uploads/2012/02/jsdevelopers.jpg" alt="" title="Javascript Programmers" width="960" height="720" class="size-full wp-image-192" /></a><p class="wp-caption-text">Javascript programming in a nutshell</p></div>
]]></content:encoded>
			<wfw:commentRss>http://docsplendid.com/archives/191/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>RIP Dennis Ritchie</title>
		<link>http://docsplendid.com/archives/185</link>
		<comments>http://docsplendid.com/archives/185#comments</comments>
		<pubDate>Thu, 13 Oct 2011 05:57:41 +0000</pubDate>
		<dc:creator>Doc Splendid</dc:creator>
				<category><![CDATA[Frontend]]></category>

		<guid isPermaLink="false">http://docsplendid.com/?p=185</guid>
		<description><![CDATA[]]></description>
				<content:encoded><![CDATA[<p><a href="http://docsplendid.com/wp-content/uploads/2011/10/cpirate.gif"><img src="http://docsplendid.com/wp-content/uploads/2011/10/cpirate-300x300.gif" alt="" title="cpirate" width="300" height="300" class="alignnone size-medium wp-image-187" /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://docsplendid.com/archives/185/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title></title>
		<link>http://docsplendid.com/archives/183</link>
		<comments>http://docsplendid.com/archives/183#comments</comments>
		<pubDate>Thu, 06 Oct 2011 08:27:36 +0000</pubDate>
		<dc:creator>Doc Splendid</dc:creator>
				<category><![CDATA[Frontend]]></category>

		<guid isPermaLink="false">http://docsplendid.com/?p=183</guid>
		<description><![CDATA[]]></description>
				<content:encoded><![CDATA[<p><img src="http://a4.sphotos.ak.fbcdn.net/hphotos-ak-ash4/301266_2386107288247_1117714077_2779721_1997396245_n.jpg" alt="The Jolly Steve" /></p>
]]></content:encoded>
			<wfw:commentRss>http://docsplendid.com/archives/183/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>JWPlayer and Firefox hunting</title>
		<link>http://docsplendid.com/archives/164</link>
		<comments>http://docsplendid.com/archives/164#comments</comments>
		<pubDate>Sat, 20 Aug 2011 03:44:57 +0000</pubDate>
		<dc:creator>Doc Splendid</dc:creator>
				<category><![CDATA[Frontend]]></category>

		<guid isPermaLink="false">http://docsplendid.com/?p=164</guid>
		<description><![CDATA[Greetings m&#8217;chums! Welcome to this week&#8217;s big adventure: trapping and shooting an old bug in a very popular tool. In the course of my everyday tinkering, I encountered a curious flaw in JWPlayer under Firefox which I think has plagued &#8230; <a href="http://docsplendid.com/archives/164">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Greetings m&#8217;chums! Welcome to this week&#8217;s big adventure: trapping and shooting an old bug in a very popular tool.</p>
<p>In the course of my everyday tinkering, I encountered a curious flaw in <a href="http://www.longtailvideo.com/players">JWPlayer</a> under Firefox which I think has plagued fellow adventurers of this fine Flash movie player for years, but which none seem to have sussed the essential nature of. Until today.</p>
<p>It all started when I found the player was firing no events. Initial investigation showed that I was never subscribing the events, because I was waiting for the event attaching method <code>jwAddEventListener</code> to arrive on the scene:</p>
<pre class="code"><code>var player = $('#myplayer');
$.doWhen(function(){
  return !!player.jwAddEventListener;
}, function(){
  //attach events
});</code></pre>
<p class="note"><em>(<code>doWhen</code> is a nifty little <a href="https://github.com/epickerel/dowhen">utility</a> I wrote that runs one function once after another function returns <code>true</code>)</em></p>
<p>A full investigation of the matter revealed that, in Firefox, the entire Javascript API for the embed was <em>never</em> being created! This was quite curious, as I&#8217;ve had <em>many</em> players fully functional in Firefox before.</p>
<p>I set about identifying what was different, and at last deduced that in all the previous cases, I had been instantiating the player after an ajax call (for content). In this case, however, the player was being created immediately after <code>jQuery(document).ready</code>.</p>
<p>Pausing briefly to brew up another <a href="http://www.youtube.com/watch?v=eELH0ivexKA">cup of brown joy</a> strong enough that the spoon stood rigid, I continued the experiment by delaying the player instantiation by two seconds with <code>setTimeout</code>. Lo and behold, the missing API was rumbled!</p>
<p>This was far from an ideal solution, of course. I wondered at what critical juncture Firefox would be in a position to correctly instantiate JWPlayer. Time to dust off an old friend: <code>window.onload</code>. A quick test showed that yes, indeed, once the <code>load</code> event had fired off, the player&#8217;s entire API reappeared like Manchurians at a near-dead pub advertising half-off pints of Brown!</p>
<p>Naturally, I didn&#8217;t want to slow other browsers down unnecessarily, so I knew that the <em>final</em> solution would have to narrow its sights on Mozilla, and only if the <code>load</code> had not yet fired. The way to determine the latter is <code>document.readyState</code>: &#8220;interactive&#8221; means the page is still in its initial rendering phase, but the DOM is available; &#8220;complete&#8221; is the word we&#8217;re looking for, the readyState when <code>load</code> has fired.</p>
<pre class="code"><code>if ($.browser.mozilla
      &#038;&#038; document.readyState !== 'complete') {
  $(window).bind('load', function(){
    //write your embed code here
  });
} else {
  //write your embed code here
}</code></pre>
<p>There you have it! Clearly, this should not be necessary; JWPlayer should do all of this internally. For now, it&#8217;s a workaround that seems 100% successful.</p>
<p>And with that, another successful week tromping through the deepest woods of my trade draws to a close. I bid your weekend be filled with lakes of Earl Grey and barrels of gorgeous Somerset gold. Tata!</p>
]]></content:encoded>
			<wfw:commentRss>http://docsplendid.com/archives/164/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>More on Randomness of Arrays</title>
		<link>http://docsplendid.com/archives/159</link>
		<comments>http://docsplendid.com/archives/159#comments</comments>
		<pubDate>Sat, 13 Aug 2011 22:39:27 +0000</pubDate>
		<dc:creator>Doc Splendid</dc:creator>
				<category><![CDATA[Frontend]]></category>

		<guid isPermaLink="false">http://docsplendid.com/?p=159</guid>
		<description><![CDATA[A few months ago, I posted about how the classic method most JS programmers would use to randomise an array completely fails. I proposed a quick solution to it, but that solution had flaws of its own. So, for those &#8230; <a href="http://docsplendid.com/archives/159">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>A few months ago, I <a href="http://docsplendid.com/archives/144">posted</a> about how the classic method most JS programmers would use to randomise an array completely fails. I proposed a quick solution to it, but that solution had flaws of its own.</p>
<p>So, for those of you who need to shuffle decks of cards, scramble virtual eggs or just want to toss a little confusion into your applications, here&#8217;s a fully working array randomiser:</p>
<pre class="code"><code>Array.randomiseArray = function(arr){
  var i, v;
  for (i=0; i&lt;arr.length; i++) {
    v = arr[i];
    arr[i] = {
      v: v,
      sort: Math.random()
    };
  }
  arr.sort(function(a, b){
      return a.sort - b.sort;
  });
  for (i=0; i&lt;arr.length; i++) {
    arr[i] = arr[i].v;
  }
  return arr;
};</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://docsplendid.com/archives/159/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>SMIRF 2.0</title>
		<link>http://docsplendid.com/archives/151</link>
		<comments>http://docsplendid.com/archives/151#comments</comments>
		<pubDate>Thu, 21 Jul 2011 02:36:50 +0000</pubDate>
		<dc:creator>Doc Splendid</dc:creator>
				<category><![CDATA[Frontend]]></category>

		<guid isPermaLink="false">http://docsplendid.com/?p=151</guid>
		<description><![CDATA[Late last year, I told you about the SMIRF JS pattern I&#8217;ve been working on. Since then, I&#8217;ve had quite a lot of opportunity to use it in the field and refine it. The biggest weakness with the old SMIRF &#8230; <a href="http://docsplendid.com/archives/151">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Late last year, I told you about the SMIRF JS pattern I&#8217;ve been working on. Since then, I&#8217;ve had quite a lot of opportunity to use it in the field and refine it.</p>
<p>The biggest weakness with the old SMIRF pattern was the need to pass the instance variables around all the time. It meant there was a <em>tiny</em> memory leak in the api, since wrapper functions needed to add the iVars argument to all calls.</p>
<p>What I&#8217;ve changed is that iVars is now accessed via a method <code>getIVars</code> in the &#8220;constructor&#8221;. There&#8217;s a localised randomly generated private key which must be passed in to get the instance variables. That way, nothing outside could grab them and clobber them (unless you write a method to deliver them, obviously!</p>
<p>So, here&#8217;s the updated pattern:</p>
<pre class="code"><code>var employeeFactory = (function(){
  var PRIVATE_KEY = String(Math.random()), giveRaise, fire;
  
  giveRaise = function(percent){
    var iVars = this.getIVars(PRIVATE_KEY);
    percent = percent || 0;
    console.log(iVars.salary);
    iVars.salary = iVars.salary * (1 + (percent/100));
    return iVars.salary;
  };
  fire = function(){
    var iVars = this.getIVars(PRIVATE_KEY);
    //long, drawn out legal process that takes 5000 lines
    iVars.currentlyEmployed = false;
  };
  
  return function(name, salary){
    //This is essentially a constructor function
    var iVars = {
      //Instance variables. All state info should be stored here
      name: name,
      salary: salary,
      currentlyEmployed: true
    };
    return {
      getIVars: function(key){
        if (key === PRIVATE_KEY) {
          return iVars;
        }
      },
      giveRaise: giveRaise,
      fire: fire
    };
  };
}());
var employee1 = employeeFactory('Bob', 30000);
var employee2 = employeeFactory('Mary', 21000);</code></pre>
]]></content:encoded>
			<wfw:commentRss>http://docsplendid.com/archives/151/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>An Array of Random Thoughts</title>
		<link>http://docsplendid.com/archives/144</link>
		<comments>http://docsplendid.com/archives/144#comments</comments>
		<pubDate>Sat, 09 Apr 2011 04:58:39 +0000</pubDate>
		<dc:creator>Doc Splendid</dc:creator>
				<category><![CDATA[Frontend]]></category>

		<guid isPermaLink="false">http://emmett.be/thewebdev/?p=144</guid>
		<description><![CDATA[Today, I was asked to supply a way (in Javascript) to create an array of all integers 0-9, but randomised, with no duplicates. Immediately, I gave this solution: var arr = [0,1,2,3,4,5,6,7,8,9].sort(function(){ return 0.5 - Math.random(); }); That should do &#8230; <a href="http://docsplendid.com/archives/144">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Today, I was asked to supply a way (in Javascript) to create an array of all integers 0-9, but randomised, with no duplicates. Immediately, I gave this solution:</p>
<pre class="code"><code>var arr = [0,1,2,3,4,5,6,7,8,9].sort(function(){
  return 0.5 - Math.random();
});
</code></pre>
<p>That should do it, right? Well, one of the tests that was run on the resulting &#8220;random&#8221; array was to see whether or not the first five members were consistently even or odd:</p>
<pre class="code"><code>var generateRands = function(){
  return [0,1,2,3,4,5,6,7,8,9].sort(function(){
    return 0.5 - Math.random();
  });
};
var isMoreEven = function(arr){
  var i, even = 0, odd = 0;
  for (i=0; i&lt;5; i++) {
    if (arr[i] % 2) {
      odd++;
    } else {
      even++;
    }
  }
  return even &gt; odd;
};
var runTests = function(iterations){
  var i, even = 0, odd = 0, arr;
  for (i=0; i&lt;iterations; i++) {
    arr = generateRands();
    if (isMoreEven(arr)) {
      even++;
    } else {
      odd++;
    }
  }
  console.log('even won', even, 'or', (even/iterations * 100) + '%',
    '; odd won', odd, 'or', (odd/iterations * 100) + '%');
};
runTests(10000);
</code></pre>
<p>The expected result would be that even and odd would hover around 50%, with some variance either way. Here&#8217;s what it *actually* outputs:</p>
<pre class="code"><code>even won 6762 or 67.62% ; odd won 3238 or 32.379999999999995%
</code></pre>
<p>WTF? It hovered consistently around this ratio with every test! I thought at first that it was perhaps a pattern in the pseudo random number generator, but no matter what I did, it hovered strongly in favour of even.</p>
<p>Keep in mind this is the method most commonly recommended on tutorial sites around the net for randomising an array&#8217;s order!</p>
<p>I added a further test to this, to see how frequently each number ends up in the first five. Here&#8217;s the test:</p>
<pre class="code"><code>var runTests = function(iterations){
  var i, j, arr, nums = [], order = [];
  for (i=0; i&lt;10; i++) {
    nums.push({
      num: i,
      count: 0
    });
  }
  for (i=0; i&lt;iterations; i++) {
    arr = generateRands();
    for (j=0; j&lt;5; j++) {
      nums[arr[j]].count++;
    }
  }
  nums.sort(function(a, b){
    return a.count - b.count;
  }, true)
  for (i=0; i&lt;10; i++) {
    order.push(nums[i].num + ' (' + nums[i].count + ')');
  }
  console.log(order);
};
runTests(10000);
</code></pre>
<p>The output was consistently something like this:</p>
<pre class="code"><code>["9 (309)", "8 (598)", "7 (1180)", "6 (2256)", "5 (3963)",
  "4 (6170)", "3 (7926)", "2 (8817)", "1 (9386)", "0 (9395)"]
</code></pre>
<p>The number in parentheses represents the number of times in 10000 that the number to the left appeared in the top five. This &#8220;random&#8221; sort didn&#8217;t seem to take array members very far from home. One and zero are the only two that I could get to swap how frequently they appeared in the first five, for some reason.</p>
<p>What I finally realised was that the flaw was in my use of sort. Sort swaps adjacent items until it reaches the conclusion that the array is in the proper order. Each item is &#8220;less than&#8221; or &#8220;greater than&#8221; the other, and this is meant to be a consistent value. If you randomise the compare function&#8217;s output, then it will swap items, then swap them back, and finally give up on your inconsistency.</p>
<p>Even was coming up more often than odd because there are a greater number of even numbers from 0-4.</p>
<p>And now, what you probably visited this page for. A *working* array randomiser:</p>
<p><em>UPDATE: I have a much better method now in <a href="http://docsplendid.com/archives/159">this post</a>!</em></p>
<pre class="code"><code>var randomSort = function(arr){
  var i, l, sortOrder = {};
  for (i=0, l=arr.length; i&lt;l; i++) {
    sortOrder[arr[i]] = Math.random();
  }
  return arr.sort(function(a, b){
    return sortOrder[a] - sortOrder[b];
  });
};
var generateRands = function(){
  return randomSort([0,1,2,3,4,5,6,7,8,9]);
};
for (var i=0; i&lt;5; i++) {
  runTests(10000);
}
</code></pre>
<p>This worked! Here&#8217;s the output:</p>
<pre class="code"><code>["4 (4933)", "0 (4953)", "7 (4983)", "6 (4990)", "9 (5002)",
  "5 (5010)", "1 (5017)", "3 (5029)", "2 (5038)", "8 (5045)"]
["9 (4915)", "4 (4940)", "2 (4941)", "8 (4957)", "5 (4974)",
  "7 (5011)", "3 (5044)", "1 (5046)", "0 (5077)", "6 (5095)"]
["2 (4947)", "4 (4963)", "5 (4977)", "0 (4987)", "3 (4988)",
  "9 (5002)", "6 (5013)", "1 (5022)", "7 (5034)", "8 (5067)"]
["8 (4871)", "4 (4938)", "9 (4962)", "1 (4977)", "0 (4989)",
  "2 (4993)", "3 (5012)", "6 (5051)", "7 (5057)", "5 (5150)"]
["7 (4944)", "3 (4953)", "8 (4968)", "5 (4976)", "0 (4991)",
  "4 (5017)", "1 (5024)", "6 (5028)", "2 (5030)", "9 (5069)"]
</code></pre>
<p>The even/odd test above works with this new method, too.</p>
<p>I just wonder how many faulty array shuffling implementations are out there that don&#8217;t work!</p>
<p><strong>Note:</strong> This randomSort is <em>not perfect</em>! Identical array values will end up adjacent to one another.</p>
]]></content:encoded>
			<wfw:commentRss>http://docsplendid.com/archives/144/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>The Static Module Instance wRapper Factory (SMIRF) pattern</title>
		<link>http://docsplendid.com/archives/131</link>
		<comments>http://docsplendid.com/archives/131#comments</comments>
		<pubDate>Wed, 15 Dec 2010 16:48:40 +0000</pubDate>
		<dc:creator>Doc Splendid</dc:creator>
				<category><![CDATA[Patterns]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[module pattern]]></category>

		<guid isPermaLink="false">http://emmett.be/thewebdev/?p=131</guid>
		<description><![CDATA[Minimise memory waste with the module pattern. <a href="http://docsplendid.com/archives/131">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
				<content:encoded><![CDATA[<p>Earlier in the year, I wrote about memory waste issues in <a href="http://emmett.be/thewebdev/archives/96">Caveats of the JS Module Pattern</a>. I&#8217;d like to offer a new pattern as a solution to those issues.</p>
<p>First, a reminder of why we like the module pattern: it provides an elegant way to have private methods and variables. For most singleton objects, there is no better option. I&#8217;ll use Christian Heilmann&#8217;s <a href="http://www.wait-till-i.com/2007/08/22/again-with-the-module-pattern-reveal-something-to-the-world/">Revealing Module pattern</a> for my examples:</p>
<pre class="code"><code>var currencyExchange = function(){
  var currencies = {
    usd: 1,//always 1, base currency
    gbp: 0.631552356,
    aud: 0.99980004,
    cad: 1.0072999
  };
  var convert = function(fromCurrency, toCurrency, amount){
    var amountInUsd = (fromCurrency === 'usd') ?
      amount : amount / currencies[fromCurrency];
    return (toCurrency === 'usd') ?
      amountInUsd : amountInUsd * currencies[toCurrency];
  };
  var changeRate = function(currency, rate){
    currencies[currency] = rate;
  };
  return {
    convert: convert,
    changeRate: changeRate
  };
}();</code></pre>
<p>The memory waste problem occurs when you use this pattern to create object instances:</p>
<pre class="code"><code>var employeeFactory = function(name, salary){
  var giveRaise = function(percent){
    salary = salary * (1 + (percent/100));
    return salary;
  };
  var fire = function(){
    //long, drawn out legal process that takes 5000 lines
  };
  return {
    giveRaise: giveRaise,
    fire: fire
  };
};
var employee1 = employeeFactory('Bob', 30000);
var employee2 = employeeFactory('Mary', 21000);</code></pre>
<p>We now have created two identical but separate versions of the giveRaise and fire functions, wasting CPU in generating the duplicates, and memory in storing them.</p>
<hr />
<h3>SMIRF it down to size</h3>
<p>Looking at the singleton example, the elegance of it is that the functions are created once as the script is first run. The reason we can&#8217;t easily do that with instantiation is that the functions need to be declared in the scope of the state variables (name and salary) that they&#8217;re operating on.</p>
<p>The SMIRF pattern provides a way to have the outer, static module which provides methods shared across all instance objects, avoiding most of the CPU and memory waste.</p>
<p>We still need to create tiny, one line &#8220;wrapper&#8221; methods for each method on an instance, but the footprint of these is minimal in comparison to that of reproducing large methods for each instance.</p>
<pre class="code"><code>var employeeFactory = function(){
  /* These are STATIC functions to hold the majority of code.
   * They should be run in the context of the instance via "call",
   * and the first arg should always be iVars.
   * The "this" keyword and iVars are the only ties these methods
   * have to the object!
   */
  var giveRaise = function(iVars, percent){
    iVars.salary = iVars.salary * (1 + (percent/100));
    return iVars.salary;
  };
  var fire = function(iVars){
    //long, drawn out legal process that takes 5000 lines
  };
  return function(name, salary){
    //This is essentially a constructor function
    var iVars = {
      //Instance variables. All state info should be stored here
      name: name,
      salary: salary
    };
    var instance = {
      //This will be our actual instance object.
      //Fns here are thin wrappers for memory efficiency
      giveRaise: function(percent){
        return giveRaise.call(instance, iVars, percent);
      },
      fire: function(){
        return fire.call(instance, iVars);
      }
    };
    return instance;
  };
}();
var employee1 = employeeFactory('Bob', 30000);
var employee2 = employeeFactory('Mary', 21000);</code></pre>
<p>Note that the methods on the instance object will never vary much from what you see above. They simply run the static methods in the context of the instance, passing the instance variables, and pass back the returned value.</p>
<p>All private variables should be stored in iVars, so that the static method signature is always the same. Publicly accessible variables, of course, would simply be on the instance object itself, accessible via the &#8220;this&#8221; keyword in the shared static methods.</p>
]]></content:encoded>
			<wfw:commentRss>http://docsplendid.com/archives/131/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
