Hacker News new | past | comments | ask | show | jobs | submit login
Advanced JavaScript Techniques (sixrevisions.com)
82 points by cwan on Oct 9, 2009 | hide | past | favorite | 47 comments



Pardon me, but what's so advanced about these techniques? Anyone writing JavaScript for living should already know these things. You want to talk advanced? How about lazy function definition [http://peter.michaux.ca/articles/lazy-function-definition-pa...]? Or say actual advanced JavaScript? http://ejohn.org/apps/learn/


Although it is helpful to the very junior developers at my company, the techniques are by no means "advanced." I suggest he change the title to "Javascript Basics Everyone Should Know."

It's not a terrible article, and he doesn't have bad advice, but as someone else points out in another comment he makes some pretty rookie mistakes (new Objects() instead of {})...


The lazy function technique can easily become an example of bad coding practice. Code needs to be easy to read, understand, and maintain. In most cases solution 2 is good enough, in all cases it's much simpler.

Advanced techniques should only be used when there is a clear justification to sacrifice simplicity. It is disastrous when developers use so-called "advanced" technique only to entertain themselves and show-off.

You are judged not by the niftyness of your code, but by the availability, maintainability, stability and functionality of your system as a whole.


Code needs to produce predictable results without bugs. All other qualities are secondary. Good code without bugs is well encapsulated and should work as a black box. Elegance is secondary to reliability. I am not saying that it is not important, just not as important as reliability. As a general rule of thumb less lines of code translates into higher reliability. I know it does not apply to every case but it is a good starting point.


Thanks for the ejohn's link. I've been reading his new book, and this pretty much all the code that he shows there. (as far as I've read)


There's also an issue with his myMethodValue. It's actually a global variable (try alert(window.myMethodValue). He should have used var myMethodValue within the function definition.


I take issue with his object literal example for function arguments. My rule of thumb is: if it's a required parameter, list it in the parameters. If it's optional, put it in an object literal argument - but DOCUMENT it in a comment at the head of the function. Using a lot of object literals as arguments can get very hairy very quickly if you don't keep track of them, and keeps your code from being self-documenting. By separating out your required and your optional parameters, you can easily see which are which.

In his namespace example, also, he uses the new Object() notation, which is not nearly as concise as var foo = {}, which does the same exact thing (similarly, var arr = [] is better than var arr = new Array()).

We could rewrite the entire namespace initialization block as:

var MY = (MY) ? MY : { CUSTOM : {} };

This sets the variable MY to itself if it exists, otherwise assign an object literal that has a member property CUSTOM that happens to be an empty object. You could now create a new function, say, MY.CUSTOM.foo = function() { alert('foo'); };


I use this function to create namespaces:

  var namespace = function(ns) {
    var scope = window;
    var tokens = ns.split(".");
    for (var idx = 0, len = tokens.length; idx < len; idx++) {
      var token = tokens[idx];
      scope = scope[token] = scope[token] || {};
    }
  };
For example: namespace("Zen.Ui");


YAHOO.namespace in YUI does the same thing, except that it creates everything under the YAHOO namespace.


Clever! How do you add your properties and methods? Another clever trick?


Thanks for sharing your rule of thumb. I have observed that inevitably most objects/functions require three 'groups' of variables, more or less I use this pattern and I would appreciate your thoughts.

   - Defaults: Must be defined within the object literal
   - User Options : part of the function arguments 
                    (user can use an object literal,
                     anon function etc.) 
   - Settings : The actual mixin used by the methods

 function aProblem(arg1, arg2, options){ 
    // define the necessary defaults
    var defaults={} //define defaults
    // use a mixin algo to combine options and
    // defaults
    var settings = mixin(options, defaults); 
    // main function routines 
    var myObj={};

    return myObj={   
      property1 : settings.property1,
      property2 : settings.property2
    }
 }


I use a similar technique when the number of optional arguments get out of control (i.e. if there is more than one optional argument). If you want to tight control, you can take advantage of the fact that a variable that is a function, the length member specifies the number of arguments declared as in:

(function(a,b,c){}).length == 3

Using that knowledge, you can do this at the top of a function:

if(arguments.callee.length > arguments.length){ throw "Required Parameter Missing"; }


While nobody who's spent more than a couple weeks in jQ is going to learn anything from this, I am at least thrilled to see that this isn't an article about how to create animated dialog boxes and image carousels.


For-loops like "for (i=0;i<myLinkCollection.length;i++)" should always be written like "for (var i=..."), unless there's an explicit "var i;" declaration somewhere. Otherwise, this creates a global variable "i", which can lead to some very confusing bugs if another function is called that also references the global "i".


But don't make the mistake of assuming that when writing "for (var i=...)" that i is scoped to the loop block. JavaScript does not have block scope. It only has function scope, with the "Global Object" scope being the top level scope.


Only with JS <1.7. Otherwise you get block scope by using 'let instead of 'var.


Only SpiderMonkey (Gecko) has that. And it will remain that way for the foreseeable future.


You'll get better performance with

  for (var i=0, l=myLinkCollection.length; i<l; i++) { }
http://robertnyman.com/2008/04/11/javascript-loop-performanc...


Probably first time I am seeing a micro-optimization having some really significant impact on a micro-benchmark test.


Better namespacing:

  function _namespace(){};
  function _namespaceLib(){};
  
  // Define your library methods
  
  (function(){
    var _private;
    this.getPrivate = function(){return _private};
  }).apply(_namespaceLib);
  
  // Wrap your code with the new scope
  
  (function(){ with (_namespaceLib) {
    // Do anything you want here
    var local = "only visible in local scope";
    
    // The library is now in scope
    alert( this.getPrivate() );
    
    // Define your external methods
    _namespace.myAPIMethod = function(){return local};
  }}).apply({});
  
  // _private and local are not accessible
  
  _namespace.myAPIMethod(); // returns "only visible in local scope"


I thought 'with' was generally frowned upon? Is it guaranteed to work correctly in all situations?

And why is this a better namespacing method?


Yes, "with":

- adds an extra look-up when resolving scope

- creates code that sometimes isn't immediately obvious

But with this technique you basically get to forget you're writing code in a namespace. You can var myFunc; all you want without polluting the global. And you can put the library in a separate file and reference its exposed methods as if they were written in the body of your application.


Number 6 is terrible -- hacking together html from strings is just not the right away to do it. He should be generating the DOM elements and appending/nesting the generated elements appropriately, not concatenating a messy string.


Unfortunately, if you are adding a lot of elements, your performance can really suffer by creating DOM elements. It helps if you "createDocumentFragment" but as far as I know, shoving a big string into the non-standard innerHTML member is still the fasted way to add a lot of content.


That's true for IE, but not for good browsers. For firefox/safari/chrome it's negligable difference if not sometimes slightly faster to use the DOM methods.

Also, using DOM methods allows you to easier attach listeners, save references to DOM elements for later updates/use etc. That means less getElementById()'s later.

Writing HTML inside js code is just horrible (IMHO). Horrible ugly code. And obviously easier to have security issues if you're including non-sanitized user data.

#6 is a horrible idea.

As far as your JS code is concerned, HTML is a (horrible, ugly) serialization of the DOM. Manipulate the DOM programatically. Don't use HTML.


Sadly, most of us have to code for IE, just as we have to code for the "good browsers".


If you're in the 'webapp' area, where IE is a minority (20% or so), I think it's justifiable to program in a clean way and live with IE users having a slower experience.

innerHTML is just the worst thing ever invented. Ugly ugly thing.


Where does that 20% stat come from?


That might be relevant if you want to continually add many elements to the DOM, but that's rarely the case in most web applications. The benefit of using strings to shave milliseconds is heavily outweighed by the unreadable, error-prone code created when one tries to shoehorn markup into a concatenated string.


One solution I've used for storing small templates in HTML: http://ejohn.org/blog/javascript-micro-templating/

  <script type="text/html" id="user_tmpl">
    <% for ( var i = 0; i < users.length; i++ ) { %>
      <li><a href="<%=users[i].url%>"><%=users[i].name%></a></li>
    <% } %>
  </script>
Quick tip: Embedding scripts in your page that have a unknown content-type (such is the case here - the browser doesn't know how to execute a text/html script) are simply ignored by the browser - and by search engines and screenreaders.

This is quick and dirty, but much more elegant than writing HTML in JS.


For anything slightly more involved I really like Pure as a javascript template engine, http://beebole.com/pure/.

Especially when working with something like json data generated elsewhere.


Best eye-opener I had on JavaScript is Douglas Crockford's site. www.crockford.com. Many folks here probably know of it, but if you've never perused that site you're missing something good.


Crockford is awesome. Here's one of my favorite pieces he wrote on his jslint javascript parser (written in javascript): http://javascript.crockford.com/tdop/tdop.html


And agreed, the 6 techniques are not that good. If your going for speed, dont expect ppl to read your code. It wont be readable. Animations are processor dependent and the code should be streamlined as possible to make it fast FOR THE PROCESSOR. It won't look like your average JS. It's a re-factor dance for me everytime. Like tuning a car, certain things work better for tuning Ferarris than they do for a Cadillac. (I don't have either) :) MOST IMPORTANT LEARN MATH!!! you now need all that calculous and trigg and geometry. You need matrices, you need x,y,z mapping. I need everything I thought I would never need...and more. Still learning


I love JavaScript as a language, there are some neat things in it (not the least of which is expando object, whoo), but there are much better tools than it for doing application development (even if we go no further than Flex or SilverLight, we've improved dramatically over JavaScript in terms of project management and toolchain availability). If you're worried about namespacing, then you're using the language with the intention of a real application programming language. There are other ways to get code to client in a web-accessible way that doesn't mean "AJAX everywhere!"


you guys should really check out: http://www.webreference.com/programming/optimize/speedup/cha...

I have been creating some pretty crazy interfaces in 3D Javascript. I try everything I read to see if its faster. I find that its resizing elements during an animation that really affect speed. Stopping event bubbling is pretty nice too. But things I didn't know like using reverse loops because comparing to "0" is faster than an int. or setting [i] into variable after the "++" so the whole length isnt processed over and over. What about using "Math." instead of (var calc = a1 * a2 / a3), var calc = Math.round((a1*a2)/a3); because using the preMthods in the dom is faster. These things really work and I saw my performance shoot through the roof!! My number one performance enhancer though? Dont use <img> tags. The way the browsers render <img> is different than (backgroun-image:url();) and takes much more out of the speed than using a CSS background.


Also, if your using trigg based JS, having good math is important. A lot of the time if you can shorten your math into more elegant equations, you will see serious performance gains. Of course I sucked at math, still do, but I'm getting better. I now run a base set of equations and just manipulate the base equations when needed.


Regarding #6, Isn't it a better idea to do something like

['<h1>',text,'</h2>'].join('')

instead of

'<h1>'+text+'<h2>'

Something like the latter is generally frowned upon in Python because it increases the number of temporary objects that have to be allocated, I'm sure the same logic holds good for most if not all Javascript implementations as well.


Are there any js frameworks/libs that do something like this on the client :

    render_as_dom(table(tr(td("one"), td("two"))));
I'd prefer to write code like this rather than have a mix of JS and html, with html rendering on the server.


Mochikit has this in Mochikit.DOM, which does this.

I wrote something like this for YUI.

http://bitbucket.org/woadwarrior/dombuilder/



Thanks,

which led me to this -

http://www.cactusjs.com/browser/trunk/DOM/tag.js

which is basically a js version of what Ive been doing in PHP with xilla tags.

Given they've implemented both 280Atlas [Obj-J on js] and Suns Lively Kernel in Javascript, there must be a way to avoid HTML generation and even code server and browser side in a similar looking pseudo-lisp dialect...


(I'm 1/3 of 280 North, btw)

In Cappuccino each "view" object (CPView, CPButton, etc) has a DIV element as it's base, and other elements contained in that (usually just IMG, canvas/VML, or subviews' DIVs). We don't output HTML at all, but rather manipulate the DOM elements at runtime.

This sort of approach definitely makes sense for the kind of highly interactive applications Cappuccino is designed for, but maybe not for more "pagey" websites where you want search engines to be able to index it, etc.


absolutely.. [Greets + Kudos, btw]

But then so many 'web pages' now are really js apps, that google must effectively do screen scraping anyway... Perhaps we should just admit that we always need an alternate feed to provide semantic meaning [aka tags] to web crawlers/readers, and be done with it.

Maybe a system where each widget can be queried for its textual content, via a standard simple API would mean all apps made with say Cappucino would be able to emit text to a crawler, without [too much] special code being written - the framework could do it?

Running a JS program on the browser to generate the page should be a legit technique, even for pages that remain static thereafter.

Have you had a look at RaphaelJS? [normalized SVG support via JS : allows JS to do flash-style animations with an open standard behind it].


What you're looking for is inria's HOP http://hop.inria.fr/ :)

See also: Parenscript, Scheme2js (part of HOP), biwascheme.


I don't understand #5. Using a library makes something a "Hybrid Application"?


here is another really good one: http://home.earthlink.net/~kendrasg/info/js_opt/




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: