1、块级作用域(1)let取代varES6提出了两个新的声明变量的命令:let和const。其中,let完全可以取代var,因为两者语义相同,而且let没有副作用。use strict;if (true) let x = hello;for (let i = 0; i 10; i+) console.log(i);上面代码如果用var替代let,实际上就声明了两个全局变量,这显然不是本意。变量应该只在其声明的代码块内有效,var命令做不到这一点。var命令存在变量提升效用,let命令没有这个问题。use strict;if(true) console.log(x); / ReferenceErro
2、r let x = hello;上面代码如果使用var替代let,console.log那一行就不会报错,而是会输出undefined,因为变量声明提升到代码块的头部。这违反了变量先声明后使用的原则。所以,建议不再使用var命令,而是使用let命令取代。(2)全局常量和线程安全在let和const之间,建议优先使用const,尤其是在全局环境,不应该设置变量,只应设置常量。这符合函数式编程思想,有利于将来的分布式运算。/ badvar a = 1, b = 2, c = 3;/ goodconst a = 1;const b = 2;const c = 3;/ bestconst a, b,
3、c = 1, 2, 3;const声明常量还有两个好处,一是阅读代码的人立刻会意识到不应该修改这个值,二是防止了无意间修改变量值所导致的错误。所有的函数都应该设置为常量。长远来看,JavaScript可能会有多线程的实现(比如Intel的River Trail那一类的项目),这时let表示的变量,只应出现在单线程运行的代码中,不能是多线程共享的,这样有利于保证线程安全。字符串静态字符串一律使用单引号或反引号,不使用双引号。动态字符串使用反引号。/ badconst a = foobar;const b = foo + a + bar;/ acceptableconst c = foobar;/
4、 goodconst a = foobar;const b = foo$abar;const c = foobar;解构赋值使用数组成员对变量赋值时,优先使用解构赋值。const arr = 1, 2, 3, 4;/ badconst first = arr0;const second = arr1;/ goodconst first, second = arr;函数的参数如果是对象的成员,优先使用解构赋值。/ badfunction getFullName(user) const firstName = user.firstName; const lastName = user.lastNa
5、me;/ goodfunction getFullName(obj) const firstName, lastName = obj;/ bestfunction getFullName( firstName, lastName ) 如果函数返回多个值,优先使用对象的解构赋值,而不是数组的解构赋值。这样便于以后添加返回值,以及更改返回值的顺序。/ badfunction processInput(input) return left, right, top, bottom;/ goodfunction processInput(input) return left, right, top, b
6、ottom ;const left, right = processInput(input);对象单行定义的对象,最后一个成员不以逗号结尾。多行定义的对象,最后一个成员以逗号结尾。/ badconst a = k1: v1, k2: v2, ;const b = k1: v1, k2: v2;/ goodconst a = k1: v1, k2: v2 ;const b = k1: v1, k2: v2,;对象尽量静态化,一旦定义,就不得随意添加新的属性。如果添加属性不可避免,要使用Object.assign方法。/ badconst a = ;a.x = 3;/ if reshape una
7、voidableconst a = ;Object.assign(a, x: 3 );/ goodconst a = x: null ;a.x = 3;如果对象的属性名是动态的,可以在创造对象的时候,使用属性表达式定义。/ badconst obj = id: 5, name: San Francisco,;objgetKey(enabled) = true;/ goodconst obj = id: 5, name: San Francisco, getKey(enabled): true,;上面代码中,对象obj的最后一个属性名,需要计算得到。这时最好采用属性表达式,在新建obj的时候,将
8、该属性与其他属性定义在一起。这样一来,所有属性就在一个地方定义了。另外,对象的属性和方法,尽量采用简洁表达法,这样易于描述和书写。var ref = some value;/ badconst atom = ref: ref, value: 1, addValue: function (value) return atom.value + value; ,;/ goodconst atom = ref, value: 1, addValue(value) return atom.value + value; ,;数组使用扩展运算符(.)拷贝数组。/ badconst len = items.l
9、ength;const itemsCopy = ;let i;for (i = 0; i console.log(Welcome to the Internet.);)();那些需要使用函数表达式的场合,尽量用箭头函数代替。因为这样更简洁,而且绑定了this。/ bad1, 2, 3.map(function (x) return x * x;);/ good1, 2, 3.map(x) = return x * x;);/ best1, 2, 3.map(x = x * x);箭头函数取代Function.prototype.bind,不应再用self/_this/that绑定 this。/
10、 badconst self = this;const boundMethod = function(.params) return method.apply(self, params);/ acceptableconst boundMethod = method.bind(this);/ bestconst boundMethod = (.params) = method.apply(this, params);简单的、单行的、不会复用的函数,建议采用箭头函数。如果函数体较为复杂,行数较多,还是应该采用传统的函数写法。所有配置项都应该集中在一个对象,放在最后一个参数,布尔值不可以直接作为参数
11、。/ badfunction divide(a, b, option = false ) / goodfunction divide(a, b, option = false = ) 不要在函数体内使用arguments变量,使用rest运算符(.)代替。因为rest运算符显式表明你想要获取参数,而且arguments是一个类似数组的对象,而rest运算符可以提供一个真正的数组。/ badfunction concatenateAll() const args = Array.prototype.slice.call(arguments); return args.join();/ goodf
12、unction concatenateAll(.args) return args.join();使用默认值语法设置函数参数的默认值。/ badfunction handleThings(opts) opts = opts | ;/ goodfunction handleThings(opts = ) / .Map结构注意区分Object和Map,只有模拟现实世界的实体对象时,才使用Object。如果只是需要key: value的数据结构,使用Map结构。因为Map有内建的遍历机制。let map = new Map(arr);for (let key of map.keys() consol
13、e.log(key);for (let value of map.values() console.log(value);for (let item of map.entries() console.log(item0, item1);Class总是用Class,取代需要prototype的操作。因为Class的写法更简洁,更易于理解。/ badfunction Queue(contents = ) this._queue = .contents;Queue.prototype.pop = function() const value = this._queue0; this._queue.s
14、plice(0, 1); return value;/ goodclass Queue constructor(contents = ) this._queue = .contents; pop() const value = this._queue0; this._queue.splice(0, 1); return value; 使用extends实现继承,因为这样更简单,不会有破坏instanceof运算的危险。/ badconst inherits = require(inherits);function PeekableQueue(contents) Queue.apply(this
15、, contents);inherits(PeekableQueue, Queue);PeekableQueue.prototype.peek = function() return this._queue0;/ goodclass PeekableQueue extends Queue peek() return this._queue0; 模块首先,Module语法是JavaScript模块的标准写法,坚持使用这种写法。使用import取代require。/ badconst moduleA = require(moduleA);const func1 = moduleA.func1;co
16、nst func2 = moduleA.func2;/ goodimport func1, func2 from moduleA;使用export取代module.exports。/ commonJS的写法var React = require(react);var Breadcrumbs = React.createClass( render() return ; );module.exports = Breadcrumbs;/ ES6的写法import React from react;const Breadcrumbs = React.createClass( render() retu
17、rn ; );export default Breadcrumbs如果模块只有一个输出值,就使用export default,如果模块有多个输出值,就不使用export default,不要export default与普通的export同时使用。不要在模块输入中使用通配符。因为这样可以确保你的模块之中,有一个默认输出(export default)。/ badimport * as myObject ./importModule;/ goodimport myObject from ./importModule;如果模块默认输出一个函数,函数名的首字母应该小写。function makeSt
18、yleGuide() export default makeStyleGuide;如果模块默认输出一个对象,对象名的首字母应该大写。const StyleGuide = es6: ;export default StyleGuide;ESLint的使用ESLint是一个语法规则和代码风格的检查工具,可以用来保证写出语法正确、风格统一的代码。首先,安装ESLint。$ npm i -g eslint然后,安装Airbnb语法规则。$ npm i -g eslint-config-airbnb最后,在项目的根目录下新建一个.eslintrc文件,配置ESLint。 extends: eslint-
19、config-airbnb现在就可以检查,当前项目的代码是否符合预设的规则。index.js文件的代码如下。var unusued = I have no purpose!;function greet() var message = Hello, World!; alert(message);greet();使用ESLint检查这个文件。$ eslint index.jsindex.js 1:5 error unusued is defined but never used no-unused-vars 4:5 error Expected indentation of 2 characters but found 4 indent 5:5 error Expected indentation of 2 characters but found 4 indent 3 problems (3 errors, 0 warnings)上面代码说明,原文件有三个错误,一个是定义了变量,却没有使用,另外两个是行首缩进为4个空格,而不是规定的2个空格。