Brendan, you've asked for other coding examples where I use the pattern of some variable being `undefined` or not to trigger different behavior (that is, to use the variable or not). Here's two more:

1. I have a templating engine DSL (called HandlebarJS) I wrote (in JS), which includes a very strict minimal subset of a "JavaScript-like" syntax for declaring template variables in the definition-header of a template section. In fact, the variable declaration stuff is massaged just slightly (for variable namespacing, mostly), and then executed as straight JavaScript.

In a template section header, I'm able to define a "local variable" for the section which has the ID reference of another sub-template section to include. If you ask to include a sub-template, and the "local variable" you give as the name of the template to include is an empty "" or is `undefined` or otherwise falsy, then the templating engine simply skips over that template section inclusion. Example:

{$: "#main" | content = data.content ? "#content" : "" $}
   <h1>Hello World</h1>
   {$= @content $}
{$}

{$: "#content"}
   <p>
       {$= data.content $}
   </p>
{$}

So, if the `data.content` variable is truthy, then the local variable `content` gets value "#content" (a string ID reference to the sub-template section of that name), and if not, then it ends up as the empty string "". Then, after the <h1> tag, a template-include is called, with {$= @content $}, which basically says, get the value out of that local variable, and if it's a reference (by ID) to a template section, then include it. If the variable referenced is empty, or undefined, or null, or whatever falsy, then simply silently don't include anything.

Of course, the `: ""` part of the variable declaration is what's relevant to our discussion. I could obviously specify another template ID in that string... but in this example I'm giving, if the `data.content` is empty, I don't want to include the markup (the <p>...</p>) from the #content template at all, so I just set the local variable to "", which results in no sub-template being included.

Here's where this gets to the point: in my template DSL, you're allowed to drop the `: ""` from ?: usage, so the declaration for main can look like slightly cleaner, like this:

{$: "#main" | content = data.content ? "#content" $}

Purely syntax sugar I'm giving there, to help the template not have so much "code" in it. If the "" or `undefined` or whatever falsy value in the "or" case can be assumed, it makes the writing of that variable declaration a little bit nicer. When I parse the data declarations from my template syntax, and then hand it off to JavaScript, I simply substitute in the `: undefined` if it's not present. I even take care of nested ?: with the optional `:` parts.

To put a finer point on it, it would be nicer/easier if I didn't have to add those implied clauses in, because the JavaScript language just supported that syntactic sugar directly.

-------------------------

2. I've got cases where I have a set of code in an embeddable widget, that someone can take the code and embed into their site. My code relies on jQuery, but at least jQuery 1.4. So, I first check to see if jQuery is already present, and if it's 1.4+, and then if so, I just use the page's copy of jQuery. Otherwise, I go ahead and load jQuery dynamically for my code to use.

So, a drastically simplified version (yes, I know the version matching logic is faulty from the over-simplification) of this code looks like this:

(function(){
  var jq = ($ && $.fn.jquery.match(/^1\.[4-9]/)) ? $ : undefined;

  ...

  if (typeof jq == "undefined") {
     // go ahead and load jQuery dynamically
  }
})();

So, how can I write this code differently? Of course there's other ways to write it.

var jq;
($ && $.fn.jquery.match(/^1\.[4-9]/)) && jq = $; // jq is either jQuery or it's still `undefined`, which I prefer

OR

var jq = ($ && $.fn.jquery.match(/^1\.[4-9]/)) ? $ : null; // jq is either jQuery or it's `null`, which I like less

OR

var jq = ($ && $.fn.jquery.match(/^1\.[4-9]/)) && $; // jq is either jQuery or it's `false`, which I like less

OR .......

And there's probably half a dozen other patterns too. I could use `null` as the sentinel value, I could use `false`, heck I could even use an empty "" string.

The point is, I prefer to use `undefined` in such cases, because semantically, I'm saying that my `jq` is in fact "undefined" (or rather, "not yet defined") if either jQuery is not present, or the version match fails. I don't prefer to use `false` or `null` or `0` or `""` as the alternate value, I prefer to use `undefined`.

And so, it'd be nice if my `var` statement could be simpler, like:

var jq = ($ && $.fn.jquery.match(/^1\.[4-9]/)) ? $;

Why? because it keeps the declaration and initialization all in one statement, which is cleaner, and because it preserves that `jq` is only ever a valid reference to jQuery, or it's strictly `undefined`... there's no other values I have to worry about it being. That also means that the check later is `typeof jq == "undefined"`, which I consider to be most semantic, rather than `typeof jq != "object"` (which fails if I use `null`) or `jq != null` (which works for either `null` or `undefined`, but in my opinion is less semantic).

-------------------------

In any case, set the `doX` argument from earlier aside, and there's still other examples of how I like to use the semantic meaning of `undefined` for signaling that a variable is not yet initialized, and that the code needs to react accordingly if so. You may disagree entirely with both above usages as well, but the point is that it's not some limited one-off niche use case, it's a pattern that I find useful across a variety of projects, and one which I wish had just a tiny bit more semantic sugar to it.

--Kyle



_______________________________________________
es-discuss mailing list
es-discuss@mozilla.org
https://mail.mozilla.org/listinfo/es-discuss

Reply via email to