为什么同事写的代码那么优雅~

大家好,我是若川,诚邀你进群交流学习。今天分享一篇相对轻松的代码简洁之道。学习源码系列、面试、年度总结、JS基础系列


内容出自《代码整洁之道》、Alex Kondov[1]的博文tao-of-react[2]和《Clean Code of Javascript》

image.png

代码整洁有什么用?

image.png
  1. 思路清晰,降低bug几率

  2. 更容易维护,利于团队协作

  3. 看起来舒服,提高效率

  4. ......

软件质量与代码整洁度成正比 --Robert.C.Martin

软件设计3R层次结构:readable, reusable, and refactorable[3] 可读性、可重用性、可重构性

下面这些原则是作者提出的一些最佳实践,但不是强制约束

关于命名

1.使用有意义且易读的变量名

???? const yyyymmdstr = moment().format("YYYY/MM/DD");???? const currentDate = moment().format("YYYY/MM/DD");

2.使用有意义的变量代替数组下标

???? 
const address = "One Infinite Loop, Cupertino 95014";
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
saveCityZipCode(address.match(cityZipCodeRegex)[1],address.match(cityZipCodeRegex)[2]
);????
const address = "One Infinite Loop, Cupertino 95014";
const cityZipCodeRegex = /^[^,\\]+[,\\\s]+(.+?)\s*(\d{5})?$/;
const [_, city, zipCode] = address.match(cityZipCodeRegex) || [];
saveCityZipCode(city, zipCode);

3.变量名要简洁,不要附加无用信息

???? 
const Car = {carMake: "Honda",carModel: "Accord",carColor: "Blue"
};
function paintCar(car, color) {car.carColor = color;
}????
const Car = {make: "Honda",model: "Accord",color: "Blue"
};
function paintCar(car, color) {car.color = color;
}

4.消除魔术字符串

???? setTimeout(blastOff, 86400000);???? const MILLISECONDS_PER_DAY = 60 * 60 * 24 * 1000; //86400000;
setTimeout(blastOff, MILLISECONDS_PER_DAY);

5.使用默认参数替代短路运算符

????
function createMicrobrewery(name) {const breweryName = name || "Hipster Brew Co.";// ...
}???? 
function createMicrobrewery(name = "Hipster Brew Co.") {// ...
}

关于函数

1.一个函数只做一件事的好处在于易于理解、易于测试。

????
function emailClients(clients) {clients.forEach(client => {const clientRecord = database.lookup(client);if (clientRecord.isActive()) {email(client);}});
}???? 
function emailActiveClients(clients) {clients.filter(isActiveClient).forEach(email);
}
function isActiveClient(client) {const clientRecord = database.lookup(client);return clientRecord.isActive();
}---------------------分割线-----------------------????
function createFile(name, temp) {if (temp) {fs.create(`./temp/${name}`);} else {fs.create(name);}
}???? 
function createFile(name) {fs.create(name);
}
function createTempFile(name) {createFile(`./temp/${name}`);
}

2.函数参数不多于2个,如果有很多参数就利用object传递,并使用解构。

推荐使用解构的几个原因:

  1. 看到函数签名可以立即了解有哪些参数

  2. 解构能克隆传递到函数中的参数对象的值(浅克隆),有助于防止副作用.

  3. linter可以提示有哪些参数未被使用

????
function createMenu(title, body, buttonText, cancellable) {// ...
}
createMenu("Foo", "Bar", "Baz", true);???? 
function createMenu({ title, body, buttonText, cancellable }) {// ...
}
createMenu({title: "Foo",body: "Bar",buttonText: "Baz",cancellable: true
});

3.函数名应该直接反映函数的作用

????
function addToDate(date, month) {// ...
}
const date = new Date();
// It's hard to tell from the function name what is added
addToDate(date, 1);???? 
function addMonthToDate(month, date) {// ...
}
const date = new Date();
addMonthToDate(1, date);

4.一个函数的抽象层级不要太多,如果你的函数做了太多事,就需要把它拆分成多个函数

????
function parseBetterJSAlternative(code) {const REGEXES = [// ...];const statements = code.split(" ");const tokens = [];REGEXES.forEach(REGEX => {statements.forEach(statement => {// ...});});const ast = [];tokens.forEach(token => {// lex...});ast.forEach(node => {// parse...});
}???? 
function parseBetterJSAlternative(code) {const tokens = tokenize(code);const syntaxTree = parse(tokens);syntaxTree.forEach(node => {// parse...});
}
function tokenize(code) {const REGEXES = [// ...];const statements = code.split(" ");const tokens = [];REGEXES.forEach(REGEX => {statements.forEach(statement => {tokens.push(/* ... */);});});return tokens;
}
function parse(tokens) {const syntaxTree = [];tokens.forEach(token => {syntaxTree.push(/* ... */);});return syntaxTree;
}

5.减少重复代码

????
function showDeveloperList(developers) {developers.forEach(developer => {const expectedSalary = developer.calculateExpectedSalary();const experience = developer.getExperience();const githubLink = developer.getGithubLink();const data = {expectedSalary,experience,githubLink};render(data);});
}
function showManagerList(managers) {managers.forEach(manager => {const expectedSalary = manager.calculateExpectedSalary();const experience = manager.getExperience();const portfolio = manager.getMBAProjects();const data = {expectedSalary,experience,portfolio};render(data);});
}???? 
function showEmployeeList(employees) {employees.forEach(employee => {const expectedSalary = employee.calculateExpectedSalary();const experience = employee.getExperience();const data = {expectedSalary,experience};switch (employee.type) {case "manager":data.portfolio = employee.getMBAProjects();break;case "developer":data.githubLink = employee.getGithubLink();break;}render(data);});
}

6.尽量使用纯函数 (函数式编程,not命令式编程)

????
const programmerOutput = [{name: "Uncle Bobby",linesOfCode: 500},{name: "Suzie Q",linesOfCode: 1500},{name: "Jimmy Gosling",linesOfCode: 150},{name: "Gracie Hopper",linesOfCode: 1000}
];
let totalOutput = 0;
for (let i = 0; i < programmerOutput.length; i++) {totalOutput += programmerOutput[i].linesOfCode;
}???? 
const programmerOutput = [{name: "Uncle Bobby",linesOfCode: 500},{name: "Suzie Q",linesOfCode: 1500},{name: "Jimmy Gosling",linesOfCode: 150},{name: "Gracie Hopper",linesOfCode: 1000}
];
const totalOutput = programmerOutput.reduce((totalLines, output) => totalLines + output.linesOfCode,0
);

7.注意函数的副作用

????
const addItemToCart = (cart, item) => {cart.push({ item, date: Date.now() });
};???? 
const addItemToCart = (cart, item) => {return [...cart, { item, date: Date.now() }];
};

8.不要过度优化

现代浏览器在运行时进行了大量的优化。很多时候,如果你再优化,那就是在浪费时间。

????
// On old browsers, each iteration with uncached `list.length` would be costly
// because of `list.length` recomputation. In modern browsers, this is optimized.
for (let i = 0, len = list.length; i < len; i++) {// ...
}???? 
for (let i = 0; i < list.length; i++) {// ...
}

关于注释

1.Comments are an apology, not a requirement. Good code mostly documents itself.

好的代码是自注释的

????
function hashIt(data) {// The hashlet hash = 0;// Length of stringconst length = data.length;// Loop through every character in datafor (let i = 0; i < length; i++) {// Get character code.const char = data.charCodeAt(i);// Make the hashhash = (hash << 5) - hash + char;// Convert to 32-bit integerhash &= hash;}
}???? 
function hashIt(data) {let hash = 0;const length = data.length;for (let i = 0; i < length; i++) {const char = data.charCodeAt(i);hash = (hash << 5) - hash + char;// Convert to 32-bit integerhash &= hash;}
}

2.git能做的事不要写在注释里

????
/*** 2016-12-20: Removed monads, didn't understand them (RM)* 2016-10-01: Improved using special monads (JP)* 2016-02-03: Removed type-checking (LI)* 2015-03-14: Added combine with type-checking (JR)*/
function combine(a, b) {return a + b;
}???? 
function combine(a, b) {return a + b;
}

关于组件

1.尽可能使用函数组件

函数式组件有更简单的语法,没有生命周期函数,构造函数。同样的逻辑和可靠性,函数式组件可以用更少的代码完成。

???? 
class Counter extends React.Component {state = {counter: 0,}constructor(props) {super(props)this.handleClick = this.handleClick.bind(this)}handleClick() {this.setState({ counter: this.state.counter + 1 })}render() {return (<div><p>counter: {this.state.counter}</p><button onClick={this.handleClick}>Increment</button></div>)}
}
????
function Counter() {const [counter, setCounter] = useState(0)handleClick = () => setCounter(counter + 1)return (<div><p>counter: {counter}</p><button onClick={handleClick}>Increment</button></div>)
}

2.函数组件中剥离逻辑代码

尽可能的把逻辑从组件中剥离出去,可以把必要的值用参数的形式传给工具类函数。在函数组件外组织你的逻辑让你能够更简单的去追踪 bug 和扩展你的功能。

????
export default function Component() {const [value, setValue] = useState('')function isValid() {// ...}return (<><inputvalue={value}onChange={e => setValue(e.target.value)}onBlur={validateInput}/><buttononClick={() => {if (isValid) {// ...}}}>Submit</button></>)
}???? 
function isValid(value) {// ...
}
export default function Component() {const [value, setValue] = useState('')return (<><inputvalue={value}onChange={e => setValue(e.target.value)}onBlur={validateInput}/><buttononClick={() => {if (isValid(value)) {// ...}}}>Submit</button></>)
}

3.控制组件长度,减少UI耦合

函数组件也是函数,同样要控制长度,如果组件太长,就要拆成多个组件

????
function Filters({ onFilterClick }) {return (<><p>Book Genres</p><ul><li><div onClick={() => onFilterClick('fiction')}>Fiction</div></li><li><div onClick={() => onFilterClick('classics')}>Classics</div></li><li><div onClick={() => onFilterClick('fantasy')}>Fantasy</div></li><li><div onClick={() => onFilterClick('romance')}>Romance</div></li></ul></>)
}// ???? Use loops and configuration objects
const GENRES = [{identifier: 'fiction',name: Fiction,},{identifier: 'classics',name: Classics,},{identifier: 'fantasy',name: Fantasy,},{identifier: 'romance',name: Romance,},
]function Filters({ onFilterClick }) {return (<><p>Book Genres</p><ul>{GENRES.map(genre => (<li><div onClick={() => onFilterClick(genre.identifier)}>{genre.name}</div></li>))}</ul></>)
}

4.尽量避免函数组件内再定义函数组件

不要在一个函数组件中再去书写一个函数组件。一个函数组件应该仅仅是一个函数。函数组件内部再定义函数组件,意味着内部的函数组件能够通过作用域访问到外层组件所有的 state 和 props,这样会使内部定义组件不可靠。把内部的组件移到外部,避免闭包和作用域的影响。

// ???? Don't write nested render functions
function Component() {function renderHeader() {return <header>...</header>}return <div>{renderHeader()}</div>
}
// ???? Extract it in its own component
import Header from '@modules/common/components/Header'
function Component() {return (<div><Header /></div>)
}

5.优化props

控制props数量、聚合props、完善渲染条件

  1. 如何把控 props 的量是一个值得商榷的问题。但是一个组件传递越多的 props 意味着它做的事情越多这是共识。当 props 达到一定数量的时候,意味着这个组件做的事情太多了。当props的数量达到5个以上的时候,这个组件就需要被拆分了。在某些极端诸如输入类型组件的情况下,可能拥有过多的props,但在通常情况下5个props能够满足大部分组件的需求。

提示:一个组件拥有越多的 props,越容易被 rerender。

  1. 一些场景下使用短路语法来进行条件渲染可能导致期望之外的问题,有可能会渲染一个 0 在界面上。避免这种情况发生,尽量使用三元操作符。尽管短路操作符能使代码变得简洁,但是三元操作符能够保证渲染的正确性。

// ???? Try to avoid short-circuit operators
function Component() {const count = 0return <div>{count && <h1>Messages: {count}</h1>}</div>
}
// ???? Use a ternary instead
function Component() {const count = 0return <div>{count ? <h1>Messages: {count}</h1> : null}</div>
}

关于其他

1.把组件放入单独的文件夹中

// ???? Don't keep all component files together
├── components├── Header.jsx├── Header.scss├── Header.test.jsx├── Footer.jsx├── Footer.scss├── Footer.test.jsx// ???? Move them in their own folder
├── components├── Header├── index.js├── Header.jsx├── Header.scss├── Header.test.jsx├── Footer├── index.js├── Footer.jsx├── Footer.scss├── Footer.test.jsx

2.尽量使用绝对路径

使用绝对路径可以在移动一个文件的时候能够尽量少的更改其它文件。绝对路径也能让你对所有依赖文件的出处一目了然。

(完)


最近组建了一个江西人的前端交流群,如果你是江西人可以加我微信 ruochuan12 私信 江西 拉你进群。


推荐阅读

我在阿里招前端,该怎么帮你(可进面试群)
毕业年限不长的前端焦虑和突破方法

前端抢饭碗系列之Vue项目如何做单元测试
老姚浅谈:怎么学JavaScript?

················· 若川简介 ·················

你好,我是若川,毕业于江西高校。现在是一名前端开发“工程师”。写有《学习源码整体架构系列》多篇,在知乎、掘金收获超百万阅读。
从2014年起,每年都会写一篇年度总结,已经写了7篇,点击查看年度总结。
同时,活跃在知乎@若川,掘金@若川。致力于分享前端开发经验,愿景:帮助5年内前端人走向前列。

点击上方卡片关注我、加个星标

今日话题

略。欢迎分享、收藏、点赞、在看我的公众号文章~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/275704.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2021 年最值得了解的 Node.js 工具(下)

大家好&#xff0c;我是若川&#xff0c;诚邀你加群长期交流。今天分享一篇用得上的 node 库。下篇。链接地址&#xff1a;https://github.com/huaize2020/awesome-nodejs。上篇是&#xff1a;2021 年最值得了解的 Node.js 工具❝前言&#xff1a;前端时间分享了这些node开源工…

【阿里内部应用】基于Blink为新商业调控打造实时大数据交互查询服务

基于Blink为新商业调控打造实时大数据交互查询服务 案例与解决方案汇总页&#xff1a;阿里云实时计算产品案例&解决方案汇总从IT到DT、从电商到新商业&#xff0c;阿里巴巴的每个细胞都存在大数据的DNA&#xff0c;如何挖掘大数据的价值成为抢占未来先机的金钥匙&#xff0…

Vite 的好与坏

大家好&#xff0c;我是若川&#xff0c;诚邀你进群交流学习。今天分享一篇关于Vite的文章。学习源码系列、面试、年度总结、JS基础系列。全文 3000 字&#xff0c;欢迎点赞关注转发一、Vite 是什么2020年4月&#xff0c;尤大大发了这么一个推&#xff1a;随后&#xff0c;2021…

Windows phone 7新开发工具发布

春节假期已经接近尾声. 马上第一个工作日就要来临. 春节真的不再是一个简简单单的节日. 有时让人感到欣喜 这意味这一年的忙碌都会因为这个节日的到来而画上一个终止符.面临一个不长也不短的假期.眼下的一年翻过去 新的一年即将到来. 似乎一切都可以重新开始. 有时又令人感到无…

opentaps mysql_opentaps 1.4 联接 mysql 笔记

opentaps 1.4 连接 mysql 笔记一、安装 MySQ 略...二、创建MySQL Database opentaps ERP CRM1.mysql -u root -h 127.0.0.1 -p 2.mysql>create database opentaps default CHARACTER SET utf8 COLLATE utf8_general_ci;3.mysql>create user opentaps;4.mysql>grant …

React 核心开发者 Dan Abramov 访谈实录

大家好&#xff0c;我是若川。面试、学习源码系列、年度总结、JS基础系列译者注&#xff1a;本译文是在「在线对话 React.js 核心开发者」一个半小时直播的基础上进行的原文翻译&#xff0c;包括了直播中的所有问答内容&#xff0c;尽可能保留了 Dan 回答的中心语义&#xff0c…

python ev3图形化编程软件下载_mPython(图形化编程软件)

mPython是盛思技术团队在BBC官方原版PythonEditor基础上、拓展开发的应用软件。可以进行可视化代码编程&#xff0c;有hex、python、blockly三种代码读写等功能。功能介绍1、不依赖网络&#xff0c;可离线安装使用2、支持hex、python、blockly三种代码的读写3、blockly模式下支…

python如何安装panda数据库_在Pycharm中安装Pandas库方法(简单易懂)

开发环境的搭建是一件入门比较头疼的事情&#xff0c;在上期的文稿基础上&#xff0c;增加一项Anaconda的安装介绍。Anaconda是Python的一个发行版本&#xff0c;安装好了Anaconda就相当于安装好了Python&#xff0c;并且里面还集成了很多Python科学计算的第三方库。比如我们需…

译文 | Vue 在哪些方面做的比 React 更好?

大家好&#xff0c;我是若川。在过去的五年中&#xff0c;我一直是一名 React 工程师。我爱React。我喜欢开发 React 应用程序。我认为它是目前最好的UI框架之一。但是&#xff0c;在这个领域有一些竞争对手。其中最大的是 Vue.js 。我以前玩过一些 Vue.js&#xff0c;但我认为…

web mp4第一帧_Web成帧器就在这里!

web mp4第一帧The Framer Team is pulling up it’s pants. I sniffed something cooking when they announced a public beta for Framer for web… FRAMER FOR WEB? Yes, I don’t know how they did it, but their powerful set of tools, plugins and animation controls …

Lucene学习总结之三:Lucene的索引文件格式(2)

2019独角兽企业重金招聘Python工程师标准>>> 四、具体格式 上面曾经交代过&#xff0c;Lucene保存了从Index到Segment到Document到Field一直到Term的正向信息&#xff0c;也包括了从Term到Document映射的反向信息&#xff0c;还有其他一些Lucene特有的信息。下面对这…

JavaScript 数组 API 全解析

在编程世界中&#xff0c;数组是指元素的集合。数组将数据作为元素进行存储&#xff0c;并在需要时将其取出。在支持数组的编程语言中广泛地采用了这个数据结构。这个手册会介绍 JavaScript 数组的所有知识。你将会学到复杂数据处理、解构、常用数组方法等内容。我为什么写这篇…

美学设计评价_死亡的孩子无法使用的设计美学

美学设计评价In the popular anime series, Soul Eater, Death the Kid is a Shinigami (Japanese death god) who vanquishes evil with his dual pistols, Liz and Patty. Although he’s strikingly powerful, his battles are often hindered by his obsessive-compulsive …

【送书】2021年哪些好书值得读(小姐姐配音)

大家好&#xff0c;我是若川。记得点上面的小姐姐再次录制的配音。为感谢大家一直以来的支持和肯定。不知道是今年第几次送书了。昨天送书的音频广受好评&#xff0c;没参与的可以参与。今天联合华章图书再送文中任选一本 * 3 包邮送&#xff0c;详细规则看文末。Web开发01《斯…

Flash获取html参数的方法

一. swf?传参 html代码:代码<html><head><meta http-equiv”Content-Type” content”text/html charsetutf-8″ /><title>as</title></head><body><object classid”clsid:D27CDB6E-AE6D-11cf-96B8-444553540000″ codebase”h…

方法重载_方法

方法重载Recently, I wrote an article about moving XD designs to Figma. It was a really interesting experiment and one that seemed to interest quite a lot of people.最近&#xff0c;我写了一篇有关将XD设计移至Figma的文章。 这是一个非常有趣的实验&#xff0c;似…

Node.js 框架设计及企业 Node.js 基础建设相关讨论

大家好&#xff0c;我是若川。19年我写的 lodash源码 文章投稿到海镜大神知乎专栏竟然通过了&#xff0c;后来20年海镜大神还star了我的博客&#xff0c;同时还转发了我的微博。时间真快啊。今天分享这篇Node.js的讨论。2021 年上半年早已过去&#xff0c;回顾 Node.js 在国内的…

DAS、NAS、SAN、iSCSI 存储方案概述

目前服务器所使用的专业存储方案有DAS、NAS、SAN、iSCSI几种。存储根据服务器类型可以分为&#xff1a;封闭系统的存储和开放系统的存储&#xff1a; &#xff08;1&#xff09;封闭系统主要指大型机. &#xff08;2&#xff09;开放系统指基于包括Windows、UNIX、Linux等操作系…

同态加法_同态—当旧趋势突然变酷时

同态加法Designers get excited at every year’s end to see what next year’s trend is going to be. What the future of design is going to look like. What they can carry forward to the next year; And Neumorphism was one among the lists which gained great atte…

网页标题设置,为什么在SERP中,显示结果不一致?

在网站建设与运营的过程中&#xff0c;我们经常会遇到各种各样的问题&#xff0c;特别是关于网页标题设置的问题&#xff0c;如果一个页面标题出错&#xff0c;那么&#xff0c;你整个页面建设的过程&#xff0c;就完全是事倍功半&#xff0c;得不偿失。 那么&#xff0c;网页标…