前端代码整洁之道

1. 前言

ES6 新增了很多语法和语法糖,在使用这些语法和语法糖的时候我们可以让我们的代码更加优雅。另外,在程序上有一些约定俗成的东西,这样会帮助我们更好地书写和阅读代码。本节我们将学习前端代码的整洁之道帮助你更好地书写你的代码。

2. 变量的使用

2.1 命名

在定义变量时最好使用驼峰命名(如:aaBbCc)的方式,并且要使用有准确意义的变量名,这样容易阅读。

// bad
var getname = function() { return 'imooc'; }
// good
var getName = function() { return 'imooc'; }

在声明变量时不要添加没必要的上下文,如果你的类名称 / 对象名称已经说明了它们是什么,不要在 (属性) 变量名里重复。

// bad
const dog = {
  dogType: '斗牛犬'
  dogColor: '黑色',
};
dog.dogType = '牧羊犬'

// good
const dog = {
  type: '斗牛犬'
  color: '黑色',
};
dog.type = '牧羊犬'

2.2 let 和 const 的选择

ES6 提出了两个新的声明变量的命令:letconst 用于代替 var,使用 let 来声明可变变量,使用 const 来声明常量。对于全局环境下的常量,变量名可以使用纯大写加下划线的方式命名。

let name = 'xiaoming';
name = 'Jack';

const PI_COUNT = 3.14;

{
  const lession = 'ES6 Wiki';
  console.log(lession);
}

在选择 letconst 时,优先使用 const,尤其是在全局环境,不应该设置变量,只应设置常量。

constlet 好的几个原因。

  • 不会对值产生副作用,也就是值被修改,告诉开发者此变量不能被修改;
  • const 比较符合函数式编程思想,运算不改变值,只是新建值;
  • JavaScript 编译器会对 const 进行优化,所以多使用 const,有利于提高程序的运行效率,也就是说 letconst 的本质区别,其实是编译器内部的处理不同。

在作用域内声明的变量需要使用,如果下文没有用到就不要声明。

// bad
const name = 'xiaoming';	// 下文没有使用就不要定义了

// good
const name = 'xiaoming';
console.log(name);

2.3 字符串

对于静态字符串一律使用单引号,不使用双引号。在拼接字符串的时候需要使用反引号的方式,更加易于阅读。

// bad
const name = "imooc";
const info = name + ' ES6 Wiki';

// good
const name = 'imooc';
const info = `${name} ES6 Wiki`;

2.4 解构赋值

在批量定义有默认值的变量时可以使用数组的解构赋值。

// bad
const a = 1, b = 2, c = 3;

// good
const [a, b, c] = [1, 2, 3];

在获取数组或对象中值时也可以优先使用解构的方式:

const arr = [1, 2, 3, 4];
const obj = {a: 1, b: 3};

// bad
const x = arr[0];
const y = arr[1];
const a = obj.a;
const b = obj.b;

// good
const [x, y] = arr;
const [a, b] = obj;

在函数参数中,如果函数接收的参数是一个对象时,可以直接在函数的括号中解构对象,这样可以在函数内部之间使用变量。

// 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 }) {}

对于函数中有返回值是对象时,对象中属性名和要返回的变量名相同时可以省了变量。

// bad
function foo() {
  const a = 'aaa';
  const b = 'bbb';
  
  return {
    a: a,
    b: b
  }
}

// good
function foo() {
  const a = 'aaa';
  const b = 'bbb';
  
  return { a, b }
}

2.5 尽量减少使用条件语法

在条件语句中,可以使用或( || )运算符来设置有默认值的变量。

// bad
function createPerson(name) {
  var newName;
  if (name) {
    newName = name;
  } else {
    newName = 'Jack';
  }
}
// good
function createPerson(name) {
  const newName = name || 'Jack';
}

如果符合条件运算符(?:)那就尽量使用条件运算符。

const age = 26;

// bad
let status = ''
if (age > 18) {
	status = '成年人'
} else {
  status = '未成年'
}
// good
const status = age > 18 ? '成年人' : '未成年';

3. 函数

3.1 使用箭头函数

在定义匿名函数时最好使用箭头函数的形式,更加简洁。

// bad
const foo = function(){}
(function() { console.log('100') })()


// good
const foo = () => {}
(() => { console.log('100') })()

// best
[1, 2, 3].map(x => x * x);

当函数只有一个参数,并且返回值是一个表达式时,可以将参数外的括号和表达式外的大括号都省略。

// bad
[1, 2, 3].map((x) => {
  return x * x;
});

// good
[1, 2, 3].map(x => x * x);

使用箭头函数的另一个好处是,在箭头函数内部是不绑定 this 的,这样在调用函数时 this 的指向是不会变的。

var title = "全局标题";
// bad
var imooc = {
	title: "慕课网 ES6 Wiki",
	getTitle : function(){
		console.log(this.title);
	}
};
imooc.getTitle();		// 慕课网 ES6 Wiki
var bar = imooc.getTitle;
bar();		// 全局标题

// good
var imooc = {
	title: "慕课网 ES6 Wiki",
	getTitle : () => {
		console.log(this.title);
	}
};
imooc.getTitle();		// 全局标题
var bar = imooc.getTitle;
bar();		// 全局标题

3.2 函数参数

在函数传参时,参数不要超过两个,这样会让你更容易测试这个函数,如果超过 2 个参数会导致组合膨胀,以至于你必须根据不同的参数对大量不同的情况进行测试。理想情况下是两个,如果参数过多可以使用对象来处理。

// bad
function fn(a,b,c,d) {
	// todo
}

// good
const params = {
  a: 1,
  b: 2,
  c: 3,
  d: true
}
function fn(params) {
	// todo
}

不要使用函数的内部的参数 arguments 来获取函数的不定参数,使用 ... 来接收。因为 arguments 获取的参数是一个类数组需要转化为真正的数组。

function foo() {
  const args = [].slice.call(arguments);
  console.log(args)
}
foo(1,2,3);	// [1,2,3]

function foo(...args) {
  console.log(args)
}
foo(1,2,3);	// [1,2,3]

当函数的参数有默认值时,可以使用最短路径的方法设置。

// bad
function foo(a, b) {
  a = a || 1;
  b = b || 2;
}

// good
function foo(a=1, b=2) {
  // todo
}

3.3 一个函数只做一件事

一个函数最好只做一件事,这是软件工程中最重要的原则。如果函数做了较多的事情,它就难以组合、测试和推测。当你让函数只做一件事情的时候,它们就很容易重构,而且代码读起来也会清晰得多。

// bad
function foo(params) {
  params.forEach(param => {
    let param1 = fun1(param);
    if (param1.isActive) {
      email(client);
    }
  });
}

// good
function foo(params) {
  params.forEach(param => {
    step1(param)
  });
}
function step1(param) {
  if (foo2(param)) {
    email(client);
  }
}
function step2(param) {
  return fun1(param).isActive
}

上文中我们提到了在定义变量时要有意义,从命名就可以知道表达什么意思,所以在定义函数名时要有意义。

// bad
function foo() {}

// good
function setTitle() {}

3. 小结

本节我们从几个方向入手通过好的写法与不好的写法进行对比,可以窥探到程序的优雅,多使用好的规范的写法养成代码规范的好习惯。