Vue2源码梳理:源码构建流程与运行时和编译时的版本选择

Vue.js 源码构建

1 )rollup 和 webpack 的对比

  • vuejs的源码呢是基于rollup构建的
    • 参考: https://github.com/rollup/rollup
  • rollup 和 webpack 都是一个构建工具
    • webpack 它会更强大一些, 会把像图片, css等静态资源通通编译成javascript
    • rollup 更适合一种javscript库的一个编译
      • 它只出了js部分,而其他资源它是不管的,所以它更轻量
      • 在编译后代码也是更友好的
    • 所以 vuejs 就选了rollup做构建

2 )rollup的构建设计

  • vuejs 是发布到 npm 上的一个包, 每个包都是需要一个package.json文件来做描述
  • 它是对项目的描述文件,它的内容实际上是一个标准的 JSON 对象
  • 比如说,常用的属性, name, version, description, main, module, …
    • main 是vue的入口,在 import vue 时,通过这个 main 来查找入口, 后缀是.js
    • module 和 main 非常类似的,在webpack2以上把 module作为默认入口, 后缀是 .esm.js
  • vuejs 源码是基于 rollup 构建的,它的构建相关配置都在 scripts 目录下
  • npm 提供了一个叫 npm scripts 的东西
    • 之前早期构建, 可能会用到gulp或者grunt
    • 它们两个都是一个以任务为基准的
    • 也就是说可以定义一系列任务
    • npm scripts 就是完成了这部分的功能
    • 也就是说它定义了很多脚本, 每个脚本都是一个任务
    • 通过 npm run xxx 可以执行不同的任务
    • 构建相关的任务,就是这三个
      • build 构建web平台相关
      • build:ssr 构建服务端渲染相关
      • build:weex 构建weex平台相关
  • 我们的源码是托管在 src 目录下,通过构建生成的目标代码在 dist 目录下
    • 在vue的仓库下,它已经默认帮我们构建出来很多版本的vuejs
    • 那为什么我们能构建如此多版本的vuejs呢?

3 )rollup构建vuejs的过程

package.json

{"script": {"build": "node scripts/build.js","build:ssr": "npm run build -- web-runtime-cjs,web-server-renderer","build:weex": "npm run build -- weex"}
}
  • 当我们去执行的这个 npm scripts 的时候,比如说,执行 npm run build
  • 它实际上就是执行了这样一个脚本 node scripts/build.js
  • 我们来看一下 scripts/build.js

scripts/build.js

const fs = require('fs')
const path = require('path')
const zlib = require('zlib')
const rollup = require('rollup')
const terser = require('terser')if (!fs.existsSync('dist')) {fs.mkdirSync('dist')
}let builds = require('./config').getAllBuilds()// filter builds via command line arg
if (process.argv[2]) {const filters = process.argv[2].split(',')builds = builds.filter(b => {return filters.some(f => b.output.file.indexOf(f) > -1 || b._name.indexOf(f) > -1)})
} else {// filter out weex builds by defaultbuilds = builds.filter(b => {return b.output.file.indexOf('weex') === -1})
}build(builds)function build (builds) {let built = 0const total = builds.lengthconst next = () => {buildEntry(builds[built]).then(() => {built++if (built < total) {next()}}).catch(logError)}next()
}function buildEntry (config) {const output = config.outputconst { file, banner } = outputconst isProd = /(min|prod)\.js$/.test(file)return rollup.rollup(config).then(bundle => bundle.generate(output)).then(({ output: [{ code }] }) => {if (isProd) {const minified = (banner ? banner + '\n' : '') + terser.minify(code, {toplevel: true,output: {ascii_only: true},compress: {pure_funcs: ['makeMap']}}).codereturn write(file, minified, true)} else {return write(file, code)}})
}function write (dest, code, zip) {return new Promise((resolve, reject) => {function report (extra) {console.log(blue(path.relative(process.cwd(), dest)) + ' ' + getSize(code) + (extra || ''))resolve()}fs.writeFile(dest, code, err => {if (err) return reject(err)if (zip) {zlib.gzip(code, (err, zipped) => {if (err) return reject(err)report(' (gzipped: ' + getSize(zipped) + ')')})} else {report()}})})
}function getSize (code) {return (code.length / 1024).toFixed(2) + 'kb'
}function logError (e) {console.log(e)
}function blue (str) {return '\x1b[1m\x1b[34m' + str + '\x1b[39m\x1b[22m'
}
  • 前面声明读取的模块
  • let builds = require('./config').getAllBuilds() 是从配置文件中,读取配置
  • 之后,再通过命令行参数对构建配置做过滤,最终调用 build() 函数 进行真正的构建
  • 所以它整个的构建的流程是非常清晰的
  • 那我们首先来分析一下这个这就是怎么拿到的

打开 .config 文件

const path = require('path')
const buble = require('rollup-plugin-buble')
const alias = require('rollup-plugin-alias')
const cjs = require('rollup-plugin-commonjs')
const replace = require('rollup-plugin-replace')
const node = require('rollup-plugin-node-resolve')
const flow = require('rollup-plugin-flow-no-whitespace')
const version = process.env.VERSION || require('../package.json').version
const weexVersion = process.env.WEEX_VERSION || require('../packages/weex-vue-framework/package.json').version
const featureFlags = require('./feature-flags')const banner ='/*!\n' +` * Vue.js v${version}\n` +` * (c) 2014-${new Date().getFullYear()} Evan You\n` +' * Released under the MIT License.\n' +' */'const weexFactoryPlugin = {intro () {return 'module.exports = function weexFactory (exports, document) {'},outro () {return '}'}
}const aliases = require('./alias')
const resolve = p => {const base = p.split('/')[0]if (aliases[base]) {return path.resolve(aliases[base], p.slice(base.length + 1))} else {return path.resolve(__dirname, '../', p)}
}const builds = {// Runtime only (CommonJS). Used by bundlers e.g. Webpack & Browserify'web-runtime-cjs-dev': {entry: resolve('web/entry-runtime.js'),dest: resolve('dist/vue.runtime.common.dev.js'),format: 'cjs',env: 'development',banner},'web-runtime-cjs-prod': {entry: resolve('web/entry-runtime.js'),dest: resolve('dist/vue.runtime.common.prod.js'),format: 'cjs',env: 'production',banner},// Runtime+compiler CommonJS build (CommonJS)'web-full-cjs-dev': {entry: resolve('web/entry-runtime-with-compiler.js'),dest: resolve('dist/vue.common.dev.js'),format: 'cjs',env: 'development',alias: { he: './entity-decoder' },banner},'web-full-cjs-prod': {entry: resolve('web/entry-runtime-with-compiler.js'),dest: resolve('dist/vue.common.prod.js'),format: 'cjs',env: 'production',alias: { he: './entity-decoder' },banner},// Runtime only ES modules build (for bundlers)'web-runtime-esm': {entry: resolve('web/entry-runtime.js'),dest: resolve('dist/vue.runtime.esm.js'),format: 'es',banner},// Runtime+compiler ES modules build (for bundlers)'web-full-esm': {entry: resolve('web/entry-runtime-with-compiler.js'),dest: resolve('dist/vue.esm.js'),format: 'es',alias: { he: './entity-decoder' },banner},// Runtime+compiler ES modules build (for direct import in browser)'web-full-esm-browser-dev': {entry: resolve('web/entry-runtime-with-compiler.js'),dest: resolve('dist/vue.esm.browser.js'),format: 'es',transpile: false,env: 'development',alias: { he: './entity-decoder' },banner},// Runtime+compiler ES modules build (for direct import in browser)'web-full-esm-browser-prod': {entry: resolve('web/entry-runtime-with-compiler.js'),dest: resolve('dist/vue.esm.browser.min.js'),format: 'es',transpile: false,env: 'production',alias: { he: './entity-decoder' },banner},// runtime-only build (Browser)'web-runtime-dev': {entry: resolve('web/entry-runtime.js'),dest: resolve('dist/vue.runtime.js'),format: 'umd',env: 'development',banner},// runtime-only production build (Browser)'web-runtime-prod': {entry: resolve('web/entry-runtime.js'),dest: resolve('dist/vue.runtime.min.js'),format: 'umd',env: 'production',banner},// Runtime+compiler development build (Browser)'web-full-dev': {entry: resolve('web/entry-runtime-with-compiler.js'),dest: resolve('dist/vue.js'),format: 'umd',env: 'development',alias: { he: './entity-decoder' },banner},// Runtime+compiler production build  (Browser)'web-full-prod': {entry: resolve('web/entry-runtime-with-compiler.js'),dest: resolve('dist/vue.min.js'),format: 'umd',env: 'production',alias: { he: './entity-decoder' },banner},// Web compiler (CommonJS).'web-compiler': {entry: resolve('web/entry-compiler.js'),dest: resolve('packages/vue-template-compiler/build.js'),format: 'cjs',external: Object.keys(require('../packages/vue-template-compiler/package.json').dependencies)},// Web compiler (UMD for in-browser use).'web-compiler-browser': {entry: resolve('web/entry-compiler.js'),dest: resolve('packages/vue-template-compiler/browser.js'),format: 'umd',env: 'development',moduleName: 'VueTemplateCompiler',plugins: [node(), cjs()]},// Web server renderer (CommonJS).'web-server-renderer-dev': {entry: resolve('web/entry-server-renderer.js'),dest: resolve('packages/vue-server-renderer/build.dev.js'),format: 'cjs',env: 'development',external: Object.keys(require('../packages/vue-server-renderer/package.json').dependencies)},'web-server-renderer-prod': {entry: resolve('web/entry-server-renderer.js'),dest: resolve('packages/vue-server-renderer/build.prod.js'),format: 'cjs',env: 'production',external: Object.keys(require('../packages/vue-server-renderer/package.json').dependencies)},'web-server-renderer-basic': {entry: resolve('web/entry-server-basic-renderer.js'),dest: resolve('packages/vue-server-renderer/basic.js'),format: 'umd',env: 'development',moduleName: 'renderVueComponentToString',plugins: [node(), cjs()]},'web-server-renderer-webpack-server-plugin': {entry: resolve('server/webpack-plugin/server.js'),dest: resolve('packages/vue-server-renderer/server-plugin.js'),format: 'cjs',external: Object.keys(require('../packages/vue-server-renderer/package.json').dependencies)},'web-server-renderer-webpack-client-plugin': {entry: resolve('server/webpack-plugin/client.js'),dest: resolve('packages/vue-server-renderer/client-plugin.js'),format: 'cjs',external: Object.keys(require('../packages/vue-server-renderer/package.json').dependencies)},// Weex runtime factory'weex-factory': {weex: true,entry: resolve('weex/entry-runtime-factory.js'),dest: resolve('packages/weex-vue-framework/factory.js'),format: 'cjs',plugins: [weexFactoryPlugin]},// Weex runtime framework (CommonJS).'weex-framework': {weex: true,entry: resolve('weex/entry-framework.js'),dest: resolve('packages/weex-vue-framework/index.js'),format: 'cjs'},// Weex compiler (CommonJS). Used by Weex's Webpack loader.'weex-compiler': {weex: true,entry: resolve('weex/entry-compiler.js'),dest: resolve('packages/weex-template-compiler/build.js'),format: 'cjs',external: Object.keys(require('../packages/weex-template-compiler/package.json').dependencies)}
}function genConfig (name) {const opts = builds[name]const config = {input: opts.entry,external: opts.external,plugins: [flow(),alias(Object.assign({}, aliases, opts.alias))].concat(opts.plugins || []),output: {file: opts.dest,format: opts.format,banner: opts.banner,name: opts.moduleName || 'Vue'},onwarn: (msg, warn) => {if (!/Circular/.test(msg)) {warn(msg)}}}// built-in varsconst vars = {__WEEX__: !!opts.weex,__WEEX_VERSION__: weexVersion,__VERSION__: version}// feature flagsObject.keys(featureFlags).forEach(key => {vars[`process.env.${key}`] = featureFlags[key]})// build-specific envif (opts.env) {vars['process.env.NODE_ENV'] = JSON.stringify(opts.env)}config.plugins.push(replace(vars))if (opts.transpile !== false) {config.plugins.push(buble())}Object.defineProperty(config, '_name', {enumerable: false,value: name})return config
}if (process.env.TARGET) {module.exports = genConfig(process.env.TARGET)
} else {exports.getBuild = genConfigexports.getAllBuilds = () => Object.keys(builds).map(genConfig)
}
  • 这个config文件在最后一行暴露了一个方法,叫 getAllBuilds,它是一个函数
    • 这个函数做了什么事情呢? Object.keys(builds).map(genConfig)
    • 拿到一个keys的数组,然后我们再通过map方法调用这个 genConfig 函数
  • 我们来看这个 builds 参数
    • 上面代码大篇幅定义了 builds 对象
    • 里面每个key对应的也都是一个对象
      • 通过注释可知,是不同版本的vuejs的编译配置
      • 每一个编译配置它都会有一个 entry 顾名思义就是入口
      • dest 顾名思义就是目标
      • 还有一个format(输出格式) 和 banner(头部注释)
  • 这个 entry 它是通过 resolve 这个函数,然后传一个字符串(文件地址)
    const aliases = require('./alias')
    const resolve = p => {const base = p.split('/')[0]if (aliases[base]) {return path.resolve(aliases[base], p.slice(base.length + 1))} else {return path.resolve(__dirname, '../', p)}
    }
    
    • resolve 函数,它就是接收一个参数。这个字符参数会通过split(‘/’) 拿到第一个值作为base
    • 之后判断 aliases 这个 aliases 也是 require 进来的,看下这个 alias 文件
      const path = require('path')
      const resolve = p => path.resolve(__dirname, '../', p)module.exports = {vue: resolve('src/platforms/web/entry-runtime-with-compiler'),compiler: resolve('src/compiler'),core: resolve('src/core'),shared: resolve('src/shared'),web: resolve('src/platforms/web'),weex: resolve('src/platforms/weex'),server: resolve('src/server'),sfc: resolve('src/sfc')
      }
      
    • 可见,alias 文件提供别名到真实地址文件的映射
    • 回到最上面的 resolve 方法内部,最终返回了从参数到真实地址的字符串
  • dest 这个key也走的 resolve, 只不过走到了 最终 else 的环节里
  • format 是构建出来的文件格式,cjs 对应的就是 xxx.common.js
    • cjs 最终生成的js文件是 module.exports = Vue
    • es 最终生成的文件是 export default Vue
    • umd 最终生成的文件是 符合 umd 规范的 vuejs 文件
  • 所以,很显然
    • 上面 web 对应的真实的路径是 path.resolve(__dirname, ‘…/src/platforms/web’),这个路径就找到了 Vue.js 源码的 web 目录
    • 然后 resolve 函数通过 path.resolve(aliases[base], p.slice(base.length + 1)) 找到了最终路径
    • 它就是 Vue.js 源码 web 目录下的 entry-runtime.js。因此,web-runtime-cjs 配置对应的入口文件就找到了
    • 它经过 Rollup 的构建打包后,最终会在 dist 目录下生成 vue.runtime.common.js
  • banner 是自己设计的头部注释
    • 里面可以 写八本,日期,作者,license 等信息
  • 再回到我们的config,最终通过 Object.keys(builds).map(genConfig)
    • 拿到这个所有keys 的一个数组,然后这个这个数组我们去调用这个 genConfig 函数
    • genConfig 就拿到每个key,然后它就会拿到这个对象,再通过 build[name]
    • name 是key对应的这个对象,构造出一个新的 config 对象
      • 里面有 input, external, plugins, output, …
    • 这个最终的 config 对象才是 rollup 打包所需要的配置结构
    • 这是个适配器来进行的转换工作
  • 返回到 let builds = require('./config').getAllBuilds()
    • 这里的 builds 是一个数组
  • 之后进行 if (process.argv[2]) {} 的判断
    • 提取到命令行输出的参数,如 – weex 等
    • 如果有参数,则会通过 filter 来过滤一些不需要的流程
  • 最终编译的时候,就调用 build(builds) 在里面进行一个个的编译
    • 里面定义一个 next() 函数,里面调用 buildEntry, 之后递归,里面有个 built 计数器
    • 而 buildEntry 传入最终的config, config作为最终rollup的参数进行构建
    • 编译完之后得到了 bundle, 通过了 bundle.generate 传入 output
    • 之后拿到 code, 判断环境,分别做处理,最终通过 write 方法,得到构建好的文件
    • 在生成的过程中,打下一些 log 信息
  • 这是整个的构建流程

4 ) Runtime Only VS Runtime + Compiler

  • 通常我们利用 vue-cli 去初始化我们的 Vue.js 项目的时候
  • 会询问我们用 Runtime Only 版本的还是 Runtime + Compiler 版本
  • 下面我们来对比这两个版本

4.1 ) Runtime Only

  • 我们在使用 Runtime Only 版本的 Vue.js 的时候,通常需要借助如 webpack 的 vue-loader 工具把 .vue 文件编译成 JavaScript
  • 在浏览器里,是不认识 .vue文件的,所以需要一个编译的过程,在编译阶段,会把 template 模板编译成 render 函数
  • 最终编译后的,就是一个 render 函数的版本,所以vue是不带编译的,也就是运行时不带编译
  • 所以它只包含运行时的 Vue.js 代码,因此代码体积也会更轻量

4.2 )Runtime + Compiler

  • 我们如果没有对代码做预编译,但又使用了 Vue 的 template 属性并传入一个字符串,则需要在客户端编译模板,如下所示:

    // 需要编译器的版本
    new Vue({template: '<div>{{ hi }}</div>'
    })
    
  • 这种一定要选择 Runtime + Compiler 版本

    // 这种情况不需要
    new Vue({render (h) {return h('div', this.hi)}
    })
    
  • 这种就不需要

  • 而 .vue文件 是在编译过程中,通过 vue-loader 处理的

  • 所以我们写的 .vue 文件在运行的时候已经编译成 js 函数了,并且模板部分已经编译成 render 函数了

  • 在 Vue.js 2.0 中,最终渲染都是通过 render 函数,如果写 template 属性,则需要编译成 render 函数

  • 那么这个编译过程会发生运行时,需要带有编译器的版本

  • 很显然,这个编译过程对性能会有一定损耗,所以通常开发阶段更推荐使用 Runtime-Only 的 Vue.js

    • 一种是运行时的性能优化,一种是编译出来的体积会更轻量

5 )总结

  • 我们可了解到 Vue.js 的构建打包过程,也知道了不同作用和功能的 Vue.js 它们对应的入口以及最终编译生成的 JS 文件
  • 在实际开发过程中我们会用 Runtime Only 版本开发比较多
  • 但为了分析 Vue 的编译过程,我们重点分析的源码是

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

jquery、vue、uni-app、小程序的页面传参方式

jQuery、Vue、Uni-app 和小程序&#xff08;例如微信小程序&#xff09;都有它们自己的页面传参方式。下面分别介绍这几种方式的页面传参方式&#xff1a; jQuery: 在jQuery中&#xff0c;页面传参通常是通过URL的查询参数来实现的。例如&#xff1a; <a href"page2…

通过https协议访问Tomcat部署并使用Shiro认证的应用跳转登到录页时协议变为http的问题

问题描述&#xff1a; 在最近的一个项目中&#xff0c;有一个存在较久&#xff0c;并且只在内部城域网可访问的一个使用Shiro框架进行安全管理的Java应用&#xff0c;该应用部署在Tomcat服务器上。起初&#xff0c;应用程序可以通过HTTP协议访问&#xff0c;一切运行都没…

FreeCodeCamp--数千免费编程入门教程,非盈利性网站,质量高且支持中文

在浏览话题“Github上获得Star最多的项目”时&#xff0c;看到了FreeCodeCamp&#xff0c;顾名思义--免费编程营地&#xff0c;于是就做了些调研&#xff0c;了解了下这是个什么项目 这是一个致力于推动编程教育的非营利性组织&#xff0c;团队由来自世界各地的杰出的技术开发…

java中常用的加密算法总结

目前在工作中常用到加密的一些场景&#xff0c;比如密码加密&#xff0c;数据加密&#xff0c;接口参数加密等&#xff0c;故通过本文总结以下常见的加密算法。 1. 对称加密算法 对称加密算法使用相同的密钥进行加密和解密。在Java中&#xff0c;常见的对称加密算法包括&…

驱动学习篇

随记&#xff0c;不定时更新驱动相关知识&#xff0c;累积驱动开发相关经验 一、知识点 1. bios与vbios的区别 BIOS&#xff08;Basic Input/Output System&#xff09;和VBios&#xff08;Video BIOS&#xff09;是计算机系统中的两个不同的组成部分&#xff0c;它们具有以…

机器人也能干的更好:RPA技术的优势和应用场景

RPA是什么&#xff1f; 机器人流程自动化RPA&#xff08;Robotic Process Automation&#xff09;是一种自动化技术&#xff0c;它使用软件机器人来高效完成重复且有逻辑性的工作。近年来&#xff0c;随着人工智能和自动化技术的不断发展和普及&#xff0c;RPA已经成为企业提高…

模拟信号和数字信号的区别

模拟和数字信号是携带信息的信号类型。两种信号之间的主要区别在于模拟信号具有连续电信号&#xff0c;而数字信号具有非连续电信号。 模拟信号和数字信号之间的差异可以通过不同类型波的例子来观察。 什么是模拟信号(Analog Signals)&#xff1f; 许多系统使用模拟信号来传输…

基于SpringBoot+Vue的小区物业管理系统

基于SpringBootVue的小区物业管理系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 房屋类型 论坛 登录界面 管理员界面 员工界面 摘要 小区物业管理系统是一个…

翻译: LLMs离通用人工智能AGI有多远 20个小时学会开车 Artificial General Intelligence

AGI&#xff0c;即人工通用智能&#xff0c;是一个令人兴奋的概念。我认为围绕它的一些混淆源于“通用”这个词的使用。正如您所知&#xff0c;人工智能是一种通用技术&#xff0c;意味着它对许多不同的事情都有用。大型语言模型的崛起导致了像ChatGPT这样的单一模型可以用于许…

鸿蒙(HarmonyOS)应用开发—— video组件实操

video 组件 harmonyOS 系统提供了基础的video。下面就直接上代码 原始video 新建项目 customVideo项目 本地视频 网络地址&#xff0c;就不用说明&#xff0c;只需要把地址换成网络地址即可 在resource 文件夹下的rawfile文件夹下 添加视频 在index.ets Video({src:$rawf…

自动化测试工具——Monkey

前言&#xff1a; 最近开始研究Android自动化测试方法&#xff0c;整理了一些工具、方法和框架&#xff0c;其中包括android测试框架&#xff0c;CTS、Monkey、Monkeyrunner、benchmark&#xff0c;以及其它test tool等等。 一、 什么是Monkey Monkey是Android中的一个命令行…

数组深入学习感悟

注&#xff1a;本文学习借鉴于《代码随想录》 一.介绍数组 数组是储存在连续内存空间中的相同类型数据的集合 数组名的理解&#xff1a; 数组名就是数组⾸元素(第⼀个元素)的地址是对的&#xff0c;但是有两个例外&#xff1a; sizeof(数组名)&#xff0c;sizeof中单独放数…

Mybatis-Plus讲义v1.0

Mybatis-Plus 课程目标 了解Mybatis-Plus 整合Mybatis-Plus 通用CRUD Mybatis-Plus的配置 条件构造器 Mybatis-Plus 的Service封装 代码生成器 1 Mybatis-Plus介绍 1.1 Mybatis-Plus介绍 MyBatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis 的增强工具&…

Ubuntu-20.04.2 mate 上安装、配置、测试 qtcreator

一、从repo中安装 Ubuntu-20.04.2的repo中&#xff0c;qtcreator安装包挺全乎的&#xff0c;敲完 sudo apt install qtcreator 看一下同时安装和新软件包将被安装列表&#xff0c;压缩包252MB&#xff0c;解压安装后933MB&#xff0c;集大成的一包。 sudo apt install qtcrea…

现代雷达车载应用——第3章 MIMO雷达技术 3.2节 汽车MIMO雷达波形正交策略

经典著作&#xff0c;值得一读&#xff0c;英文原版下载链接【免费】ModernRadarforAutomotiveApplications资源-CSDN文库。 3.2 汽车MIMO雷达波形正交策略 基于MIMO雷达技术的汽车雷达虚拟阵列合成依赖于不同天线发射信号的可分离性。当不同天线的发射信号正交时&#x…

软件设计模式:UML类图

文章目录 前言一、&#x1f4d6;设计模式概述1.软件设计模式的产生背景2.软件设计模式3.设计模式分类 二、&#x1f4e3;UML图1.类图概述2.类的表示法3.类与类之间的关系关联关系&#xff08;1&#xff09;单向关联&#xff08;2&#xff09;双向关联&#xff08;3&#xff09;…

CCF编程能力等级认证GESP—C++6级—20230923

CCF编程能力等级认证GESP—C6级—20230923 单选题&#xff08;每题 2 分&#xff0c;共 30 分&#xff09;判断题&#xff08;每题 2 分&#xff0c;共 20 分&#xff09;编程题 (每题 25 分&#xff0c;共 50 分)小杨买饮料小杨的握手问题 答案及解析单选题判断题编程题1编程题…

vba中字典的应用实例

vba中熟练使用字典可以帮我们解决很多问题&#xff0c;以下为字典的应用方法及案例&#xff1a; Sub dictionary() Dim d As New dictionary 定义字典 Dim mykey As Variant Dim myitems d.Add "1100000", "身份证" 字典录入key关键字和item条目 d.Add &q…

C语言归并排序(合并排序)算法以及代码

合并排序是采用分治法&#xff0c;先将无序序列划分为有序子序列&#xff0c;再将有序子序列合并成一个有序序列的有效的排序算法。 原理&#xff1a;先将无序序列利用二分法划分为子序列&#xff0c;直至每个子序列只有一个元素(单元素序列必有序)&#xff0c;然后再对有序子序…

AtCoder Beginner Contest 333 A~F

A.Three Threes&#xff08;循环&#xff09; 题意&#xff1a; 给出一个正整数 N N N&#xff0c;要求输出 N N N个 N N N 分析&#xff1a; 按要求输出即可 代码&#xff1a; #include <bits/stdc.h> using namespace std;void solve() {int n;cin >> n;fo…