Code Conventions for the JavaScript Programming Language
javascript.crockford.com
javascript.crockford.com
Is the 80 col limit still valid in the modern day with such large screen displays? . His line indentation convention is inconsistent. In one place he says to use 8 spaces, in another he says to use 4. Then when you look at a switch, its 0. . variable declarations: If he's referring to the way that JSLint enforces it, that's stupid. ex:
function foo(){
myGlobal = "foo";
}
var myGlobal;
"All functions should be declared before they are used"Yes, but not in the way that JSLint enforces it. See above.
"Inner functions should follow the var statement."
umm, no? This has a different meaning from a function declaration.
"Do not use _ (underbar) as the first character of a name. It is sometimes used to indicate privacy, but it does not actually provide privacy. "
It's private because you weren't invited to use it, not because I have a bomb waiting for you.
"If privacy is important, use the forms that provide private members. Avoid conventions that demonstrate a lack of competence."
Whatever, show me an efficient, non-convoluted pattern that allows inheritance of privileged members. Avoid conventions that demonstrate a lack of concern for memory consumption and efficiency.
"Global variables should be in all caps."
umm, no. That convention is reserved for constants.
"Each group of statements (except the default) should end with break, return, or throw. Do not fall through."
Arbitrary. I think DRY is preferable when it's warranted.
"Avoid use of the continue statement. It tends to obscure the control flow of the function. "
It's ok to use labels, but not continue? I don't understand this logic.
"Avoid doing assignments in the condition part of if and while statements. "
It's a legitimate convention if wrapped with an extra pair of parenthesis. Note that Mozilla's strict mode will honor this convention.
function foo(){
myGlobal = "foo";
}
var myGlobal;
This is clear if you only have this one function, but with a large js file I know I'd rather not be searching through the code for global variables. That's also why "Inner functions should follow the var statement", it's an easy way to keep track of scope."Do not use _ (underbar) as the first character of a name. It is sometimes used to indicate privacy, but it does not actually provide privacy. " It's private because you weren't invited to use it, not because I have a bomb waiting for you.
No, it's private because it throws an error if you try to use it outside of the proper scope. From what I can tell about Python, for example, adding underbars enforces privacy, JavaScript doesn't.
"Global variables should be in all caps." umm, no. That convention is reserved for constants.
That convention in other languages is for constants. Crockford points out that js doesn't have constants. He also constantly points out the dangers of global variables, how you should minimize their use. The purpose of all caps is to give a visual cue that they're global, the purpose of all caps in other languages is to give a visual cue that they're constants.
"Each group of statements (except the default) should end with break, return, or throw. Do not fall through." Arbitrary. I think DRY is preferable when it's warranted.
Crockford used to think the same. He tells the story of a user who suggested fall-through should be flagged by JSLint. Crockford gave him a detailed response explaining that there was nothing wrong with fall-through. The user agreed, and included a bug report for JSLint in his response. Crockford found the bug in JSLint and it was caused by... fall-through.
"Avoid doing assignments in the condition part of if and while statements. " It's a legitimate convention if wrapped with an extra pair of parenthesis. Note that Mozilla's strict mode will honor this convention.
Crockford points out the problems you can run into doing that:
Is
if (a = b) {
a correct statement? Or was if (a == b) {
intended?It's easy enough to tell if you're the one who wrote it, but what happens to the poor sorry schlub who's trying to debug the code later on (especially if that schlub is you 6 months later)?
That's not true, an initial underscore is simply used as the convention to indicate that something is private:
>>> class Foo(object):
... def __init__(self):
... self._bar = 48
...
>>> a=Foo()
>>> a._bar
48 >>> class Foo(object):
... def __init__(self):
... self.__a = 42
... def look_here(self):
... print self.__a
...
>>> f = Foo()
>>> f.__a
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'Foo' object has no attribute '__a'
>>> f.look_here()
42 >>> class Foo(object):
... def __do_something(self):
... print 'something was done'
...
>>> f = Foo()
>>> f.__do_something()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute '__do_something'
>>> f._Foo__do_something()
something was doneThis is a good example of Python making it harder for you to do the wrong thing. Sure.. you could access that "private" attribute, but you have to do it in a way that isn't obvious, and definitely more hard to read.
And what about functions in the outer scope? Why should one be forced to place them in a particular order to use them in an inner scope? God forbid if you have this:
function first(){
//stuff
someVal = second()
//stuff
}
function second(){
//stuff
anotherVal = first()
//stuff
}
"No, it's private because it throws an error if you try to use it outside of the proper scope."This is what I'm talking about:
function Point(x, y){
this._x = parseInt(x,10);
this._y = parseInt(y,10);
}
Point.prototype = {
get x() this._x,
set x(v) this._x = parseInt(v,10),
get y() this._y,
set y(v) this._y = parseInt(v,10)
}
You simply don't document the "private" properties. Pretending JavaScript is more robust than it is helps no one and wastes memory."That convention in other languages is for constants. Crockford points out that js doesn't have constants."
It's been supported since JavaScript 1.5.
"The purpose of all caps is to give a visual cue that they're global"
Hungarian notation works fine thank you.
"Crockford used to think the same. He tells the story of a user who suggested fall-through should be flagged by JSLint. Crockford gave him a detailed response explaining that there was nothing wrong with fall-through. The user agreed, and included a bug report for JSLint in his response. Crockford found the bug in JSLint and it was caused by... fall-through."
I don't see the relevance.
"if (a = b) {"
I've already pointed out that there is already a common, testable convention in place:
if((a = b)){
Use Mozilla's strict mode and you'll be able to see the difference.I can't speak for Crockford, but I would note that "function foo() = {}" is equivalent to "var foo = function () {}", so it may be for the same reason for declaring global variables up top.
You simply don't document the "private" properties. Pretending JavaScript is more robust than it is helps no one and wastes memory.
I don't think we're talking about the same thing. I'm talking about private variables, the same way they are used in other programming languages: variables that cannot be accessed from outside the object. When you try to access private variables in other languages it throws an error, and you want it to throw an error, that's why you make it private. You don't want it accessed. Crockford shows how you can do that in js. Consider this version of the code you gave:
function Point(x, y){ this._x = parseInt(x,10); this._y = parseInt(y,10); var _private = 'foo' } Point.prototype = { get x() this._x, set x(v) this._x = parseInt(v,10), get y() this._y, set y(v) this._y = parseInt(v,10) }
var myPoint = new Point(100,50); alert(myPoint._x); alert(myPoint._private);
The last alert will show 'undefined', that's intentional.
Const is not supported in IE (https://developer.mozilla.org/En/Core_JavaScript_1.5_Referen...), and wasn't originally supported in js.
I've already pointed out that there is already a common, testable convention in place: if((a = b))
Avoiding assignments in conditionals is general advice in more than just one language. Besides here's what Mozilla says about it:
assignment in a conditional (Note: you can suppress this warning by including an extra set of parentheses around the assignment) (https://developer.mozilla.org/en/New_in_Rhino_1.6R6)*
Also:
It is advisable to not use simple assignments in a conditional expression, because the assignment can be confused with equality when glancing over the code. For example, do not use the following code:*
If you need to use an assignment in a conditional expression, a common practice is to put additional parentheses around the assignment.
In other words you can put () around the assignment, but that doesn't mean you should or that it's a best practice.
Crockford literally wrote the book on JavaScript, and I've seen his defense of some of his coding conventions in various talks, so I'm inclined to give him the benefit of the doubt. If you disagree with some of them, hell, email the guy. He might explain it in better detail.
Which is an irrelevant point anyway since it still doesn't justify hijacking an already commonly accepted convention for some other purpose.
"In other words you can put () around the assignment, but that doesn't mean you should or that it's a best practice."
The point is that the meaning is clarified by using the convention.
"It is advisable to not use simple assignments in a conditional expression,..."
I would not presume to know what level of brevity is desirable for a developer in a given situation. Conventions like the one mentioned are available for clarification of such constructs.
"Crockford literally wrote the book on JavaScript, and I've seen his defense of some of his coding conventions in various talks, so I'm inclined to give him the benefit of the doubt."
Accepting an argument based on perceived authority is a logical fallacy. "the book on JavaScript" has some questionable things as well I hear:
Function.prototype.method = function(name, func) {
this.prototype[name] = func;
return this;
};
I do truly hope people don't consider such examples a good idea.A great example of site respecting the 80 chars rules is Paul Graham's essays site, reading it is a pure pleasure also because of the fine presentation.
Yes. With my previous notebook screen (1440x900) I could fit two 83-character-wide Emacs buffers side by side. With my current screen (1600x900) I can fit two 94-character-wide Emacs buffers side by side.
set textwidth=80I would rather replace the whole article with "Write readable code". Following these conventions are neither sufficient or necessary to accomplish that.
2. For a body of code written by multiple people to be readable, it helps considerably if the conventions those people follow are consistent. A document like this one can help with that.
3. It doesn't seem reasonable to expect that the author of a document like this should provide all the counter-arguments to every position he takes. It's not an in-depth analysis of what constitutes good JavaScript code, it's just a set of coding conventions.
I'm not convinced of this (at least it doesn't hold true for me). I used to believe it, mostly because it seems to be common wisdom. But I've realized over time that I can just as easily read code that's written using K&R style braces, or BSD style, or even Whitesmiths, and it really doesn't matter to me whether indentation is 2, 4, or 8 spaces.
I think some of my point of view comes from being a heavy Emacs user and having written a lot of Lisp code in the past. I don't tend to see braces/parens much for example - I let the editor take care of them.
The most important part about code conventions is that you have them. It really doesn't matter what they are. In fact, I wish fewer styleguides would pretend to be right and more would just acknowledge that they're simply whatever the originator prefers. But it's still very important that everyone agrees to follow them, even if they disagree with some of the individual aspects.
What is annoying and distracting is having conflicting styles in the same single chunk of code. Sort of like how I would not want a book to randomly change line spacing, character spacing, etc. from paragraph to paragraph. I don't really care what the spacings are, and I certainly have no problem going from one book to another where these are totally different, but I do not want them flip-flopping around in the text of a single book.
... and if you don't want to rehash those arguments, jwz has a nice summary: http://www.jwz.org/doc/tabs-vs-spaces.html
I guess that's just how these things go.
But one difference I noticed was the use of "cuddled" else in Crockford's list:
} else {
instead of PBP's: }
else {
Conway believes this is more readable and inline with K&R style (used in both conventions/practises). "Avoid lines longer than 80 characters."
This one really bugs me. 80 characters doesn't fit a whole lot of stuff. In a case where a line is more than 80 chars long I would rather see this: document.getElementsByClassName("externalLinkBig")[0].setAttribute("class", "externalLinkSmall");
than this rather ugly solution: document.getElementsByClassName("externalLinkBig")[0].setAttribute("class",
"externalLinkSmall"); document
.getElementsByClassName("externalLinkBig")[0]
.setAttribute("class", "externalLinkSmall");For all we know it may execute 'document' as a statement, and then the next lines.
Not nice IMHO
If you can fit 160 chars on the display, use 160.
document
.getElementsByClassName( 'externalLinkBig' )[0]
.setAttribute( 'class', 'externalLinkSmall' );
80 columns is definitely my preferred (but not "I'll complain") line length because I don't have my editor maximized (cringe) and long lines aren't as easy to read (especially when there's several long lines in a row, it's hard to keep them straight near the far right). 'onNextTimespanClick': function(e, el) {
return this
.onNavigationClickStopEvent(e, el)
.scrollToTop()
.animateNavChange(
this.getSelectedNavigationEl(),
$$(
'div.navigation a[href='
+ this.getHashFromUrl(el.href)
+ ']',
this.navigationContainer
)
)
.refreshItems();
}, document.getElementsByClassName("externalLinkBig")[0].setAttribute(
"class", "externalLinkSmall"
);