view core-javascript/solution-1.rst @ 213:0ea90a1819c2 default tip

Custom theming
author Radomir Dopieralski <radomir.dopieralski@allegro.pl>
date Wed, 27 Jun 2012 16:35:54 +0200
parents 58e4f484903f
children
line wrap: on
line source

Solution one
============

Here's the code we're studying.

.. literalinclude:: /core-javascript-work/exercise-1.js
   :language: javascript


Verbal summary
--------------

We are making sure that there's an object AAA and giving it an
attribute AAA.fff, which is a function.  We won't say more about the
function in this summary.


Hoisting once-only arguments
----------------------------

First, we'll hoist the argument to the anonymous function into its
body.  We can always do this, without changing the meaning, provided the
function is called only once.

.. literalinclude:: /core-javascript-work/solution-1-a.js
   :language: javascript

There, that's better.  We no longer have to read to the end of the
function to find out what BBB is (and in particular its relationship
with AAA).


What is AAA?
------------

Next, we'll hide (or ignore) the assigment to BBB.fff.  This
assignment sets an attribute on the object pointed to by the variable
BBB.  In other words, it mutates the object pointed to by BBB, but the
variable BBB still points to the same object as it did before.

.. literalinclude:: /core-javascript-work/solution-1-b.js
   :language: javascript


If AAA starts out as an object then the expression

.. code-block:: javascript

   AAA || {}

evaluates to AAA, while if AAA is undefined then it evaluates to the
newly created object literal (the left-and-right curly braces).  In
either case, this value is assigned to the local variable BBB, which
is then returned by the anonymous function and bound to AAA.

Put another way, if AAA starts off as undefined then it is bound to a
new object, while if it starts off as an object then it finishes as
the same object.

Therefore, our truncated version of the original exercise is equivalent to

.. literalinclude:: /core-javascript-work/solution-1-c.js
   :language: javascript

This idiom is very common in JavaScript, and is (as here) a
consequence of using objects as namespaces (which is better than using
the global object) and defensiveness about the order in which files
are loaded.

Here's a command line session that shows this equivalence.  To begin
with AAA is undefined and the assignment binds AAA to a new object.
For the second assignment AAA is defined and the assignment binds AAA
to the object is already bound to.

.. code-block:: javascript

   js> var AAA = AAA || {}
   js> AAA
   [object Object]
   js> pointer = AAA
   [object Object]
   js> var AAA = AAA || {}
   js> pointer === AAA
   true


The assignment to BBB.fff
-------------------------

Reading the code, it looks as if BBB is local to the anonymous
function.  As a variable it is, but its value is not.  The value of
BBB is bound to the global object AAA at the end of the function call.

The following is almost equivalent to our original JavaScript code.
Note that BBB.hhh has been changed to AAA.hhh.

.. literalinclude:: /core-javascript-work/solution-1-d.js
   :language: javascript


Caveat
------

Why did I say *almost equivalent*?  Because we might subsequently do
something like


.. code-block:: javascript

   var CCC = AAA;
   AAA = undefined;

For the original code the closure variable BBB still exists and points
to the same object as CCC, even though AAA is undefined.  Thus, the
reference to BBB.hhh in the original code will continue to work.

For the revised code, when the value of AAA is set to undefined the
reference to AAA.hhh will fail.