JavaScript 的简洁之道

译者:前端小智

原文:https://devinduct.com/blogpost/22/javascript-clean-code-best-practices

为了保证可读性,本文采用的音译而非直意。

简介

如果你关注代码本身和代码的编写方式,而不是只关心它是否能工作,那么你写代码是有一定的水准。专业开发人员将为未来的自己和“其他人”编写代码,而不仅仅只编写当前能工作就行的代码。

在此基础上,简洁代码可以定义为自解释的、易于人理解的、易于更改或扩展的代码。

以下列表一些好编写方式,仅供参考,当然,如果你有更好的方式,欢迎留言。

1. 强类型检查

===代替 ==

// 如果处理不当,它会极大地影响程序逻辑。这就像,你想向左走,但由于某种原因,你向右走	
0 == false // true	
0 === false // false	
2 == "2" // true	
2 === "2" // false	
// 例子	
const value = "500";	
if (value === 500) {	
  console.log(value);	
  // 条件不成立,不会进入	
}	
if (value === "500") {	
  console.log(value);	
  // 条件成立,会进入	
}

2.变量

用知名其意的方式为变量命名,通过这种方式,当一个人看到它们时,易于搜索和理解。

不好的方式:

let daysSLV = 10;	
let y = new Date().getFullYear();	
let ok;	
if (user.age > 30) {	
  ok = true;	
}

好的方式:

const MAX_AGE = 30;	
let daysSinceLastVisit = 10;	
let currentYear = new Date().getFullYear();	
...	
const isUserOlderThanAllowed = user.age > MAX_AGE;

不要在变量名中添加额外的不需要的单词。

不好的方式:

let nameValue;	
let theProduct;

好的方式:

let name;	
let product;

不要简写变量上下文。

不好的方式:

const users = ["John", "Marco", "Peter"];	
users.forEach(u => {	
  doSomething();	
  doSomethingElse();	
  // ...	
  // ...	
  // ...	
  // ...	
  // 当上面代码很多的时候 ,这 `u` 是什么鬼	
  register(u);	
});

好的方式:

const users = ["John", "Marco", "Peter"];	
users.forEach(user => {	
  doSomething();	
  doSomethingElse();	
  // ...	
  // ...	
  // ...	
  // ...	
  register(user);	
});

不要添加不必要的上下文。

不好的方式:

const user = {	
  userName: "John",	
  userSurname: "Doe",	
  userAge: "28"	
};	
...	
user.userName;

好的方式:

const user = {	
  name: "John",	
  surname: "Doe",	
  age: "28"	
};	
...	
user.name;

3. 函数

使用长而具有描述性的名称。考虑到函数表示某种行为,函数名称应该是动词或短语,用以说明其背后的意图以及参数的意图。函数的名字应该说明他们做了什么。

不好的方式:

function notif(user) {	
  // implementation	
}

好的方式:

function notifyUser(emailAddress) {	
  // implementation	
}

避免使用大量参数。理想情况下,函数应该指定两个或更少的参数。参数越少,测试函数就越容易,参数多的情况可以使用对象。

不好的方式:

function getUsers(fields, fromDate, toDate) {	
  // implementation	
}

好的方式:

function getUsers({ fields, fromDate, toDate }) {	
  // implementation	
}	
getUsers({	
  fields: ['name', 'surname', 'email'],	
  fromDate: '2019-01-01',	
  toDate: '2019-01-18'	
});

使用默认参数替代 || 操作

不好的方式:

function createShape(type) {	
  const shapeType = type || "cube";	
  // ...	
}

好的方式:

function createShape(type = "cube") {	
  // ...	
}

一个函数应该只做一件事,不要在一个函数中执行多个操作。

不好的方式:

function notifyUsers(users) {	
  users.forEach(user => {	
    const userRecord = database.lookup(user);	
    if (userRecord.isVerified()) {	
      notify(user);	
    }	
  });	
}

好的方式:

function notifyVerifiedUsers(users) {	
  users.filter(isUserVerified).forEach(notify);	
}	
function isUserVerified(user) {	
  const userRecord = database.lookup(user);	
  return userRecord.isVerified();	
}

使用Object.assign设置对象默认值。

不好的方式:

const shapeConfig = {	
  type: "cube",	
  width: 200,	
  height: null	
};	
function createShape(config) {	
  config.type = config.type || "cube";	
  config.width = config.width || 250;	
  config.height = config.height|| 250;	
}	
createShape(shapeConfig);

好的方式:

const shapeConfig = {	
  type: "cube",	
  width: 200	
  // Exclude the 'height' key	
};	
function createShape(config) {	
  config = Object.assign(	
    {	
      type: "cube",	
      width: 250,	
      height: 250	
    },	
    config	
  );	
  ...	
}	
createShape(shapeConfig);

不要使用标志作为参数,因为它们告诉函数做的比它应该做的多。

不好的方式:

function createFile(name, isPublic) {	
  if (isPublic) {	
    fs.create(`./public/${name}`);	
  } else {	
    fs.create(name);	
  }	
}

好的方式:

function createFile(name) {	
  fs.create(name);	
}	
function createPublicFile(name) {	
  createFile(`./public/${name}`);	
}

不要污染全局变量。如果需要扩展现有对象,请使用ES类和继承,而不是在原生对象的原型链上创建函数。

不好的方式:

Array.prototype.myFunc = function myFunc() {	
  // implementation	
};

好的方式:

class SuperArray extends Array {	
  myFunc() {	
    // implementation	
  }	
}

4. 条件

避免使用反面条件。

不好的方式:

function isUserNotBlocked(user) {	
  // implementation	
}	
if (!isUserNotBlocked(user)) {	
  // implementation	
}

好的方式:

function isUserBlocked(user) {	
  // implementation	
}	
if (isUserBlocked(user)) {	
  // implementation	
}

使用条件简写。这可能微不足道,但值得一提。仅对布尔值使用此方法,并且如果你确信该值不会是 undefinednull的,则使用此方法。

不好的方式:

if (isValid === true) {	
  // do something...	
}	
if (isValid === false) {	
  // do something...	
}

好的方式:

if (isValid) {	
  // do something...	
}	
if (!isValid) {	
  // do something...	
}

尽可能避免条件句,而是使用多态性和继承。

不好的方式:

class Car {	
  // ...	
  getMaximumSpeed() {	
    switch (this.type) {	
      case "Ford":	
        return this.someFactor() + this.anotherFactor();	
      case "Mazda":	
        return this.someFactor();	
      case "McLaren":	
        return this.someFactor() - this.anotherFactor();	
    }	
  }	
}

好的方式:

class Car {	
  // ...	
}	
class Ford extends Car {	
  // ...	
  getMaximumSpeed() {	
    return this.someFactor() + this.anotherFactor();	
  }	
}	
class Mazda extends Car {	
  // ...	
  getMaximumSpeed() {	
    return this.someFactor();	
  }	
}	
class McLaren extends Car {	
  // ...	
  getMaximumSpeed() {	
    return this.someFactor() - this.anotherFactor();	
  }	
}

5. 类

class 是JavaScript中新的语法糖。一切工作就像以前的原型,只是它现在看起来不同,你应该更喜欢他们比ES5普通功能。

不好的方式:

const Person = function(name) {	
  if (!(this instanceof Person)) {	
    throw new Error("Instantiate Person with `new` keyword");	
  }	
  this.name = name;	
};	
Person.prototype.sayHello = function sayHello() { /**/ };	
const Student = function(name, school) {	
  if (!(this instanceof Student)) {	
    throw new Error("Instantiate Student with `new` keyword");	
  }	
  Person.call(this, name);	
  this.school = school;	
};	
Student.prototype = Object.create(Person.prototype);	
Student.prototype.constructor = Student;	
Student.prototype.printSchoolName = function printSchoolName() { /**/ };

好的方式:

class Person {	
  constructor(name) {	
    this.name = name;	
  }	
  sayHello() {	
    /* ... */	
  }	
}	
class Student extends Person {	
  constructor(name, school) {	
    super(name);	
    this.school = school;	
  }	
  printSchoolName() {	
    /* ... */	
  }	
}

使用链接。许多库(如jQuery和Lodash)都使用这种模式。在类中,只需在每个函数的末尾返回 this就可以将更多的该类方法链接到它上。

不好的方式:

class Person {	
  constructor(name) {	
    this.name = name;	
  }	
  setSurname(surname) {	
    this.surname = surname;	
  }	
  setAge(age) {	
    this.age = age;	
  }	
  save() {	
    console.log(this.name, this.surname, this.age);	
  }	
}	
const person = new Person("John");	
person.setSurname("Doe");	
person.setAge(29);	
person.save();

好的方式:

class Person {	
  constructor(name) {	
    this.name = name;	
  }	
  setSurname(surname) {	
    this.surname = surname;	
    // Return this for chaining	
    return this;	
  }	
  setAge(age) {	
    this.age = age;	
    // Return this for chaining	
    return this;	
  }	
  save() {	
    console.log(this.name, this.surname, this.age);	
    // Return this for chaining	
    return this;	
  }	
}	
const person = new Person("John")	
    .setSurname("Doe")	
    .setAge(29)	
    .save();

总结

这只是改进代码的一小部分。一般生活入,这里所说的原则是人们通常不遵守的原则。他们尝试着去做,但出于各种原因,就没有坚持下去。也许在项目开始时,代码是简洁的,但是当要在截止日期前完成时,这些原则常常被忽略,并被转移到“TODO”或“REFACTOR”部分。在这一点上,你的客户更希望您在最后期限之前完成任务,而不是编写简洁的代码。


640?wx_fmt=png

作为一个前端工程师也要掌握的几种文件路径知识

说Node.js做后端开发,stream有必要了解下

深入理解Javacript从作用域作用域链开始

【JS必知必会】高阶函数详解与实战

640?wx_fmt=jpeg

交流学习

大家好,我是koala,公众号「程序员成长指北」作者。目前在做一个node工程师进阶路线,加入我们一起学习吧!

640?wx_fmt=png

加入我们

640?wx_fmt=jpeg


640?wx_fmt=png在看点这里 640?wx_fmt=gif


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值