「为什么代码要整洁?」——代码整洁度对于项目质量的影响,让我们通过这边文章来教你js和ts的代码整洁技巧,让你的项目更出众(上)

简介: 代码质量与整洁度成正比。有的团队在赶工期的时候,不注重代码的整洁,代码写的越来越糟糕,项目越来越混乱,生产力也跟着下降,那就必须找更多人来提高生产力,开发成本越来越高。

前言


为什么代码要整洁?


代码质量与整洁度成正比。有的团队在赶工期的时候,不注重代码的整洁,代码写的越来越糟糕,项目越来越混乱,生产力也跟着下降,那就必须找更多人来提高生产力,开发成本越来越高。


整洁的代码是怎样的?


清晰表达意图、消除重复、简单抽象、能通过测试。 换句话说:具有可读性、可重用性和可重构性。


命名

名副其实:不使用缩写、不使用让人误解的名称,不要让人推测。


// bad: 啥?
const yyyymmdstr = moment().format(YYYY/MM/DD);
// bad: 缩写
const cD = moment().format(YYYY/MM/DD);
// good:
const currentDate = moment().format(YYYY/MM/DD);
const locations = [Austin, New York, San Francisco];
// bad:推测l是locations的项
locations.forEach(l => doSomeThing(l));
// good
locations.forEach(location => doSomeThing(location));

使用方便搜索的名称:避免硬编码,对数据用常量const记录。

// bad: 86400000指的是?
setTimeout(goToWork, 86400000);
// good: 86400000是一天的毫秒数
const MILLISECONDS_PER_DAY = 60 * 60 * 24 * 1000;
setTimeout(goToWork, MILLISECONDS_PER_DAY);


类名应该是名词,方法名应该是动词。

// bad
function visble() {}
// good
function getVisble() {}


多个变量属于同一类型的属性,那就他们整合成一个对象。同时省略多余的上下文。


// bad:可以整合
const carMake = Honda,
const carModel = Accord,
const carColor = Blue,
// bad: 多余上下文
const Car = {
 carMake: Honda,
 carModel: Accord,
 carColor: Blue,
};
// good
const Car = {
 make: Honda,
 model: Accord,
 color: Blue,
};


其他:


不要写多余的废话,比如theMessage的the可以删除。


统一术语。比如通知一词,不要一会在叫notice,一会叫announce。


用读得通顺的词语。比如getElementById就比 useIdToGetElement好读。


函数(方法)


删除重复的代码,don't repeat yourself。很多地方可以注意dry,比如偷懒复制了某段代码、try...catch或条件语句写了重复的逻辑。

// bad
 try {
    doSomeThing();
    clearStack();
 } catch (e) {
    handleError(e);
    clearStack();
 }
 // good
 try {
   doSomeThing();
 } catch (e) {
   handleError(e);
 } finally {
   clearStack();
 }



形参不超过三个,对测试函数也方便。多了就使用对象参数。


同时建议使用对象解构语法,有几个好处:


能清楚看到函数签名有哪些熟悉,


可以直接重新命名,


解构自带克隆,防止副作用,


Linter检查到函数未使用的属性。

// bad
function createMenu(title, body, buttonText, cancellable) {}
// good
function createMenu({ title, body, buttonText, cancellable }) {}


函数只做一件事,代码读起来更清晰,函数就能更好地组合、测试、重构。

// bad: 处理了输入框的change事件,并创建文件的切片,并保存相关信息到localStorage
 function handleInputChange(e) {
   const file = e.target.files[0];
   // --- 切片 ---
   const chunkList = [];
   let cur = 0;
   while (cur < file.size) {
     chunkList.push({
     chunk: file.slice(cur, cur + size)
   });
   cur += size;
 }
 // --- 保存信息到localstorage ---
 localStorage.setItem(file, file.name);
 localStorage.setItem(chunkListLength, chunkList.length);
 }
 // good: 将三件事分开写,同时自顶而下读,很舒适
 function handleInputChange(e) {
   const file = e.target.files[0];
   const chunkList = createChunk(file);
   saveFileInfoInLocalStorage(file, chunkList);
 }
 function createChunk(file, size = SLICE_SIZE) {
   const chunkList = [];
   let cur = 0;
   while (cur < file.size) {
     chunkList.push({
       chunk: file.slice(cur, cur + size)
     });
     cur += size;
   }
   return chunkList
 }
 function saveFileInfoInLocalStorage(file, chunkList) {
   localStorage.setItem(file, file.name);
   localStorage.setItem(chunkListLength, chunkList.length);
 }



自顶向下地书写函数,人们都是习惯自顶向下读代码,如,为了执行A,需要执行B,为了执行B,需要执行C。如果把A、B、C混在一个函数就很难读了。(看前一个的例子)。


不使用布尔值来作为参数,遇到这种情况时,一定可以拆分函数。


// bad
function createFile(name, temp) {
  if (temp) {
    fs.create(`./temp/${name}`);
  } else {
    fs.create(name);
  }
}
// good
function createFile(name) {
  fs.create(name);
}
function createTempFile(name) {
  createFile(`./temp/${name}`);
}



避免副作用。


常见就是陷阱就是对象之间共享了状态,使用了可变的数据类型,比如对象和数组。对于可变的数据类型,使用immutable等库来高效克隆。


避免用可变的全局变量。


副作用的缺点:出现不可预期的异常,比如用户对购物车下单后,网络差而不断重试请求,这时如果添加新商品到购物车,就会导致新增的商品也会到下单的请求中。


集中副作用:遇到不可避免的副作用时候,比如读写文件、上报日志,那就在一个地方集中处理副作用,不要在多个函数和类处理副作用。


其它注意的地方:


// bad:注意到cart是引用类型!
const addItemToCart = (cart, item) => {
  cart.push({ item, date: Date.now() });
};
// good
const addItemToCart = (cart, item) => {
  return [...cart, { item, date: Date.now() }];
};


封装复杂的判断条件,提高可读性。

// bad
if (!(obj => obj != null && typeof obj[Symbol.iterator] === 'function')) {
  throw new Error('params is not iterable')
}
// good
const isIterable = obj => obj != null && typeof obj[Symbol.iterator] === 'function';
if (!isIterable(promises)) {
  throw new Error('params is not iterable')
}


在方法中有多条件判断时候,为了提高函数的可扩展性,考虑下是不是可以使用能否使用多态性来解决。


// 地图接口可能来自百度,也可能来自谷歌
const googleMap = {
  show: function (size) {
    console.log('开始渲染谷歌地图', size));
  }
};
const baiduMap = {
  render: function (size) {
    console.log('开始渲染百度地图', size));
  }
};
// bad: 出现多个条件分支。如果要加一个腾讯地图,就又要改动renderMap函数。
function renderMap(type) {
  const size = getSize();
  if (type === 'google') {
    googleMap.show(size);
  } else if (type === 'baidu') {
    baiduMap.render(size);
  }
};
renderMap('google')
// good:实现多态处理。如果要加一个腾讯地图,不需要改动renderMap函数。
// 细节:函数作为一等对象的语言中,作为参数传递也会返回不同的执行结果,也是“多态性”的体现。
function renderMap (renderMapFromApi) {
  const size = getSize();
  renderMapFromApi(size);
}
renderMap((size) => googleMap.show(size));



其他


如果用了TS,没必要做多余类型判断。


注释

一般代码要能清晰的表达意图,只有遇到复杂的逻辑时才注释。


// good:由于函数名已经解释不清楚函数的用途了,所以注释里说明。
// 在nums数组中找出 和为目标值 target 的两个整数,并返回它们的数组下标。
const twoSum = function(nums, target) {
 let map = new Map()
 for (let i = 0; i < nums.length; i++) {
   const item = nums[i];
   const index = map.get(target - item)
   if (index !== undefined){
     return [index, i]
   }
   map.set(item, i)
 }
 return []
};
// bad:加了一堆废话
const twoSum = function(nums, target) {
 // 声明map变量
 let map = new Map()
 // 遍历
 for (let i = 0; i < nums.length; i++) {
   const item = nums[i];
   const index = map.get(target - item)
   // 如果下标为空
   if (index !== undefined){
     return [index, i]
   }
   map.set(item, i)
 }
 return []
};


相关文章
|
15天前
|
JavaScript 前端开发 测试技术
在 golang 中执行 javascript 代码的方案详解
本文介绍了在 Golang 中执行 JavaScript 代码的四种方法:使用 `otto` 和 `goja` 嵌入式 JavaScript 引擎、通过 `os/exec` 调用 Node.js 外部进程以及使用 WebView 嵌入浏览器。每种方法都有其适用场景,如嵌入简单脚本、运行复杂 Node.js 脚本或在桌面应用中显示 Web 内容。
50 15
在 golang 中执行 javascript 代码的方案详解
|
26天前
|
JavaScript 前端开发
JavaScript中的原型 保姆级文章一文搞懂
本文详细解析了JavaScript中的原型概念,从构造函数、原型对象、`__proto__`属性、`constructor`属性到原型链,层层递进地解释了JavaScript如何通过原型实现继承机制。适合初学者深入理解JS面向对象编程的核心原理。
25 1
JavaScript中的原型 保姆级文章一文搞懂
|
1月前
|
JavaScript
原生js炫酷随机抽奖中奖效果代码
原生js随机抽奖是一个炫酷的根据数据随机抽奖的代码,该网页可进行随机抽取一个数据,页面动画高科技、炫酷感觉的随机抽奖效果,简单好用,欢迎下载!
45 3
原生js炫酷随机抽奖中奖效果代码
|
23天前
|
JavaScript 前端开发 安全
JavaScript与TypeScript的对比,分析了两者的特性及在实际项目中的应用选择
本文深入探讨了JavaScript与TypeScript的对比,分析了两者的特性及在实际项目中的应用选择。JavaScript以其灵活性和广泛的生态支持著称,而TypeScript通过引入静态类型系统,提高了代码的可靠性和可维护性,特别适合大型项目。文章还讨论了结合使用两种语言的优势,以及如何根据项目需求和技术背景做出最佳选择。
42 4
|
25天前
|
CDN
如何在项目中使用Moment.js库?
如何在项目中使用Moment.js库?
|
19天前
|
JSON JavaScript 关系型数据库
node.js连接GBase 8a 数据库 并进行查询代码示例
node.js连接GBase 8a 数据库 并进行查询代码示例
|
22天前
JS+CSS3文章内容背景黑白切换源码
JS+CSS3文章内容背景黑白切换源码是一款基于JS+CSS3制作的简单网页文章文字内容背景颜色黑白切换效果。
17 0
|
前端开发 JavaScript
8 种技巧让你编写更简洁的 JavaScript 代码
8 种技巧让你编写更简洁的 JavaScript 代码
255 0
8 种技巧让你编写更简洁的 JavaScript 代码
|
Web App开发 JavaScript 前端开发