Hacker News new | comments | show | ask | jobs | submit login
Ask HN: Javascript best practices?
51 points by mattiss on Sept 22, 2009 | hide | past | web | favorite | 47 comments
How much does it make sense to decompose your javascript routines into separate files? Do you have .js for related classes and methods and one page wide .js to call everything else?

EDIT: The above was just an example, I'm looking for most things related to JS.




Always use "var" to define a variable, unless you know exactly what you are doing. e.g.:

  var foo = 'bar';
When you don't use "var" the Javascript interpreter breaks out of the current scope and continues to do so all the way until it hits the final global scope (generally the window object in browsers). If it does not find the variable, it then defines it. If it does find it, it will trample the found variable with the new value. For example:

  var foo = 'bar';

  function baz() {
    foo = 'baz';
  }

  baz();

  // now foo == 'baz';
  console.log(foo);
  >>'baz'
Google "Javascript var keyword" for more info.

EDIT: I'll add that this functionality, which is part of a general language feature known as a "closure", is incredibly powerful when used successfully, but that's out of the scope of my comment.


Also, "scope" means inside a function, and not inside a control block (e.g. for loops).

I would estimate global variables will cause at least 50% of the headaches an intermediate JavaScript developer experiences. It's particularly bad when you're dealing with rows of data, for example.

Get in the habit of declaring every variable in the top line of the function concerned before you use it. If you haven't already mastered closures, this will make things a lot easier for you.


I like to use separate files for organization during development and then merge and minify for deployment. Just make sure you have an automated process because you don't want to make mistakes doing it by hand.


Any tool suggestions for the job of minifying and deployment?



+1 for YUI

+2 Grok Douglas Crockford's DOM theory then optimize how your scripts use the DOM, it is very easy to abuse the DOM, don't. Grok the DOM.


Sprockets looks promising if you're using Ruby. Haven't had a chance to use it in a project yet. http://github.com/sstephenson/sprockets


Already mentioned, but django-compress if you're using django:

http://code.google.com/p/django-compress/


JSMin is also good.


Gzip?


Apache should do this.


Make sure it actually does, too ... http://www.whatsmyip.org/http_compression/

Better yet, use Google Page Speed.


Many frameworks have some tools for dealing with multiple javascript files. I use django-compress for example and love it.

It allows you to have many different javascript files to separate your code logically, and it automatically compresses them into one file for you for deployment. In this way you don't have to compromise speed for clarity.

If you're interested in advanced JS I highly recommend this book. http://jspro.org/


Thanks, I totally forgot about the Resig book since it was announced. Just bought.

I really liked _Javascript: The Good Parts_:

http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockfor...

Particularly because it's purely about style and code organization, and not about the best way to get consistent DOM access between Gecko, WebKit, and IE.


That book is outstanding. Crockford's JSLint validator is also superb. Highly recommended for any script of more than a few lines in length.


i just had a look (thanks for the link). i downloaded some code--good stuff, no doubt better with the full explanations.

for various reasons i'm not buying the book. i do strongly recommend reading resig's blog posts. some excellent gems there. i've incorporated some great util functions from these posts, for example.

nothing is as good as working with coders who are better than you, tho ;-)


I have been eyeing books for months now. Pro Javascript Techniques has been one of them. Living in a country where shipping costs as much as a book is hard.


Living in a country where shipping costs as much as a book is hard.

Might Safari Books Online work for you?

http://www.safaribooksonline.com/

I prefer the physical book to reading from a browser, but if the price is right...


Checkout Better World Books http://www.betterworldbooks.com . Cheap worldwide shipping. Another option is to buy second hand.


I like Douglas Crockford's opinions and advice on many aspects of JavaScript:

http://javascript.crockford.com/

Conventions:

http://javascript.crockford.com/code.html

and his book "JavaScript The Good Parts" is well worth a read, even to experiences JS developers

http://www.amazon.com/exec/obidos/ASIN/0596517742/wrrrldwide...


Just my 2 cents: Javascript gives you plenty of rope to hang yourself with. Personally, I try to stay away from prototypical objects unless the style fits very cleanly with what I'm trying to do. Otherwise,the best way I've found to keep my sanity is to pick whatever language you're developing the backend with, and use as many conventions you've established there as possible.

For me, this means my Javascript looks more like Python -- it can be a little weird, but switching between the frontend and the backend is easier that way.

I'd also recommend using objects as namespaces if you're not dealing with prototypical objects. It makes grepping easier - you can search for 'Graphs.init' instead of 'init' in this example:

var Graphs = {

    state_variable: null, // store global state somehow

    init: function() {
        // Some initialization code
    },

    refresh: function(img_element, url) {
        // some code to refresh the src url
    }
};


Just remember that sometimes doing things the "right" way can really slow your code down. I started coding believing that text should be added with createTextNode and any HTML element should be created via createElement.

This causes two issues:

1. Memory leaks from deleted or hidden DOM that is still referenced.

2. Performance. innerHTML is still probably the fastest method of adding elements, as dirty as it seems.


I'll assume this is for client side js, since that's what most people use =)

Most of the js I write involves jQuery. As such, I find it's very useful to separate reusable components into jQuery plugins in separate files. If you don't use jQuery or another library which allows plugins, then it's best to create your own namespaced module.

See the "Module pattern" for more info: http://www.yuiblog.com/blog/2007/06/12/module-pattern/

Depending on the complexity of your code, you might want to look into javascript build systems -- there's at least one for every major web framework.

Here's some advantages they offer: - Allow bunding of many js files into one mega js file. (reduces HTTP requests for faster page loading) - Specify javascript dependencies using special syntax. (easier maintenance) - Versioning support (so users don't get an old cached version of your code)

When bundling js files, I try to aim for a maximum of two js files per page. One contains code which is global to the whole site (this is cached on subsequent views), and the second which contains page specific code.



I tend to create a page controller js file that my html file loads. I do not embed any JavaScript in the page rather, I grab any dom elements that I need via JavaScript so that way there is a clean separation between code and HTML. I tend to prefer Dojo as far as frameworks, so i will use dojo.byId or dijit.byId to grab references to my nodes in my page init function.

I intentionally make my controller file procedural and then I have a custom life-cycle event controller that fires off events for page init, reload, load data, page unload, etc.. so my developers can just fill in the blanks. Any data access is done by calling methods on a service facade which again is purposefully procedural. The service facade then calls any server side services we need (we don't do form posts any more, JSON is far more robust for submitting data). Finally, we use Dijit for any of our widget and any of our model / utility / OO needs.

I know it's no purely JavaScript best practices, and it is more related to project file layout and architecture, but I find it gives me the best architecture for my team size (100+). It helps me on-board people quickly and graduate their skill set while maintaining clean code and allowing advanced features.

I can start a junior on pure html layout, then we can train them to do controller modification, then to work on service facades and then when they have a good foundation in prototype base OO we can graduate them into building reusable widgets and subsystems for the controller and service facade developers. It works well and allows developers to work proficiently at their skill set without mucking up the whole system.

As well the service facades make it easy to contract out entire web projects while my internal team builds server side services to support the effort. This allows us to expand our work force, to a larger pool, without having to vet new developers to deep into business rules to get them up and running.


3 years ago, I started a blog about javascript called Javascript Kata at http://www.javascriptkata.com . I will try to write more and more about best practices and new ways of doing things.


Can anyone elaborate on when one giant JS file (benefit here is of course reducing HTTP requests) becomes too large? Right now I am splitting up JS files in a fairly simple manner: a single site-wide file with common methods and utilities, and then a handful of smaller files for various aspects of the site. I think that they are each small enough to all be combined into one single one... but when is that single file too large?


Most of the time never. Additional files means additional connection overhead. Browsers typically won't open more than 2 simultaneous connections to the same host, so too many assets can quickly lead to noticeable delays.

The one exception I can think of is if you have a lot of JS code, but some of it needs to load faster. In that case you may want to split the code into several files based on load priority. If you go that route you may want to also use multiple asset subdomains or ideally a CDN to minimize latency.


I found this quite good for constructing tidy javascript code, http://ejohn.org/apps/learn/

I haven't had time to look into this but there's also a project called Doloto to help optimise your javascript, http://research.microsoft.com/en-us/projects/doloto/


Use ===, !== etc instead of == or !=. They aren't the same


* Comment with JSDoc style

* Auto-build docs and script for development and production environemnts (easy to concatenate and then pipe this to YUI Compressor)

* Use an MVC project organization or something like-minded. You can't just throw files representing widgets around.

* Write unit tests. JSUnit and SrewUnit (I prefer the latter) work well for this.

* Format your code nicely (this goes for any code but I find a ton of terribly formatted JS)

* Use one common library for any core object prototype changes (on Element, Array, Function, etc.) and don't modify them further.

* JSLint code you're unsure about.

* The best way to dynamically load code is just to write script tags to the document.

A few style-concerned ones...

* Don't use the module pattern. It's rarely appropriate, hiding methods does nobody good, just use a closure.

* Only create elements when absolutely necessary and destroy ones that you will no longer use. There's no garbage collector in that regard.

* Use a routing system to manipulate and read document.location.hash (and the browser history) so that pages have real URLs and navigate like webpages.

* Callbacks and delegates are great, they should be used all over the place.

* Use events and listeners to connect the parts of your app.


agreed.

rules on serverside are a bit different. especially the module pattern is a must there.

in the future you might be able to pick one of those module loaders http://wiki.commonjs.org/wiki/CommonJS


Great points

Just curious. For large scale projects, do you suggest building on top of existing javascript libraries (i.e. prototype, jQuery, mootools, etc)?


+1 for jQ


If it's UI-based, I'd use ExtJS. Otherwise, MooTools. Both of these are very performant and give you a lot to work with in a neat package. jQuery UI, MochaUI, etc. are all miles behind ExtJS when it comes to behaving (reliably and efficiently) as a real tookit (with widgets and layouts).

In my opinion, jQuery is suitable for progressive enhancement but not for dedicated apps.


* For unit tests, also check out Jasmine.

* +1 on not using the module pattern.



Unfortunately they recommend the bad variant of hungarian notation. Bad, bad, bad :-(


Which variant of hungarian notation do you prefer?


See http://www.joelonsoftware.com/articles/Wrong.html, particularly the section "I'm Hungary", for a comparison between two different styles of Hungarian notation.


I remember having read that before; will take a new look and implement the good parts in my code.

Thanks!


The none kind.


When I hear "best practices" I reach for my Giant Spiked Club of Holy Wrath.


Why? What's so terrible about finding out about how those more experienced than yourself do things? I'm assuming, of course, that sound reasoning is supporting the practice rather than simple cargo culting.


It's cargo culting more often than not.

For some reason, people don't follow good advices which require changing code logic, refactoring and such: they follow advices where you need to format everything in the longest possible way and write a lot of boilerplate.

Because it's just easier for some people.


Obfuscate variable and function names with junk words. On Windows, Jasob was easily the best http://www.jasob.com/ for it (I tried using many others including online offerings). You need to do this if worried about others seeing and using your code, especially competitors.

edit: am I stupid? But when you obfuscate, you also radically shorten the length of a JS file, thus making it quicker to download: EG:

function c(g){var m=0;while(m<g.length){var r=g[m];r.l=d(r.n,r.o);if(r.j==true){ r.k=e(r.n,r.o,r.l);}else{r.k=0;}r.t=f(r.l+r.k);m++;}}


You are talking about minifying, which is great for bandwidth reduction and I suppose obfuscation.

However this post was about JS design principles.




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

Search: