The JavaScript coding standard, based on the Google JavaScript Style Guide, defines Magento requirements for code formatting and style for teams that develop Magento JavaScript and jQuery code.
Use RFC 2119 to interpret the 鈥渕ust,鈥 鈥渕ust not,鈥 鈥渞equired,鈥 鈥渟hall,鈥 鈥渟hall not,鈥 鈥渟hould,鈥 鈥渟hould not,鈥 鈥渞ecommended,鈥 鈥渕ay,鈥 and 鈥渙ptional鈥 keywords.
The Magento system uses the jQuery library including the standard and custom jQuery widgets. For the jQuery widget coding standard, see jQuery widget coding standard.
Some parts of Magento code might not comply with this coding standard.
This coding standard is recommended for third-party Magento developers.
Contents:
JSHint tool
Use JSHint to ensure the quality of your JavaScript code.
JSHint is a community-driven tool that detects errors and potential problems in JavaScript code. Its flexibility enables you to customize it to your coding standard and expected code execution environment. jQuery core passes JSHint.
Formatting
See one of the following sections:
- Anonymous functions
- End of file
- Function arguments
- Indentation
- Indent wrapped lines
- Line length
- Line termination
- Multiline string literals
- Parentheses
- Statements and conditions
- Strings
Anonymous functions
When you declare an anonymous function in the list of arguments for a function call, indent the body of the function four spaces from the left edge of the statement, or four spaces from the left edge of the function keyword.
This makes the body of the anonymous function easier to read.
End of file
The last line in a file also must end with a single linefeed (LF) character.
In other words, a file always ends with an empty line. This reduces quantity of the changed lines in a diff and makes code safer in files concatenation process.
Function arguments
When possible, list all function arguments on the same line.
If doing so exceeds the 120-column limit, you must line-wrap the arguments in a readable way.
To save space, try to wrap as close to 80 columns as possible (remember 120-column limit), or put each argument on its own line to enhance readability.
The indentation should be four spaces.
The following patterns are the most common patterns for argument wrapping:
Indentation
Indentation should consist of four spaces.
Tabs are not allowed.
Indent wrapped lines
You should indent all wrapped lines to be left-aligned to the expression above, or indented four spaces.
Line length
Source code line length must not exceed 120 characters.
Recommended line length is 80 characters.
- If a comment line contains an example command or a literal URL longer than 120 characters, that line can be longer than 120 characters for ease of cutting and pasting.
- Do not be concerned about header guards that exceed 120 characters.
Line termination
Line termination follows the UNIX text file convention.
Lines must end with a single linefeed (LF) character.
Linefeed characters are represented as ordinal 10, or hexadecimal (0x0A).
Do not use carriage returns (CR) as is the convention in Mac OS (0x0D) or the carriage return–linefeed combination (CRLF) as is standard in Windows OS (0x0D, 0x0A).
Multiline string literals
Use string concatenation:
var myString = 'JavaScript was originally developed in Netscape, by Brendan Eich. ' +
'Battling with Microsoft over the Internet, Netscape considered their client-server solution ' +
'as a distributed OS, running a portable version of Sun Microsystem’s Java. ' +
'Because Java was a competitor of C++ and aimed at professional programmers, ' +
'Netscape also wanted a lightweight interpreted language that would complement Java ' +
'by appealing to nonprofessional programmers, like Microsoft’s VB.[9] (see JavaScript and Java)';
Parentheses
Use sparingly and in general only where required by the syntax and semantics.
Never use parentheses for:
- Unary operators such as
delete
,typeof
, andvoid
- After keywords such as
return
,throw
- For
case
,in
, ornew
, and others like them
Semicolons
Always put semicolons as statement terminators. The following example shows how missing semicolons can be particularly dangerous:
// 1.
MyClass.prototype.myMethod = function() {
return 42;
} // No semicolon here.
(function() {
// Some initialization code wrapped in a function to create a scope for locals.
})();
// 2. Trying to do one thing on Internet Explorer and another on Firefox.
var x = {
'i': 1,
'j': 2
} // No semicolon here.
// I know you'd never write code like this, but throw me a bone.
[normalVersion, ffVersion][isIE]();
// 3. conditional execution a la bash
var THINGS_TO_EAT = [apples, oysters, sprayOnCheese] // No semicolon here.
-1 == resultOfOperation() || die();
So what happens?
- JavaScript error鈥攆irst the function returning 42 is called with the second function as a parameter, then the number 42 is 鈥渃alled鈥 resulting in an error.
- The 鈥榥o such property in undefined鈥 error is likely to appear at runtime as it tries to call
x[ffVersion][isIE]()
. die
is called unlessresultOfOperation()
isNaN
andTHINGS_TO_EAT
gets assigned the result ofdie()
.
Why? JavaScript requires statements to end with a semicolon, except when it thinks it can safely infer their existence.
In each of the examples above, a function declaration, or an object, or an array literal is used inside a statement.
The closing brackets are not enough to indicate the end of the statement. JavaScript never ends a statement if the next token is an infix or bracket operator.
Statements and conditions
Do not put statements on the same line as conditions.
Incorrect:
if (true) return;
if (true) blah();</pre>
Correct:
if (true) {
return;
}
if (true) {
blah();
}
Strings
For consistency, single-quotes are preferred to double quotes. This is helpful when creating strings that include HTML:
var msg = '<span class="text">Hello World!</div>';
Naming conventions
See one of the following sections:
Constants
Constants may contain both alphanumeric characters and underscores (_
).
All letters used in a constant name must be capitalized, while all words in a constant name must be separated by an underscore.
For example, EMBED_SUPPRESS_EMBED_EXCEPTION
is an acceptable name, but EMBED_SUPPRESSEMBEDEXCEPTION
is not.
Constants must be defined as class members with the const
modifier.
In JavaScript constants are declared using the @const
annotation. But Internet Explorer does not parse the @const
keyword, so omit it, if possible.
For example, variables can be used instead of constants for storing simple values. Applying the naming convention used for constants (ALL CAPS) in naming these variables would indicate that their value is not supposed to be changed.
Example:
/**
* The number of seconds in a minute.
* @type {number}
*/
obj.example.SECONDS_IN_A_MINUTE = 60;
For non-primitives, use the @const
annotation.
/**
* The number of seconds in each of the given units.
* @type {Object.<number>}
* @const
*/
obj.example.SECONDS_TABLE = {
minute: 60,
hour: 60 * 60
day: 60 * 60 * 24
File names
File names should be all lowercase to avoid confusion on case-sensitive platforms.
File names should contain only alphanumeric characters, and dash character (-
) as words separator, end with .js
:
- Correct:
dialog-popup-base-features.js
- Incorrect:
dialog_popup_base_features.js
Code style
See one of the following sections:
- Curly braces
- Functions and methods
- [Variables and properties
Curly braces
Because of implicit semicolon insertion, always start your curly braces on the same line as whatever they are opening.
For example:
if (something) {
// ...
} else {
// ...
}
Functions and methods
Function names may contain only alphanumeric characters.
Underscores are not permitted.
Numbers are permitted in function names, but are discouraged in most cases.
Function names must always start with a lowercase letter.
When a function name consists of more than one word, use camelCase formatting, which capitalizes the first letter of each word.
Class method names should start with an English verb in infinitive form that describes the method.
Verbosity is generally encouraged. Function names should be as verbose as is needed to fully describe their purpose and behavior.
Examples of acceptable function names include:
filterInput()
getElementById()
widgetFactory()
For object-oriented programming, accessors for instances or static variables should always have the get
or set
prefix.
In design patterns, such as the singleton or factory patterns, implementation method names should contain the pattern name where practical to provide the better behavior description.
Methods that return certain status flags or other Boolean values should have the has
or is
prefix, instead of get
.
For object methods that are declared with the private
or protected
modifier, the method name should start with underscore (_
).
This is the only acceptable use of an underscore in a method name. Public methods should never contain an underscore.
Variables and properties
Variable names may contain only alphanumeric characters.
Underscores (_
) are not permitted.
Numbers are permitted in variable names, but are discouraged in most cases.
Instance variables that are declared with the private
or protected
modifier, should start with a single underscore.
This is the only acceptable use of the underscore in a variable name. Member variables declared as public
should never start with an underscore.
Function names and variable names must always start with a lowercase letter and follow the camelCase capitalization convention.
Verbosity is generally encouraged.
Variables names should always be as verbose as needed to describe the data that the developer intends to store in them.
Terse variable names such as i
or n
are discouraged for all, but the smallest loop contexts.
If a loop contains more than 20 lines of code, the index variables should have more descriptive names.
Coding constructs
See one of the following sections:
- Array and object literals
- Binary and ternary operators
- Boolean expressions
- Boolean operators
- Conditional (ternary) operators (? and :)
- Exceptions and custom exceptions
- Function declarations within blocks
- Standard features
- Method definitions
- Closures
Array and object literals
Use array and object literals instead of array and object constructors.
The following example is correct. Always use the more readable array literal:
var a = [x1, x2, x3];
var a2 = [x1, x2];
var a3 = [x1];
var a4 = [];
The following example is incorrect because array constructors are error-prone due to their arguments. Because of this, if someone changes the code to pass one argument instead of two arguments, the array might not have the expected length.
Object constructors don鈥檛 have the same problems, but for readability and consistency object literals should be used.
var o = {};
var o2 = {
a: 0,
b: 1,
c: 2,
'strange key': 3
};
Binary and ternary operators
Always put the operator on the preceding line, so that you don鈥檛 have to think about implicit semi-colon insertion issues.
Boolean expressions
Pay attention to the values of the following Boolean expressions:
False | True |
---|---|
null | 0 |
undefined | [] (empty array) |
'' (the empty string) |
{} (empty object) |
0 (the number) |
The following code samples are equivalent:
Correct - long form | Correct - short form | Note |
---|---|---|
while (x != null) |
while (x) |
Equal as long as x is not 0, empty string, or false |
if (y != null && y != '') |
if (y) |
Here are some examples of non-obvious Boolean expressions results:
Boolean('0') == true '0' != true
0 != null 0 == [] 0 == false
Boolean(null) == false null != true null != false
Boolean(undefined) == false undefined != true undefined != false
Boolean([]) == true [] != true [] == false
Boolean({}) == true {} != true {} != false
Boolean operators (&& and ||)
These binary Boolean operators are short-circuited, and evaluate to the last evaluated term.
The following code samples are equal:
Correct—long form | Correct—short form | Notes |
---|---|---|
function foo(opt_win) { var win; if (opt_win) { win = opt_win; } else { win = window; } // ... } |
function foo(opt_win) { var win = opt_win || window; // ... } |
That is why the || operator is the default. |
if (node) { if (node.kids) { if (node.kids[index]) { foo(node.kids[index]); } } } |
if (node && node.kids && node.kids[index]) { foo(node.kids[index]); } var kid = node && node.kids && node.kids[index]; if (kid) { foo(kid); } |
&& is also useful for code shortening. |
Conditional (ternary) operators (? and :)
The following code samples are equal:
Correct - long form | Correct - short form |
---|---|
if (val != 0) { return foo(); } else { return bar(); } |
return val ? foo() : bar(); |
Custom toString() method
Must always succeed without side effects.
You can control how your objects are converted to string by defining a custom toString()
method.
The method should:
- Always succeed.
- Not have side-effects.
Otherwise you can run into serious problems. For example:
toString()
calls a method that does an assert.- The assert tries to output the name of the object in which it failed.
toString()
is called.
Function declarations within blocks
ECMAScript allows function declarations only in the root statement list of a script or a function.
To define a function within a block, use a variable initialized with a function expression.
Wrong:
if (x) {
function foo() {}
}
Correct:
if (x) {
var foo = function() {}
}
Exceptions and custom exceptions
You cannot avoid exceptions if you are doing something non-trivial (using an application development framework, and so on).
Without custom exceptions, returning error information from a function that also returns a value can be tricky, not to mention inelegant. Bad solutions include passing in a reference type to hold error information or always returning Objects with a potential error member.
These basically amount to a primitive exception handling hack. Feel free to use custom exceptions when appropriate.
Standard features
For maximum portability and compatibility, use standard features whenever possible.
For example, string.charAt(3)
instead of string[3]
, and element access with DOM functions instead of using an application-specific shorthand.
Method definitions
There are several ways to attach methods and properties to a constructor, but the preferred style is:
Foo.prototype.bar = function() {
// ...
};
Or you can also use this style:
Foo.prototype = {
bar: function() {
// ...
},
circle: function() {
// ...
}
};
Closures
Keep in mind is that a closure keeps a pointer to its enclosing scope.
As a result, attaching a closure to a DOM element can create a circular reference and thus, a memory leak.
Wrong:
function foo(element, a, b) {
element.onclick = function() { /* uses a and b */ };
}
The function closure keeps references to elements 鈥渁鈥 and 鈥渂鈥 even if it never uses them.
Because elements also keep references to the closure, it is a cycle that will not be cleaned up by garbage collection. In these situations, the code can be structured as follows:
Correct:
function foo(element, a, b) {
element.onclick = bar(a, b);
}
function bar(a, b) {
return function() { /* uses a and b */ }
}
General recommendations
See one of the following sections:
- Do not use eval
- Do not use with()
- Use this with caution
- Array and object initializers
- Do not use associative arrays
- Use deferred initialization
- Do not modify built-in objects
- Declare variables
Do not use eval()
Avoid using eval()
.
The eval()
function makes for confusing semantics and is dangerous to use if the string passed to eval()
contains user input. Usually better options exist allowing to omit eval()
, so its usage is generally not permitted. However, it is accepted for unserializing tasks (for example, to evaluate RPC responses), as it makes them much easier.
Do not use with()
Do not use the with()
statement.
Using with()
clouds the semantics of your program, because its object can have properties that collide with local variables, which can drastically change the meaning of your program.
Example: what will be the result of the following code execution?
with (foo) {
var x = 3;
return x;
}
Answer: anything.
The local variable x could be clobbered by a property of foo, and perhaps it even has a setter, in which case assigning 3 could cause lots of other code to execute.
Use this with caution
Semantic of this can be tricky. It can refer to either:
- global object (in most cases)
- the scope of the caller (in eval)
- a node in the DOM tree (when attached using an event handler HTML attribute)
- a newly created object (in a constructor)
- other object - if a function was called by call() or apply().
To avoid confusion, use this
only in object constructors, methods, and in closures setting up.
Array and object initializers
Single-line array and object initializers are allowed when they fit on a line as follows:
var arr = [1, 2, 3]; // No space after [ or before ].
var obj = {a: 1, b: 2, c: 3}; // No space after { or before }.
Multi-line array and object initializer must be indented four spaces.
Long identifiers or values present problems for aligned initialization lists, so always prefer non-aligned initialization.
For example:
Object.prototype = {
a: 0,
b: 1,
lengthyName: 2
};
The following is incorrect:
WRONG_Object.prototype = { a : 0, b : 1, lengthyName: 2 };
Do not use associative arrays
Do not use associative arrays.
If you need a map/hash
, use Object
instead of Array
, because the features you need are actually Object
features.
Array
just happens to extend Object
.
Use deferred initialization
It is sometimes impossible to initialize variables at the point of declaration, so deferred initialization is a good solution.
Use explicit scope
Always use explicit scope. This increases code portability and clarity.
For example, do not rely on window being in the scope chain. You might want to use your function in another application, for which this window is not the content window.
Do not modify built-in objects
-
Modifying built-ins like
Object.prototype
andArray.prototype
is strictly forbidden. -
Modifying other built-ins like
Function.prototype
is less dangerous, but still leads to debugging issues in production and should be avoided.
Declare variables
If you do not declare a variable, it is placed in the global context, potentially clobbering existing values.
It also makes hard to define the variable scope. For example, it can be Document
, Window
or local
scope.
So always declare variables with var
.
Using only one var per scope (function) promotes readability.
var foo = "bar,"
num = 1,
arr = [1, 2, 3];
Find us on