Vue2.x源码:new Vue()做了啥?
创始人
2025-05-30 01:52:12

vue源码版本vue2.5.2

new Vue()做了啥?

new Vue()会执行_init方法,而_init方法在initMixin函数中定义。

src/core/instance/index.js文件中定义了Vue

function Vue (options) {this._init(options)
}initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)export default Vue

initMixin函数 初始化

定义的Vue.prototype._init

 export function initMixin (Vue: Class) {Vue.prototype._init = function (options?: Object) {const vm: Component = this// a uid,自增IDvm._uid = uid++vm._isVue = true// merge options 合并optionsif (options && options._isComponent) {initInternalComponent(vm, options)} else {vm.$options = mergeOptions(resolveConstructorOptions(vm.constructor),options || {},vm)}vm._renderProxy = vm// expose real selfvm._self = vm// 初始化生命周期相关实例属性initLifecycle(vm)//初始化事件initEvents(vm)//定义$createElement() createElement的执行过程initRender(vm)// 执行beforeCreate生命周期钩子callHook(vm, 'beforeCreate')initInjections(vm) // resolve injections before data/props//将data代理至Vue._data data的代理initState(vm)// 初始化provideinitProvide(vm) // resolve provide after data/props// 执行created生命周期钩子callHook(vm, 'created')// 当options中存在el属性,则执行挂载if (vm.$options.el) {//挂载#app $mount执行过程vm.$mount(vm.$options.el)}}
}

initLifecycle函数

initLifecycle 初始化生命周期相关变量即在vue实例上挂载一些属性并设置默认值,如$parent,$root,$children,$ref,vm._watcher,vm.__inactive,vm._directInactive,vm._isMounted,vm._isDestroyed,vm._isBeingDestroyed

export function initLifecycle (vm: Component) {const options = vm.$options// locate first non-abstract parentlet parent = options.parent//当前组件存在父级并且当前组件不是抽象组件if (parent && !options.abstract) {//通过while循环来向上循环,如果当前组件的父级是抽象组件并且也存在父级,那就继续向上查找当前组件父级的父级while (parent.$options.abstract && parent.$parent) {//更新parentparent = parent.$parent}//把该实例自身添加进找到的父级的$children属性中parent.$children.push(vm)}//直到找到第一个不是抽象类型的父级时,将其赋值vm.$parentvm.$parent = parent//设置实例根元素。判断如果当前实例存在父级,那么当前实例的根实例$root属性就是其父级的根实例$root属性,如果不存在,那么根实例$root属性就是它自己vm.$root = parent ? parent.$root : vmvm.$children = []vm.$refs = {}vm._watcher = nullvm._inactive = nullvm._directInactive = false//实例是否已挂载vm._isMounted = false//实例是否已销毁vm._isDestroyed = false//实例是否正准备销毁vm._isBeingDestroyed = false
}

initEvents 初始化事件

initEvents 初始化事件。 初始化的是父组件在模板中使用v-on或@注册的监听子组件内触发的事件。

export function initEvents (vm: Component) {
//在vm上新增_events属性并将其赋值为空对象,用来存储事件。vm._events = Object.create(null)vm._hasHookEvent = false// init parent attached events//获取父组件注册的事件赋给listeners,const listeners = vm.$options._parentListeners//如果listeners不为空,则调用updateComponentListeners函数,将父组件向子组件注册的事件注册到子组件的实例中if (listeners) {updateComponentListeners(vm, listeners)}
}

初始化渲染initRender

initRender函数 初始化渲染.。

export function initRender (vm: Component) {vm._vnode = null // the root of the child treevm._staticTrees = null // v-once cached treesconst options = vm.$optionsconst parentVnode = vm.$vnode = options._parentVnode // the placeholder node in parent treeconst renderContext = parentVnode && parentVnode.context//实例上插槽vm.$slots = resolveSlots(options._renderChildren, renderContext)vm.$scopedSlots = emptyObject//在实例上定义_c函数和$_createElement函数vm._c = (a, b, c, d) => createElement(vm, a, b, c, d, false)vm.$createElement = (a, b, c, d) => createElement(vm, a, b, c, d, true)const parentData = parentVnode && parentVnode.datadefineReactive(vm, '$attrs', parentData && parentData.attrs || emptyObject, null, true)defineReactive(vm, '$listeners', options._parentListeners || emptyObject, null, true)}

初始化inject选项

inject 选项中的每一个数据key都是由其上游父级组件提供的,所以我们应该把每一个数据key从当前组件起,不断的向上游父级组件中查找该数据key对应的值,直到找到为止。如果在上游所有父级组件中没找到,那么就看在inject 选项是否为该数据key设置了默认值,如果设置了就使用默认值,如果没有设置,则抛出异常。

export function initInjections (vm: Component) {
//调用resolveInject把inject选项中的数据转化成键值对的形式赋给resultconst result = resolveInject(vm.$options.inject, vm)if (result) {toggleObserving(false)//遍历result中的每一对键值Object.keys(result).forEach(key => {//调用defineReactive函数将其添加当前实例上defineReactive(vm, key, result[key])})toggleObserving(true)}
}

注意,在把result中的键值添加到当前实例上之前,会先调用toggleObserving(false),而这个函数内部是把shouldObserve = false,这是为了告诉defineReactive函数仅仅是把键值添加到当前实例上而不需要将其转换成响应式

resolveInject函数内部是如何把inject 选项中数据转换成键值对的。

export function resolveInject (inject: any, vm: Component): ?Object {if (inject) {// inject is :any because flow is not smart enough to figure out cached//创建一个空对象result,用来存储inject 选项中的数据key及其对应的值,作为最后的返回结果。const result = Object.create(null)const keys = hasSymbol? Reflect.ownKeys(inject).filter(key => {/* istanbul ignore next */return Object.getOwnPropertyDescriptor(inject, key).enumerable}): Object.keys(inject)for (let i = 0; i < keys.length; i++) {const key = keys[i]//provideKey就是上游父级组件提供的源属性const provideKey = inject[key].fromlet source = vm//while循环,从当前组件起,不断的向上游父级组件的_provided属性中(父级组件使用provide选项注入数据时会将注入的数据存入自己的实例的_provided属性中)查找,直到查找到源属性的对应的值,将其存入result中while (source) {if (source._provided && hasOwn(source._provided, provideKey)) {result[key] = source._provided[provideKey]break}source = source.$parent}if (!source) {//是否有default属性,如果有的话,则拿到这个默认值,官方文档示例中说了,默认值可以为一个工厂函数,所以当默认值是函数的时候,就去该函数的返回值,否则就取默认值本身。如果没有设置默认值,则抛出异常。if ('default' in inject[key]) {const provideDefault = inject[key].defaultresult[key] = typeof provideDefault === 'function'? provideDefault.call(vm): provideDefault} else if (process.env.NODE_ENV !== 'production') {warn(`Injection "${key}" not found`, vm)}}}return result}
}

官方文档中说inject 选项可以是一个字符串数组,也可以是一个对象,在上面的代码中只看见了处理当为对象的情况,那如果是字符串数组呢?怎么没有处理呢?
其实在初始化阶段_init函数在合并属性的时候还调用了一个将inject 选项数据规范化的函数normalizeInject

初始化initState

从Vue 2.0版本起,Vue不再对所有数据都进行侦测,而是将侦测粒度提高到了组件层面,对每个组件进行侦测,所以在每个组件上新增了vm._watchers属性,用来存放这个组件内用到的所有状态的依赖,当其中一个状态发生变化时,就会通知到组件,然后由组件内部使用虚拟DOM进行数据比对,从而降低内存开销,提高性能。

export function initState (vm: Component) {
//实例上新增了一个属性_watchers,用来存储当前实例中所有的watcher实例,无论是使用vm.$watch注册的watcher实例还是使用watch选项注册的watcher实例,都会被保存到该属性中。vm._watchers = []const opts = vm.$options//先判断实例中是否有props选项,如果有,就调用props选项初始化函数initProps去初始化props选项;if (opts.props) initProps(vm, opts.props)//先判断实例中是否有props选项,如果有,就调用props选项初始化函数initProps去初始化props选项;if (opts.methods) initMethods(vm, opts.methods)//接着再判断实例中是否有data选项,如果有,就调用data选项初始化函数initData去初始化data选项;如果没有,就把data当作空对象并将其转换成响应式if (opts.data) {initData(vm)} else {observe(vm._data = {}, true /* asRootData */)}//接着再判断实例中是否有computed选项,如果有,就调用computed选项初始化函数initComputed去初始化computed选项if (opts.computed) initComputed(vm, opts.computed)//最后判断实例中是否有watch选项,如果有,就调用watch选项初始化函数initWatch去初始化watch选项if (opts.watch && opts.watch !== nativeWatch) {initWatch(vm, opts.watch)}
}

开发中有注意到我们在data中可以使用props,在watch中可以观察data和props,之所以可以这样做,就是因为在初始化的时候遵循了这种顺序,先初始化props,接着初始化data,最后初始化watch。

props处理initProps

在此之前,在合并options时已将props规范化

function initProps (vm: Component, propsOptions: Object) {
//propsData,父组件传入的真实props数据const propsData = vm.$options.propsData || {}//props,指向vm._props的指针,所有设置到props变量中的属性都会保存到vm._props中const props = vm._props = {}// cache prop keys so that future props updates can iterate using Array// instead of dynamic object key enumeration.//指向vm.$options._propKeys的指针,缓存props对象中的key,将来更新props时只需遍历vm.$options._propKeys数组即可得到所有props的keyconst keys = vm.$options._propKeys = []//当前组件是否为根组件const isRoot = !vm.$parent// root instance props should be converted//如果不是,那么不需要将props数组转换为响应式的,toggleObserving(false)用来控制是否将数据转换成响应式if (!isRoot) {toggleObserving(false)}for (const key in propsOptions) {keys.push(key)//调用validateProp函数校验父组件传入的props数据类型是否匹配并获取到传入的值valueconst value = validateProp(key, propsOptions, propsData, vm)//将键和值通过defineReactive函数添加到props(即vm._props)中defineReactive(props, key, value)// static props are already proxied on the component's prototype// during Vue.extend(). We only need to proxy props defined at// instantiation here.//判断这个key在当前实例vm中是否存在,如果不存在,则调用proxy函数在vm上设置一个以key为属性的代码,当使用vm[key]访问数据时,其实访问的是vm._props[key]if (!(key in vm)) {proxy(vm, `_props`, key)}}toggleObserving(true)
}

methods处理initMethods

function initMethods (vm: Component, methods: Object) {const props = vm.$options.propsfor (const key in methods) {if (process.env.NODE_ENV !== 'production') {//如果methods中某个方法只有key而没有方法体时,抛出异常:提示用户方法未定义if (typeof methods[key] !== 'function') {warn(`Method "${key}" has type "${typeof methods[key]}" in the component definition. ` +`Did you reference the function correctly?`,vm)}//如果methods中某个方法名与props中某个属性名重复了,就抛出异常:提示用户方法名重复了if (props && hasOwn(props, key)) {warn(`Method "${key}" has already been defined as a prop.`,vm)}//判断如果methods中某个方法名如果在实例vm中已经存在并且方法名是以_或$开头的,就抛出异常:提示用户方法名命名不规范if ((key in vm) && isReserved(key)) {warn(`Method "${key}" conflicts with an existing Vue instance method. ` +`Avoid defining component methods that start with _ or $.`)}}//将method绑定到实例vm上,然后通过this.xxx来访问methods选项中的xxx方法了vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm)}
}

data处理initData

function initData (vm: Component) {//获取到用户传入的data选项,赋给变量data,同时将变量data作为指针指向vm._data,然后判断data是不是一个函数,如果是就调用getData函数获取其返回值,将其保存到vm._data中。如果不是,就将其本身保存到vm._data中let data = vm.$options.datadata = vm._data = typeof data === 'function'? getData(data, vm): data || {}//如果不是对象的话,就抛出警告:提示用户data应该是一个对象。if (!isPlainObject(data)) {data = {}process.env.NODE_ENV !== 'production' && warn('data functions should return an object:\n' +'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',vm)}// proxy data on instanceconst keys = Object.keys(data)const props = vm.$options.propsconst methods = vm.$options.methodslet i = keys.lengthwhile (i--) {const key = keys[i]if (process.env.NODE_ENV !== 'production') {//判断data对象中是否存在某一项的key与methods中某个属性名重复,如果存在重复,就抛出警告:提示用户属性名重复。if (methods && hasOwn(methods, key)) {warn(`Method "${key}" has already been defined as a data property.`,vm)}}//判断是否存在某一项的key与prop中某个属性名重复,如果存在重复,就抛出警告:提示用户属性名重复if (props && hasOwn(props, key)) {process.env.NODE_ENV !== 'production' && warn(`The data property "${key}" is already declared as a prop. ` +`Use prop default value instead.`,vm)//调用proxy函数将data对象中key不以_或$开头的属性代理到实例vm上,这样,我们就可以通过this.xxx来访问data选项中的xxx数据了} else if (!isReserved(key)) {proxy(vm, `_data`, key)}}// observe data//调用observe函数将data中的数据转化成响应式observe(data, true /* asRootData */)
}

computed处理initComputed

function initComputed (vm: Component, computed: Object) {// $flow-disable-line//义了一个变量watchers并将其赋值为空对象,同时将其作为指针指向vm._computedWatchersconst watchers = vm._computedWatchers = Object.create(null)// computed properties are just getters during SSRconst isSSR = isServerRendering()for (const key in computed) {//遍历computed选项中的每一项属性,首先获取到每一项的属性值,记作userDefconst userDef = computed[key]
//判断userDef是不是一个函数,如果是函数,则该函数默认为取值器getter,将其赋值给变量getter;如果不是函数,则说明是一个对象,则取对象中的get属性作为取值器赋给变量getterconst getter = typeof userDef === 'function' ? userDef : userDef.get//如果上面两种情况取到的取值器不存在,则抛出警告:提示用户计算属性必须有取值器if (process.env.NODE_ENV !== 'production' && getter == null) {warn(`Getter is missing for computed property "${key}".`,vm)}if (!isSSR) {// create internal watcher for the computed property.//判断如果不是在服务端渲染环境下,则创建一个watcher实例,并将当前循环到的的属性名作为键,创建的watcher实例作为值存入watchers对象中watchers[key] = new Watcher(vm,getter || noop,noop,computedWatcherOptions)}// component-defined computed properties are already defined on the// component prototype. We only need to define computed properties defined// at instantiation here.//判断当前循环到的的属性名是否存在于当前实例vm上if (!(key in vm)) {//不存在,调用defineComputed函数为实例vm上设置计算属性defineComputed(vm, key, userDef)} else if (process.env.NODE_ENV !== 'production') {//存在,则在非生产环境下抛出警告if (key in vm.$data) {warn(`The computed property "${key}" is already defined in data.`, vm)} else if (vm.$options.props && key in vm.$options.props) {warn(`The computed property "${key}" is already defined as a prop.`, vm)}}}
}

defineComputed函数 该函数接受3个参数,分别是:target、key和userDef。其作用是为target上定义一个属性key,并且属性key的getter和setter根据userDef的值来设置

export function defineComputed (target: any,key: string,userDef: Object | Function
) {
//义了变量sharedPropertyDefinition,它是一个默认的属性描述符。
//定义了变量shouldCache,用于标识计算属性是否应该有缓存。该变量的值是当前环境是否为非服务端渲染环境,如果是非服务端渲染环境则该变量为true。也就是说,只有在非服务端渲染环境下计算属性才应该有缓存const shouldCache = !isServerRendering()//判断如果userDef是一个函数,则该函数默认为取值器getterif (typeof userDef === 'function') {//判断如果userDef是一个函数,则该函数默认为取值器getter,此处在非服务端渲染环境下并没有直接使用userDef作为getter,而是调用createComputedGetter函数创建了一个getter,这是因为userDef只是一个普通的getter,它并没有缓存功能,所以我们需要额外创建一个具有缓存功能的getter,而在服务端渲染环境下可以直接使用userDef作为getter,因为在服务端渲染环境下计算属性不需要缓存。由于用户没有设置setter函数,所以将sharedPropertyDefinition.set设置为noopsharedPropertyDefinition.get = shouldCache? createComputedGetter(key): createGetterInvoker(userDef)sharedPropertyDefinition.set = noop} else {//如果userDef不是一个函数,那么就将它当作对象处理。在设置sharedPropertyDefinition.get的时候先判断userDef.get是否存在,如果不存在,则将其设置为noop,如果存在,则同上面一样,在非服务端渲染环境下并且用户没有明确的将userDef.cache设置为false时调用createComputedGetter函数创建一个getter赋给sharedPropertyDefinition.get。然后设置sharedPropertyDefinition.set为userDef.set函数sharedPropertyDefinition.get = userDef.get? shouldCache && userDef.cache !== false? createComputedGetter(key): createGetterInvoker(userDef.get): noopsharedPropertyDefinition.set = userDef.set || noop}if (process.env.NODE_ENV !== 'production' &&sharedPropertyDefinition.set === noop) {//如果用户没有设置setter的话,那么就给setter一个默认函数,这是为了防止用户在没有设置setter的情况下修改计算属性,从而为其抛出警告sharedPropertyDefinition.set = function () {warn(`Computed property "${key}" was assigned to but it has no setter.`,this)}}//调用Object.defineProperty方法将属性key绑定到target上,其中的属性描述符就是上面设置的sharedPropertyDefinitionObject.defineProperty(target, key, sharedPropertyDefinition)
}

createComputedGetter

该函数是一个高阶函数,其内部返回了一个computedGetter函数,所以其实是将computedGetter函数赋给了sharedPropertyDefinition.get。当获取计算属性的值时会执行属性的getter,而属性的getter就是 sharedPropertyDefinition.get,也就是说最终执行的 computedGetter函数

function createComputedGetter (key) {return function computedGetter () {//储在当前实例上_computedWatchers属性中key所对应的watcher实例const watcher = this._computedWatchers && this._computedWatchers[key]//如果watcher存在,则调用watcher实例上的depend方法和evaluate方法,并且将evaluate方法的返回值作为计算属性的计算结果返回if (watcher) {if (watcher.dirty) {watcher.evaluate()}if (Dep.target) {watcher.depend()}return watcher.value}}
}function createGetterInvoker(fn) {return function computedGetter () {return fn.call(this, this)}
}

initwatch处理

watch的几种写法

  watch: {a: function (val, oldVal) {console.log('new: %s, old: %s', val, oldVal)},// methods选项中的方法名b: 'someMethod',// 深度侦听,该回调会在任何被侦听的对象的 property 改变时被调用,不论其被嵌套多深c: {handler: function (val, oldVal) { /* ... */ },deep: true},// 该回调将会在侦听开始之后被立即调用d: {handler: 'someMethod',immediate: true},// 调用多个回调e: ['handle1',function handle2 (val, oldVal) { /* ... */ },{handler: function handle3 (val, oldVal) { /* ... */ },}],// 侦听表达式'e.f': function (val, oldVal) { /* ... */ }}

initWatch函数

function initWatch (vm: Component, watch: Object) {
//在函数内部会遍历watch选项for (const key in watch) {//拿到每一项的key和对应的值handlerconst handler = watch[key]//判断handler是否为数组,如果是数组则循环该数组并将数组中的每一项依次调用createWatcher函数来创建watcherif (Array.isArray(handler)) {for (let i = 0; i < handler.length; i++) {createWatcher(vm, key, handler[i])}//不是数组,则直接调用createWatcher函数来创建watcher} else {createWatcher(vm, key, handler)}}
}

createWatcher 函数

function createWatcher (vm: Component,//当前实例keyOrFn: string | Function,//被侦听的属性表达式handler: any,//watch选项中每一项的值options?: Object//用于传递给vm.$watch的选项对象
) {
//判断handle是一个对象时,handler = handler.handlerif (isPlainObject(handler)) {options = handlerhandler = handler.handler}
//如果handle是一个字符串,则直接在实例上找if (typeof handler === 'string') {handler = vm[handler]}return vm.$watch(keyOrFn, handler, options)
}

分开解析-如果是一个对象

  if (isPlainObject(handler)) {//将handler对象整体记作optionsoptions = handler//把handler对象中的handler属性作为真正的回调函数记作handlerhandler = handler.handler}

则为以下情况

watch:{c: {handler: function (val, oldVal) { /* ... */ },deep: true},// 该回调将会在侦听开始之后被立即调用d: {handler: 'someMethod',immediate: true},}

分开解析-如果handler为一个字符串

if (typeof handler === 'string') {handler = vm[handler]
}

则为以下情况

watch:{// methods选项中的方法名b: 'someMethod',}

Vue.prototype.$watch

 //src\core\instance\state.js
Vue.prototype.$watch = function (expOrFn: string | Function,cb: any,options?: Object
): Function {const vm: Component = this
//判断回调函数是否是一个对象if (isPlainObject(cb)) {return createWatcher(vm, expOrFn, cb, options)}options = options || {}options.user = trueconst watcher = new Watcher(vm, expOrFn, cb, options)if (options.immediate) {cb.call(vm, watcher.value)}return function unwatchFn () {watcher.teardown()}
}

初始化provide

var Parent = {provide: {foo: 'bar'},// ...
}const Provider = {provide () {return {[s]: 'foo'}}
}
export function initProvide (vm: Component) {const provide = vm.$options.provideif (provide) {vm._provided = typeof provide === 'function'? provide.call(vm): provide}
}

相关内容

热门资讯

游戏“第一省”,坐不住了! 游... 文/冯玲玲游戏大省广东坐不住了。近日,广东发布《关于推动广东网络游戏产业高质量发展的若干政策措施》(...
并购重组预期加持!宜宾纸业股价... 本报(chinatimes.net.cn)记者何一华 李未来 北京报道宜宾纸业(600793.SH)...
德邦证券董事会大洗牌:梁雷任董... 新京报贝壳财经讯(记者胡萌)5月30日,德邦证券公示新一届董事会、监事会人员,公司新一任董事长由山东...
原创 成... 今年以来,成都的舞厅经历了比较长时间的整顿,多数舞厅在5月8日获准重新开门营业,到现在已经稳定运行了...
“小雨伞”母公司手回集团港股上... 5月30日,手回集团(2621.HK)在港交所上市。根据手回集团此前披露,此次IPO,手回集团发行2...
决策曲线拆解分析兼随机森林DC... 临床决策曲线(DCA)解析兼绘制随机森林的DCA曲线(R&...
异动快报:海格通信(00246... 证券之星5月30日盘中消息,13点45分海格通信(002465)触及涨停板。目前价格13.89,上涨...
商丘,三线城市!排名第29位! 第一财经·新一线城市研究所5月28日发布《2025新一线城市魅力排行榜》,在中国内地337座地级及以...
传统药企转型面临两难选择?放弃... 近日誉衡药业(002437.SZ)公告称,公司于2025年5月23日与兴和制药有限公司就佩玛贝特片签...
版权代理吃相太难看,连作者都觉... 一家可能都没授权资格的公司,居然也敢向自媒体发律师函讨要版权费。这事儿听起来是不是有点离谱了?最近,...
V观财报|*ST京蓝因涉嫌信披...   中新经纬5月30日电 30日晚,*ST京蓝公告,收到立案告知书。  公告显示,因涉嫌信息披露违法...
Java基础--日期API学习 一、前言         java标准库中,最早提供了两种处理日期和时间的类ÿ...
ES调试与优化工作笔记 本文主要涉及关于elastcisearch 关于内存,mapping,查...
两券商IT人员曝出老鼠仓,一位... 财联社5月30日讯(记者 高艳云)5月30日,安徽证监局与吉林证监局同日披露罚单,两名券商资深IT人...
Labubu太火了!英国人为抢... 最近在英国,有一样毛绒玩具红到了“出圈”,甚至让人忍不住怀疑:这到底是抢玩具,还是在打仗?这里,说的...
MySQL-分库分表方案 一、业务背景 随着业务量的增长,数据量会随之增长,单机情况下DB服务器会...
堆、堆排序 堆的基本操作操作:         1、插入一个数:          ...
广东1130亿饮料富豪,第二个... 来源 | 深蓝财经撰文 | 杨波近日,东鹏饮料赴港上市的消息持续引发关注。一个市值超1600亿,手握...
赵小中连任,长沙银行还有道“考... 文丨徐风5月21日,长沙银行在召开股东大会的同时完成了董事会的换届选举,赵小中当选第八届董事长,实现...
嘉应制药遭证监会立案调查,直指... 5月28日晚间,老牌药企广东嘉应制药股份有限公司(002198.SZ,下称“嘉应制药”)发布公告,公...
腾讯三大工具:ARC+智影+E... ARC实验室(网站) ARC官网-腾讯 (tencent.com)  ...
个人小站折腾后记 个人小站折腾后记 🏠个人主页:shark-Gao 🧑个...
华夏银行聘任龚伟华为首席信息官... 作者 | 林秋彤编辑 | 杨希新媒体编辑丨实习生 宋语菡5月30日,华夏银行发布公告称,吴永飞因到龄...
ST百利:收到湖南证监局《行政... 5月30日晚间,湖南百利工程科技股份有限公司(ST百利,603959.SH)公告,5月29日,公司收...
天元宠物重大资产重组,最大受益... “宠物代工龙头”天元宠物披露了收购案的最新进展。5月29日晚间,杭州天元宠物用品股份有限公司(下称“...
上手Servlet程序 目录 1、手动打包 1.1、创建项目 1.2、引入依赖 1.3、创建目录 1.4、编写代码 1.5、...
第一次认真周赛总结 T1:一个 整数的 二进制形式中 奇数位上bit==1 和 偶数 位上bit=...
1年进账270亿,深圳中药龙头... 最近,华润三九陷入了“悲喜交加”之中。喜的是,2024年华润三九的营收、净利润皆创新高,营收为276...
论文阅读:MPViT : Mu... 中文标题:基于多路视觉Transformer的密集预测 提出问题 创新点 提出了一种...
前安克创新创始人创业公司冲刺I... 近期,深圳智岩科技股份有限公司(以下简称“智岩科技”)正式启动上市辅导,辅导机构为中金公司。智岩科技...