The case against Hungarian notation in JavaScript
For years, I’ve used Hungarian Notation when programming in JavaScript. Both of my books use Hungarian notation for all code examples and recommend that others do the same. Now, I’ve been aware of the arguments against using Hungarian notation for a while as well, but most just said, “don’t use it” without offering much in the way of an alternative. For a while, I feverishly pushed forth Hungarian notation as the most appropriate way to write JavaScript code. Recently, however, I’ve had a change of heart.
Truth be told, I’ve found more issues in enterprise applications with JavaScript using Hungarian notation. My list of complaints are as follows:
- No consistency – If you go to one company and look at their code, then go to another company and look at theirs, the Hungarian notation may not line up. In one company, a prefix of “d” might denote a double while another may use it to denote a DOM element and another may use it to denote a
Dateobject. So Hungarian notation isn’t portable, you can’t take it with you from company to company. This lack of consistency introduces the possibility of errors as developers try to adapt to new environments and coding systems. This is bad. - Functions become ugly – in true Hungarian notation, function names should also be prefixed. The problem is that JavaScript functions are actually objects, so do you prefix it with the object type (a function, perhaps “fn”) or the return type (maybe “i” in the case of a function that returns the type)? Code becomes less readable when functions are prefixed, so often they’re left off. Now you have inconsistency and no way to figure out what the function is returning without examining the source code.
- Doesn’t work with OOP – confusion sets in when talking about properties and methods of objects. Should properties be prefixed as well? If you do, then you end up with code looking like
oCar.iYear = 2005, which is hard to read. So, most developers don’t prefix properties or methods, which is once again inconsistent. It’s just as important, if not more so, to know the data type of the properties on an object. Very bad. - Too many exceptions – the previous points are all about exceptions to Hungarian notation. There are other exceptions, such as iteration variable (think
iinforloops). Too many exceptions negate a rule.
After thinking about these problems for a while, I decided that Hungarian notation is just not the way to go for JavaScript. There are too many problems to overcome. So I started from scratch, and after looking over some the ECMAscript 4 spec, I’ve come up with what I believe is a better, more flexible, and more readable way of expressing the data type of variables, properties, and functions. Here’s the format I’ve been using lately:
variable_name /*:data_type*/ = value;
So what’s going on here? Basically, the data type is expressed in a special inline comment that begins with a colon (:), inspired by the syntax for ECMAScript 4. Unlike Hungarian notation, this is a full description of the data type (String, Number, etc.) instead of just a prefix, so there can be no confusion as to the intended data type of the variable. What’s more, this can be used with functions for both arguments and return values:
function add(value1 /*:int*/, value2 /*:int*/) /*:int*/ {
return value1 + value2;
}
Here, each argument gets its own comment indicating the data type (int). The function also gets its own comment after the parentheses to indicate the return value of the function (also int). What’s more, this works perfectly well for object properties too:
function MyObject() {
this.age /*:int*/ = 28;
this.name /*:String*/ = "Nicholas";
}
There are many reasons I like this syntax as an alternative to Hungarian notation:
- It’s verbose – there can be no confusion as to what data type was intended. Even if one developer uses
intand another usesNumber, it’s still clear what the intended data type is. - It’s a syntax hook – this technique makes it very obvious as to the type of data a variable will contain. This gives editors, documentation tools, etc., a standard syntax hook to grasp onto. Editors can use this for help with autocomplete, for example.
- Better readability – scanning the code, it’s much easier to tell what’s going on . The code “reads” clearer, such as, “define name as a string.”
- Easily removed – since this technique involves using comments, code crunchers or minifiers won’t be affected. These comments will be stripped out just like all the others. No change to your build process is necessary.
The bottom line is that I consider these data type comments to be a better way of writing self-documenting JavaScript code. I’ve tried training myself towards using data type comments and away from Hungarian notation, and it’s now become just as comfortable for me. I highly recommend sticking to the known JavaScript data types and those that will be in ECMAScript 4: Array, Boolean, byte, char, Date, decimal, double, Error, float, Function, int, long, Number, Object, RegExp, sbyte, short, String, uint, ulong, ushort, and Void. Void should be used for any functions that don’t return a value; Object should be used for any variable or argument that can be any type (use similar to its use Java or C#). By sticking to these, you can guarantee forward compatibility with ECMAScript 4, minimizing any code changes in the future (should anyone besides Firefox decide to implement it, of course).
I’m sure this post won’t go over well with many JavaScript developers, but I just ask that you have an open mind and give this a shot.
Disclaimer: Any viewpoints and opinions expressed in this article are those of Nicholas C. Zakas and do not, in any way, reflect those of my employer, my colleagues, Wrox Publishing, O'Reilly Publishing, or anyone else. I speak only for myself, not for them.
Both comments and pings are currently closed.




23 Comments
This is a good idea for keeping track of what was intended (during creation), but you still have to look back to the line of creation to determine what was intended. With the Hungarian Notation (that you’ve promoted in your books) the intention follows the variable name everywhere it goes (not requiring reference back to the line of creation).
Lonnie Best on November 1st, 2006 at 8:49 am
What do you do for variables containing host objects. E.g. for a generalised node would you use any of the following (particularly given that IE uses COM objects):-
var node /* : Node */;
var node /* : Element */;
var node /* : HTMLElement */;
?
Julian Turner on November 1st, 2006 at 9:04 am
It’s my oppinion that this line is hard to read :
function add(value1 /*:int*/, value2 /*:int*/) /*:int*/
The arguments aren’t quite clear at a first glance.
Razvan Mocanu on November 1st, 2006 at 9:21 am
I personally don’t like Hungarian notation. I went from using it, to not using it, then back to using it (for the books).
Julian, I’d use the most specific type. If the element is a <div/>, then its obviously an HTMLElement (in an HTML DOM). If its <myHome/> in an XML DOM, it’s Element. That’s how I’d do it, at least.
My own personal opinion: I like it. I’m not a fan of ECMAScript 4′s syntax, but I like this. Its much better than Hungarian, if you ask me.
Jeremy McPeak on November 1st, 2006 at 9:50 am
Lonnie – this is the same as other languages where you define the type of the variable at the point of declaration. You do have to look back, which I don’t see as a downside. That’s what a variable declaration is supposed to do!
Julian – I echo Jeremy’s response, use the one that’s most specific and most understandable (just like any other OO language). In the case of IE, I’d use the object names that are supposed to be implemented (HTMLElement, HTMLDivElement, etc.) as opposed to saying anything about COM objects.
Razvan – the arguments may not be as clear to you when you first start using this. As with everything else, it takes time to get used to the syntax. You can make it more readable by putting only one argument per line.
Nicholas C. Zakas on November 1st, 2006 at 1:25 pm
Yahoo uses scriptdoc.
http://www.scriptdoc.org/
Here’s an example:
* @constructor
* @param {String} id of the element that is linked to this instance
* @param {String} sGroup the group of related DragDrop objects
* @param {object} config an object containing configurable attributes
* Valid properties for DragDrop:
* padding, isTarget, maintainOffset, primaryButtonOnly
*/
YAHOO.util.DragDrop = function(id, sGroup, config) {
if (id) {
this.init(id, sGroup, config);
}
};
Les on November 1st, 2006 at 2:50 pm
Jeremy, Nicholas
Thanks, as you say, best to use the type name as set out in the W3C JavaScript bindings, and not worry about COM.
I will experiment with this style, and I like the idea.
Regards
Julian
Julian Turner on November 1st, 2006 at 4:28 pm
Les – yes, I know many people who use ScriptDoc because they use JSDoc. Using data type comments doesn’t mean you can’t use ScriptDoc too; they aren’t mutually exclusive. My issue with ScriptDoc is that the information is too far away from the code so you’re more likely to forget to change the comment if/when the code changes.
Nicholas C. Zakas on November 1st, 2006 at 4:48 pm
I guess this style turns into a headache when you want to comment a block of code.
JCurtis on November 2nd, 2006 at 6:45 pm
JCurtis – why is that? This doesn’t prevent you from using block comments anywhere else.
Nicholas C. Zakas on November 3rd, 2006 at 12:41 am
JCurtis may be thinking of this, which produces a syntax error in IE6
/*
var i /* : int */ = 1;
*/
On a separate note, when I look at the ECMA4 working group documents, some of the machine types like "byte" no longer seem to be proposed. I.e. the typing system seems to be in a state of flux. Is this your understanding?
Julian Turner on November 3rd, 2006 at 4:06 am
Does this mean we’re all going to get a new copy of your book with the revised notation?
I’m just about to start reading your book, JS for Web Devs, this weekend so I’ll try and substitute as I’m going along.
Why not leave the comments out of the code and instead put it at the end of the line:
var i = 1; /*:int*/
or
function foo(bar, fnord) { /*:int:string:int*/
This allows for code to be readable quickly but still has the information close to the code.
Andrew Herron on November 3rd, 2006 at 12:03 pm
Julian – Good point. This is where I point out that the "best practices" way of commenting out a block of code is actually to use single-line comments, not block quotes.
Andrew – I believe having the comments within the code is more readable and more like other programming languages. As soon as you remove the data type from the area of the variable, you’re inviting forgetfulness. And yes, the ECMAScript 4 proposal is still in flux. Who knows what we’ll end up with when it’s finished.
Nicholas C. Zakas on November 3rd, 2006 at 3:29 pm
Yes, I was thinking of what Julian said. And I think that single-line comments for blocks are good when your editor supports this operation, so you can do it quickly. Here is the idea I have just came up with:
var x = 5; // Number
var z = 2; // Number
function f(x, y) { // f(Point, Point):Double
}
JCurtis on November 4th, 2006 at 4:33 am
JCurtis – again, you’re confusing the point. By moving the data type comment away from the code, you’re introducing the possibility of forgetting to update the comment when the code is changed. And your method also doesn’t allow other implementation comment on the same line. So I can’t do this with your technique:
var x /*:int*/ = 100; //left coordinate
I respect your right to disagree with me, but I hardly think your proposal is a better solution.
Nicholas C. Zakas on November 4th, 2006 at 3:18 pm
I don’t really like Hungarian notation. If a language is statically typed, you can’t get away with not using its proper type, and if it’s dynamically typed, I see using different types on the same variable as a time-saver.
I do, however, like Pascal-style type declarations. I hope they make their way into the language itself one day (for cases in which type safety is needed). However, I like Pascal’s way of only declaring the type at the end of same-typed variables. Example:
program AddingExample;
procedure Add(a, b: word; var c: word);
begin
c := a + b
end;
var
TheAnswer: word;
begin
Add(2, 3, TheAnswer);
WriteLn(TheAnswer)
end.
That is, instead of:
function add(value1 /*:int*/, value2 /*:int*/) /*:int*/
it would be more concise to write:
function add(value1, value2 /*:int*/) /*:int*/
wouldn’t it?
zooplah on November 5th, 2006 at 3:31 am
zooplah – Yes, it would be more concise, but it would also be a bit less clear. In ECMAScript 4, each variable needs to be declared with its own data type, which is why I’m using the same technique.
Nicholas C. Zakas on November 5th, 2006 at 2:56 pm
I hate Pascal-type syntax. I really, really wish ECMAScript wouldn’t use it.
var string myString = "value";
is hella easier to read than
var myString : string = "value";
That doesn’t do anything for the topic at hand; I just needed to vent
Jeremy on November 5th, 2006 at 8:36 pm
Jeremy – when you say "easier to read", you really mean "easier for me to read."
Is there really that much of a difference between, "Define a string variable called myString," and "define a variable myString of type string"?
Nicholas C. Zakas on November 5th, 2006 at 11:54 pm
Oh no! Its hella easier to read for everyone!
Jeremy on November 6th, 2006 at 9:16 am
I have been experimenting converting my code base to your commented-out annotated proposal, and am finding that it is a discipline which is making my code easier to read and work with.
There are some problems I am finding in deciding what to write for the type annotation. My working approach is:-
1. Wildcard (*)
At the moment I am using the VB "Any" word. Easy to search and replace against.
2. Current Native Types
Object, Array, String, Number, RegExp, Boolean.
3. Proposed new native types
For floating point, I am sticking with Number.
For integers, I am sticking with "int", rather than "uint".
For chars, I am using "char", but I don’t think the current spec is proposing this.
4. JavaScript DOM Bindings.
I am using the w3 DOM Bindings, Window, Document, HTMLElement, HTMLIFrameElement etc.
This is in the hope that Microsoft moves to this for a future IE.
5. Other Host Objects (ActiveX, COM etc)
I am not sure how to deal with these.
At present, I am opting for
/*: HostObject(Scripting.FileSystemObject)*/
/*: HostObject(Word.Application)*/
Which I can do a search and replace on later.
6. Union Types
For unions I am using
/*: (Boolean,Number)*/
7. Array/Object property typing
The spec currently proposes
"Array.<String>" etc
although there is a counter proposal for
"Array of String"
I am sticking with the latter at the moment.
Julian
Julian Turner on November 27th, 2006 at 7:43 am
I agree with Jeremy about the Pascal-like syntax being a bit awkward. Now, I love Pascal, much more than C, but JavaScript already uses a C-like syntax and mixing that with a Pascal-like syntax seems a bit chimeric.
zooplah on January 5th, 2007 at 12:14 pm
Zooplah – well, you probably won’t like JavaScript 2.0 so much then. It uses the Pascal-style typing system. I’m just following suit.
Nicholas C. Zakas on January 5th, 2007 at 1:11 pm
Comments are automatically closed after 14 days.