Manual:Coding conventions/JavaScript

Jump to: navigation, search
shortcut: CC/JS

This page describes coding conventions for JavaScript files in the MediaWiki codebase. See also the general conventions.

Linting[edit | edit source]

We use JSHint as our code quality tool. The settings for MediaWiki core can be found in .jshintrc. Many editors have plugins to provide live linting while you type (see "Plugins for text editors" on

The following options should be used in all projects.

	// Enforcing
	"bitwise": true,
	"eqeqeq": true,
	"freeze": true,
	"latedef": true,
	"noarg": true,
	"nonew": true,
	"undef": true,
	"unused": true

A typical MediaWiki-related project using jQuery and supporting IE8 might add es3: true, browser: true, and whitelist some globals:

	// Enforcing
	"bitwise": true,
	"eqeqeq": true,
	"es3": true,
	"freeze": true,
	"latedef": true,
	"noarg": true,
	"nonew": true,
	"undef": true,
	"unused": true,

	// Environment
	"browser": true,

	"globals": {
		"mediaWiki": false,
		"jQuery": false

To avoid confusion with negated options, groups "Enforcing" and "Relaxing" are used (see For example bitewise: true prohibits use of bitwise operators, whereas multistr: true tolerates use of multi-line strings.

See .jshintrc in MediaWiki core and VisualEditor for example. MediaWiki extensions must have their own .jshintrc file. Otherwise, validation will rely on an unrelated closest configuration file found by JSHint file.

Whitespace[edit | edit source]

  • Indentation with tabs.
  • No trailing whitespace.
  • Use blank lines to separate one block of logically related code from another.
  • One space on both sides of binary operators and assignment operators.
  • Keywords followed by a "(" (left parenthesis) must be separated by one space. This gives visual distinction between keywords and function invocations.
  • There should be no space between the function name and left parenthesis of an argument list.
  • There should be one space on the insides of parentheses (such as in if statements, function calls, and arguments lists).
  • Don't use operators as if they are functions (such as delete, void, typeof, new, return, ..).

These and other aspects of our style guide are enforced with JSCS.

Whitespace examples
Yes No = bar + baz;

if ( foo ) { = doBar();

function foo() {
    return bar;

foo = function () {
    return 'bar';

foo = typeof bar;

function baz( foo, bar ) {
    return 'gaz';

baz( 'banana', 'pear' );

foo = bar[ 0 ]; 
foo = bar[ baz ]; 
foo = [ bar, baz ];;

if( foo ){ = doBar () ;

function foo () {
    return bar;

foo = function() {

foo = typeof( bar );

function baz(foo, bar) {
    return 'gaz';

baz('banana', 'pear');

foo = bar[0]; 
foo = bar[baz]; 
foo = [bar,baz];

Structure[edit | edit source]

( function ( mw, $ ) {
    // Code here will be invoked immediately
    var foo, bar,
        baz = 42,
        quux = 'apple';

    function local( x ) {
        return x * quux.length;

    // Statements
    foo = local( baz );
    bar = baz + foo;

    return baz;
}( mediaWiki, jQuery ) );

Closure[edit | edit source]

Avoid leakage of variables from or to other modules by wrapping files in a closure. This gives the contained code its own scope.

This pattern is known as an immediately-invoked function expression (or "iffy"[1]).

Files (e.g. jQuery plugins) that don't reference the mediaWiki object should omit the mediaWiki and mw arguments from the iffy.

Declarations[edit | edit source]

Variables must be declared before use and should be the first statement of the function body. Each assignment must be on its own line. Declarations that don't assign a value are listed together on the same line.

Functions should be declared before use. In the function body, function declarations should go below the var statement.

Line length[edit | edit source]

Lines should wrap at no more than 80–100 characters. If a statement does not fit on a single line, split the statement over multiple lines. The continuation of a statement should be indented one extra level.

Function calls and objects should either be on a single line or split over multiple lines with one line for each segment. Avoid closing a function call or object at a different indentation than its opening.

Line breaking examples
Yes No
// One line
if ( && === 'that' ) {
    return { first: 'Who', second: 'What' };
} else { 'first', 'second' );

// Multi-line (one component per line)
if ( && === 'that' &&
    ! 'this' )
) {
    // Continuation of condition indented one level.
    // Condition closed at original indentation.
    return {
        first: 'Who',
        second: 'What',
        third: 'I don\'t know'
} else {
        [ 'first', 'array', 'parameter' ],
// Mixed one line and multi-line
if ( && === 'that' &&
    ! 'this' ) ) {

    // No varying number of segments per line.
    // Closing parenthesis should be on the left.
    return { first: 'Who', second: 'What',
        third: 'I don\'t know' };

} else { 'first', 'second',
        'third' );

    // Avoid statements looking like they are broken
    // up but still together (looks like a call with
    // one parameter).
        'first', 'second', 'third'
        [ 'first', 'array', 'parameter' ], 'second'

Comments[edit | edit source]

Comments should be on their own line and go over the code they describe. Comments separate themselves from the opening syntax with a single space and start with a capital letter. Periods should only be used when making full sentences.

Use line comments (// foo.) inside code. Save block comments (/* foo */) for documentation blocks and for commenting out code.

In older versions of MediaWiki, JavaScript code was often very poorly commented to keep the file size down. Nowadays modules are automatically minified by ResourceLoader.

Equality[edit | edit source]

  • Use strict equality operators (=== and !==) instead of (loose) equality (== and !=). The latter does type coercion.
  • No Yoda conditionals[2]

Type checks[edit | edit source]

  • string: typeof val === 'string'
  • number: typeof val === 'number'
  • boolean: typeof val === 'boolean'
  • null: val === null
  • object: val === Object(val)
  • Plain Object: jQuery.isPlainObject( val )
  • Function: jQuery.isFunction( val )
  • Array: jQuery.isArray( val )
  • HTMLElement: obj.nodeType
  • undefined:
    • Local variables: variable === undefined
    • Properties: obj.prop === undefined
    • Global variables: typeof variable === 'undefined'

Quotes[edit | edit source]

Use single quotes instead of double quotes for string literals. Remember there are no "magic quotes" in JavaScript. E.g. \n and \t work everywhere.

Globals[edit | edit source]

Only mediaWiki and jQuery should be used (in addition to the browser's native APIs). You should expose your code's functionality to other clients as functions and properties of an object within mediaWiki, e.g. mediaWiki.echo, and possibly as documented mw.config configuration variables.

For backward compatibility, many wg-prefixed variables are exposed in global scope. Don't use these, instead use mw.config functions. (See task T72470).

Naming[edit | edit source]

All variables and functions must use lowerCamelCase for their naming. For functions, verb phrases are preferred (so getFoo() instead of foo()).

The only exception are constructors used with the new operator. Those names must start with an uppercase letter (UpperCamelCase). JavaScript has no dedicated syntax for classes or constructors, they are declared as any other function. As such there is no compile-time or run-time warning for instantiating a regular function or omitting the new operator on a constructor. This naming convention is our only defence.

Names with acronyms in them should treat the acronym as a normal word and only uppercase the first letter. For example ".getHtmlApiSource()" as opposed to ".getHTMLAPISource()".

jQuery[edit | edit source]

See also jQuery

To avoid confusion with raw elements and other variables, prefix variables storing an instance of jQuery with a dollar sign ( e.g. $foo = $( '#bar' )). This matters because the DOM (e.g. foo = document.getElementById( 'bar' )) returns null if no elements were found, therefore (since null casts to boolean false) one would test the plain variable like if ( foo ). jQuery objects on the other hand (like any array or object in JavaScript) cast to boolean true. If you confuse a jQuery object with the return value of a DOM method, a condition could fail badly. In such case one would use if ( $foo.length ) instead.

Creating elements[edit | edit source]

To create a plain element, use the simple <tag> syntax in the jQuery constructor:

$hello = $( '<div>' )
    .text( 'Hello' );

When creating elements based on the tag name from a variable (which may contain arbitrary html):

// Fetch 'span' or 'div' etc.
tag = randomTagName();
$who = $( document.createElement( tag ) );

Only use $('<a title="valid html" href="#syntax">like this</a>'); when you need to parse HTML (as opposed to creating a plain element).

Collections[edit | edit source]

Different types of collections sometimes look similar but have different behaviour and should be treated as such. This confusion is mostly caused by the fact that arrays in JavaScript look a lot like arrays in other languages, but are in fact just an extension of Object. We use the following conventions:

Avoid using a for-in loop to iterate over an array (as opposed to a plain object). A for-in will iterate over the keys instead of over the indices:

  • keys are strings
  • order not guaranteed
  • index can have gaps
  • might include non-numerical properties

Pitfalls[edit | edit source]

  • Be careful to preserve compatibility with left-to-right and right-to-left languages (i.e. float: right or text-align: left), especially when styling text containers. Putting those declarations in CSS file will allow them to be automagically flipped for RTL-languages by ResourceLoader.
  • Use attr() and prop() appropriately.
    Read more:
  • Consistently quote attribute selector values: [foo="bar"] instead of [foo=bar] (jqbug 8229).
  • As of jQuery 1.4 the jQuery constructor has a new feature that allows passing an object as second argument, like jQuery( '<div>', { foo: 'bar', click: function () {}, css: { .. } } );. Don't use this. It makes code harder to follow, fails on attributes (such as 'size') that are also methods, and is unstable due to this mixing of jQuery methods with element attributes. A future jQuery method or plugin or called "title" might convert an element into a heading, which means the title attribute can also no longer be set through this method. Be explicit and call .attr(), .prop(), .on() etc. directly.
  • String methods substr(), substring(), and slice() have similar signatures. Prefer slice(). (Example commit.) If need to extract a string of a certain length from a positive non-zero offset, only then should you use substr().
    • substr() doesn't support negative start in IE8 and below.
    • substring() doesn't support negative indices. And its start/end parameters are silently swapped if start is larger than end.

Documentation[edit | edit source]

Use JSDuck to build documentation (see The documentation comment structure is broadly similar to the doxygen format we use in PHP but details differ to accommodate for JavaScript-specific language constructs (such as object inheritance, emitting events and arbitrary augmentation of an constructor's prototype).

Standard RubyGems install: gem install jsduck
See the installation guide for more information.
Generate documentation
$ jsduck
Set up configuration for new projects
Create a JSDuck configuration file (at jsduck.json). See for example JSDuck config for MediaWiki and JSDuck config for OOjs.

Documentation comments[edit | edit source]

  • Text in free-form blocks (e.g. description of methods, parameters, return values etc.) should be sentence case.
  • End sentences in a full stop.
  • Continue sentences belonging to an annotation on the next line, indented with one additional space.
  • Value types should be separated by a pipe character. Use only types that are listed in the Types section or the identifier of a different class as specified in your project (e.g. {mw.Title}).
 * Get the user name.
 * Elaborate in an extra paragraph after the first one-line summary in
 * the imperative mood.
 * @param {string} foo Description of a parameter that spans over on the
 *  next line of the comment.
 * @param {number} bar
 * @return {string} User name

Tags[edit | edit source]

We use the following annotations. They should be used in the order as they are described here, for consistency. See JSDuck/Tags for more documentation about how these work.

  • @abstract
  • @private
  • @static
  • @class Name (name is optional, engine will guess name from context)
  • @singleton
  • @extends ClassName
  • @mixins ClassName
  • @constructor
  • @inheritable
  • @member
  • @method name (name is optional, guessed)
  • @property name (name is optional, guessed)
  • @inheritdoc
  • @deprecated
  • @param {Type} name Optional text.
  • @return {Type} Optional text.
  • @chainable
  • @throws {Type}

Types[edit | edit source]

Primitive types and special values:

  • boolean
  • number
  • string
  • undefined
  • null

Built-in classes:

  • Object
  • Array
  • Function
  • Date
  • RegExp
  • Error

Browser classes:

  • HTMLElement

Reuse ResourceLoader modules[edit | edit source]

Don't reinvent the wheel. ResourceLoader makes a lot of useful MediaWiki functionality and jQuery plugins available as tested and documented ResourceLoader modules that your code can (literally) depend on. Scan the list of RL modules before rolling your own code.

Follow ResourceLoader best practices.

Final notes[edit | edit source]

Use CSS for styling many elements[edit | edit source]

Don't apply styling to lots of elements at once; this has poor performance. Instead use a common parent's class (or add one) and apply CSS in a .css or .less file. Thanks to ResourceLoader, this will all be loaded in the same HTTP request, so there's no performance penalty for having a separate CSS file. Do not set CSS into inline "style" attributes, don't insert "style" elements from JS either.

Environment[edit | edit source]

There are a few things that MediaWiki specifically (or inherently due to use of jQuery), does not support:

  • jQuery doesn't support environments that have manipulated the Object.prototype as it's considered harmful.
  • Both MediaWiki and jQuery do not support environments that have manipulated the global undefined variable as it's considered harmful. As of ECMAScript5 this is no longer an issue since it is made read-only (as it should be), but in older browsers this can cause issues.

Enforcing[edit | edit source]

In order to enforce the conventions and/or guidelines, you should consider setting up Continous integration to check many of them so reviewers don't have to.

References[edit | edit source]

  2. yodaconditional.jpg

Coding conventionsManual:Coding conventions
General All languagesManual:Coding conventions#Code structure · Security for developersSecurity for developers · Pre-commit checklistManual:Pre-commit checklist · Performance guidelinesPerformance guidelines (draft) · Style guideStyle guide · Accessibility guide for developersAccessibility guide for developers (draft)
PHP Code conventionsManual:Coding conventions/PHP · PHPUnit test conventionsManual:PHP unit testing/Writing unit tests#Test_conventions · Security checklist for developersSecurity checklist for developers
JavaScript Code conventionsManual:Coding conventions/JavaScript · Learning JavaScriptLearning JavaScript
CSS Code conventionsManual:Coding conventions/CSS
Database Code conventionsManual:Coding conventions/Database
Python Code conventionsManual:Coding conventions/Python
Ruby Code conventionsManual:Coding conventions/Ruby
Selenium/Cucumber Code conventionsManual:Coding conventions/Selenium
Java Code conventionsManual:Coding conventions/Java
API client code Standards for API client librariesAPI:Client code/Gold standard