| ## 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. |
| |
| ```js |
| // 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. |
| |
| ```js |
| var a = !arr.length; |
| a++; |
| a = b + c; |
| ``` |
| |
| |
| **[MUST]** Place 1 space before the leading brace. |
| |
| ```js |
| // 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`. |
| |
| ```js |
| // 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. |
| |
| ```js |
| // 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. |
| |
| ```js |
| // good |
| |
| function funcName() { |
| } |
| |
| var funcName = function funcName() { |
| }; |
| |
| funcName(); |
| |
| |
| // bad |
| |
| function funcName () { |
| } |
| |
| var funcName = function funcName () { |
| }; |
| |
| funcName (); |
| ``` |
| |
| |
| **[MUST]** Place no space between `,` and `;`. |
| |
| ```js |
| // good |
| callFunc(a, b); |
| |
| // bad |
| callFunc(a , b) ; |
| ``` |
| |
| |
| **[MUST]** Place no space after `(` and `[` and before `)` and `]`. |
| |
| ```js |
| // 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. |
| |
| ```js |
| // 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. |
| |
| ```js |
| // 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 `;`. |
| |
| ```js |
| // 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: |
| |
| ```js |
| 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. |
| |
| ```js |
| // 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 semicolon must not be ignored at the end of a statement. |
| |
| |
| **[MUST]** The `{}` must not be ignored even if there is only one line. |
| |
| ```js |
| // good |
| if (condition) { |
| callFunc(); |
| } |
| |
| // bad |
| if (condition) callFunc(); |
| if (condition) |
| callFunc(); |
| ``` |
| |
| |
| **[MUST]** Place no semicolon at the end of a function definition. |
| |
| ```js |
| // good |
| function funcName() { |
| } |
| |
| // bad |
| function funcName() { |
| }; |
| |
| // For function expression, the semicolon must not be ignored. |
| var funcName = function () { |
| }; |
| ``` |
| |
| |
| **[MUST]** No trailing comma in object and array declarations. |
| |
| |
| ```js |
| // 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. |
| |
| ```js |
| var loadingModules = {}; |
| function loadProduct() { |
| } |
| ``` |
| |
| |
| **[MUST]** Use UpperCamelCase (Pascal) for class names. |
| |
| ```js |
| function Element(options) { |
| } |
| ``` |
| |
| |
| **[SUGGEST]** All of the letters of a abbreviation should be both upper cases or both lower cases. |
| |
| ```js |
| 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. |
| |
| |
| ```js |
| // 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. |
| |
| ```js |
| // 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 . |
| |
| ```js |
| // 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. |
| |
| ```js |
| // 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. |
| |
| ```js |
| // good |
| num + ''; |
| |
| // bad |
| new String(num); |
| num.toString(); |
| String(num); |
| ``` |
| |
| |
| **[SUGGEST]** Use `+` to convert a value to number. |
| |
| ```js |
| // good |
| +str; |
| |
| // bad |
| Number(str); |
| ``` |
| |
| |
| **[MUST]** The second parameter must not be ignored when using `parseInt`. |
| |
| ```js |
| // 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. |
| |
| ```js |
| // 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 `"`. |
| |
| ```js |
| // 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. |
| |
| ```js |
| // 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. |
| |
| ```js |
| 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. |
| |
| ```js |
| // 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. |
| |