Front end code specification - JavaScript style guide
Based on github project [airbnb](https://github.com/airbnb/javascript "airbnb") translation also adds some personal understanding. The specification helps us better improve code readability and avoid some unnecessary bug s. leleshuo
1. Object
1.1 create objects using literals eslint: no-new-object
// bad const item = new Object(); // good const item = {};
1.2 when creating an object with a dynamic attribute name, put all the defined attributes in one place of the object.
function getKey(k) { return `a key named ${k}`; } // bad const obj = { id: 5, name: 'San Francisco', }; obj[getKey('enabled')] = true; // good getKey('enabled ') is the dynamic property name const obj = { id: 5, name: 'San Francisco', [getKey('enabled')]: true, };
1.3 method abbreviation eslint: object-shorthand
// bad const atom = { value: 1, addValue: function (value) { return atom.value + value; }, }; // good const atom = { value: 1, // Object method addValue(value) { return atom.value + value; }, };
1.4 do not directly call object Methods on prototype, such as hasOwnProperty, propertyIsEnumerable, isPrototypeOf
// bad console.log(object.hasOwnProperty(key)); // good console.log(Object.prototype.hasOwnProperty.call(object, key)); // best const has = Object.prototype.hasOwnProperty; // Make a cache within the function of the module /* or */ import has from 'has'; // https://www.npmjs.com/package/has // ... console.log(has.call(object, key));
1.5 for shallow copy of objects, the extension operator... Is more recommended than object assign. When deconstructing assignment to obtain several attributes specified by the object, it is recommended to use the rest operator, which is also
// very bad const original = { a: 1, b: 2 }; const copy = Object.assign(original, { c: 3 }); delete copy.a; // so does this change the original // bad const original = { a: 1, b: 2 }; const copy = Object.assign({}, original, { c: 3 }); // copy => { a: 1, b: 2, c: 3 } // good const original = { a: 1, b: 2 }; const copy = { ...original, c: 3 }; // copy => { a: 1, b: 2, c: 3 } const { a, ...noA } = copy; // noA => { b: 2, c: 3 }
2. Array
2.1 assign values with literal values. eslint: no-array-constructor
// bad const items = new Array(); // good const items = [];
2.2 use the extension operator to make a shallow copy of the array, similar to the shallow copy of the object above
// bad const len = items.length; const itemsCopy = []; let i; for (i = 0; i < len; i += 1) { itemsCopy[i] = items[i]; } // good const itemsCopy = [...items];
2.3 the... Operator is recommended instead of array From to convert an array of classes into an array.
const foo = document.querySelectorAll('.foo'); // good const nodes = Array.from(foo); // best const nodes = [...foo];
3. Deconstruction
3.1 use the deconstruction assignment of the object to obtain and use one or more attribute values of the object. eslint: prefer-destructuring
// bad function getFullName(user) { const firstName = user.firstName; const lastName = user.lastName; return `${firstName} ${lastName}`; } // good function getFullName(user) { const { firstName, lastName } = user; return `${firstName} ${lastName}`; } // best function getFullName({ firstName, lastName }) { return `${firstName} ${lastName}`; }
3.2 array deconstruction
const arr = [1, 2, 3, 4]; // bad const first = arr[0]; const second = arr[1]; // good const [first, second] = arr;
4. String
4.1 single quotation mark '' shall be used for string. eslint: quotes
// bad const name = "Capt. Janeway"; // bad - the template should contain inserted text or line breaks const name = `Capt. Janeway`; // good const name = 'Capt. Janeway';
4.2 + should not be used to connect newline strings.
// bad const errorMessage = 'This is a super long error that was thrown because \ of Batman. When you stop to think about how Batman had anything to do \ with this, you would get nowhere \ fast.'; // bad const errorMessage = 'This is a super long error that was thrown because ' + 'of Batman. When you stop to think about how Batman had anything to do ' + 'with this, you would get nowhere fast.'; // good const errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';
4.3 use string template instead of + to splice strings. eslint: prefer-template template-curly-spacing
// bad function sayHi(name) { return 'How are you, ' + name + '?'; } // bad function sayHi(name) { return ['How are you, ', name, '?'].join(); } // bad function sayHi(name) { return `How are you, ${ name }?`; } // good function sayHi(name) { return `How are you, ${name}?`; }
5. Functions
5.1 use named function expressions instead of function declarations. eslint: func-style
// bad function foo() { // ... } // bad const foo = function () { // ... }; // good const short = function longUniqueMoreDescriptiveLexicalFoo() { // ... };
5.2 give priority to rest Syntax... Instead of arguments. eslint: prefer-rest-params
// bad function concatenateAll() { const args = Array.prototype.slice.call(arguments); return args.join(''); } // good function concatenateAll(...args) { return args.join(''); }
5.3 flexible use of
// bad const x = [1, 2, 3, 4, 5]; console.log.apply(console, x); // good const x = [1, 2, 3, 4, 5]; console.log(...x); // bad new (Function.prototype.bind.apply(Date, [null, 2016, 8, 5])); // good new Date(...[2016, 8, 5]);
6. Semicolon
6.1 when JavaScript encounters a line break without a semicolon, it will use the rule of automatic semiconductor insertion to decide whether to add a semicolon at the end of the line. However, ASI contains some strange behavior. If JavaScript makes a mistake about your line feed, your code will break. Therefore, the explicit use of semicolons will reduce this uncertainty.
// bad (function () { const name = 'Skywalker' return name })() // good (function () { const name = 'Skywalker'; return name; }()); // good ;(() => { const name = 'Skywalker'; return name; }());
7. Naming convention
7.1 avoid naming with one letter and make your naming more semantic. eslint: id-length
// bad function q() { // ... } // good function query() { // ... }
7.2 name your objects, functions and instances with camelCase. eslint: camelcase
// bad const OBJEcttsssss = {}; const this_is_my_object = {}; function c() {} // good const thisIsMyObject = {}; function thisIsMyFunction() {}
7.3 name the class with PascalCase. eslint: new-cap
// bad function user(options) { this.name = options.name; } const bad = new user({ name: 'nope', }); // good class User { constructor(options) { this.name = options.name; } } const good = new User({ name: 'yup', });
7.4 do not underline before or after. eslint: no-underscore-dangle
JavaScript has no concept of private properties or methods. Although the pre underline usually means "private" conceptually, in fact, these attributes are completely public, so this part is also the content of your API. This concept may lead developers to mistakenly believe that changing this will not cause a crash or do not require testing.
// bad this.__firstName__ = 'Panda'; this.firstName_ = 'Panda'; this._firstName = 'Panda'; // good this.firstName = 'Panda';
7.5 when exporting a function by default, the function name and file name are unified.
function makeStyleGuide() { // ... } export default makeStyleGuide;
7.6 when you export a constructor / class / singleton / function library object, use PascalCase.
const AirbnbStyleGuide = { es6: { } }; export default AirbnbStyleGuide;
8. Notes
8.1 / * **/
// bad // make() returns a new element // based on the passed in tag name // // @param {String} tag // @return {Element} element function make(tag) { // ... return element; } // good /** * make() returns a new element * based on the passed-in tag name */ function make(tag) { // ... return element; }
8.2 single line comments use / / to place single line comments above the annotated area. If the comment is not on the first line, add a blank line before the comment
// bad const active = true; // is current tab // good // is current tab const active = true; // bad function getType() { console.log('fetching type...'); // set the default type to 'no type' const type = this._type || 'no type'; return type; } // good function getType() { console.log('fetching type...'); // set the default type to 'no type' const type = this._type || 'no type'; return type; } // also good function getType() { // set the default type to 'no type' const type = this._type || 'no type'; return type; }
8.3 add a space at the beginning of all notes for easy reading. eslint: spaced-comment
// bad //is current tab const active = true; // good // is current tab const active = true; // bad /** *make() returns a new element *based on the passed-in tag name */ function make(tag) { // ... return element; } // good /** * make() returns a new element * based on the passed-in tag name */ function make(tag) { // ... return element; }
8.4 prefix the comments with FIXME 'or TODO', which helps other developers quickly understand the problems you pointed out or the solutions you suggested.
class Calculator extends Abacus { constructor() { super(); // FIXME: shouldn't use a global here total = 0; } } class Calculator extends Abacus { constructor() { super(); // TODO: total should be configurable by an options param this.total = 0; } }
--lele(Excellent code Porter)