说明:含义不清晰,不能作到「望文生义」html
BadCode前端
var l = data.length;
GoodCodevue
// 闭包只有一行代码,可使用单字变量 data.map(d => d.length)
说明:含义不清晰,不能作到「望文生义」react
BadCodeios
var obj = {}; var obj2 = {...obj, key: 1};
GoodCodegit
var obj = {}; var objWithKey = {...obj, key: 1};
此处动词没有包含时态
变量名应该是名词或者名词短语。github
例外:redux
说明:canvas
BadCodeaxios
// 以名词开头,看不明白什么有什么功能 function option() {} // 时态不对 function updatedTime() {}
GoodCode
function selectOption() {} function updateTime() {}
例外:
说明:含义不清晰,不能作到「望文生义」
BadCode
var uo = function updateOrder(){} var as = [].slice; var ex = Object.extends; var nu = number
GoodCode
// weixin/wx 是专有名词 var weixinUser = {}; var wx = weixin; // POI 是专有名词 var poi = {};
例外:专有 API,如 alert
说明:在上层做用域下的代码,会被更多函数使用到。其名称应该尽可能长或者通用,以保证可以搜索到。
BadCode
// 在全局变量上定义了一个 item 变量,可是很难从命名上理解其做用是什么。 window.item = {}
GoodCode
window.primaryProductItem = {};
说明:变量中加符号,每每是为了约定其优先级或者做用域。符号应该在变量名前面。
BadCode
function getDot_(){} function privateFn$$ (){}
GoodCode
function _getDot() {} function $$privateFn() {}
说明:类做为实例的所属,其名称表达的含义要一脉相承
BadCode
class Person() {} var dog = new Person(); // dog is a Person ?
GoodCode
class Person() {} var jack = new Person();
说明:粗暴的翻译,更容易形成误解,还不如写拼音
BadCode
// 渲染「页面顶部的执行人」 // 仍是渲染「执行砍头的人」? function renderHeadExecutantPeople(){}
GoodCode
function renderHeader() {}
说明:避免通一个概念在不一样的代码用多种不一样的单词描述。
BadCode
// 远程请求这个概念,前后用了 get/fetch/query // 三个名词去描述 function getUserInfo() {} function fetchProductInfo() {} function queryPayment() {}
GoodCode
// 统一用 get 描述 // 阅读代码的人能体会到其中的共性 function getUserInfo() {} function getProductInfo() {} function getPayment() {}
例外:专有词
说明:双关语容易引发歧义
BadCode
// 订单类型,仍是排序类型? var orderType
GoodCode
var sortType
说明:命名每每是实现的隐喻,若是存在差别则会让阅读者看不懂代码。
BadCode
// empty 的命名含义和实现截然相反 // (我真的见过这种代码) function getProduct(id) { axios.delete('/product', {id}); }
GoodCode
function deleteProduct(id) { axios.delete('/product', {id}); }
说明:布尔变量的名称中,若是加上 「not」之类的否认词,则至关于作了一次了逻辑判断。
BadCode
const notEmpty = !!array.length;
GoodCode
const empty = !array.length;
说明:代码太长说明作的事情不够专注,同时也会让阅读变得很困难。
说明:一样功能的代码不要重复三次
说明:代码里的逻辑分支要尽可能少,只作一件事情,而且要处理好边界和异常状况。
说明:函数的输入越多,每每就表明功能约复杂
说明:对于比较奇怪的业务逻辑,或者由于系统、接口缘由而写的比较奇怪的逻辑。要经过注释标注出来
BadCode
framework.doSomeThing(); framework.reset(); // 阅读者心里 OS:这里为啥要作一次 reset? framework.continueSomeThing();
GoodCode
framework.doSomeThing(); // framework 有个 bug,这里必需要作一次 rest 附连接: http://github.com/issuse/*** framework.reset(); framework.continueSomeThing();
说明:纯函数比较好测试,逻辑也比较清晰,能够放心的引入和删除。
BadCode
let status; function method() { if (status) { ... } }
GoodCode
function method(status) { if (status) { ... } }
说明:修改参数会致使函数的做用变得不可预测
BadCode
function updateObj(obj, value) { obj.key = value; return obj; }
GoodCode
function updateObj(obj, value) { return {...obj, key: value}; }
说明:this 的指向常常不固定,会致使代码难以理解。若是调用方不熟悉的话,很容易引发 Bug。
BadCode
function method() { console.log(this.value); } method() // 报错 var obj = { method, value: 1} obj.method() // 输出 1
GoodCode
function method(value) { console.log(value); }
说明:错误也是一种逻辑分支,若是不处理的话,代码就不够健壮。前端代码处理错误的方式通常为提示用户有异常发生。若是错误不影响业务流程,则写入日志里并上报。
BadCode
function method(data) { try { return JSON.parse(data) } catch (e) {} }
GoodCode
function method(data) { try { return JSON.parse(data) } catch (e) { alert('数据处理失败') } }
说明:magic number 是指直接在代码中硬编码的数字,每每具备一些业务含义。
这样会致使:
BadCode
if (status === 1) { ... } else if (type === 4) { ... }
GoodCode
enum Status { Closed } enum Type { Array } if (status === Status.Closed) { ... } else if (type === Type.Array) { ... }
说明:原子性意味着独立,且不可分割。其它属性都由原子业务属性推导、计算而来,这样能保证状态的一致。
BadCode
// 当 status 为 open 的时候展现弹窗 // 其它状态则隐藏弹窗 { data() { return { showAlert: false, status: 'closed', } }, onStatusChange() { if (status === 'open') { this.showAlert = true; } else { this.showAlert = false; } } }
GoodCode
// showAlert 为非原子的状态 // 其状态能够由 status 推导而来 { data() { return { status: 'closed', } }, computed: { showAlert() { return this.status === 'open'; } } }
说明:
BadCode
// 在一个列表中,用户能够对数据作多选 // 而后删除他们 class extends React.Component { async componentDidMount() { const listData = getData(); this.setState({ listData }) } check = (item) => { const listData = this.state.listData.map(i => { if (i === item) { return {...item, checked: true} } return i; }); this.setState({ listData }); } delete() { // 返回给后端的数据结构,会多出一个 checked 字段 deleteItems(this.state.listData.filter(i => i.checked)); } render() { const list = this.state.listData.map(item => { const className = ['item']; if (item.checked) className.push('active'); return <label className={className} onClick={() => this.check(item)} >{item.naem}</label>; }); return <> {list} <button onClick={this.delete}>delete</button> </> } }
GoodCode
// 在一个列表中,用户能够对数据作多选 // 而后删除他们 class extends React.Component { async componentDidMount() { const listData = getData(); // 使用独立的 selected 来保存 UI 状态 this.setState({ listData, selected: [] }) } check = (item) => { let { selected } = this.state; selected = selected.findOrInsert(s => s.id, item); this.setState({ selected }); } delete() { const { selected, listData } = this.state; deleteItems(listData.filter(i => selected.includes(i.id)))); } render() { const { selected, listData } = this.state; const list = listData.map(item => { const className = ['item']; if (selected.includes(item.id)) className.push('active'); return <label className={className} onClick={() => this.check(item)} >{item.naem}</label>; }); return <> {list} <button onClick={this.delete}>delete</button> </> } }
说明:react 的 render 应该是纯函数,在 render 里运行 setState 会致使重复渲染,或者死循环。
BadCode
// 若是 type 为 http 的话,则自动转换为 https class extends React.Component { render() { const { type } = this.state; if (type === 'http') { this.setState({ type: 'https'}) } return <label>{type}</label>; } }
GoodCode
// 若是 type 为 http 的话,则自动转换为 https class extends React.Component { get type() { const { type } = this.state; if (type === 'http') return 'https'; return type; } render() { const type = this.type; return <label>{type}</label>; } }
说明:
BadCode
// foo 和 bar 互相依赖,致使了死循环 { data() { return { foo: 1, }; }, computed: { bar() { return this.foo + 1; } }, watch() { bar() { this.foo = this.bar + 1; }, } }
说明:好比用双等号作判断
BadCode
const foo = '0'; const bar = 0 // 作数据判断时不能用双等号 foo == bar // true foo ? 1 : 2 // 1 bar ? 1 : 2 // 2 // 仅经过变量有没有 length 来判断是否为数组 if(obj.length) { obj.forEach(...) }
GoodCode
const foo = '0'; const bar = 0 foo === bar // false if (Array.isArray(obj)) { obj.forEach(...) }
说明:这样作会致使数据的异常。若是须要作这种操做,最好使用数组函数,或者操做拷贝数据。
BadCode
const array = [1,2,3,4,5,6,7,8,9,10]; // 删除数组中的偶数 for (var i = 0; i < array.length; i++) { if (array[i] % 2 == 0) array.splice(i); } // array 变成了 [1]
GoodCode
const array = [1,2,3,4,5,6,7,8,9,10]; array.filter(a => !(a % 2))
说明:
大多数场景下,setTimeout 后面传递一个时间是为了先执行后续的 A 代码,再延后执行代码闭包里的 B 代码,如右边示例代码。
但若是随着业务迭代,A 被改为异步,或者执行时间很长的话。以前作的延迟执行的防护措施就时效了,也许反而 B 会比 A 先执行。
BadCode
// 代码的原本意图是让 B 延后执行 setTimeout(() => { B(); }, 1000); A(); // 代码的意图是让 render 在下一帧执行 // 可是不一样设备,一帧时间是不固定的 setTimeout(() => { render() }, 16);
GoodCode
// A 函数内要想办法使用 Promise 串接起来 await A(); b(); // 使用系统提供的 API 执行动画帧 requestAnimationFrame(() => { render(); });
说明:陈旧的 API 每每有不少问题,好比安全、性能、不易读等。
BadCode
// 判断是否为数组 Object.prototype.toString.call(array) === "[object Array]" // 查找数组里第一个偶数 for (var i = 0; i < array.length; i++) { if (array[i] % 2 === 0) return array[i]; } // 遍历对象的 key for (var key in obj) { console.log(key); } // 判断字符串/数组是否包含 'some text'.indexOf('some') >= 0 // 去除首位空格 ' some text '.replace(/(^\s+|\s+$)/g, '') // 新建对象/数组 const array = new Array(); const obj = new Object();
GoodCode
Array.isArray(array) array.find(a => a % 2 === 0); Object.keys(obj).forEach(console.log) 'some text'.includes('some') ' some text '.trim() const array = []; const obj = {};
说明:
React Ref 通常是用来处理和原生 DOM 交互的场景,好比 canvas。
大部分对于 React ref 的使用都是错误的,大多都拿来用来控制子元素。这种场景咱们更推荐用数据流(redux,mobx)或者用状态提高去作。
React 官方有对「状态提高」的描述 https://react.docschina.org/d...
BadCode
class List extends React.Component { async refresh() { this.setState({ items: getItems(), }); } render() { return this.state.items.map(i => <label>{i}</label>); } } class extends React.Component { onRefresh = () => { // 用 ref 去调用子元素的方法 this.list.refresh(); } render() { return <> <List ref={l => this.list = l}></List> <button onClick={this.onRefresh}/> </>; } }
GoodCode
class List extends React.Component { render() { return this.props.items.map(i => <label>{i}</label>); } } class extends React.Component { // 把数据状态提高到父组件作操做 refresh = async () => { this.setState({ items: getItems(), }); } render() { return <> <List items{this.state.items}></List> <button onClick={this.refresh}/> </>; } }
说明:
字符串拼接 url 须要处理 encode 或者 decode 的状况,还有对于 ?和 # 的判断不对的话,很容易形成漏洞或者 Bug。
目前浏览器和 Node 都已经提供了标准的 URL 解析方法。
https://developer.mozilla.org...
BadCode
// 这段代码既没有对 key、value 作 encode // 也没有考虑 url 中 # 出现的状况 const url = location.href; if (url.indexOf('?') >= 0) { return url + key + '=' + value; } else { return url + '?' + key + '=' + value; }
GoodCode
// 使用标准的 URL 解析,风险会下降不少 const url = new URL(urlStr); url.searchParams.set(key, value); return url.toString();
说明:
咱们应该指望 if 条件内是个「真」值,而不是一个「假」值。
第二种状况会致使代码不易理解。
解决办法参考 布尔逻辑
BadCode
// if 条件内指望的是一个「假」值 if (!(status !== Closed) { ... } if (!(status !== Closed || type !== Array)) { ...}
GoodCode
if (status === Closed) { ... } if (status === Closed && type === Array) { ... }
例外:if 条件里能够被 「且」(&&)逻辑拆分红多个子条件
说明:复杂的条件判断会让代码不易理解,逻辑上有漏洞的话容易引发 Bug。
解决办法:声明中间变量
BadCode
if (srcElem != dropElem && (srcElem.nextSibling || srcElem.nextElementSibling) != dropElem) {...} if (selectedItem || (selectedEmployee && selectedEmployee.empId && selectedEmployee) || employee) { ... }
GoodCode
const nextSibling = srcElem.nextSibling || srcElem.nextElementSibling if (srcElem != dropElem && nextSibling != dropElem ) { ... } // 复杂的逻辑判断能够经过 && 作拆分 if ( !Array.isArray(cur) && cur != null && typeof src[key] === 'object' && typeof cur === 'object' ) { ... }
说明:
人们阅读嵌套三元表达式时,容易混淆语法的优先级,进而致使理解错代码的含义。
对于这种状况,建议改为 if else。
若是是在 react render 里,则建议独立成函数。
BadCode
function render(props) { const value = props.value; return <> {value < 10 ? value > 0 ? value : 200 - value : 100 - value} </>; }
GoodCode
function getValue(value) { if (value < 10) { if (value > 0) return value; return 200 - value; } return 100 - value; } function render(props) { const value = props.value; return <> {getValue(value)} </>; }
说明:过深的嵌套会致使理解困难。
解决办法:合并判断条件,或者独立成函数。
BadCode
if (status = Opened) { if (type = 'array') { if (code = Success) { doSomething(); } } }
GoodCode
if (status = Opened && type = 'array' &&code = Success) { doSomething(); }