上图是我阅读书籍——代码整洁之道,绘制的思维导图。写本篇博客的目的是为了加强记忆,其中关于类模块没有总结,是因为最近在研究设计模式,有一定基础后,写一篇设计模式的学习笔记,其中会包括关于写类需要注意的整洁。
一,命名
采用描述性名称
bad
//获取当前时间
let yyddss = new Date();
good
let curDate = new Date();
说明副作用
bad
function getOss(){
if(!oss){
return new Oss();
}
return oss;
}
good
function createOrReturnOss(){
if(!oss){
return new Oss();
}
return oss;
}
oss
不存在则创建,否则返回oss
。名称createOrReturnOss
恰当表述清楚。
避免编码
bad
class Person{
p_name = '整洁';
p_age = '20';
//...
}
good
class Person{
name = '整洁';
age = '20';
//...
}
m_,f_
之类的前缀没有意义
统一的命名规则
构造函数使用大驼峰命名
bad
function user(){
//...
}
let u = new user();
good
function User(){
//...
}
let user = new User();
变量,函数使用小驼峰或下划线分隔
bad
let myname = '整洁';
function getname(){
//...
}
good
let my_name = '整洁';
//或
let myName = '整洁';
function getName(){
//...
}
//或
function get_name(){
//...
}
清除魔法字符,数字
不要有硬代码,字符串,数字使用变量进行命名
bad
setTimeout(()=>{
//...
},200);
good
const WAIT_TIME = 200;
setTimeout(()=>{
//...
}, WAIT_TIME)
二,注释
不在代码中保存注释掉的代码
有git版本控制,不需要担心代码丢失,需要时查看历史记录找回即可
bad
getName();
//getAge();
//getWifeName();
good
getName();
减少注释
好的代码就是文档,需要写注释前优先考虑重构代码。将精力花写出整洁有表达力的代码,而不是写大量的注释
bad
//data是否含有id
function isIdIncludeData(data,id){
//数组长度
let len = data.length;
//循环数组
for(let i = 0;i<len;i++){
//如果存在则返回true
if(id === data[i]){
return true;
}
}
//不存在则返回false
return false;
}
good
//data是否含有id
function isIdIncludeData(data,id){
let len = data.length;
for(let i = 0;i<len;i++){
if(id === data[i]){
return true;
}
}
return false;
}
三,函数
参数越少越好
参数增多,参数组合传入就越多,不利用于测试,而且参数越多说明该函数做的不只一件事情。不可避免时可以使用一个对象包裹传入
bad
function createPerson (name,age,sex){
//...
}
good
let personInfo = {
name:'js',
age:20,
sex:'men'
}
function createPerson (personInfo){
//...
}
一个函数只做一件事
bad
function isAdmin(admin){
let isInAdmins = admins.includes(admin);
if(isAdmin){
arrs.forEach(arr=>{
//...
})
return true;
}
datas.forEach(data=>{
//...
})
return false;
}
good
function arrsEach(){
arrs.forEach(arr=>{
//...
})
}
function datasEach(){
datas.forEach(data=>{
//...
})
}
function isAdmin(admin){
return admins.includes(admin);
}
function arrsOrDatasEach(){
isAdmin()? arrsEach():datasEach();
}
删除死函数
删除代码中不调用的函数,需要时历史记录中找回
bad
function getName(){
//...
}
function getAge(){
//...
}
getName();
good
function getName(){
//...
}
getName();
分离try...catch...
try...catch...
中的代码使用函数包裹,分离出来。
bad
function haveError(){
try{
datas.forEach(data=>{
//....
})
}catch(e){
//...
}
}
good
function haveError(){
try{
datasEach();
}catch(e){
//...
}
}
function datasEach(){
datas.forEach(data=>{
//....
})
}
不重复
类似功能抽离公共代码
bad
function arrsEach(){
arrs.forEach(arr=>{
//...
})
}
function datasEach(){
datas.forEach(data=>{
//...
})
}
function isAdmin(admin){
return admins.includes(admin);
}
function arrsOrDatasEach(){
isAdmin()? arrsEach():datasEach();
}
good
function each(params){
params.forEach(param=>{
//...
})
}
function isAdmin(admin){
return admins.includes(admin);
}
function arrsOrDatasEach(){
isAdmin()? each(arrs):each(datas);
}
减少if...else...
或switch...case...
嵌套链
bad
function getType(data){
let type = typeof data,
stringType = 'string',
numberType = 'number',
//...;
if(type === stringType){
Number(data);
}else if(type===numberType){
String(data);
}
//...
}
good
let typeMaps = new Map([
['string',data=>{
Number(data);
}],
['number',data=>{
String(data);
}]]);
function getType(data){
let type = typeof data;
typeMaps.has(type)&&typeMaps.get(type)();
}
判断条件
封装判断条件
bad
if(isHavePerson()&&isAdmin()){
//...
}
good
if(isPoss()){
//...
}
避免否定性条件
bad
function isHavePerson(){
//...
}
if(!isHavePerson()){
//...
}
good
function isHavePerson(){
//...
}
if(isHavePerson()){
//...
}
封闭边界条件
bad
if(num+1>2){
//...
}
good
let one = 1,
two = 2,
sum = num + one,
isBigger = sum > two;
if(isBiggeer){
//...
}
四,对象和数据结构
使用getters,setters
javaScipt没有接口或类型,也没有public
和private
关键字。
使用原因:
- 获取一个对象属性在背后做更多的事情,不需要在代码库中查找修改每一处访问;
set
方便添加已验证;- 封装内部实现;
- 使用
getting,setter
时,容易添加日志和错误处理 - 延迟加载对象属性,从服务器获取值然后在赋值给对象属性
bad
class Person{
constructor(age = 20){
this.age = age;
}
}
const person = new Person ();
person.age = 120;
console.log(person.age);
good
class Person {
constructor(age = 20){
this._age = age;
}
set age(val){
//年龄大于100或小0,为不合理
let isErrorAge = val>100||val<0;
isErrorAge ? null:this._age = val;
}
get age(){
return this._age;
}
}
const person = new Person ();
person.age = 120;
console.log(person.age);
私有成员
利用ES5闭包实现
bad
function Person(name){
this.name = name;
}
Person.prototype.getName = function (){
return this.name;
}
const person = new Person ('hai');
person.getName();//hai
delete person.name;
person.getName();//undefind
good
function Person(name){
this.getName = function (){
return name;
}
}
const person = new Person ('hai');
person.getName();//hai
delete person.name;
person.getName();//hai
//或es6 class
class Person {
//私有成员 ES2020新添加语法,#前缀声明私有成员
#age;
constructor(age = 20) {
this.#age = age;
}
setAge(age){
this.#age = age;
}
getAge() {
return this.#age;
}
}
参考jquery链式调用思想
jquery中讲究链式调用,链式调用使用代码更加简洁,减少逻辑。每个方法最后均返回this
bad
class Person {
constructor(){
this.name = 'hai';
this.age = 20;
this.sex = 'man';
}
setName(name){
this.name = name;
}
setAge(age){
this.age = age;
}
setSex (sex){
this.sex = sex;
}
}
const person =new Person();
person.setName('java');
person.setAge(25);
person.setSex('wemen');
good
class Person{
constructor(){
this.name = 'hai';
this.age = 20;
this.sex = 'man';
}
setName(name){
this.name = name;
return this;
}
setAge(age){
this.age = age;
return this;
}
setSex (sex){
this.sex = sex;
return this;
}
}
const person = new Person();
person.setName('java')
.setAge(25)
.setSex('wemen');
五,代码美化
注意代码格式,当然我们要借助工具,自动格式化代码。
函数调用方与被调用方应该靠近
人习惯性地从上往下进行阅读。由于这个原因,代码应该按从上往下让人阅读
bad
class Person {
name = 'javaScipt';
age = 20;
wife = "java";
setAge(age) {
this.age = age;
}
getAge() {
return this.age;
}
getWife() {
return this.wife;
}
setWife(name) {
this.wife = name;
}
getSelfInfo() {
return `名字:${this.getName()},年龄:${this.getAge()},女朋友:${this.getWife()}`
}
setName(name) {
this.name = name;
}
getName() {
return this.name;
}
}
const person = new Person();
console.log(person.getSelfInfo());
good
class Person {
name = 'javaScipt';
age = 20;
wife = "java";
setName(name) {
this.name = name;
}
getName() {
return this.name;
}
setAge(age) {
this.age = age;
}
getAge() {
return this.age;
}
setWife(name) {
this.wife = name;
}
getWife() {
return this.wife;
}
getSelfInfo() {
return `名字:${this.getName()},年龄:${this.getAge()},女朋友:${this.getWife()}`
}
}
const person = new Person();
console.log(person.getSelfInfo());