iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > html >如何封装代码
  • 908
分享到

如何封装代码

2024-04-02 19:04:59 908人浏览 独家记忆
摘要

本篇内容介绍了“如何封装代码”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!为什么要封装代码?我们经常听说:

本篇内容介绍了“如何封装代码”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

为什么要封装代码?

我们经常听说:“写代码要有良好的封装,要高内聚,低耦合”。那怎样才算良好的封装,我们为什么要封装呢?其实封装有这样几个好处:

  1.   封装好的代码,内部变量不会污染外部。

  2.   可以作为一个模块给外部调用。外部调用者不需要知道实现的细节,只需要按照约定的规范使用就行了。

  3.   对扩展开放,对修改关闭,即开闭原则。外部不能修改模块,既保证了模块内部的正确性,又可以留出扩展接口,使用灵活。

怎么封装代码?

js生态已经有很多模块了,有些模块封装得非常好,我们使用起来很方便,比如JqueryVue等。如果我们仔细去看这些模块的源码,我们会发现他们的封装都是有规律可循的。这些规律总结起来就是设计模式,用于代码封装的设计模式主要有工厂模式,创建者模式,单例模式,原型模式四种。下面我们结合一些框架源码来看看这四种设计模式:

工厂模式

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

function factory(type) {    switch(type) {      case 'type1':        return new Type1();      case 'type2':        return new Type2();      case 'type3':        return new Type3();    }  }

上述代码中,我们传入了type,然后工厂根据不同的type来创建不同的对象。

实例: 弹窗组件

下面来看看用工厂模式的例子,假如我们有如下需求:

我们项目需要一个弹窗,弹窗有几种:消息型弹窗,确认型弹窗,取消型弹窗,他们的颜色和内容可能是不一样的。

针对这几种弹窗,我们先来分别建一个类:

function infoPopup(content, color) {}  function confirmPopup(content, color) {}  function cancelPopup(content, color) {}

如果我们直接使用这几个类,就是这样的:

let infoPopup1 = new infoPopup(content, color);  let infoPopup2 = new infoPopup(content, color);  let confirmPopup1 = new confirmPopup(content, color);  ...

每次用的时候都要去new对应的弹窗类,我们用工厂模式改造下,就是这样:

// 新加一个方法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);    }  }

然后我们使用popup就不用new了,直接调用函数就行:

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) {}

封装成模块

这个popup不仅仅让我们调用的时候少了一个new,他其实还把相关的各种弹窗都封装在了里面,这个popup可以直接作为模块export出去给别人调用,也可以挂载在window上作为一个模块给别人调用。因为popup封装了弹窗的各种细节,即使以后popup内部改了,或者新增了弹窗类型,或者弹窗类的名字变了,只要保证对外的接口参数不变,对外面都没有影响。挂载在window上作为模块可以使用自执行函数:

(function(){       function popup(type, content, color) {      if(this instanceof popup) {        return new this[type](content, color);      } else {        return new popup(type, content, color);      }    }    popup.prototype.infoPopup = function(content, color) {}    popup.prototype.confirmPopup = function(content, color) {}    popup.prototype.cancelPopup = function(content, color) {}   window.popup = popup;  })()  // 外面就直接可以使用popup模块了  let infoPopup1 = popup('infoPopup', content, color);

jQuery的工厂模式

jQuery也是一个典型的工厂模式,你给他一个参数,他就给你返回符合参数DOM对象。那jQuery这种不用new的工厂模式是怎么实现的呢?其实就是jQuery内部帮你调用了new而已,jQuery的调用流程简化了就是这样:

(function(){    var jQuery = function(selector) {      return new jQuery.fn.init(selector);   // new一下init, init才是真正的构造函数    }    jQueryjQuery.fn = jQuery.prototype;     // jQuery.fn就是jQuery.prototype的简写    jQuery.fn.init = function(selector) {      // 这里面实现真正的构造函数    }    // 让init和jQuery的原型指向同一个对象,便于挂载实例方法    jQueryjQuery.fn.init.prototype = jQuery.fn;     // 最后将jQuery挂载到window上    window.$ = window.jQuery = jQuery;  })();

上述代码结构来自于jQuery源码,从中可以看出,你调用时省略的new在jQuery里面帮你调用了,目的是为了使大量调用更方便。但是这种结构需要借助一个init方法,最后还要将jQuery和init的原型绑在一起,其实还有一种更加简便的方法可以实现这个需求:

var jQuery = function(selector) {    if(!(this instanceof jQuery)) {      return new jQuery(selector);    }    // 下面进行真正构造函数的执行  }

上述代码就简洁多了,也可以实现不用new直接调用,这里利用的特性是this在函数被new调用时,指向的是new出来的对象,new出来的对象自然是类的instance,这里的this instanceof jQuery就是true。如果是普通调用,他就是false,我们就帮他new一下。

建造者模式

建造者模式是用于比较复杂的大对象的构建,比如Vue,Vue内部包含一个功能强大,逻辑复杂的对象,在构建的时候也需要传很多参数进去。像这种需要创建的情况不多,创建的对象本身又很复杂的时候就适用建造者模式。建造者模式的一般结构如下:

function Model1() {}   // 模块1  function Model2() {}   // 模块2  // 最终使用的类  function Final() {    this.model1 = new Model1();    this.model2 = new Model2();  }  // 使用时  var obj = new Final();

上述代码中我们最终使用的是Final,但是Final里面的结构比较复杂,有很多个子模块,Final就是将这些子模块组合起来完成功能,这种需要精细化构造的就适用于建造者模式。

实例:编辑器插件

假设我们有这样一个需求:

写一个编辑器插件,初始化的时候需要配置大量参数,而且内部的功能很多很复杂,可以改变字体颜色和大小,也可以前进后退。

一般一个页面就只有一个编辑器,而且里面的功能可能很复杂,可能需要调整颜色,字体等。也就是说这个插件内部可能还会调用其他类,然后将他们组合起来实现功能,这就适合建造者模式。我们来分析下做这样一个编辑器需要哪些模块:

  1.   编辑器本身肯定需要一个类,是给外部调用的接口

  2.   需要一个控制参数初始化和页面渲染的类

  3.   需要一个控制字体的类

  4.   需要一个状态管理的类 

// 编辑器本身,对外暴露  function Editor() {    // 编辑器里面就是将各个模块组合起来实现功能    this.initer = new htmlInit();    this.fontController = new FontController();    this.stateController = new StateController(this.fontController);  }  // 初始化参数,渲染页面  function HtmlInit() {  }  HtmlInit.prototype.initStyle = function() {}     // 初始化样式  HtmlInit.prototype.renderDom = function() {}     // 渲染DOM  // 字体控制器  function FontController() {  }  FontController.prototype.changeFontColor = function() {}    // 改变字体颜色  FontController.prototype.changeFontSize = function() {}     // 改变字体大小  // 状态控制器  function StateController(fontController) {    this.states = [];       // 一个数组,存储所有状态    this.currentState = 0;  // 一个指针,指向当前状态    this.fontController = fontController;    // 将字体管理器注入,便于改变状态的时候改变字体  }  StateController.prototype.saveState = function() {}     // 保存状态  StateController.prototype.backState = function() {}     // 后退状态  StateController.prototype.forwardState = function() {}     // 前进状态

上面的代码其实就将一个编辑器插件的架子搭起来了,具体实现功能就是往这些方法里面填入具体的内容就行了,其实就是各个模块的相互调用,比如我们要实现后退状态的功能就可以这样写:

StateController.prototype.backState = function() {    var state = this.states[this.currentState - 1];  // 取出上一个状态    this.fontController.changeFontColor(state.color);  // 改回上次颜色    this.fontController.changeFontSize(state.size);    // 改回上次大小  }

单例模式

单例模式适用于全局只能有一个实例对象的场景,单例模式的一般结构如下:

function Singleton() {}  Singleton.getInstance = function() {    if(this.instance) {      return this.instance;    }    this.instance = new Singleton();    return this.instance;  }

上述代码中,Singleton类挂载了一个静态方法getInstance,如果要获取实例对象只能通过这个方法拿,这个方法会检测是不是有现存的实例对象,如果有就返回,没有就新建一个。

实例:全局数据存储对象

假如我们现在有这样一个需求:

我们需要对一个全局的数据对象进行管理,这个对象只能有一个,如果有多个会导致数据不同步。

这个需求要求全局只有一个数据存储对象,是典型的适合单例模式的场景,我们可以直接套用上面的代码模板,但是上面的代码模板获取instance必须要调getInstance才行,要是某个使用者直接调了Singleton()或者new Singleton()就会出问题,这次我们换一种写法,让他能够兼容Singleton()和new Singleton(),使用起来更加傻瓜化:

function store() {    if(store.instance) {      return store.instance;    }    store.instance = this;  }

上述代码支持使用new store()的方式调用,我们使用了一个静态变量instance来记录是否有进行过实例化,如果实例化了就返回这个实例,如果没有实例化说明是第一次调用,那就把this赋给这个这个静态变量,因为是使用new调用,这时候的this指向的就是实例化出来的对象,并且最后会隐式的返回this。

如果我们还想支持store()直接调用,我们可以用前面工厂模式用过的方法,检测this是不是当前类的实例,如果不是就帮他用new调用就行了:

function store() {    // 加一个instanceof检测    if(!(this instanceof store)) {      return new store();    }     // 下面跟前面一样的    if(store.instance) {      return store.instance;    }    store.instance = this;  }

然后我们用两种方式调用来检测下:

如何封装代码

实例:vue-router

vue-router其实也用到了单例模式,因为如果一个页面有多个路由对象,可能造成状态的冲突,vue-router的单例实现方式又有点不一样,下列代码来自vue-router源码:

let _Vue;  function install(Vue) {    if (install.installed && _Vue === Vue) return;    install.installed = true    _Vue = Vue  }

每次我们调用vue.use(vueRouter)的时候其实都会去执行vue-router模块的install方法,如果用户不小心多次调用了vue.use(vueRouter)就会造成install的多次执行,从而产生不对的结果。vue-router的install在第一次执行时,将installed属性写成了true,并且记录了当前的Vue,这样后面在同一个Vue里面再次执行install就会直接return了,这也是一种单例模式。

可以看到我们这里三种代码都是单例模式,他们虽然形式不一样,但是核心思想都是一样的,都是用一个变量来标记代码是否已经执行过了,如果执行过了就返回上次的执行结果,这样就保证了多次调用也会拿到一样的结果。

原型模式

原型模式最典型的应用就是JS本身啊,JS的原型链就是原型模式。JS中可以使用Object.create指定一个对象作为原型来创建对象:

const obj = {    x: 1,    func: () => {}  }  // 以obj为原型创建一个新对象  const newObj = Object.create(obj);  console.log(newObj.__proto__ === obj);    // true  console.log(newObj.x);    // 1

上述代码我们将obj作为原型,然后用Object.create创建的新对象都会拥有这个对象上的属性和方法,这其实就算是一种原型模式。还有JS的面向对象其实更加是这种模式的体现,比如JS的继承可以这样写:

function Parent() {    this.parentAge = 50;  }  function Child() {}  Child.prototype = new Parent();  ChildChild.prototype.constructor = Child;      // 注意重置constructor  const obj = new Child();  console.log(obj.parentAge);    // 50

这里的继承其实就是让子类Child.prototype.__proto__的指向父类的prototype,从而获取父类的方法和属性。

“如何封装代码”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

--结束END--

本文标题: 如何封装代码

本文链接: https://www.lsjlt.com/news/84701.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何封装代码
    本篇内容介绍了“如何封装代码”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!为什么要封装代码?我们经常听说:...
    99+
    2024-04-02
  • vue如何封装swiper代码
    这篇文章将为大家详细讲解有关vue如何封装swiper代码,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。data(){     r...
    99+
    2024-04-02
  • 怎么封装Python代码包
    这篇文章主要介绍“怎么封装Python代码包”,在日常操作中,相信很多人在怎么封装Python代码包问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么封装Python代码包”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-16
  • python封装实例代码分析
    这篇“python封装实例代码分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“pytho...
    99+
    2024-04-02
  • RecyclerView上拉加载封装代码
    RecyclerView上拉加载,先看效果:网上有很多这类得框架,不过在自己的项目只用到上拉加载的功能,所以自己封装一个简单点的。主要依赖BaseRecyPRAdapter这类public abstract class BaseRecyPR...
    99+
    2023-05-30
    recyclerview 上拉加载 recycle
  • PHP如何实现记录代码运行时间封装类
    这篇文章给大家分享的是有关PHP如何实现记录代码运行时间封装类的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。示例代码class TimeCost {  pr...
    99+
    2024-04-02
  • java封装类是如何封装的
    在Java中,封装是一种面向对象编程的概念,用于隐藏内部实现细节,并通过公共方法提供对数据的访问和操作。封装类是为了封装基本数据类型...
    99+
    2023-10-23
    java
  • java语言中封装类代码示例
    在面向对象程序设计方法中,封装(Encapsulation)是指一种将抽象性函式接口的实现细节部分包装‘隐藏起来的方法。数据被保护在内部,隐藏内部实现细节,对外提供接口与外部交互。使用封装的步骤将类的所有属性使用关键字private去修饰,...
    99+
    2023-05-30
  • 详解spring封装hbase的代码实现
    前面我们讲了spring封装MongoDB的代码实现,这里我们讲一下spring封装Hbase的代码实现。hbase的简介:此处大概说一下,不是我们要讨论的重点。HBase是一个分布式的、面向列的开源数据库,HBase在Hadoop之上提供...
    99+
    2023-05-31
    spring hbase sprin
  • golang如何封装
    在Go语言中,封装指的是把数据和操作数据的方法绑定在一起,形成一个独立的单元,从而避免外部使用者直接访问数据,保证数据安全和操作的有效性。本文将介绍如何在Go语言中实现封装。可见性控制在Go语言中,可见性控制通过命名来实现。如果一个变量或者...
    99+
    2023-05-19
  • 如何封装ajax
    小编给大家分享一下如何封装ajax,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧! 以前开发用了很多AJAX的技术比如EXT,prototype,jQuery等...
    99+
    2024-04-02
  • vue3项目中封装axios的示例代码
    目录axios的基本使用axios.all()方法axios一些基本配置axios的拦截器封装axios-封装基础属性封装拦截器封装公用的拦截器对单个请求传入拦截器对request请...
    99+
    2022-12-19
    vue3封装axios vue3项目中封装axios vue封装axios
  • PHP中封装性的代码审查策略
    引言:在软件开发领域,代码审查是一种常见的实践,旨在提高代码质量和开发团队的效率。封装性是面向对象编程的重要原则之一,它能够有效地隐藏对象的内部实现细节并提供公共接口,从而降低系统的耦合度。本文将介绍一些在PHP中实施封装性代码审查的策略,...
    99+
    2023-10-21
    PHP 代码审查(Code Review) 封装性(Encapsulation)
  • Python封装zabbix-get接口的代码分享
    Zabbix 是一款强大的开源网管监控工具,该工具的客户端与服务端是分开的,我们可以直接使用自带的zabbix_get命令来实现拉取客户端上的各种数据,在本地组装参数并使用Popen...
    99+
    2024-04-02
  • SpringBoot如何封装JDBC
    这篇文章主要为大家展示了“SpringBoot如何封装JDBC”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“SpringBoot如何封装JDBC”这篇文章吧。Spring Boot中可以在配置文...
    99+
    2023-06-22
  • ts如何封装axios
    本篇内容主要讲解“ts如何封装axios”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“ts如何封装axios”吧!什么样封装才是最合理的别再用 promise 包了,好吗?看了一下,很多人封装 ...
    99+
    2023-07-05
  • php如何封装app
    小编给大家分享一下php如何封装app,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!php封装app的方法:1、创建json.php文件和demo.php文件;2...
    99+
    2023-06-21
  • PHP如何封装pdo
    这篇文章主要介绍了PHP如何封装pdo,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、前言最近需要写脚本来实现崩溃日志的入库,不出所料又是脱离于框架的,那么行吧,咱们只能自...
    99+
    2023-06-22
  • python如何封装token
    这篇文章主要介绍了python如何封装token的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇python如何封装token文章都会有所收获,下面我们一起来看看吧。python 封装tokenimport&nb...
    99+
    2023-07-04
  • Vue封装如何axios
    这篇文章主要介绍“Vue封装如何axios”,在日常操作中,相信很多人在Vue封装如何axios问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Vue封装如何axios”的疑惑有所帮助!接下来,请跟着小编一起来...
    99+
    2023-07-05
软考高级职称资格查询
推荐阅读
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作