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

大家好,我是若川,诚邀你进群交流学习。今天分享一篇相对轻松的代码简洁之道。学习源码系列、面试、年度总结、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,一经查实,立即删除!

相关文章

[转]让你赚大钱成富翁的4个投资习惯

本文转自&#xff1a;http://bbs.jrj.com.cn/msg,68723793.html 第一条&#xff1a;对自己进行投资  这是最大最大的投资&#xff0c;当然收获也是最为丰盛的。艺不压身&#xff0c;这句话非常有哲理。朋友今年27岁&#xff0c;可是毫不夸张地说&#xff0c;他已经具有了百万…

thymeleaf th:href url传递多参数

<a th:href"{/teacherShowMember(class_id${class.classId}&#xff0c;class_name${class.className})}"></a> thymeleaf使用&#xff08;,,&#xff09;的形式解析多个参数,结合${}放置变量十分方便 传统URL传递多参数使用&#xff1f;&拼接 <a…

spring 加载java类_在Spring中基于Java类进行配置的完整步骤

在Spring中基于Java类进行配置的完整步骤发布于 2020-7-7|复制链接基于Java配置选项&#xff0c;可以编写大多数的Spring不用配置XML&#xff0c;下面前言JavaConfig 原来是 Spring 的一个子项目&#xff0c;它通过 Java 类的方式提供 Bean 的定义信息&#xff0c;在 Spring4 的…

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

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

技术点

前端所用技术 后台页面 感谢 H-ui、FlatLab 提供静态页面支持Ztree&#xff1a;jQuery树插件DataTables&#xff1a;jQuery表格插件Layer&#xff1a;web弹层组件Distpicker&#xff1a;中国省市区地址三级联动插件KindEditor&#xff1a;富文本编辑器 简洁方便 没UEditor那么多…

扫描java类文件_java递归与非递归实现扫描文件夹下文件的实例代码

java递归与非递归实现扫描文件夹下所有文件java扫描指定文件夹下面的所有文件&#xff0c;供大家参考&#xff0c;具体内容如下扫描一个文件夹下面的所有文件&#xff0c;因为文件夹的层数没有限制可能多达几十层几百层&#xff0c;通常会采用两种方式来遍历指定文件夹下面的所…

【阿里内部应用】基于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 …

这10道springboot常见面试题你需要了解下

1、什么是Spring Boot&#xff1f;多年来&#xff0c;随着新功能的增加&#xff0c;spring变得越来越复杂。只需访问https://spring.io/projects页面&#xff0c;我们就会看到可以在我们的应用程序中使用的所有Spring项目的不同功能。如果必须启动一个新的Spring项目&#xff0…

Silverlight中使用MIRIA进行触屏编程

Silverlight for Windows phone7中可以使用XNA提供的功能进行触屏编程&#xff0c;不过暂时还没有网页Silverlight的XNA移植。经过搜索发现MIRIA这个开源项目http://miria.codeplex.com/ 可以在Silverlight中实现Touch、Gesture的功能。 用法如下&#xff1a; 1、项目中引用MIG…

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模式下支…

02-15 GUCCI 我喜欢的

我觉得&#xff0c;GUCCI是低调的奢华&#xff0c;价格不是很高&#xff0c;容易接近&#xff0c;符合我的风格&#xff0c;是现阶段我的选择 样式我喜欢 希望我的生活质量步步高升&#xff0c;将来不再为追求物质生活而奋斗。 转载于:https://www.cnblogs.com/yd1227/archive/…

php 批量修改mysql 数据表,字段 字符集编码

$sql"SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA 数据库名称";$r$pdo->query($sql,2);foreach($r as $v){//if($v[TABLE_NAME]!monxin_index_user){continue;} 代码来源 梦行云软件$sql"alter table ".$v[TABLE_NAME]." conver…

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;但我认为…

表单提交中Get和Post方式的区别及EncType表明提交数据的格式详解

表单提交中Get和Post方式的区别1. get是从服务器上获取数据&#xff0c;post是向服务器传送数据。2. get是把参数数据队列加到提交表单的ACTION属性所指的URL中&#xff0c;值和表单内各个字段一一对应&#xff0c;在URL中可以看到。post是通过HTTP post机制&#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 …