提升代码复用性:探讨Mixin类在面向对象语言中的独特作用和优势

  

 🎬 江城开朗的豌豆:个人主页

 🔥 个人专栏 :《 VUE 》 《 javaScript 》

 📝 个人网站 :《 江城开朗的豌豆🫛 》 

⛺️ 生活的理想,就是为了理想的生活 !

在这里插入图片描述

目录

 ⭐  专栏简介

 📘  文章引言

一、mixin是什么

Vue中的mixin

局部混入

全局混入

注意事项:

二、使用场景

三、源码分析

替换型

合并型

队列性

叠加型

小结:

⭐  写在最后


 ⭐  专栏简介

        欢迎来到前端入门之旅!这个专栏是为那些对Web开发感兴趣、刚刚开始学习前端的读者们打造的。无论你是初学者还是有一些基础的开发者,我们都会在这里为你提供一个系统而又亲切的学习平台。我们以问答形式更新,为大家呈现精选的前端知识点和最佳实践。通过深入浅出的解释概念,并提供实际案例和练习,让你逐步建立起一个扎实的基础。无论是HTML、CSS、JavaScript还是最新的前端框架和工具,我们都将为你提供丰富的内容和实用技巧,帮助你更好地理解并运用前端开发中的各种技术。

        同时,我们也会关注最新的前端趋势和发展动态。随着Web技术的不断演进,前端开发也在不断推陈出新。我们会及时介绍最新的前端框架、工具和技术,使你能够站在前沿,与时俱进。通过掌握最新的前端技术,你将能够在竞争激烈的Web开发领域中有更大的竞争力。

 📘  文章引言

一、mixin是什么

Mixin是面向对象程序设计语言中的类,提供了方法的实现。其他类可以访问mixin类的方法而不必成为其子类

Mixin类通常作为功能模块使用,在需要该功能时“混入”,有利于代码复用又避免了多继承的复杂

Vue中的mixin

先来看一下官方定义

mixin(混入),提供了一种非常灵活的方式,来分发 Vue 组件中的可复用功能。

本质其实就是一个js对象,它可以包含我们组件中任意功能选项,如datacomponentsmethods createdcomputed等等

我们只要将共用的功能以对象的方式传入 mixins选项中,当组件使用 mixins对象时所有mixins对象的选项都将被混入该组件本身的选项中来

Vue中我们可以局部混入全局混入

局部混入

定义一个mixin对象,有组件optionsdatamethods属性

var myMixin = {
  created: function () {
    this.hello()
  },
  methods: {
    hello: function () {
      console.log('hello from mixin!')
    }
  }
}

组件通过mixins属性调用mixin对象

Vue.component('componentA',{
  mixins: [myMixin]
})

该组件在使用的时候,混合了mixin里面的方法,在自动执行create生命钩子,执行hello方法

全局混入

通过Vue.mixin()进行全局的混入

Vue.mixin({
  created: function () {
      console.log("全局混入")
    }
})

使用全局混入需要特别注意,因为它会影响到每一个组件实例(包括第三方组件)

PS:全局混入常用于插件的编写

注意事项:

当组件存在与mixin对象相同的选项的时候,进行递归合并的时候组件的选项会覆盖mixin的选项

但是如果相同选项为生命周期钩子的时候,会合并成一个数组,先执行mixin的钩子,再执行组件的钩子

二、使用场景

在日常的开发中,我们经常会遇到在不同的组件中经常会需要用到一些相同或者相似的代码,这些代码的功能相对独立

这时,可以通过Vuemixin功能将相同或者相似的代码提出来

举个例子

定义一个modal弹窗组件,内部通过isShowing来控制显示

const Modal = {
  template: '#modal',
  data() {
    return {
      isShowing: false
    }
  },
  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  }
}

定义一个tooltip提示框,内部通过isShowing来控制显示

const Tooltip = {
  template: '#tooltip',
  data() {
    return {
      isShowing: false
    }
  },
  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  }
}

通过观察上面两个组件,发现两者的逻辑是相同,代码控制显示也是相同的,这时候mixin就派上用场了

首先抽出共同代码,编写一个mixin

const toggle = {
  data() {
    return {
      isShowing: false
    }
  },
  methods: {
    toggleShow() {
      this.isShowing = !this.isShowing;
    }
  }
}

两个组件在使用上,只需要引入mixin

const Modal = {
  template: '#modal',
  mixins: [toggle]
};
 
const Tooltip = {
  template: '#tooltip',
  mixins: [toggle]
}

通过上面小小的例子,让我们知道了Mixin对于封装一些可复用的功能如此有趣、方便、实用

三、源码分析

首先从Vue.mixin入手

源码位置:/src/core/global-api/mixin.js

export function initMixin (Vue: GlobalAPI) {
  Vue.mixin = function (mixin: Object) {
    this.options = mergeOptions(this.options, mixin)
    return this
  }
}

主要是调用merOptions方法

export function mergeOptions (
  parent: Object,
  child: Object,
  vm?: Component
): Object {

if (child.mixins) { // 判断有没有mixin 也就是mixin里面挂mixin的情况 有的话递归进行合并
    for (let i = 0, l = child.mixins.length; i < l; i++) {
    parent = mergeOptions(parent, child.mixins[i], vm)
    }
}

  const options = {} 
  let key
  for (key in parent) {
    mergeField(key) // 先遍历parent的key 调对应的strats[XXX]方法进行合并
  }
  for (key in child) {
    if (!hasOwn(parent, key)) { // 如果parent已经处理过某个key 就不处理了
      mergeField(key) // 处理child中的key 也就parent中没有处理过的key
    }
  }
  function mergeField (key) {
    const strat = strats[key] || defaultStrat
    options[key] = strat(parent[key], child[key], vm, key) // 根据不同类型的options调用strats中不同的方法进行合并
  }
  return options
}

从上面的源码,我们得到以下几点:

  • 优先递归处理 mixins
  • 先遍历合并parent 中的key,调用mergeField方法进行合并,然后保存在变量options
  • 再遍历 child,合并补上 parent 中没有的key,调用mergeField方法进行合并,保存在变量options
  • 通过 mergeField 函数进行了合并

下面是关于Vue的几种类型的合并策略

  • 替换型
  • 合并型
  • 队列型
  • 叠加型

替换型

替换型合并有propsmethodsinjectcomputed

strats.props =
strats.methods =
strats.inject =
strats.computed = function (
  parentVal: ?Object,
  childVal: ?Object,
  vm?: Component,
  key: string
): ?Object {
  if (!parentVal) return childVal // 如果parentVal没有值,直接返回childVal
  const ret = Object.create(null) // 创建一个第三方对象 ret
  extend(ret, parentVal) // extend方法实际是把parentVal的属性复制到ret中
  if (childVal) extend(ret, childVal) // 把childVal的属性复制到ret中
  return ret
}
strats.provide = mergeDataOrFn

同名的propsmethodsinjectcomputed会被后来者代替

合并型

和并型合并有:data

strats.data = function(parentVal, childVal, vm) {    
    return mergeDataOrFn(
        parentVal, childVal, vm
    )
};

function mergeDataOrFn(parentVal, childVal, vm) {    
    return function mergedInstanceDataFn() {        
        var childData = childVal.call(vm, vm) // 执行data挂的函数得到对象
        var parentData = parentVal.call(vm, vm)        
        if (childData) {            
            return mergeData(childData, parentData) // 将2个对象进行合并                                 
        } else {            
            return parentData // 如果没有childData 直接返回parentData
        }
    }
}

function mergeData(to, from) {    
    if (!from) return to    
    var key, toVal, fromVal;    
    var keys = Object.keys(from);   
    for (var i = 0; i < keys.length; i++) {
        key = keys[i];
        toVal = to[key];
        fromVal = from[key];    
        // 如果不存在这个属性,就重新设置
        if (!to.hasOwnProperty(key)) {
            set(to, key, fromVal);
        }      
        // 存在相同属性,合并对象
        else if (typeof toVal =="object" && typeof fromVal =="object") {
            mergeData(toVal, fromVal);
        }
    }    
    return to
}

mergeData函数遍历了要合并的 data 的所有属性,然后根据不同情况进行合并:

  • 当目标 data 对象不包含当前属性时,调用 set 方法进行合并(set方法其实就是一些合并重新赋值的方法)
  • 当目标 data 对象包含当前属性并且当前值为纯对象时,递归合并当前对象值,这样做是为了防止对象存在新增属性

队列性

队列性合并有:全部生命周期和watch

function mergeHook (
  parentVal: ?Array<Function>,
  childVal: ?Function | ?Array<Function>
): ?Array<Function> {
  return childVal
    ? parentVal
      ? parentVal.concat(childVal)
      : Array.isArray(childVal)
        ? childVal
        : [childVal]
    : parentVal
}

LIFECYCLE_HOOKS.forEach(hook => {
  strats[hook] = mergeHook
})

// watch
strats.watch = function (
  parentVal,
  childVal,
  vm,
  key
) {
  // work around Firefox's Object.prototype.watch...
  if (parentVal === nativeWatch) { parentVal = undefined; }
  if (childVal === nativeWatch) { childVal = undefined; }
  /* istanbul ignore if */
  if (!childVal) { return Object.create(parentVal || null) }
  {
    assertObjectType(key, childVal, vm);
  }
  if (!parentVal) { return childVal }
  var ret = {};
  extend(ret, parentVal);
  for (var key$1 in childVal) {
    var parent = ret[key$1];
    var child = childVal[key$1];
    if (parent && !Array.isArray(parent)) {
      parent = [parent];
    }
    ret[key$1] = parent
      ? parent.concat(child)
      : Array.isArray(child) ? child : [child];
  }
  return ret
};

生命周期钩子和watch被合并为一个数组,然后正序遍历一次执行

叠加型

叠加型合并有:componentdirectivesfilters

strats.components=
strats.directives=

strats.filters = function mergeAssets(
    parentVal, childVal, vm, key
) {    
    var res = Object.create(parentVal || null);    
    if (childVal) { 
        for (var key in childVal) {
            res[key] = childVal[key];
        }   
    } 
    return res
}

叠加型主要是通过原型链进行层层的叠加

小结:

  • 替换型策略有propsmethodsinjectcomputed,就是将新的同名参数替代旧的参数
  • 合并型策略是data, 通过set方法进行合并和重新赋值
  • 队列型策略有生命周期函数和watch,原理是将函数存入一个数组,然后正序遍历依次执行
  • 叠加型有componentdirectivesfilters,通过原型链进行层层的叠加

⭐  写在最后

请大家不吝赐教,在下方评论或者私信我,十分感谢🙏🙏🙏.

✅ 认为我某个部分的设计过于繁琐,有更加简单或者更高逼格的封装方式

✅ 认为我部分代码过于老旧,可以提供新的API或最新语法

✅ 对于文章中部分内容不理解

✅ 解答我文章中一些疑问

✅ 认为某些交互,功能需要优化,发现BUG

✅ 想要添加新功能,对于整体的设计,外观有更好的建议

最后感谢各位的耐心观看,既然都到这了,点个 👍赞再走吧!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/147583.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

黑客常用信息收集工具-02

信息收集是突破网络系统的第一步。黑客在进入目标主机之前,通常会使用一些专门的黑客工具对目标主机进行扫描,从扫描结果中分析这些计算机的弱点,从而确定进入目标主机的方法和手段。 接上文&#xff1a;黑客常用信息收集工具-01 tcpdump&#xff0c;tcpdump 可以抓所有层的数…

振弦传感器钢筋计埋设与安装方法

振弦传感器钢筋计埋设与安装方法 振弦传感器是一种常用的钢筋计测量设备&#xff0c;它通过测量钢筋振动的频率和振幅来判断钢筋的应力状态和疲劳程度&#xff0c;从而实现对钢筋的检测和监测。振弦传感器的钢筋计埋设和安装是使用该设备的关键步骤&#xff0c;下面将详细介绍…

(免费领源码)python#django#mysql公交线路查询系统85021- 计算机毕业设计项目选题推荐

摘 要 本论文主要论述了如何使用django框架开发一个公交线路查询系统&#xff0c;本系统将严格按照软件开发流程进行各个阶段的工作&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述该系统的当前背景以及系统开发的目的&#xff0c;后续章节将严格按…

微信小程序万能建站源码系统 一键换模板,五分钟创建一个小程序 带完整搭建教程

随着微信小程序的普及&#xff0c;越来越多的企业和个人选择开发自己的小程序。但是&#xff0c;开发一个小程序需要专业的技术和经验&#xff0c;这让很多初学者和没有编程基础的人望而却步。今天&#xff0c;罗峰给大家介绍一款微信小程序万能建站源码系统&#xff0c;让你轻…

PP-YOLOv2: A Practical Object Detector(2021.4)

文章目录 Abstract1. Introduction2. Revisit PP-YOLOPre-ProcessingBaseline ModelTraining Schedule 3. Selection of RefinementsPath Aggregation Network Mish Activation FunctionLarger Input SizeIoU Aware Branch 4. Experiments6. Conclusions 原文地址 源代码 Abstr…

STC89C52+HX711完成电子秤设计

一、项目背景 电子秤是一种通过传感器测量物体质量的设备&#xff0c;被广泛应用于商业和工业领域。传统的机械秤已经逐渐被电子秤取代&#xff0c;因为电子秤具有更高的精度、更方便的使用和更多的功能。 本项目利用STC89C52单片机和HX711模块完成电子秤设计&#xff0c;具有…

基于猕猴感觉运动皮层的神经元运动调制分析

公开数据集中文版详细描述参考前文&#xff1a;https://editor.csdn.net/md/?not_checkout1&spm1011.2124.3001.6192神经元Spike信号分析参考前文&#xff1a;https://blog.csdn.net/qq_43811536/article/details/134359566?spm1001.2014.3001.5501 目录 0. 公开数据集1.…

如何选择正确的SSL证书?

SSL证书已经成为网站安全管理的重要部分&#xff0c;但是市场上SSL证书种类繁多&#xff0c;很多新手在初次购买时都会感到困惑。下面我们就一起来看看如何快速地选择正确的SSL证书。 第一步&#xff1a;明确SSL证书的主要分类 SSL证书主要有三种类型&#xff1a;单域名证书、…

解决LX音乐切换音乐来源失败问题

之前免费听歌神器落雪音乐不能用了&#xff0c;原因懂得都懂 LX音乐Github链接 可以通过切换音乐来源进行解决 一、下载自定义音源文件 免费下载链接 下载一 百度网盘&#xff1a;1o7v 下载二 CSDN资源&#xff1a;自定义音源 全部音源文件来源 蓝奏云&#xff1a;8mno 下…

MDM如何配置数据审批功能

MDM基础数据平台是进行清洗和治理企业的主数据&#xff0c;使企业的主数据具有唯一性、准确性、一致性、及时性&#xff0c;通过主数据数据清洗功能将错误数据和重复数据进行清洗&#xff0c;从而保证企业数据能够做到以上那几点&#xff0c;然后再分发至下游系统&#xff0c;使…

超声波清洗机的工作原理是什么样的?值得入手的超声波清洗机推荐

超声波清洗机最常见的应该是在眼镜店了吧&#xff0c;眼镜店用来清洗眼镜频率非常高的&#xff01;超声波清洗机在清洁方面也是非常快速、高效的&#xff01;像眼镜党配戴眼镜脏的第一时间就会想到去眼镜店清洗&#xff0c;但也有很多朋友是随便清洗一下就了事了&#xff0c;其…

基于vue 2.0的H5页面中使用H5自带的定位,高德地图定位,搜索周边商户,覆盖物标记,定位到当前城市

基于vue的H5页面中使用高德地图定位&#xff0c;搜索周边商户&#xff0c;覆盖物标记 首先安装高德地图插件 npm i amap/amap-jsapi-loader --save地图承载容器 <template><div id"container"></div> </template>地图容器样式 <style…

关于跨域问题的个人理解

我也工作蛮多年了&#xff0c;期间既做过前端也做过后端。对于跨域问题&#xff0c;究竟是由前端程序员还是后端程序员来解决&#xff0c;我在不同的时期有不同的理解。现在&#xff0c;我更倾向于认为跨域问题应该由前端程序员来解决&#xff0c;即使在解决跨域问题的过程中涉…

全志R128基础组件开发指南——图像采集

图像采集 CSI&#xff08;DVP&#xff09; 图像采集 SENSOR -> CSI 通路 CSI &#xff08;CMOS sensor interface&#xff09;接口时序上可支持独立 SYNC 和嵌入 SYNC(CCIR656)。支持接收 YUV422 或 YUV420 数据。 VSYNC 和HSYNC 的有效电平可以是正极性&#xff0c;也可…

计算机网络之物理层

物理层 1. 物理层的基本概念 2.物理层下面的传输媒体 传输媒体可分为两类&#xff0c;一类是导引型传输媒体&#xff0c;另一类是非导引型传输媒体。 3.传输方式 3.1 串行传输和并行传输 串行传输&#xff1a;串行传输是指数据是一个比特依次发送的&#xff0c;因此在发送端…

如何使用Servlet写一个简单的网站

文章目录 前言1. 创建项目2. 引入依赖3. 创建目录4. 编写代码5. 打包程序6. 部署7.验证程序将 tomcat 集成到 idea 中 前言 前面我们学习了Java中常用的 HTTP 服务器 tomcat 的安装和使用&#xff0c;那么今天我们将使用这个 HTTP 服务器为大家写一个简单的网站&#xff0c;这…

AI技术如何融合应用于工业物联网

人工智能技术在近年来得到飞跃性地发展&#xff0c;在自主识别、分析、判断、规划等功能方面都进步显著&#xff0c;也已经应用于越来越多的行业产业。 在工业物联网领域&#xff0c;人工智能也将成为一大助力&#xff0c;通过与工业物联网系统集成融合&#xff0c;能够为工业…

Word多出一页空白页删不掉?这5个方法要记好!

“我在用Word编写文档时经常会遇到一个问题&#xff0c;文档排版都完成了&#xff0c;但是总会有一个空白页是无法删掉的&#xff0c;怎么解决这个问题呢&#xff1f;请大家帮帮我&#xff01;” 在使用Word编辑文档时&#xff0c;可能很多用户有时都会遇到一个常见问题&#x…

小型洗衣机哪个牌子质量好?性价比高的迷你洗衣机推荐

这两年内衣洗衣机可以称得上较火的小电器&#xff0c;小小的身躯却有大大的能力&#xff0c;一键可以同时启动洗、漂、脱三种全自动为一体化功能&#xff0c;在多功能和性能的提升上&#xff0c;还可以解放我们双手的同时将衣物给清洗干净&#xff0c;让越来越多小伙伴选择一款…

vue中bus的详细使用

vue中关于兄弟组件bus的使用方法 首先&#xff0c;bus可以用在任何组件之间的传值 废话不多说&#xff0c;请看下面代码解说 首先&#xff0c;先创建bus.js文件&#xff0c;然后在引用&#xff0c;这里有两种引用方法&#xff1a;局部引用和全局引用。 // bus.js文件内容 imp…