vue2源码分析-vue入口文件global-api分析
文章背景
- vue项目开发过程中,首先会有一个初始化的流程,以及我们会使用到很多全局的api,如
this.$set
this.$delete
this.$nextTick
,以及初始化方法extend
,initUse
,initMixin
,initExtend
,initAssetRegisters
等等那它们是怎么实现,让我们一起来探究下吧
源码目录
global-api代码初始化
代码路径
src\vue-2.6.14\src\core\global-api\index.js
代码分析
vue挂载的全局属性
vue.util
公共方法-
warn
代码警告处理
-
extend
将源数据中的值拷贝到目标数据中
-
mergeOptions
合并选项
-
defineReactive
定义响应式数据
set
set 方法,修改对象的某个属性,以更新视图del
del 方法,删除数组的某个索引下的数据 或者 对象的某个属性nextTick
nextTick方法observable
调用observer类的observe方法,将对象变为响应式对象,并且返回该响应式对象options
vue的一些选项
初始化方法
extend
-
- extend函数此处用于扩展,将源数据中的值拷贝到目标数据中,数据类型兼容到了 对象和数组
initUse
-
- 初始化插件
initMixin
-
- 初始化混入 逻辑有点多,后期详细补充
initExtend
-
- 构造一个vue的子类
initAssetRegisters
(Vue)-
- 注册或者获取全局组件、指令、过滤器
/* @flow */import config from '../config'
import { initUse } from './use'
import { initMixin } from './mixin'
import { initExtend } from './extend'
import { initAssetRegisters } from './assets'
import { set, del } from '../observer/index'
import { ASSET_TYPES } from 'shared/constants'
import builtInComponents from '../components/index'
import { observe } from 'core/observer/index'import {warn,extend,nextTick,mergeOptions,defineReactive
} from '../util/index'
export function initGlobalAPI(Vue: GlobalAPI) {// note 初始化全局api sjf-step2debuggerconst configDef = {}configDef.get = () => config// 初始化vue的全局config配置if (process.env.NODE_ENV !== 'production') {configDef.set = () => {// set在修改对象的字段时触发,此处表示在设置 Vue的config属性时触发warn('Do not replace the Vue.config object, set individual fields instead.')}//在开发环境中,不允许替换整个Vue.config 对象,只允许设置单独的字段}Object.defineProperty(Vue, 'config', configDef)// // exposed util methods.// NOTE: these are not considered part of the public API - avoid relying on// them unless you are aware of the risk.Vue.util = {//将全局方法,挂载到Vue的util方法上warn,extend,mergeOptions,defineReactive}Vue.set = set// set 方法,修改对象的某个属性,以更新视图Vue.delete = del // del 方法,删除数组的某个索引下的数据 或者 对象的某个属性Vue.nextTick = nextTick // nextTick方法// set delete nextTick 除了可以使用 this.$set,this.$delete,this.$nextTick调用,亦可以在Vue实例上直接调用// 2.6 explicit observable APIVue.observable = (obj) => {observe(obj)// 调用observer类的observe方法,将对象变为响应式对象return obj//并且返回该响应式对象}Vue.options = Object.create(null)//调用 Object.create(null) 创建一个没有原型链的空对象ASSET_TYPES.forEach(type => {Vue.options[type + 's'] = Object.create(null)})// ASSET_TYPES = ['component','directive','filter'] // 遍历ASSET_TYPES数组,给Vue.options添加三个属性,分别是components,directives,filters// this is used to identify the "base" constructor to extend all plain-object// components with in Weex's multi-instance scenarios.Vue.options._base = Vue// 将vue赋值给Vue.options._base,用于在weex的多实例场景下,标识“基础”构造函数,以扩展所有纯对象组件extend(Vue.options.components, builtInComponents)// 将builtInComponents对象的属性,复制到Vue.options.components上// extend函数此处用于扩展initUse(Vue)//初始化插件initMixin(Vue)//初始化混入 逻辑有点多,后期详细补充initExtend(Vue)//构造一个vue的子类 initAssetRegisters(Vue) // 注册或者获取全局组件、指令、过滤器
}
extend 扩展数据
代码路径
src\vue-2.6.14\src\shared\util.js- extend函数此处用于扩展,将源数据中的值拷贝到目标数据中,数据类型兼容到了 对象和数组
- 入参说明
-
- to 目标值,_from 源数据
- 核心代码说明
-
const key in
_from
-
- _from 可以是一个数组 ,也可以是一个对象
-
- 如果是数组,则key是数组的索引
-
- 如果是对象,则key是对象的键值
export function extend (to: Object, _from: ?Object): Object {// sjf-note-best-code// 将源数据中的值拷贝到目标数据中,数据类型兼容到了 对象和数组for (const key in _from) {// const key in _from // _from 可以是一个数组 ,也可以是一个对象// 如果是数组,则key是数组的索引// 如果是对象,则key是对象的键值to[key] = _from[key]}//当我们还在苦逼地用 Array.isArray 判断数据类型是否是数组来区分代码写两套逻辑时, vue源代码已经实现了,一个代码同时兼容了数组和对象的拷贝,简直不要太优秀啊return to
}
- 优秀代码设计思想
-
- 当我们还在苦逼地用 Array.isArray 判断数据类型是否是数组来区分代码写两套逻辑时, vue源代码已经实现了,一个代码同时兼容了数组和对象的拷贝,简直不要太优秀啊
initUse 初始化插件
代码路径
src\vue-2.6.14\src\core\global-api\use.js- 入参说明
- plugin 参数 有可能是函数也有能是对象
-
- 当是对象时需要访问
install
属性并且使用apply修改this为plugin后调用
- 当是对象时需要访问
-
- 当是函数时则直接调用
- 核心代码说明
installedPlugins
-
- 定义 installedPlugins 参数,
-
- 读取vue实例上的_installedPlugins属性,如果读取不到则赋值为空数组
-
- 缓存插件,将插件添加到已安装插件的数组中
- 防止插件的重复加载
-
- 如果插件已经安装,则将插件直接返回
import { toArray } from '../util/index'export function initUse (Vue: GlobalAPI) {Vue.use = function (plugin: Function | Object) {const installedPlugins = (this._installedPlugins || (this._installedPlugins = []))// _installedPlugins 函数内部的变量 用来存储已经注册的插件// _installedPlugins 不存在时,初始化为一个空数组// vue源码中并没有声明 _installedPlugins 并且此处是非箭头函数if (installedPlugins.indexOf(plugin) > -1) {// 防止插件的重复加载return this}const args = toArray(arguments, 1)// toArray 方法将参数转化为数组// arguments 是一个类数组对象,有length属性,但是没有数组的方法// 通过toArray方法将arguments转化为数组,并且去掉第一个参数args.unshift(this)//再将this添加到args数组的头部if (typeof plugin.install === 'function') {// 如果插件有install方法,则调用install方法plugin.install.apply(plugin, args)} else if (typeof plugin === 'function') {// 如果插件是一个函数,则直接调用plugin.apply(null, args)}installedPlugins.push(plugin)//缓存插件,将插件添加到已安装插件的数组中return this}
}
initMixin 初始化混入
- 初始化混入 逻辑有点多,后期单独出一篇文章详细补充
initExtend 初始化vue组件对象
代码路径
src\vue-2.6.14\src\core\global-api\extend.js
函数说明- 基于构造函数Vue,创建了一个Vue组件对象,并初始化
vue选项式api
核心代码说明 - 获取父类的
cid
,也就是组件的id,即组件的标识 cachedCtors
,定义一个缓存对象-
- 如果缓存对象中已经有了当前类的id,则表明在此操作前已经创建过了
-
- 通过id访问到缓存对象中的子类,并直接返回
-
- 这样做可以提高性能,避免重复的子类创建
- 获取到组件的name属性
-
- 如果当前传入的组件选项中有name属性则直接读取,否则访问Super(父类的)name属性
-
- name是组件的标识,一般确实永不到,但是
组件递归
的时候必须要写,否则无法调用子组件
- name是组件的标识,一般确实永不到,但是
- 调用
validateComponentName
校验name属性是否合法 - sub类的处理
-
- 通过函数的方式创建一个sub类,并将父类的原型链继承到子类中(原型链继承方式),同时还需要修正constructor的指向
-
- 将父类的options字段和传入组件对象选项进行合并,并保存在子类sub的options字段中
-
- 将父类保存到子类的 super 字段中,确保子类能拿到父类
- 初始化
props
-
- props 是当前组件的props属性
-
- const in props 遍历对象的属性
-
- 将 组件传入的props属性代理到组件实例的_props属性上
- 初始化
computed
-
- computed 是当前组件的computed属性
-
- const in props 遍历对象的属性
-
defineComputed
逻辑暂时没看,后期单独出一期文章补充
- 将
extend
,mixin
,use
等api添加到子类中 - 新增
superOptions
,extendOptions
,sealedOptions
等选项 - 将子类返回
/* @flow */import { ASSET_TYPES } from 'shared/constants'
import { defineComputed, proxy } from '../instance/state'
import { extend, mergeOptions, validateComponentName } from '../util/index'export function initExtend (Vue: GlobalAPI) {/*** Each instance constructor, including Vue, has a unique* cid. This enables us to create wrapped "child* constructors" for prototypal inheritance and cache them.*/// sjf-note-best-codeVue.cid = 0//初始化cid为0 可以理解为组件的标识let cid = 1 /*** Class inheritance*/Vue.extend = function (extendOptions: Object): Function {// 基于构造函数Vue,创建了一个Vue组件对对象,并初始化vue选项式apiextendOptions = extendOptions || {}// extendOptions是一个对象,如果没有传入,则初始化为空对象// extendOptions 是组件传入的选项const Super = this//将this(vue的实例)赋值给Superconst SuperId = Super.cidconst cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})//定义一个缓存对象,用生成的id作为属性键,如果cachedCtors[SuperId]存在则表明该组件的构造函数已经生成,直接返回即可if (cachedCtors[SuperId]) {return cachedCtors[SuperId]}const name = extendOptions.name || Super.options.name// extendOptions 当前组件的选项 的 // Super 是 Vue的实例 options 是Vue的选项// 如果传入了extendOptions.name 则使用extendOptions.name 否则使用Super.options.nameif (process.env.NODE_ENV !== 'production' && name) {//判断是否是开发环境validateComponentName(name)//校验组件名称是否合法, 如果不合法会抛出异常}const Sub = function VueComponent (options) {this._init(options)//此处的this是vue实例 ,调用了_init方法,初始化组件实例}Sub.prototype = Object.create(Super.prototype)// Super.prototype 是Vue的原型对象// Object.create(Super.prototype) 创建了一个新的对象,该对象的原型是Super.prototype// Object.create() 方法创建一个新对象,不会有原型链上的属性和方法Sub.prototype.constructor = Sub// consturctor指向自身 sjf-todo// 通过函数的方式创建一个sub类,并将父类的原型链继承到子类中(原型链继承方式),同时还需要修正constructor的指向Sub.cid = cid++//组件的cid自增1Sub.options = mergeOptions(//将父类的options字段和传入组件对象选项进行合并,并保存在子类sub的options字段中Super.options,//Vue的选项extendOptions//当前组件的选项)Sub['super'] = Super//将Super(根组件的实例)赋值给当前组件的super属性
// 将父类保存到子类的 super 字段中,确保子类能拿到父类// For props and computed properties, we define the proxy getters on// the Vue instances at extension time, on the extended prototype. This// avoids Object.defineProperty calls for each instance created.if (Sub.options.props) {//如果当前组件有props属性,则初始化propsinitProps(Sub) }if (Sub.options.computed) {//如果当前组件有computed属性,则初始化computedinitComputed(Sub)}// allow further extension/mixin/plugin usageSub.extend = Super.extendSub.mixin = Super.mixinSub.use = Super.use
// Vue的一些原生API 等扩展到子构造器上边// create asset registers, so extended classes// can have their private assets too.ASSET_TYPES.forEach(function (type) {Sub[type] = Super[type]})// enable recursive self-lookupif (name) {Sub.options.components[name] = Sub}// keep a reference to the super options at extension time.// later at instantiation we can check if Super's options have// been updated.Sub.superOptions = Super.optionsSub.extendOptions = extendOptionsSub.sealedOptions = extend({}, Sub.options)
// Vue的一些原生API 等扩展到子构造器上边// cache constructorcachedCtors[SuperId] = Subreturn Sub}
}function initProps (Comp) {const props = Comp.options.props// props 是当前组件的props属性for (const key in props) { // const in props 遍历对象的属性proxy(Comp.prototype, `_props`, key)// proxy 代理数据// 此处是将 组件传入的props属性代理到组件实例的_props属性上}
}function initComputed (Comp) {const computed = Comp.options.computed// computed 是当前组件的computed属性for (const key in computed) {// const in computed 遍历对象的属性defineComputed(Comp.prototype, key, computed[key])// defineComputed 代理数据// 此处是将 组件传入的computed属性代理到组件实例的_props属性上}
}
initAssetRegisters 注册或者获取全局组件、指令、过滤器
- src\vue-2.6.14\src\core\global-api\assets.js
函数说明 - 注册或者获取全局
component
组件、directive
指令、filter
过滤器
函数入参说明 - id
标识名称id
definition
定义类型是函数或者对象-
- 当type 是directive或者filter的时候,是函数
-
- 当type是components的时候是,对象
核心代码说明
- 当type是components的时候是,对象
- 判断是是否有传入 definition 参数
-
- 无则表明不是注册全局组件、指令、过滤器,而直接读取,直接通过标识名称id读取返回即可
-
- 有则标明是注册
- 校验组件名是否合规
-
- 非生产环境 并且type值是component组件名称,则需要校验组件名是否合规
-
- 如果不合规则在
validateComponentName
函数中抛出异常,下文有说明
- 如果不合规则在
- 根据type类型分别做逻辑处理
component
- type为
component
,并且isPlainObject
判断 definition类型是 object,则执行下边逻辑 -
- 读取 name 属性,如果读不到definition的name属性,则使用标识名称id
-
- 调用 vue 的extend扩展定义,并重新赋值
directive
-
- type值为 directive ,并且 definition的类型为 function
-
- 定义一个对象有
bind
和update
属性,赋值为definition
- 定义一个对象有
- 以上逻辑处理好了directive和component选项下的definition,filter选项不需要特殊处理
- 根据
选项式api
对象读取到指定id的component
组件、directive
指令、filter
过滤器并赋值为 definition - 将 definition返回给调用者
/* @flow */import { ASSET_TYPES } from 'shared/constants'
import { isPlainObject, validateComponentName } from '../util/index'export function initAssetRegisters (Vue: GlobalAPI) {/*** Create asset registration methods.*//* 'component','directive','filter'*/
// 注册或者获取全局组件、指令、过滤器debuggerASSET_TYPES.forEach(type => {//定义资源注册方法Vue[type] = function (id: string,//标识名称iddefinition: Function | Object//定义函数或者对象 // 当type 是directive或者filter的时候,是函数// 当type是components的时候是,对象): Function | Object | void {// console.log("id_definition",type,id,definition)if (!definition) {// 没有传入definition 的时候,则之直接读取并返回return this.options[type + 's'][id]} else {/* istanbul ignore if */if (process.env.NODE_ENV !== 'production' && type === 'component') {// 非生产环境 交易案组件名称,如果不合规,则抛出异常validateComponentName(id)}if (type === 'component' && isPlainObject(definition)) {definition.name = definition.name || id//设置 definition.name属性 // 值为组件传入的name || iddefinition = this.options._base.extend(definition)// 调用 vue 的extend扩展定义,并重新赋值}if (type === 'directive' && typeof definition === 'function') {definition = { bind: definition, update: definition }// 自定义指令的处理逻辑}this.options[type + 's'][id] = definitionreturn definition}}})
}
源码中使用到的小代码片段补充
ASSET_TYPES
export const ASSET_TYPES = ['component','directive','filter'
]
proxy代理函数
- 代码引用地址 src\vue-2.6.14\src\core\instance\state.js
- 使用
defineProperty
代理数据
const sharedPropertyDefinition = {//代理数据的配置enumerable: true,//是否可枚举configurable: true,//是否可修改删除get: noop,//get方法,用于读取数据 noop 定义一个临时的空的函数set: noop//set方法,用于设置数据 noop 定义一个临时的空的函数
}export function proxy (target: Object, sourceKey: string, key: string) {// 代理数据sharedPropertyDefinition.get = function proxyGetter () {return this[sourceKey][key] //返回数据}sharedPropertyDefinition.set = function proxySetter (val) {this[sourceKey][key] = val//设置数据}Object.defineProperty(target, key, sharedPropertyDefinition)// 通过Object.defineProperty方法,将sharedPropertyDefinition的get和set方法绑定到target对象的key属性上
}
toArray 将目标数组中的数据,从指定位置开始拷贝
- 代码引用地址 src\vue-2.6.14\src\shared\util.js
- 将目标数组中的数据,从指定位置开始拷贝
代码实现原理
- 接收字段
-
- list 源数据
-
- start 从源数据的哪个位置开始拷贝 默认为 0
- 声明一个变量i值为 list.length - start
- while 循环
-
- 然后将 i + start
-
- 则 最后的 i + start 仍然等于 list.length
-
- 当i的值为0时,循环结束
- 则实现了将原数组从指定位置拷贝到目标数组的操作
代码优秀设计思想分析,它凭什么优秀 - 第一点,一般拷贝数组,
- 常规的操作就是 for 循环,遍历数组中的每一个数据,然后根据条件判断,将数组中满足条件的数据拿到或者将不满足条件的数据过滤掉,这样确实能够处理数据,但是却需要将每条数据都循环一遍 .
- 优秀的写法 此处,使用了while循环,不需要循环每一条数据,在调件变量为false的时候就跳出了循环,提高了代码的执行效率
- 可拷贝从指定位置开始的数据
- 语法层面上使用了
new Array(i)
- 创建了指定数组,并且指定了位数,同时生明其中的每个变量都为empty
- 很多人都知道new Array 却不知道 可以传入个数参数
当我们还开为这中需求苦恼,并且写一堆js时,vue源码中已经写出来如此优秀的代码,值得参考
export function toArray (list: any, start?: number): Array<any> {// sjf-note-best-codestart = start || 0let i = list.length - startconst ret: Array<any> = new Array(i)// new Array() 创建一个空数组// new Array(i) 创建i个为空的数组// 相当于 Array.fill(0,i,undefined)while (i--) {ret[i] = list[i + start]//先将 i = list.length - start // 然后将 i + start // 则 最后的 i + start 仍然等于 list.length// 只不过是i 的值是从 list.length - start 到 0 递减// 当i的值为0时,循环结束}// while循环的优点是,即即使数组的数据没有处理完成,并且不需要break或者return false 以及 throw new Error()来结束循环,就可以自动结束循环return ret// 将处理好的数组返回
}
isPlainObject
- 代码引用地址 src\vue-2.6.14\src\shared\util.js
- 判断 数据类型是否是 object
export function isPlainObject (obj: any): boolean {return _toString.call(obj) === '[object Object]'
}
validateComponentName
- 代码引用地址 src\vue-2.6.14\src\core\util\options.js
- 校验组件名是否合法
export function validateComponentName (name: string) {if (!new RegExp(`^[a-zA-Z][\\-\\.0-9_${unicodeRegExp.source}]*$`).test(name)) {warn('Invalid component name: "' + name + '". Component names ' +'should conform to valid custom element name in html5 specification.')}if (isBuiltInTag(name) || config.isReservedTag(name)) {// warn('Do not use built-in or reserved HTML elements as component ' +'id: ' + name)}
}
isBuiltInTag 判断组件名是不是Vue内置的
- 引用地址 src\vue-2.6.14\src\shared\util.js
export const isBuiltInTag = makeMap('slot,component', true)
// 判断组件名是不是内置的标签,不是原生html的标签而是vue内置的标签
isReservedTag
- 判断是否是 原生html或者isSVG标签
export const isReservedTag = (tag: string): ?boolean => {return isHTMLTag(tag) || isSVG(tag)
}
export const isHTMLTag = makeMap('html,body,base,head,link,meta,style,title,' +'address,article,aside,footer,header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,' +'div,dd,dl,dt,figcaption,figure,picture,hr,img,li,main,ol,p,pre,ul,' +'a,b,abbr,bdi,bdo,br,cite,code,data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,' +'s,samp,small,span,strong,sub,sup,time,u,var,wbr,area,audio,map,track,video,' +'embed,object,param,source,canvas,script,noscript,del,ins,' +'caption,col,colgroup,table,thead,tbody,td,th,tr,' +'button,datalist,fieldset,form,input,label,legend,meter,optgroup,option,' +'output,progress,select,textarea,' +'details,dialog,menu,menuitem,summary,' +'content,element,shadow,template,blockquote,iframe,tfoot'
)
export const isSVG = makeMap('svg,animate,circle,clippath,cursor,defs,desc,ellipse,filter,font-face,' +'foreignobject,g,glyph,image,line,marker,mask,missing-glyph,path,pattern,' +'polygon,polyline,rect,switch,symbol,text,textpath,tspan,use,view',true
)
致谢
- 感谢vue源码给予了我学习借鉴的机会
- 感谢日常项目中给我的锻炼
- 这篇文章是vue初始化流程的代码,其实没什么难度,但是这是最开始的一步,无法跳过,后期会有核心代码的分析,如果感兴趣请关注
- 感谢您百忙之中抽时间阅读我写的博客,谢谢你的肯定,也希望对您能有所帮助
- 如果您有更好的见解请在评论区留言或者私聊我,期待与您的交流
相关文章:

vue2源码分析-vue入口文件global-api分析
文章背景 vue项目开发过程中,首先会有一个初始化的流程,以及我们会使用到很多全局的api,如 this.$set this.$delete this.$nextTick,以及初始化方法extend,initUse, initMixin , initExtend, initAssetRegisters 等等那它们是怎么实现,让我们一起来探究下吧 源码目录 global-…...

Javascript原型 ,原型链如何理解使用 ?有什么特点?
文章目录 图解原型原型链总结有需要的请私信博主,还请麻烦给个关注,博主不定期更新,或许能够有所帮助!!请关注公众号 图解 原型 常被描述为 — 种基于原型的语言–每个对象拥有一个原型对象 当试图访问 一个对象的属性…...

Flutter混合栈管理方案对比
1.Google官方(多引擎方案) Google官方建议的方式是多引擎方案,即每次使用一个新的FlutterEngine来渲染Widget树,存在的主要问题是每个引擎都要有比较大的内存等资源消耗,虽然Flutter 2.0之后的FlutterEngineGroup通过在…...

Asp .Net Core 集成 Newtonsoft.Json
简介 Newtonsoft.Json是一个在.NET环境下开源的JSON格式序列化和反序列化的类库。它可以将.NET对象转换为JSON格式的字符串,也可以将JSON格式的字符串转换为.NET对象。这个类库在.NET开发中被广泛使用,因为它功能强大、易于使用,并且有良好的性能。 使用Newtonsoft.Json,…...

GPT对话知识库——ARM-Cortex架构分为哪几个系列?每个系列有几种工作模式?各种工作模式之间的定义和区别?每种架构不同的特点和应用需求?
目录 1,问: 1,答: 2,问: 2,答: Cortex-A系列 Cortex-R系列 Cortex-M系列 3,问: 3,答: ARM Cortex-A架构 ARM Cortex-R架构…...

795. 前缀和(acwing)
文章目录 795.前缀和题目描述前缀和 795.前缀和 题目描述 输入一个长度为n的整数序列。 接下来再输入m个询问,每个询问输入一对l, r。 对于每个询问,输出原序列中从第l个数到第r个数的和。 输入格式 第一行包含两个整数n和m。 第二行包含n个整数&a…...

1910_野火FreeRTOS教程阅读笔记_prvStartFirstTask函数
1910_野火FreeRTOS教程阅读笔记_prvStartFirstTask函数 全部学习汇总: g_FreeRTOS: FreeRTOS学习笔记 这是教程中的一个函数,通过汇编来实现的。注释部分以及结合后面的讲解部分,可能还是有一点点细节的地方让初学者疑惑。我结合我自己的理解…...
图论练习5
Going Home Here 解题思路 模板 二分图最优匹配,前提是有完美匹配(即存在一一配对)左右集合分别有顶标,当时,为有效边,即选中初始对于左集合每个点,选择其连边中最优的,然后对于每…...

[C++] Volatile 和常量Const优化
Volatile的作用 volatile 表明某个变量的值可能在外部被改变,因此对这些变量的存取不能缓存到寄存器,每次使用时需要重新存取。 Const 和 Volatile的示例 示例1 int main() {const int a 1;int* pa const_cast<int*>(&a);*pa 4;cout &l…...

嵌入式学习day32 网络
htons();//host to network short 将端口号转换为网络通信中的大端存储 eg:htons(50000); ntohs();//host to network short 将大端存储转换为主机端口号 inet_addr();将IP地址转换为二进制 eg:inet_addr(192.168.1.170); inet_ntoa()…...

算法D33 | 贪心算法3 | 1005.K次取反后最大化的数组和 134. 加油站 135. 分发糖果
1005.K次取反后最大化的数组和 本题简单一些,估计大家不用想着贪心 ,用自己直觉也会有思路。 代码随想录 Python: class Solution:def largestSumAfterKNegations(self, nums: List[int], k: int) -> int:nums.sort(keylambda x: abs(x), reverseT…...

html地铁跑酷
下面是一个简单的HTML代码来展示一个地铁跑酷游戏: <!DOCTYPE html> <html> <head><title>地铁跑酷</title><style>#player {position: absolute;top: 0;left: 0;width: 50px;height: 50px;background-color: red;}</style…...

利用GPT开发应用001:GPT基础知识及LLM发展
文章目录 一、惊艳的GPT二、大语言模型LLMs三、自然语言处理NLP四、大语言模型LLM发展 一、惊艳的GPT 想象一下,您可以与计算机的交流速度与与朋友交流一样快。那会是什么样子?您可以创建哪些应用程序?这正是OpenAI正在助力构建的世界&#x…...

Golang Ants 构建协程池
构建的协程池实现两个目标: 1、限制协程池里开启的协程数量 2、当任务数大于协程数时,一个协程可以同时处理多个任务 3、监控是哪个协程ID处理了具体的任务 package mainimport ("fmt""runtime""strconv""string…...

【金三银四】面试题汇总(持续编写中)
Java八股文面试题汇总(持续编写中~) Java基础集合JUCJVM 数据库MySQLRedis 框架篇SSMSpringBoot 数据结构与算法数据结构与算法--汇总篇27道基础算法题,学完让你对算法有豁然开朗的感觉(推荐小白) 消息中间件RabbitMQK…...

Hive的数据存储
Hive的数据存储在HDFS的:/user/hive/warehouse中 The /user folder in HDFS is a directory typically used to store user-specific data and configurations. It serves as the home directory for Hadoop users, analogous to the /home directory in Unix-like …...

ORACLE 如何使用dblink实现跨库访问
dbLink是简称,全称是databaselink。database link是定义一个数据库到另一个数据库的路径的对象,database link允许你查询远程表及执行远程程序。在任何分布式环境里,database都是必要的。另外要注意的是database link是单向的连接。在创建dat…...

Sentinel 面试题及答案整理,最新面试题
Sentinel的流量控制规则有哪些,各自的作用是什么? Sentinel的流量控制规则主要包括以下几种: 1、QPS(每秒查询量)限流: 限制资源每秒的请求次数,适用于控制高频访问。 2、线程数限流…...

Qt在windows编译hiredis依赖库
目录 0 前言1 Qt安装遇到的问题2 hiredis源码下载2.0 redis源码下载2.1 hiredis源码下载2.2 编译hiredis源码2.3 遇到的问题列表参考资料0 前言 当前参与的项目需要用Qt对redis进行操作,以前没玩过这块,顺手记下笔记梳理起来~ 1 Qt安装 安装版本下载:https://download.qt…...

【工作向】protobuf编译生成pb.cc和pb.py文件
序言 首先通过protoc --version查看protoc版本,避免pb文件生成方和使用方版本不一致 1. 生成pb.cc 生成命令 protoc -I${proto_file_dir} --cpp_out${pb_file_dir} *.proto参数: -I表示 proto 文件的路径; --cpp_out 表示输出路径ÿ…...

android 快速实现 垂直SeekBar(VerticalSeekBar)
1.话不多说上源码: package com.example.widget;import android.content.Context; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.MotionEvent;/*** Class to create a vertical slider*/ public class VerticalSeekBar…...

算法刷题day23:双指针
目录 引言概念一、牛的学术圈I二、最长连续不重复序列三、数组元素的目标和四、判断子序列五、日志统计六、统计子矩阵 引言 关于这个双指针算法,主要是用来处理枚举子区间的事,时间复杂度从 O ( N 2 ) O(N^2) O(N2) 降为 O ( N ) O(N) O(N) …...

学术论文GPT的源码解读与二次开发:从ChatPaper到gpt_academic
前言 本文的前两个部分最早是属于此旧文的《学术论文GPT的源码解读与微调:从ChatPaper到七月论文审稿GPT第1版》,但为了每一篇文章各自的内容更好的呈现,于是我今天做了以下三个改动 原来属于mamba第五部分的「Mamba近似工作之线性Transfor…...

报表生成器FastReport .Net用户指南:表达式(下)
在上一篇文章《报表生成器FastReport .Net用户指南:表达式(上)》中,我们已经介绍了表达式中的表达式编辑器、引用报告对象、使用 .Net 函数、数据元素参考这四部分,接下来让我们继续介绍表达式中的:引用数据…...

JavaScript极速入门(1)
初识JavaScript JavaScript是什么 JavaScript(简称JS),是一个脚本语言,解释型或者即时编译型语言.虽然它是作为开发Web页面的脚本语言而著名,但是也应用到了很多非浏览器的环境中. 看似这门语言叫JavaScript,其实在最初发明之初,这门语言的名字其实是在蹭Java的热度,实际上和…...

鸿蒙Harmony应用开发—ArkTS声明式开发(通用属性:浮层)
设置组件的遮罩文本。 说明: 从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 overlay overlay(value: string | CustomBuilder, options?: { align?: Alignment; offset?: { x?: number; y?: number } })…...

Meta AI移动设备上部署LLM的新框架MobileLLM
Meta AI 研究团队推出的 MobileLLM 标志着大语言模型(LLMs)朝着模拟人类理解和生成自然语言迈出了革命性的一步。LLMs 在处理和分析大量数据集方面的能力已经显著影响了自动化客户服务、语言翻译和内容创作等多个领域。然而,由于传统 LLMs 在计算和存储资源方面的需求庞大,…...

使用Tesseract-OCR对PDF等图片文件进行文字识别
安装 用 Homebrew 来安装 Tesseract brew install tesseract 2. 完成 tessearact 的安装后,还需要安装中文数据包,执行以下两个操作, brew info tesseract 执行这个指令的目的,是找到 Homebrew 把 tesseract 安装在文件夹内&am…...

部署YOLOv8模型的实用常见场景
可以的话,GitHub上点个小心心,翻不了墙的xdm,csdn也可以点个赞,谢谢啦 车流量检测(开源代码github): test3 meiqisheng/YOLOv8-DeepSORT-Object-Tracking (github.com) 车牌检测࿰…...

SpringBoot缓存
目录 缓存支持 缓存集成 redis缓存集成 缓存支持 Spring 框架只提供抽象,不提供具体的缓存存储,底层需要依赖第三方存储组件,如果当前应用没有注册CacheManager 或者 CacheResolver 实例,Spring Boot 会按以下缓存组件的顺序来…...