Coding Standard

Please follow this standard when contribute to ECharts project.

Code Style

File

[MUST] JavaScript Source files must be encoded in UTF-8 without BOM.

Indentation

[MUST] 4 space indentation. tabs and 2 space are not allowed.

[MUST] case and default in switch must be indented.

// good
switch (variable) {
    case '1':
        // do...
        break;
    case '2':
        // do...
        break;
    default:
        // do...
}
// bad
switch (variable) {
case '1':
    // do...
    break;
case '2':
    // do...
    break;
default:
    // do...
}

Space

[MUST] Set off binary operator with spaces. But place no space between unary operator and its operand.

var a = !arr.length;
a++;
a = b + c;

[MUST] Place 1 space before the leading brace.

// good
if (condition) {
}
set('attr', {
    some: 'xxx',
    any: 'yyy'
});
function funcName() {
}
// bad
if (condition){
}
set('attr',{
    some: 'xxx',
    any: 'yyy'
});
function funcName(){
}

[MUST] Place 1 space after if / else / for / while / function / switch / do / try / catch / finally.

// good
if (condition) {
}
while (condition) {
}
(function () {
})();
// bad
if(condition) {
}
while(condition) {
}
(function() {
})();

[MUST] In the object creating statement, place 1 space after :, but no space before it.

// good
var obj = {
    a: 1,
    b: 2,
    c: 3
};
// bad
var obj = {
    a : 1,
    b:2,
    c :3
};

[MUST] Place no space between the function name and ( in function declaration, expression of named function and function call.

// good
function funcName() {
}
var funcName = function funcName() {
};
funcName();
// bad
function funcName () {
}
var funcName = function funcName () {
};
funcName ();

[MUST] Place no space between , and ;.

// good
callFunc(a, b);
// bad
callFunc(a , b) ;

[MUST] Place no space after ( and [ and before ) and ].

// good
callFunc(param1, param2, param3);
save(this.list[this.indexes[i]]);
needIncream && (variable += increament);
if (num > list.length) {
}
while (len--) {
}
// bad
callFunc( param1, param2, param3 );
save( this.list[ this.indexes[ i ] ] );
needIncreament && ( variable += increament );
if ( num > list.length ) {
}
while ( len-- ) {
}
// good
var arr1 = [];
var arr2 = [1, 2, 3];
var obj1 = {};
var obj2 = {name: 'obj'};
var obj3 = {
    name: 'obj',
    age: 20,
    sex: 1
};
// bad
var arr1 = [ ];
var arr2 = [ 1, 2, 3 ];
var obj1 = { };
var obj2 = { name: 'obj' };
var obj3 = {name: 'obj', age: 20, sex: 1};

[MUST] Must no trailing space in each line.

Line Break

[MUST] Place line break in the end of a statement.

[MUST] No more than 120 characters per line.

[MUST] Place operator at the beginning of a line if it break lines.

// good
if (user.isAuthenticated()
    && user.isInRole('admin')
    && user.hasAuthority('add-admin')
    || user.hasAuthority('delete-admin')
) {
    // Code
}
var result = number1 + number2 + number3
    + number4 + number5;
// bad
if (user.isAuthenticated() &&
    user.isInRole('admin') &&
    user.hasAuthority('add-admin') ||
    user.hasAuthority('delete-admin')) {
    // Code
}
var result = number1 + number2 + number3 +
    number4 + number5;

[MUST] Start a new line for ), ], } if the content inside the brackets occupies multiple lines. Make the same indent as the line where the corresponding (, [, { placed.

// good
if (product) {
    product.load();
    if (user.isAuthenticated()
        && user.isInRole('admin')
        && user.hasAuthority('add-admin')
    ) {
        sendProduct(user, product);
    }
}
var arr = [
    'candy', 'sugar'
];
// bad
if (product) {
    product.load();
    if (user.isAuthenticated()
        && user.isInRole('admin')
        && user.hasAuthority('add-admin')) {
        sendProduct(user, product);
    }
}
var arr = [
        'candy', 'sugar'
    ];

[MUST] Must not break lines before , or ;.

// good
var obj = {
    a: 1,
    b: 2,
    c: 3
};
foo(
    aVeryVeryLongArgument,
    anotherVeryLongArgument,
    callback
);
// bad
var obj = {
    a: 1
    , b: 2
    , c: 3
};
foo(
    aVeryVeryLongArgument
    , anotherVeryLongArgument
    , callback
);

[SUGGEST] Suggestion about line break and indent:

if (user.isAuthenticated()
    && user.isInRole('admin')
    && user.hasAuthority('add-admin')
) {
    // Code
}
foo(
    aVeryVeryLongArgument,
    anotherVeryLongArgument,
    callback
);
baidu.format(
    dateFormatTemplate,
    year, month, date, hour, minute, second
);
$('#items')
    .find('.selected')
    .highlight()
    .end();
var result = thisIsAVeryVeryLongCondition
    ? resultA : resultB;
var result = condition
    ? thisIsAVeryVeryLongResult
    : resultB;

[MUST] Start a new line for else and catch if using multi-line blocks.

// good
if (condition) {
    // some statements;
}
else {
    // some statements;
}
try {
    // some statements;
}
catch (ex) {
    // some statements;
}
// bad
if (condition) {
    // some statements;
} else {
    // some statements;
}
try {
    // some statements;
} catch (ex) {
    // some statements;
}

Statement

[MUST] The comma must not be ignored at the end of a statement.

[MUST] The {} must not be ignored even if there is only one line.

// good
if (condition) {
    callFunc();
}
// bad
if (condition) callFunc();
if (condition)
    callFunc();

[MUST] Place no comma at the end of a function definition.

// good
function funcName() {
}
// bad
function funcName() {
};
// For function expression, the comma must not be ignored.
var funcName = function () {
};

[MUST] No trailing comma in object and array declarations.

// good
var obj = {
    attr1: 'xxx',
    attr2: 'yyy'
};
var arr = [
    'xxx',
    'yyy'
];
// bad
var obj = {
    attr1: 'xxx',
    attr2: 'yyy',
};
var arr = [
    'xxx',
    'yyy',
];

Naming Conventions

[MUST] Use lowerCamelCase for variables, properties and function names.

var loadingModules = {};
function loadProduct() {
}

[MUST] Use UpperCamelCase (Pascal) for class names.

function Element(options) {
}

[SUGGEST] All of the letters of a abbreviation should be both upper cases or both lower cases.

function parseSVG() {
}
var svgParser;

Language features

Compatibility

[MUST] The JavaScript code of ECharts should be based on ECMAScript Language Specification Edition 3 (ES3). The language features that not supported by ES3 (namely, features that are only supported by ES5, ES6 or upper versions) must not be used.

But there is an exception that ES Module can be used.

Language features can be polyfilled by some utilities, but must not by modifying the prototype of the built-in JS objects.

// good
import * as zrUtil from 'zrender/src/core/util';
zrUtil.each(array, function (val, index) {
    sum += val;
});
var result = zrUtil.map(array, function (val) {
    return parse(val);
});
var pos = zrUtil.indexOf(array, val);
var obj2 = zrUtil.extend({}, obj1);
function Element() {
    // ...
}
// bad
array.forEach(function (val, index) {
    sum += val;
});
let result = array.map(function (val) {
    return parse(val);
});
const pos = array.indexOf(val);
var obj2 = Object.assign({}, obj1);
class Element {
    // ...
}
String.prototype.trim = function () {
};

Variable

[MUST] Variables must be declared by var. And a var can not declares more than one variable.

// good
var name = 'MyName';
var hangModules = [];
var missModules = [];
var visited = {};
// bad
name = 'MyName';
var hangModules = [],
    missModules = [],
    visited = {};

Condition

[MUST] In equality expression, == can only be used on null or undefined detection. === should be used in the rest of cases .

// good
if (age === 30) {
    // ...
}
if (type == null) {
    // ...
}
// bad
if (age == 30) {
    // ......
}

[SUGGEST] Use xxx == null to determine null or undefined.

[SUGGEST] Try best to make the meaning of null and undefined the same, namely, do not make users or developers distinguishing whether a variable is null or undefined.

[SUGGEST] The function expression or function declaration should not be placed inside a loop body.

// good
function clicker() {
    // ......
}
for (var i = 0, len = elements.length; i < len; i++) {
    var element = elements[i];
    addListener(element, 'click', clicker);
}
// bad
for (var i = 0, len = elements.length; i < len; i++) {
    var element = elements[i];
    addListener(element, 'click', function () {});
}

Type Conversion

[SUGGEST] Use + '' to convert a value to string.

// good
num + '';
// bad
new String(num);
num.toString();
String(num);

[SUGGEST] Use + to convert a value to number.

// good
+str;
// bad
Number(str);

[MUST] The second parameter must not be ignored when using parseInt.

// good
parseInt(str, 10);
// bad
parseInt(str);

String, Object, Array

[MUST] Use ' but not " to define a string.

[MUST] Use object literal {} to create a plain object.

// good
var obj = {};
// bad
var obj = new Object();

[MUST] If all of the properties of an object literal do not need quotation marks, they should ignore them. If quotation marks is necessary, use ' but not ".

// good
var info = {
    name: 'someone',
    age: 28
};
// bad
var info = {
    'name': 'someone',
    'age': 28
};
var info2 = {
    "age": 40
};

[MUST] The prototype of built-in objects must not be modified.

// Forbidden
String.prototype.trim = function () {
};

[SUGGEST] Try best to use . but not [] to visit properties of an object.

[SUGGEST] hasOwnProperty should be used to when using for ... in ..., in case that some extra properties is added on the prototype of Object in some runtime environment.

var newInfo = {};
for (var key in info) {
    if (info.hasOwnProperty(key)) {
        newInfo[key] = info[key];
    }
}

[MUST] Use array literal [] to create an array, except intending to create an array with a given length.

// good
var arr = [];
var arr2 = new Array(1e4);
// bad
var arr = new Array();

[MUST] Do not use for in in array traverse.

Others

[MUST] Do not use eval and with. new Function can be used.