Hacker News new | past | comments | ask | show | jobs | submit login
JavaScript Patterns Collection (shichuan.github.com)
108 points by sjclemmy on March 18, 2013 | hide | past | favorite | 31 comments



Some have commented that the linked article may not always contain best practices. The following links always seem to get fantastic praise - they're permanently in my JS bookmarks. Having an understanding of the core language rather than using frameworks is a great start; these articles will certainly help.

Eloquent JavaScript: http://eloquentjavascript.net/contents.html

Learning JavaScript Design Patterns: http://addyosmani.com/resources/essentialjsdesignpatterns/bo...

JS The Right Way: http://jstherightway.com/

Learning Advanced JavaScript: http://ejohn.org/apps/learn/

Ask HN: JavaScript Dev Tools: http://news.ycombinator.com/item?id=3550998

MVC Architecture for JS: http://michaux.ca/articles/mvc-architecture-for-javascript-a...

Large-Scale JS Application Architecture: http://addyosmani.com/largescalejavascript/

Mozilla Developer Network - Intro to OO JS: https://developer.mozilla.org/en-US/docs/JavaScript/Introduc...


I'm a big fan of JavaScript Garden: http://bonsaiden.github.com/JavaScript-Garden/#intro


This is a nice list. Thanks for the alternatives.


I'm going to be critical and say that I don't like the format of this reference; each entry in the table of contents links to a source file in github (opening in a new window/tab) instead of being, for example, a collapsed code box in the same tab.

Second, they're not .js files, but .html files with (in my opinion) obsolete / unnecessary html boilerplate surrounding it. If it's simply a page to demonstrate / display JS patterns, they should be plain .js files, I think; from what I've seen, those should run equally well in a browser and node.js.

I'm also not a fan of tab-based indentation, the examples could be a lot more compact (and readable) horizontally if using two-space indentation instead of tabs.


>I'm also not a fan of tab-based indentation, the examples could be a lot more compact (and readable) horizontally if using two-space indentation instead of tabs.

That's the forte of using tabs. Change your display width of tabs to 2 spaces instead of 4.

Tabs for indentation, spaces for alignment.


> Tabs for indentation, spaces for alignment.

And complete mess when someone other than you opens your file :)


Is there a way to change the tab width on GitHub's code viewer?


Two space indentation is great if you have a CGA monitor and don't have much horizontal room.


Also great for viewing the code on GitHub.


I'm not sure about this. The very first link I clicked had some iffy advice.

The "Function declaration" section makes an unsubstantiated claim that function declarations are an antipattern, neglecting to mention the significant difference in effect between a declaration and a function expression assigned to a variable. Declarations are subject to function hoisting; IIFEs and expressions assigned to variables aren't. (But the variables themselves are, which is further confusing.) In other words:

  fnDeclaration(); // This function is ready for use.
  function fnDeclaration() {
    console.log('This function is ready for use.');
  }

  // - but -

  fnExpression(); // TypeError: undefined is not a function.
  typeof fnExpression; // 'undefined'
  var fnExpression = function() {
    console.log('This function is ready for use.');
  };

  fnExpression(); // This function is ready for use.
  typeof fnExpression; // 'function'
Named function expressions are neat, I guess, but the trailing F looks more like an odd, Hungarian stylistic choice than a fix for a serious issue in IE<8. Given that the author(s) either didn't know or just forgot to mention (at first) the IE problems you could meet with if you followed this advice, I'm a little bit concerned about this reference.


Personally, I prefer function declaration for most functions (unless they are bound dynamically). The reason is very simple: the "function" keyword at the beginning of the line makes it very clear and obvious what's going on. I prefer the code to be its own documentation.


Also, aside from hoisting, there is a much better solution for named+assigned function declarations, because the reason for naming such a function is to use it recursively. Hence, just use the verb form of the word "recurse" and it immediately self-documents that the function is recursive:

    var fibs = function recurse(n, curr, last) {
        curr = curr || 1;
        last = last || 0;
        return n <= 0 ? last : recurse(n - 1, curr + last, curr);
    };


Good luck with your stack traces.


I can't for the life of me figure out what the right-hand side of this is doing (from https://github.com/shichuan/javascript-patterns/blob/master/...):

  var global = (function () {
    return this || (1, eval)('this');
  }());
Why not just use 'this'?


The comma operator takes two expressions, evaluates them both, and returns the second. In this case, (1, eval) becomes a reference to the eval function and then gets fed 'this'. Since the call is now indirect, the eval happens in the global scope where 'this' is guaranteed to be the global object.

It's kind of crazy. Details here: http://tinyurl.com/3mzf89r

The right side is needed for ES5 strict mode, where `this` does not become the global object in a function that wasn't called with `new`, call(), or apply(). In that case the left side will be something falsy and the right side will take over. Details here: http://tinyurl.com/cwbxvxh


Thanks! I knew what the comma operator was doing, but had no idea why.


Good discussion here [0]. I didn't know either until reading it.

[0] http://stackoverflow.com/questions/9107240/1-evalthis-vs-eva...


I'm not sure if there's some broken javascript on my browser, but the big blue navigation box sits right on top of the content, making about half the text unreadable!


Looks like it breaks on small window sizes.


Aha, you're right. Although I wouldn't call almost-full-screen on a modern MacBook Pro small.


Recommended usage:

   git clone https://github.com/shichuan/javascript-patterns.git
   cd javascript-patterns/
   cd design-patterns/
   ls


Design patterns are signs of deficiencies in the language. http://c2.com/cgi/wiki?AreDesignPatternsMissingLanguageFeatu...


Bookmarked! I always forget to remove an element from the DOM right before performing several transformations on it [0]. This is a handy list to have.

(A nav bar that didn't obscure text on narrower windows would also be nice)

[0] https://github.com/shichuan/javascript-patterns/blob/master/...


Thanks for the list, looks like I have some reading to do...

One thing I was hoping to see was some good AJAX patterns, not just saying oh well that's pattern X, but actual examples. I found this link, but sadly they never finished the following parts of the article: enterprisejquery.com/2010/07/enterprise-ajax-patterns-part-1-from-enterprise-beginnings/


What's the best pattern to use for a rails app? I've been name-spacing my js so that objects get instantiated based on controller/action using the Garber-Irish Technique. I've found this a great technique, however, I still need a way to organize my js objects into modules/submodules for example. have anyone looked into this?



That menu on the left really gets in the way. Maybe add a button to remove it?


Bookmarklet to toggle it:

  javascript:(function(){var style = document.getElementById('toc').style; style.display === 'none' ? style.display = '' : style.display = 'none';})()


I opened this page:

https://github.com/shichuan/javascript-patterns/blob/master/...

and saw this pattern used several times:

    if (value == 0) {
        return result0;
    } else if (value == 1) {
        return result1;
    } else if (value == 2) {
        return result2;
    }
I can't think of a coding standard or best practice in any language that would suggest combining return and else like that. Instead it would be:

    if (value == 0) {
        return result0;
    }
    if (value == 1) {
        return result1;
    }
    if (value == 2) {
        return result2;
    }
or:

    if (value == 0) return result0;
    if (value == 1) return result1;
    if (value == 2) return result2;
Then on this page:

https://github.com/shichuan/javascript-patterns/blob/master/...

there is this code:

    // optimization 1 - cache the length of the array with the use of `max`
    for (var i = 0, max = myarray.length; i < max; i++) {
        // do something with myarray[i]
    }
The code is OK, but 'max' is a very poor name. It sounds too much like Math.max, and it isn't the maximum value for the loop. It's one greater than that.

If you want to cache the array length like this, then any of these names would be far better than max: either 'length' to match the 'array.length', or 'len' for something shorter, or 'n' if you want it really short. These names all better reflect the meaning of this variable: the length of the array. ('n' stands for 'number', as in the number of elements in the array.)

Later on the page it recommends:

    // preferred 1
    var i, myarray = [];
    for (i = myarray.length; i--;) {
        // do something with myarray[i]
    }
I'm not a fan of running loops backwards for optimization except where it's really necessary. When I'm reading the code I rarely know whether the backwards loop is simply an optimization, or essential to the algorithm. It adds mystery to the code, and I don't like that.

Of course a comment could be added saying "Backwards loop is for optimization only" or "Backwards loop is needed for the algorithm", but I've never seen a backwards loop aficionado do this.

A few years ago I worked with someone who hated jQuery and libraries in general and preferred to write his own bare metal DOM loops for everything. And he wrote them all backwards. Later on he warmed up a bit to the idea of using jQuery, after seeing a 20-line bare metal function be reduced to a simple and straightforward selector, but when we started going through the code it was never clear if we needed to add a ":last" to the selector to make it match the backwards loop or not.

It's pretty rare that this kind of loop optimization will make much difference, unless the work done in the loop body is truly minimal.

Then on this page:

https://github.com/shichuan/javascript-patterns/blob/master/...

it has this code:

    // somewhere else in the code
    // a method was added to all objects
    if (typeof Object.prototype.clone === 'undefined') {
        Object.prototype.clone = function () {
        };
    }
Now this is part of a discussion about why you should use 'hasOwnProperty()' in a for-in loop to avoid enumerating Object.prototype additions, but there should also be a mention that you should not extend Object.prototype at all, ever, unless you are 100% certain that all the code in your page or project is under your own control and carefully uses hasOwnProperty().

For example, the Google Maps API has for-in loops that do not use hasOwnProperty(). If you extend Object.prototype, then no matter how careful you are in the rest of your own code, you'll have some confusing problems if you later want to add a Google map to your page.

(At least the Maps API used to work this way - it's possible that they have started using hasOwnProperty() now - I haven't checked it in a while. But the same problem could occur with any third-party code you may want to use.)

OK, well, on this page:

https://github.com/shichuan/javascript-patterns/blob/master/...

it does mention that you shouldn't extend Object.prototype, but there's no hint as to why you shouldn't.

On this page:

https://github.com/shichuan/javascript-patterns/blob/master/...

    switch (inspect_me) {
        case 0:
            result = "zero";
            break;
        case 1:
            result = "one";
            break;
        default:
            result = "unknown";
    }
Omitting the break; on the last case in a switch statement is a bad idea. It's too easy to add another case below that and forget the break statement. Better to use break on every case even if it is redundant at the end.


In addition, per Crockford, shouldn't we be using "===" instead of "==" in a best practice demo?


I clicked on the Builder Pattern , it linked to a file but it would be more interesting to have a bit of an explanation. That why UML diagrams are usefull. right now https://github.com/shichuan/javascript-patterns/blob/master/... is hard to understand. I would propose a simple exemple for the builder pattern .

let's say we have an array of datas : [0,10,200,50] and we want a representation of the data.

So the director would use different builders to represent these datas ( a bar chart , a line chart , etc ...).

What i find important with design patterns and often lacking in books is real use cases.You often get strange exemples that , may be interesting but you actually can use them in a real application. Usually the builder ,the fly-weight and the chain of reponsability are often explained badly or with horrible exemples.

I dream of a book that does 2 things :

- explain each pattern with real exemples and propose a list of real uses cases where the pattern would be usefull

- has an extended tutorial at the end of the book the makes the user actually build a full application with all the patterns studied. For instance , a drawing application with different shapes, pens , filters , commands , menus , undo , redo , data serialization , that would use all the main design patterns and make them work together.

If such a book exists ( in java , as3 , C# , javascript ,... (just not in C++ or smalltalk ;) ) ) , i would be interested to know about it.

Now javascript has some patterns of its own ( module pattern , etc ... ) that's interesting to know them too.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

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

Search: