Javascript code style

Lecture




  1. Syntax
    1. Braces
    2. Line length
    3. Indentation
    4. Semicolon
  2. Naming
  3. Nesting levels
  4. Functions = Comments
  5. Functions - under code
  6. Comments
  7. Style guides
    1. Automated Check Tools
  8. Total

The code should be as readable and understandable. This requires a good style of writing code. In this chapter, we will look at the components of this style.

Syntax

Cheat Sheet with syntax rules:

  Javascript code style

We analyze the main points.

Braces

Written on the same line, the so-called "Egyptian" style. Before the bracket - a space.

  Javascript code style

If you already have experience in development and you are used to making brackets on a separate line - this is also an option. In the end, you decide. But in the main JavaScript frameworks (jQuery, Dojo, Google Closure Library, Mootools, Ext.JS, YUI ...) the style is exactly that.

If the condition and code are short enough, for example if (cond) return null; , then writing in one line is quite readable ... But, as a rule, a separate line is still perceived better.

Line length

The maximum length of the string is agreed in the command. As a rule, it is either 80 or 120 characters, depending on what monitors the developers have.

Longer lines need to be broken. If this is not done, the translation of a very long line will be made by the editor, and this may be less beautiful and readable.

Indentation

Indenting need two types:

  • Horizontal indent, with nesting - two (or four) spaces.

    As a rule, spaces are used because they allow you to make more flexible "configuration indentation" than the symbol "Tab".

    For example:

    1 function removeClass(obj, cls) {
    2    var targetObj = obj,
    3        targetClass = cls, // <-- пробельный отступ выравнен!
    4        className = obj.className; // <--
    5    ...
    6 }

    Variables are declared vertically here, because In general, the human eye perceives (“scans”) vertically aligned information better than horizontally. This is a well-known fact among designers and to us, programmers, it will also be useful for better organization of the code.

  • Vertical indent, for better breakdown of the code - line feed.

    Used to separate logical blocks within a single function. In the example below, the functions pow , data x,n and their if processing are separated.

    01 function pow(..) {
    02    ..
    03 }
    04             // <--
    05 x = ...
    06 n = ...
    07             // <--
    08 if (n <= 1) {
    09    ...
    10 }
    11 ..

    Insert an extra line feed where it makes the code more readable. There should not be more than 9 lines of code in a row without vertical indent.

Semicolon

Semicolons should be set, even if they seem to be missing.

There are languages ​​in which the semicolon is optional, and nobody puts it there. In JavaScript, it is also not required, but you need to install. What is the difference?

It is that subtle errors are possible in JavaScript without a semicolon. You will see some examples later in the tutorial. Such is the feature of syntax. And therefore it is recommended to always put it.

Naming

General rule:

  • The variable name is a noun.
  • The function name is a verb or begins with a verb. It happens that the names for short make nouns, but the verbs are clearer.

For names, English is used (not translit) and camel notation.

For more details, read about function names and variable names.

Nesting levels

There should be few nesting levels.

For example, it is better to do checks in cycles through “continue” so that there is no additional level if(..) { ... } :

Instead:

1 for ( var i=0; i<10; i++) {
2    if (i подходит) {
3      ... // <- уровень вложенности 2
4    }
5 }

Use:

1 for ( var i=0; i<10; i++) {
2    if (i не подходит) continue ;
3    ... // <- уровень вложенности 1
4 }

The situation is similar with if/else and return . The following two designs are identical.

First:

1 function isEven(n) { // проверка чётности
2    if (n % 2 == 0) {
3      return true ;
4    } else {
5      return false ;
6    }
7 }

Second:

1 function isEven(n) { // проверка чётности
2    if (n % 2 == 0) {
3      return true ;
4    }
5  
6    return false ;
7 }

If there is a return in the if block, then the else is not needed.

It is better to quickly handle simple cases, return the result, and then deal with the complex, without an additional level of nesting.

In the case of the isEven function, it would be easier to proceed:

function isEven(n) { // проверка чётности
   return n % 2 == 0;
}

.. It would seem, you can go further, there is an even shorter version:

function isEven(n) { // проверка чётности
   return !(n % 2);
}
... However, the code !(n % 2) less obvious than n % 2 == 0 . Therefore, in fact, the latter is worse. The main thing for us is not the brevity of the code, but its simplicity and readability.

Functions = Comments

Functions should be small. If the function is large - it is desirable to break it into several.

This rule is difficult to follow, but worth it. What is the comment here?

Calling a separate small function is not only easier to debug and test - the fact of its presence is an excellent comment .

Compare, for example, the two showPrimes(n) functions to display primes up to n .

First option:

01 function showPrimes(n) {
02    nextPrime:
03    for ( var i=2; i<n; i++) {
04
05      for ( var j=2; j<i; j++) {
06        if ( i % j == 0) continue nextPrime;
07      }
08     
09      alert(i); // простое
10    }
11 }

The second option is the subfunction isPrime(n) to check for simplicity:

01 function showPrimes(n) {
02   
03    for ( var i=2; i<n; i++) {
04      if (!isPrime(i)) continue ;
05      
06      alert(i); // простое
07    }
08 }
09
10 function isPrime(n) {
11    for ( var i=2; i<n; i++) {
12      if ( n % i == 0) return false ;
13    }
14    return true ;
15 }

The second option is simpler and clearer, isn't it? Instead of a piece of code, we see a description of the action that takes place there (check isPrime ).

Functions - under code

There are two ways to arrange the functions necessary to execute code.

  1. Functions on the code that uses them:

    01 // объявить функции
    02 function createElement() {
    03    ...
    04 }
    05
    06 function setHandler(elem) {
    07    ...
    08 }
    09
    10 function walkAround() {
    11    ...
    12 }
    13
    14 // код, использующий функции
    15 var elem = createElement();
    16 setHandler(elem);
    17 walkAround();

  2. First the code, and the functions below:
    01 // код, использующий функции
    02 var elem = createElement();
    03 setHandler(elem);
    04 walkAround();
    05
    06 // --- функции ---
    07
    08 function createElement() {
    09    ...
    10 }
    11
    12 function setHandler(elem) {
    13    ...
    14 }
    15
    16 function walkAround() {
    17    ...
    18 }

... In fact, there is still a third "style" in which the functions are randomly scattered around the code, but this is not our method, is it?

As a rule, it is better to allocate functions under the code that uses them. That is, this is the 2nd way.

The fact is that when reading such a code, we want to know first of all what it does , and only then what functions help it. If the code goes first, then it just gives the necessary information. As for the functions, it is quite possible that we will not need to read them, especially if they are adequately named and what they are doing is understandable.

The first method, however, has the advantage that at the time of reading we already know what functions exist.

Thus, if no one thinks about the names of functions, it may be the best choice. Try both options, but in my practice, the second one is preferable.

Comments

The code needs comments. They can be divided into several types.

  1. Reference comment before the function - about what exactly it does, what parameters it takes and what it returns.

    For such comments, there is a JSDoc syntax.

    01 /**
    02   * Возвращает x в степени n, только для натуральных n
    03   *
    04   * @param {number} x Число для возведения в степень.
    05   * @param {number} n Показатель степени, натуральное число.
    06   * @return {number} x в степени n.
    07   */
    08 function pow(x, n) {
    09    ...
    10 }

    Such comments are processed by many editors, such as Aptana and the editors from JetBrains. They take them into account when autocompleting.

  2. A brief comment on what exactly happens in this block of code.

    In good code, it is rarely needed, since everything is clear from the variables, function names.

  3. There are several ways to solve the problem. Why was this one chosen?

    As a rule, it is possible to understand from the code what it does. Of course, everything happens, but in the end, you see this code. Much more important may be what you do not see !

    Why is this done that way? To this the response code itself does not give.

    For example, you tried to solve the problem differently, but it did not work out - write about it. Why did you choose this particular solution? This is especially important in cases when not the first method that comes to mind, but some other one is used.

    Without this, for example, this situation is possible:

    • You open the code that was written some time ago, and you see that it is “non-optimal”.
    • You think: "What a fool I was," and rewrite under the "more obvious and correct" option.
    • ... The rush, of course, is good, but only this option you have already thought about before. And they refused, and why - they forgot. In the process of rewriting, they remembered, of course (fortunately), but the result was a loss of time to re-think.

    Comments that explain code behavior are very important. They help to understand what is happening and make the right decision about the development of the code.

  4. What non-obvious features does this code provide? Where else in the code are they used?

    In a good code should be at least unobvious. But where it is - please comment.

  5. The architectural commentary is “how it is, in general, arranged.” Applied technologies, interaction flow. For this, in particular, UML is used, but it is possible without it. The main thing is to be understood.

What is interesting, in the code of novice developers, most of the comments are usually of type 2. But in fact, these comments are the most unnecessary. And the thing is that people are too lazy to invent the correct names and structure the functions. Well nothing. Life will force: /

Style guides

When a whole team is involved in writing a project, there should be one code standard describing where and when to put spaces, commas, line breaks, etc.

Now, when there are so many finished projects, it makes no sense to invent your entire style guide. You can take already ready, and to which, if desired, you can always add something.

Most are in English, let me know if you find a good translation:

  • Google JavaScript Style Guide
  • JQuery Core Style Guidelines
  • Idiomatic.JS (there is a translation)
  • Dojo Style Guide

In order to begin development, the elements of styles indicated in this chapter will suffice. In the future, look at these guides, find "your" style.

Automated Check Tools

There are online services that check the style of the code.

The most famous are:

  • JSLint - checks the code for compliance with the JSLint style, in the online interface, you can enter the code at the top, and various test settings at the bottom to make it softer.
  • JSHint is another version of JSLint that weakens requirements in a number of places.
  • Closure Linter - check for compliance with the Google JavaScript Style Guide.

All of them are also available in the form of programs that can be downloaded.

Total

The described principles of code design are relevant in most projects. There are other useful conventions.

Following (or not following) them, it is necessary to remember that any style tips are good only when they make the code more readable, understandable, easier to maintain.

Importance: 4

What flaws do you see in the style of this example?

01 function pow(x,n)
02 {
03    var result=x;
04    for ( var i=1;i<n;i++) {result*=x;}
05    return result;
06 }
07
08 x=prompt( "x?" , '' )
09 n=prompt( "n?" , '' )
10 if (n<=0)
11 {
12    alert( 'Степень ' +n+ 'не поддерживается, введите целую степень, большую 0' );
13 }
14 else
15 {
16    alert(pow(x,n))
17 }

Decision

You may have noticed the following disadvantages:

  1. There are no spaces - between the parameters, around operators, with the nested call alert(pow(...)) .
  2. The variables x and n assigned without var .
  3. Braces are located on a separate line.
  4. Logically different code fragments: prompt input and its if processing are not separated by a vertical space.
  5. The string with alert too long, it is better to split it into two.
  6. Not everywhere there are semicolons.
[Open task in new window]

Importance: 4

What flaws do you see in the style of this example?

01 function pow(x, n) {
02    if (n < 1 || n != Math.round(n)) {
03      return NaN; // проверка: n должно быть целым, 1 или больше
04    }
05
06    return result(x, n);
07  
08    // ----
09
10    function result(x, n) {
11      return (n == 1) ? x : x*result(x, n-1); (n == 1) ? x : x*result(x, n-1);
12    }
13
14 }

Decision

The main error is the wrong choice of the function name result .

  1. First, it is a noun, and therefore there can be no function (unless there is any special agreement on naming).
  2. Secondly, the result variable is traditionally used to store the “current result of a function”. Here this tradition is broken.

How to call a function correctly? One option is the prefix do , i.e. doPow , it means that this function does the actual work.

Also not the best option - check with the comment. Typically, the code becomes more readable if you make unobvious actions in a new function. In this case, the name of this function will serve as a comment.

PS Recursion during exponentiation is not the best choice, a normal cycle will be faster, but this is more a flaw in logic than an error of style.

Corrected code:

01 function pow(x, n) {
02    if (!isNatural(n)) {
03      return NaN;
04    }
05
06    return doPow(x, n);
07  
08    // ----
09    function isNatural(n) {
10      return n >= 1 && n == Math.round(n);
11    }
12
13    function doPow(x, n) {
14      return (n == 1) ? x : x*doPow(x, n-1); (n == 1) ? x : x*doPow(x, n-1);
15    }
16
17 }

[Open task in new window]

Comments


To leave a comment
If you have any suggestion, idea, thanks or comment, feel free to write. We really value feedback and are glad to hear your opinion.
To reply

Scripting client side JavaScript, jqvery, BackBone

Terms: Scripting client side JavaScript, jqvery, BackBone