#### 2 全局常量和线程安全 // bad var a = 1, b = 2, c = 3; // good const a = 1; const b = 2; const c = 3; // best const [a, b, c] = [1, 2, 3]; 1. 在let和const之间,建议优先使用const,尤其是在全局环境,不应该设置变量,只应设置常量。这符合函数式编程思想,有利于将来的分布式运算。 2. const声明常量还有两个好处,一是阅读代码的人立刻会意识到不应该修改这个值,二是防止了无意间修改变量值所导致的错误。
### 6.2 字符串 // bad const a = “foobar”; const b = ‘foo’ + a + ‘bar’; // acceptable const c = foobar; // good const a = ‘foobar’; const b = foo${a}bar; const c = ‘foobar’; 静态字符串一律使用单引号或反引号,不使用双引号。动态字符串使用反引号。 ### 6.3 解构赋值 1. 使用数组成员对变量赋值,优先使用解构赋值。
const arr = [1, 2, 3, 4]; // bad const first = arr[0]; const second = arr[1]; // good const [first, second] = arr; 2. 函数的参数如果是对象的成员,优先使用解构赋值。
// bad function getFullName(user) { const firstName = user.firstName; const lastName = user.lastName; } // good function getFullName(obj) { const { firstName, lastName } = obj; } // best function getFullName({ firstName, lastName }) { } $_PROBLEM:不明白,需要参考函数部分 3. 如果函数返回多个值,优先使用对象的解构赋值,而不是数组的解构赋值。这样便于以后添加返回值,以及更改返回值的顺序。
// bad function processInput(input) { return [left, right, top, bottom]; } // good function processInput(input) { return { left, right, top, bottom }; } const { left, right } = processInput(input); ### 6.4 对象 1. 单行定义的对象,最后一个成员不以逗号结尾。多行定义的对象,最后一个成员以逗号结尾。 2. 对象尽量静态化,一旦定义,就不得随意添加新的属性。如果添加属性不可避免,要使用Object.assign方法。
// bad const a = {}; a.x = 3; // if reshape unavoidable const a = {}; Object.assign(a, { x: 3 }); // good const a = { x: null }; a.x = 3; 3. 如果对象的属性名是动态的,可以在创造对象的时候,使用属性表达式定义。
var ref = ‘some value’; // bad const atom = { ref: ref, value: 1, addValue: function (value) { return atom.value + value; }, }; // good const atom = { ref, value: 1, addValue(value) { return atom.value + value; }, }; ### 6.5 数组 1. 使用扩展运算符(…)拷贝数组。
// bad const len = items.length; const itemsCopy = []; let i; for (i = 0; i < len; i++) { itemsCopy[i] = items[i]; } // good const itemsCopy = […items]; 2. 使用Array.from方法,将类似数组的对象转为数组。
// bad function divide(a, b, option = false ) { } // good function divide(a, b, { option = false } = {}) { } 4. 不要在函数体内使用arguments变量,使用rest运算符(…)代替。因为rest运算符显式表明你想要获取参数,而且arguments是一个类似数组的对象,而rest运算符可以提供一个真正的数组。
// bad function concatenateAll() { const args = Array.prototype.slice.call(arguments); return args.join(‘’); } // good function concatenateAll(…args) { return args.join(‘’); } 5. 使用默认值语法设置函数参数的默认值。
// bad function handleThings(opts) { opts = opts || {}; } // good function handleThings(opts = {}) { // … } ### 6.7 Map结构 let map = new Map(arr); for (let key of map.keys()) { console.log(key); } for (let value of map.values()) { console.log(value); } for (let item of map.entries()) { console.log(item[0], item[1]); } 注意区分Object和Map,只有模拟实体对象时,才使用Object。如果只是需要key:value的数据结构,使用Map。因为Map有内建的遍历机制。
### 6.8 Class 1. 总是用class,取代需要prototype操作。因为class的写法更简洁,更易于理解。
// bad function Queue(contents = []) { this._queue = […contents]; } Queue.prototype.pop = function() { const value = this._queue[0]; this._queue.splice(0, 1); return value; } // good class Queue { constructor(contents = []) { this._queue = […contents]; } pop() { const value = this._queue[0]; this._queue.splice(0, 1); return value; } } 2. 使用extends实现继承,因为这样更简单,不会有破坏instanceof运算的危险。
// bad const inherits = require(‘inherits’); function PeekableQueue(contents) { Queue.apply(this, contents); } inherits(PeekableQueue, Queue); PeekableQueue.prototype.peek = function() { return this._queue[0]; } // good class PeekableQueue extends Queue { peek() { return this._queue[0]; } } ### 6.9 模块 1. 首先,Module语法是JavaScript模块的标准写法,坚持使用这种写法。使用import取代require。
// bad const moduleA = require(‘moduleA’); const func1 = moduleA.func1; const func2 = moduleA.func2; // good import { func1, func2 } from ‘moduleA’; 2. 使用export取代module.exports。