style_guide.rst 12.3 KB
Newer Older
1

2
.. _style-guide:
3

4 5
JavaScript Style Guide
======================
6

7
This document defines JavaScript style conventions, which are split into essential, coding and naming conventions.
8 9 10 11

Essential Conventions
---------------------

12
Essential conventions include generic patterns that you should adhere to in order to write *readable*, *consistent* and *maintainable* code.
13 14 15 16

Minimizing Globals
^^^^^^^^^^^^^^^^^^

Marco Mariani's avatar
Marco Mariani committed
17
Variable declarations should always be done using *var* to not declare them as
18
global variables. This avoids conflicts from using a variable name across
Marco Mariani's avatar
Marco Mariani committed
19
different functions as well as conflicts with global variables declared by third
20 21
party plugins.

Marco Mariani's avatar
Marco Mariani committed
22 23
.. XXX always pub good+bad or bad+good examples in the same order

24 25 26 27
Good Example

.. code-block:: javascript

28 29 30
  function sum(x, y) {
    var result = x + y;
    return result;
31 32 33 34 35 36
  }

Bad Example

.. code-block:: javascript

37 38 39 40
  function sum(x, y) {
    // missing var declaration, implied global
    result = x + y;
    return result;
41 42 43
  }


44 45
Using JSLint
^^^^^^^^^^^^
46 47

`JSLint <http://www.jslint.com/>`_ is a quality tool that inspects code and warns
48 49
about potential problems. It can be used online and can also be integrated
into several development environments, so errors can be highlighted while
50 51 52 53
writing code.

Before validating your code in JSLint, you should use a code
beautifier to fix basic syntax errors (like indentation) automatically. There
Marco Mariani's avatar
Marco Mariani committed
54
are a number of beautifiers available online. The following ones seem to work best:
55 56 57 58

* `JSbeautifier.org <http://jsbeautifier.org/>`_
* `JS-Beautify <http://alexis.m2osw.com/js-beautify/>`_

59 60 61 62 63
In this project, JavaScript sources have to begin with the header:

.. code-block:: javascript

    /*jslint indent: 2, maxlen: 80, nomen: true */
64

65 66
which means it uses two spaces indentation, 80
maximum characters per line and allows variable names starting with '_'.
Marco Mariani's avatar
Marco Mariani committed
67 68 69
Other JSLint options can be added in sub functions if necessary.

Some allowed options are:
70 71 72 73 74 75

* ``ass: true`` if assignment should be allowed outside of statement position.
* ``bitwise: true`` if bitwise operators should be allowed.
* ``continue: true`` if the continue statement should be allowed.
* ``newcap: true`` if Initial Caps with constructor function is optional.
* ``regexp: true`` if ``.`` and ``[^...]`` should be allowed in RegExp literals. They match more material than might be expected, allowing attackers to confuse applications. These forms should not be used when validating in secure applications.
Marco Mariani's avatar
Marco Mariani committed
76
* ``unparam: true`` if warnings should be silenced for unused parameters.
77 78 79 80 81


Coding Conventions
------------------

82
Coding conventions include generic patterns that ensure the written code is consistently formatted.
83 84


85 86
Using two-space indentation
^^^^^^^^^^^^^^^^^^^^^^^^^^^
87 88

Tabs and 2-space indentation are being used equally. Since a lot of errors on
Marco Mariani's avatar
Marco Mariani committed
89
JSLint often result from mixed use of space and tab, using 2 spaces throughout
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
prevents these errors up front.


Good Example

.. code-block:: javascript

  function outer(a, b) {
    var c = 1,
      d = 2,
      inner;
    if (a > b) {
      inner = function () {
        return {
          "r": c - d
        };
      };
    } else {
      inner = function () {
        return {
          "r": c + d
        };
      };
    }
114 115
    return inner;
  }
116 117 118 119 120

Bad Example

.. code-block:: javascript

121 122 123 124 125 126 127 128 129
  function outer(a, b) {
  var c = 1,
  d = 2,
  inner;

  if (a > b) {
  inner = function () {
  return {
  r: c - d
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
  }}}};


Using shorthand for conditional statements
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

An alternative for using braces is the shorthand notation for conditional
statements. When using multiple conditions, the conditional statement can be
split on multiple lines.

Good Example

.. code-block:: javascript

  // single line
  var results = test === true ? alert(1) : alert(2);

  // multiple lines
  var results = (test === true && number === undefined ?
                 alert(1) : alert(2));

  var results = (test === true ?
                 alert(1) : number === undefined ?
                 alert(2) : alert(3));

Bad Example

.. code-block:: javascript

  // multiple conditions
  var results = (test === true && number === undefined) ?
    alert(1) :
    alert(2);

Opening Brace Location
^^^^^^^^^^^^^^^^^^^^^^

Always put the opening brace on the same line as the previous statement.

Bad Example

.. code-block:: javascript

173
  function func()
174
  {
175 176 177 178
    return
    {
      "name": "Batman"
    };
179 180 181 182 183 184 185
  }


Good Example

.. code-block:: javascript

186 187 188
  function func() {
    return {
      "name": "Batman"
189 190 191 192 193 194 195
    };
  }


Closing Brace Location
^^^^^^^^^^^^^^^^^^^^^^

Marco Mariani's avatar
Marco Mariani committed
196
The closing brace should be on the same indent level as the original function call.
197 198 199 200 201 202

Bad Example

.. code-block:: javascript

  function func() {
203 204 205
    return {
             "name": "Batman"
           };
206 207 208 209 210 211
  }

Good Example

.. code-block:: javascript

212 213 214 215 216
  function func() {
    return {
      "name": "Batman"
    };
  }
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258


Variable Declaration Location
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Every variables should be declared at the top of its function.

Bad Example

.. code-block:: javascript

  function first() {
    var a = 1, b = 2,
      c, d;

    // ...
  }

  function second() {
    var a = 1, b = 2, c;
    var d;

    // ...
  }

Good Example

.. code-block:: javascript

  function third() {
    var a = 1, b = 2, c, d;

    // ...
  }

  function fourth() {
    var a = 1,
      b = 2,
      c,
      d;

    // ...
259 260 261 262 263 264
  }


Function Declaration Location
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

265
Non anonymous functions should be declared before use and before every statements.
266 267 268 269 270

Bad Example

.. code-block:: javascript

271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
  if (...) {
    return {
      "namedFunction": function namedFunction() { ... }
    };
  }

  // or
  if (...) {
    function namedFunction() { ... }
    return {
      "namedFunction": namedFunction
    };
  }

Good Example

.. code-block:: javascript

  function namedFunction() { ... }

  if (...) {
    return {
      "namedFunction": namedFunction
    };
  }


Anonymous Function Location
^^^^^^^^^^^^^^^^^^^^^^^^^^^

Execept if you want to keep your function without name, anonymous functions must
not be declared in the same place as the variables.

Bad Example

.. code-block:: javascript

  function first() {
    var a = 1, b = 2, func = function () {
      return a;
    };
    // ...
  }

Good Example

.. code-block:: javascript

  function second() {
    var a = 1, b = 2;

    function func() {
      return a;
    };
    // ...
  }

You can assign a variable to an anonymous function inside **non-loop** statements.

Bad Example

.. code-block:: javascript

  function third() {
    var a = 1, b = 2, func;

    for (...) {
      b.forEach(function () { ... });
339
    }
340 341
    // ...
  }
342 343 344 345 346

Good Example

.. code-block:: javascript

347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
  function fourth() {
    var a = 1, b = 2, func;

    if (...) {
      func = function () { ... };
    } else {
      func = function () { ... };
    }
    // ...
  }

  function fifth() {
    var a = [], b = [];

    function func() { ... }

    for (...) {
      b.forEach(func);
    }
    // ...
367 368 369 370 371 372 373 374 375 376 377
  }


Naming Conventions
------------------

Naming conventions include generic patterns for setting names and identifiers throughout a script.

Constructors
^^^^^^^^^^^^

Marco Mariani's avatar
Marco Mariani committed
378
Constructor functions (called with the ``new`` statement) should always start with a capital letter:
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427

.. code-block:: javascript

  // bad example
  var test = new application();

  // good example
  var test = new Application();


Methods/Functions
^^^^^^^^^^^^^^^^^

A method/function should always start with a small letter.

.. code-block:: javascript

  // bad example
  function MyFunction() {...}

  // good example
  function myFunction() {...}


TitleCase, camelCase
^^^^^^^^^^^^^^^^^^^^

Follow the camel case convention, typing the words in lower-case, only capitalizing the first letter in each word.

.. code-block:: javascript

  // Good example constructor = TitleCase
  var test = new PrototypeApplication();

  // Bad example constructor
  var test = new PROTOTYPEAPPLICATION();

  // Good example functions/methods = camelCase
  myFunction();
  calculateArea();

  // Bad example functions/methods
  MyFunction();
  CalculateArea();


Variables
^^^^^^^^^

Marco Mariani's avatar
Marco Mariani committed
428
Variable names with multiple words should always use an underscore between them.
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451

.. code-block:: javascript

  // bad example
  var deliveryNote = 1;

  // good example
  var delivery_note = 1;


Confusing variable names should end with the variable type.

.. code-block:: javascript

  // implicit type
  var my_callback = doSomething();
  var Person = require("./person");

  // confusing names + var type
  var do_something_function = doSomething.bind(context);
  var value_list = getObjectOrArray();
  // value_list can be an object which can be cast into an array

Marco Mariani's avatar
Marco Mariani committed
452 453 454
To use camelCase, when sometimes it is not possible to declare a function
directly, the function variable name should match some pattern which shows
that it is a function.
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481

.. code-block:: javascript

  // good example
  var doSomethingFunction = function () { ... };
  // or
  var tool = {"doSomething": function () { ... }};

  // bad example
  var doSomething = function () { ... };


Element Classes and IDs
^^^^^^^^^^^^^^^^^^^^^^^

JavaScript can access elements by their ID attribute and class names. When
assigning IDs and class names with multiple words, these should also be
separated by an underscore (same as variables).

Example

.. code-block:: javascript

  // bad example
  test.setAttribute("id", "uniqueIdentifier");

  // good example
482
  test.setAttribute("id", "unique_identifier");
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500

Discuss - checked with jQuery UI/jQuery Mobile, they don't use written name conventions, only

* events names should fit their purpose (pageChange for changing a page)
* element classes use “-” like in ui-shadow
* "ui" should not be used by third party developers
* variables and events use lower camel-case like pageChange and activePage


Underscore Private Methods
^^^^^^^^^^^^^^^^^^^^^^^^^^

Private methods should use a leading underscore to separate them from public methods (although this does not technically make a method private).

Good Example

.. code-block:: javascript

501 502 503 504 505 506 507 508 509 510 511
  var person = {
    "getName": function () {
      return this._getFirst() + " " + this._getLast();
    },
    "_getFirst": function () {
      // ...
    },
    "_getLast": function () {
      // ...
    }
  };
512 513 514 515 516

Bad Example

.. code-block:: javascript

517 518 519 520
  var person = {
    "getName": function () {
      return this.getFirst() + " " + this.getLast();
    },
521
    // private function
522 523
    "getFirst": function () {
      // ...
524 525 526 527 528 529 530
    }
  };


No Abbreviations
^^^^^^^^^^^^^^^^

Marco Mariani's avatar
Marco Mariani committed
531
Abbreviations should not be used to avoid confusion.
532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550

Good Example

.. code-block:: javascript

  // delivery note
  var delivery_note = 1;

Bad Example

.. code-block:: javascript

  // delivery note
  var del_note = 1;


No Plurals
^^^^^^^^^^

Marco Mariani's avatar
Marco Mariani committed
551
Plurals should not be used as variable names.
552 553 554 555 556 557 558 559 560 561 562 563 564

.. code-block:: javascript

  // good example
  var delivery_note_list = ["one", "two"];

  // bad example
  var delivery_notes = ["one", "two"];


Use Comments
^^^^^^^^^^^^

Marco Mariani's avatar
Marco Mariani committed
565 566
Comments should be used within reason but include enough information so that a
reader can get a first grasp of what a part of code is supposed to do.
567 568 569 570 571 572 573 574

Good Example

.. code-block:: javascript

  var person = {
    // returns full name string
    "getName": function () {
575
      return this._getFirst() + " " + this._getLast();
576
    }
577
  };
578 579 580 581 582

Bad Example

.. code-block:: javascript

583 584 585
  var person = {
    "getName": function () {
      return this._getFirst() + " " + this._getLast();
586
    }
587
  };
588 589 590 591 592


Documentation
^^^^^^^^^^^^^

Marco Mariani's avatar
Marco Mariani committed
593
You can use `YUIDoc <http://yuilibrary.com/projects/yuidoc>`_ and its custom comment
594
tags together with Node.js to generate the documentation from the script file
Marco Mariani's avatar
Marco Mariani committed
595
itself. Comments should look like this:
596 597 598 599 600

Good Example

.. code-block:: javascript

601
  /**
602 603
   * Reverse a string
   *
604 605 606 607 608
   * @param  {String} input_string String to reverse
   * @return {String} The reversed string
   */
  function reverse(input_string) {
    // ...
609 610 611 612 613 614 615
    return output_string;
  };

Bad Example

.. code-block:: javascript

616 617
  function reverse(input_string) {
    // ...
618
    return output_string;
619
  };
620 621 622 623 624


Additional Readings
-------------------

Marco Mariani's avatar
Marco Mariani committed
625
Resources, additional reading materials and links:
626

627 628
* `JavaScript Patterns <http://shop.oreilly.com/product/9780596806767.do>`_, main resource used.
* `JSLint <http://www.jslint.com/>`_, code quality tool.
629
* `JSLint Error Explanations <http://jslinterrors.com/>`_, a useful reference.
630
* `YUIDoc <http://yuilibrary.com/projects/yuidoc>`_, generate documentation from code.