美文网首页
高质量前端代码是怎样写的?

高质量前端代码是怎样写的?

作者: 阿克兰 | 来源:发表于2022-07-29 18:08 被阅读0次

过长的if else-if

//优化前
howManyDays(year, month){
    if(month === 1 ||
        month === 3 ||
        month === 5 ||
        month === 7 ||
        month === 8 ||
        month === 10 ||
        month === 12
    ){
        return 31
    }else if(month === 2){
        return isLeapYear(year) ? 29 : 28
    }else{
        return 30
    }
}
//优化后
howManyDays(year, month){
    const table = {
        1: 31, 3: 31, 5: 31, 7: 31, 8: 31, 10: 31, 12:31,
        4: 30, 6:30, 9: 30, 11: 30,
        2: isLeapYear(year) ? 29 : 28
    }
    return table[month]
}
//优化前
function calculateGrade(score){
    if(score>=90){
        return 'A'
    }else if(score >= 80){
        return 'B'
    }else if(score >= 70){
        return 'C'
    }else if(score >= 60){
        return 'D'
    }else {
        return 'E'
    }
}
//优化后
function calculateGrade(score){
    const table = {
        100: 'A', 
        90: 'A',
        80: 'B',
        70: 'C',
        60: 'D',
        others: 'E'
    }
    return table[Math.floor(score/10)*10] || table['others']
}    



策略/状态模式

策略模式基本结构:减少了if…else的数量,提升了代码的可读性,通过传入一个状态来选取具体的策略
假如我们需要做一个计算器,需要支持加减乘除,为了判断用户具体需要进行哪个操作,我们需要4个if…else来进行判断,如果支持更多操作,那if…else会更长,不利于阅读,看着也不优雅。所以我们可以用策略模式优化如下:

function calculator(type, a, b) {
  const strategy = {
    add: function(a, b) {
      return a + b;
    },
    minus: function(a, b) {
      return a - b;
    },
    division: function(a, b) {
      return a / b;
    },
    times: function(a, b) {
      return a * b;
    }
  }
  
  return strategy[type](a, b);
}

// 使用时
calculator('add', 1, 1);


状态模式基本架构

function stateFactor(state) {
  const stateObj = {
    status: '',
    state: {
      state1: function(){},
      state2: function(){},
    },
    run: function() {
      return this.state[this.status];
    }
  }
  
  stateObj.status = state;
  return stateObj;
}

// 使用时
stateFactor('state1').run();

外观模式(常用)

外观模式基本结构:将一个个小模块封装成更高级的接口内部,传给外部一个简单的接口
当我们设计一个模块时,里面的方法可以会设计得比较细,但是暴露给外面使用的时候,不一定非得直接暴露这些细小的接口,外部使用者需要的可能是组合部分接口来实现某个功能,我们暴露的时候其实就可以将这个组织好。

function model1() {}

function model2() {}

// 可以提供一个更高阶的接口,组合好了model1和model2给外部使用
function use() {
  model2(model1());
}

实例:常见的接口封装
外观模式说起来其实非常常见,很多模块内部都很复杂,但是对外的接口可能都是一两个,我们无需知道复杂的内部细节,只需要调用统一的高级接口就行,比如下面的选项卡模块:

// 一个选项卡类,他内部可能有多个子模块
function Tab() {}

Tab.prototype.renderHTML = function() {}    // 渲染页面的子模块
Tab.prototype.bindEvent = function() {}    // 绑定事件的子模块
Tab.prototype.loadCss = function() {}    // 加载样式的子模块

// 对外不需要暴露上面那些具体的子模块,只需要一个高级接口就行
Tab.prototype.init = function(config) {
  this.loadCss();
  this.renderHTML();
  this.bindEvent();
}

迭代器模式

迭代器模式基本结构:*当后端传来大量结构相似的数据时,js的数组并不能很好的处理这些数据时,我们可以自己按照需求封装迭代器功能
迭代器模式模式在JS里面很常见了,数组自带的forEach就是迭代器模式的一个应用,我们也可以实现一个类似的功能:

function Iterator(items) {
  this.items = items;
}

Iterator.prototype.dealEach = function(fn) {
  for(let i = 0; i < this.items.length; i++) {
    fn(this.items[i], i);
  }
}

备忘录模式

备忘录模式基本结构:**加一个缓存对象,来记录之前获取过的数据或者操作的状态,后面可以用来加快访问速度或者进行状态回滚
备忘录模式类似于JS经常使用的缓存函数,内部记录一个状态,也就是缓存,当我们再次访问的时候可以直接拿缓存数据,可以用其实现操作的前进后退功能:

function memo() {
  const cache = {};
  
  return function(arg) {
    if(cache[arg]) {
      return cache[arg];
    } else {
      // 没缓存的时候先执行方法,得到结果res
      // 然后将res写入缓存
      cache[arg] = res;
      return res;
    }
}

桥接模式

桥接模式人如其名,其实就相当于一个桥梁,把不同维度的变量桥接在一起来实现功能。假设我们需要实现三种形状(长方形,圆形,三角形),每种形状有三种颜色(红色,绿色,蓝色),这个需求有两个方案,一个方案写九个方法,每个方法实现一个图形:

function redRectangle() {}
function greenRectangle() {}
function blueRectangle() {}
function redCircle() {}
function greenCircle() {}
function blueCircle() {}
function redTriangle() {}
function greenTriangle() {}
function blueTriangle() {}


使用桥接模式后,我们可以观察重复代码拆成多个维度,再将这些维度拼接起来
function rectangle(color) {     // 长方形
  showColor(color);
}

function circle(color) {     // 圆形
  showColor(color);
}

function triangle(color) {   // 三角形
  showColor(color);
}

function showColor(color) {   // 显示颜色的方法
  
}

// 使用时,需要一个红色的圆形
let obj = new circle('red');

享元模式

当我们观察到代码中有大量相似的代码块,他们做的事情可能都是一样的,只是每次应用的对象不一样,我们就可以考虑用享元模式。现在假设我们有一个需求是显示多个弹窗,每个弹窗的文字和大小不同:

// 已经有一个弹窗类了
function Popup() {}

// 弹窗类有一个显示的方法
Popup.prototype.show = function() {}

如果我们不用享元模式,一个一个弹就是这样:
var popup1 = new Popup();
popup1.show();

var popup2 = new Popup();
popup2.show();

使用享元模式后:
var popupArr = [
  {text: 'popup 1', width: 200, height: 400},
  {text: 'popup 2', width: 300, height: 300},
]

var popup = new Popup();
for(var i = 0; i < popupArr.length; i++) {
  popup.show(popupArr[i]);    // 注意show方法需要接收参数
}

模板方法模式

模板方法模式其实类似于继承,就是我们先定义一个通用的模板骨架,然后后面在这个基础上继续扩展。我们通过一个需求来看下他的基本结构,假设我们现在需要实现一个导航组件,但是这个导航类型还比较多,有的带消息提示,有的是横着的,有的是竖着的,而且后面还可能会新增类型:

// 先建一个基础的类
function baseNav() {
}

baseNav.prototype.action = function(callback){}  //接收一个回调进行特异性处理


实例:弹窗

还是之前用过的弹窗例子,我们要做一个大小文字可能不同的弹窗组件,只是这次我们的弹窗还有取消和确定两个按钮,这两个按钮在不同场景下可能有不同的行为,比如发起请求什么的。但是他们也有一个共同的操作,就是点击这两个按钮后弹窗都会消失,这样我们就可以把共同的部分先写出来,作为一个模板:

function basePopup(word, size) {
  this.word = word;
  this.size = size;
  this.dom = null;
}

basePopup.prototype.init = function() {
  // 初始化DOM元素
  var div = document.createElement('div');
  div.innerHTML = this.word;
  div.style.width = this.size.width;
  div.style.height = this.size.height;
  
  this.dom = div;
}

// 取消的方法
basePopup.prototype.cancel = function() {
  this.dom.style.display = 'none';
}

// 确认的方法
basePopup.prototype.confirm = function() {
  this.dom.style.display = 'none';
}

工厂模式

**封装的模块就像一个工厂一样批量的产出需要的对象。常见工厂模式的一个特征就是调用的时候不需要使用new,而且传入的参数比较简单。但是调用次数可能比较频繁,经常需要产出不同的对象,频繁调用时不用new也方便很多。一个工厂模式的代码结构如下所示:

function factory(type) {
  switch(type) {
    case 'type1':
      return new Type1();
    case 'type2':
      return new Type2();
    case 'type3':
      return new Type3();
  }
}
// 我们传入了type,然后工厂根据不同的type来创建不同的对象
实例: 弹窗组件
我们项目需要一个弹窗,弹窗有几种:消息型弹窗,确认型弹窗,取消型弹窗,他们的颜色和内容可能是不一样的,工厂模式改造:
 // 新加一个方法popup把这几个类都包装起来
function popup(type, content, color) {
  switch(type) {
    case 'infoPopup':
      return new infoPopup(content, color);
    case 'confirmPopup':
      return new confirmPopup(content, color);
    case 'cancelPopup':
      return new cancelPopup(content, color);
  }
}
// 调用方法
let infoPopup1 = popup('infoPopup', content, color); 
改造成面向对象
上述代码虽然实现了工厂模式,但是switch始终感觉不是很优雅。我们使用面向对象改造下popup,将它改为一个类,将不同类型的弹窗挂载在这个类上成为工厂方法:
function popup(type, content, color) {
  // 如果是通过new调用的,返回对应类型的弹窗
  if(this instanceof popup) {
    return new this[type](content, color);
  } else {
    // 如果不是new调用的,使用new调用,会走到上面那行代码
    return new popup(type, content, color);
  }
}

// 各种类型的弹窗全部挂载在原型上成为实例方法
popup.prototype.infoPopup = function(content, color) {}
popup.prototype.confirmPopup = function(content, color) {}
popup.prototype.cancelPopup = function(content, color) {}

参考链接https://blog.csdn.net/m0_52009348/article/details/122395937

相关文章

  • 高质量前端代码是怎样写的?

    过长的if else-if 策略/状态模式 策略模式基本结构:减少了if…else的数量,提升了代码的可读性,通过...

  • 前端开发规范

    前端代码规范 Front Standard Guide 前端 JS 项目开发规范 规范的目的是为了编写高质量的代码...

  • 学贵有疑——卓跃师生茶话会

    怎样写出高质量的代码? 有什么好的学习方法学起来效率会更高?如何保持对代码的兴趣? 进入二阶段,感觉自己没有一阶段...

  • 编写高质量前端代码

    ### 高质量的HTML代码 1. 做到标签的语义化,不过度使用div而忽略一些其他的具有语义化的标签,例如标题就...

  • 一稿设计,多端适配优雅的解决方案 - rem

    规范目的 为提高前端团队开发效率,输出高质量的前端页面代码,提高UI设计还原度,特编写该规范文档。本文档如有不对或...

  • 前端开发规范(通用)

    前端开发规范—通用 规范的目的是为了编写高质量的代码,提升协作效率,降低沟通成本。 一、编程规约 (一)命名规范 ...

  • 怎样写出好代码

    怎样写出好代码 【指南】如何写出好代码 代码就是设计(Jack W.Reeves, 1992) 代码是最有价值的交...

  • 搜索框模糊查询

    前端html代码 前端js代码 前端css代码 后端php返回json

  • 2019-04-28

    前端 生成工程代码时选择的前端组件是Angular,所以前端资源会按如下流程生成:a, 生成工程代码或者实体代码的...

  • 编写高质量的代码-web前端开发

    开发须知 1.增加代码可读性 添加必要的注释 请考虑维护者的心情2.注重项目前期构思 构建好框架在动手写代码 避免...

网友评论

      本文标题:高质量前端代码是怎样写的?

      本文链接:https://www.haomeiwen.com/subject/nduqwrtx.html