一行代码说起-盲人摸象

JS就是一门这样的语言,你无时不刻想骂娘,但是不知不觉中,你就也写出了当年骂娘的语法,并且窃喜到:这个磨人的小妖精。

后记:这篇博文,最贴切的名字,应该是,在VUE3中的setUp方法中,如何拿到dom的ref引用。

再次后记

终于在官方文档中读到了这种用法的出处:
在虚拟 DOM 补丁算法中,如果 VNode 的 ref 键对应于渲染上下文中的 ref,则 VNode 的相应元素或组件实例将被分配给该 ref 的值。这是在虚拟 DOM 挂载/打补丁过程中执行的,因此模板引用只会在初始渲染之后获得赋值。
在这里插入图片描述

分割线

在一个vue2项目里,瞄到了同事一行代码,大意如下:

//模板
<template>
	<div>
		<qhse-detail ref="detailRef" />
		<div @click="detailRef.onView(row.id)"></div>
	</div>
<template>
//js
<script lang="ts">
import { defineComponent, reactive, ref, toRefs } from '@vue/composition-api'

export default defineComponent({
	setup(props) {
		 const detailRef = ref<{ onView?: (id: string) => void }>()
		 return { detailRef }
	}
})

 </script>

通过composition-api,使可以使用vue3中的api。

当时看到const detailRef = ref<{ onView?: (id: string) => void }>()这行代码的时候,是很蒙圈的。因为对ref()方法的认知比较浅显,结合官网和一干博文关于ref(),reactive(),toRef(),toRefs等API的介绍,我的认知还停留在ref()肯定会有入参这一观念上。

ref()

首先明确一点,在setup方法中,vue中的this是还没有初始化出来的。而在模板中绑定的内部数据,调用的内部方法以及一干响应式的效果,都是基于this的。对于那些在this还为初始化完成就想在模板中使用的数据,vue2中要使用类似于Vue.set( target, propertyName/index, value )或者Object.assign(this.obj, { d: 4 })这样的API。

而在setup方法中,最后的return语句包含的属性,可以在this还没有被初始化出来的时候就可以使用(这个表述我自己也存疑。PS:后记,这句话确实不准确,最新的解释是,在setup方法中,返回的属性,不用显示的声明在vuedata中,就可以通过this访问。),并且在this初始化之后,同名属性也会被包含在this中。

分割线
        <div @click="demoClick" style="height: 100px; width: 100px; background: red">
            {{ demoRef }}
        </div>

	setup(props) {
		const demoRef = ref(0)
        setTimeout(() => {
        	//这里要通过value改变值
            demoRef.value = 1
            //demoRef在这里,是object
            console.log(typeof demoRef)
        }, 1000)
	},
	 methods: {
        demoClick() {
            console.log(this.demoRef)
            //demoRef在这里,是number了!!!!
            console.log(typeof this.demoRef)
            //所以,改变demoRef的值,直接赋值
            this.demoRef = 2
        }
    }

上面代码,在setup方法中,创建了demoRef,并且绑定到页面上,页面渲染成功后,div中的值是0,此时demoRef是一个对象;延迟执行的方法中,要想改变demoRef的值,要通过value,页面同时变成1。在点击事件中,demoRef的类型就已经是number了,改变它的值,直接赋值就可,页面也跟随变化。由于不了解原理,不清楚ref()底层到底干了什么,只能通过表象来观察。

但是这里不管怎么说,都在刻意理解的范畴中,不管它底层做了什么,都是建立了代理和监听,实现了响应式的效果。紧接着,奇怪的现象在下面:

奇怪的现象

        <div  ref="demoRef"  @click="demoClick" style="height: 100px; width: 100px; background: red">
            {{ demoRef }}
        </div>

	setup(props) {
	 	//只要模板中,如果节点或者组件的ref属性,有和这个变量名称相同的,那么demoRef刚初始化出来,其value属性,就已经是一个dom节点或者是vue组件
		const demoRef = ref(0)
        setTimeout(() => {
        	//这里要通过value改变值--然而并没有卵用,它并不会改变
            demoRef.value = 1
            //demoRef在这里,依然是RefImpl类型的object,只不过它的value,已经是一个dom节点!!!
            console.log(typeof demoRef)
        }, 1000)
	},
	 methods: {
        demoClick() {
            console.log(this.demoRef)
            //demoRef在这里,是div类型的dom节点了!!!!
            console.log(typeof this.demoRef)
            //赋值也没用---!!!
            this.demoRef = 2
        }
    }

只需要在模板中加上和ref()函数返回值变量名称相同的ref属性,就翻了天了。首先,demoRef刚初始化完成,它依然是个RefImpl,但是它的value属性值,是div dom节点!!!(模板中的ref属性,如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例);因为div有了ref属性,所以,在this.$refs上,会有一个名为demoRef的dom节点引用;同时,因为在setup方法中,return了demoRef,所以,在this实例上也有一个名为demoRef的属性,它是一个和this.$refs.demoRef一模一样的对象;这两个地方的demoRef,是一个互为影子一样的存在。如下图:
在这里插入图片描述

也就是当模板中,有同名ref属性的节点存在时,ref()函数入参,不管是啥,是0也好,是一个亿也好,是基本数据也好,是对象也好,甚至像同事写的不传参数,或者索性传null也好,都是徒劳,人家压根不会考虑,直接就把ref属性代表的节点或者组件引用赋值给RefImpl的value了。这种通过函数返回值变量名和模板ref属性之间弱的不能再弱的关联,所产生的的奇怪效应,真实让人心里默念一万个MMP!而且奇葩的是官网上,是没有找到有关这种使用方法的介绍的,所以,这究竟是一种奇技淫巧,还是底层故意设计的,还是恰巧能跑的经典案例,不得而知。但是总而言之,它就这样存在着,还希望有缘人度化一二。

只要将模板ref改个名字,或者ref()返回值变量名称改一下,ref还是refref()还是ref(),一切恢复如初:
在这里插入图片描述

补充于2022-04-21

今天一度感觉遇上鬼了。后来也只想通了一半。
基于前述观察到的现象,我始终确信了,当const aRefName = ref(null),在setUp中初始化的时候,它的value值就已经是ref所属性所标记的dom节点或者组件实例了。因为在第一次写这个博文的时候,是通过console观察无误的,他的值如下图所示:

如上图所示,抛开所有,不管咋说,ref方法返回的值,就是一个正经八百的对象,它有一个value属性,从console里展开value属性,也确实是一个vue组件实例,项目里,大量的代码,也确实是这么写的。
直到今天,我想做一个操作:既然之前我把这种写法,理解成,是在this还没初始化之前,通过特殊的写法,拿到dom或者vue实例的引用,那么理论上,我就可以在setUp方法中,通过使用这种方式拿到的引用,调用vue组件实例的一些方法,个中细节,它应该帮我去处理,结果却被啪啪打脸。(现在想想当然是不合适了,还没有渲染出来,就去拿人家的值,当然不合适,所以今天碰到的鬼,原因是基于在console里观察到,formRef初始化的时候,value属性确实是有值的。)
在这里插入图片描述
我的写法如上图所示,我想通过doFormFillUp()方法,调用formRef中vaule属性中的重置方法,结果哐哐报错。
在console中打印formRef,发现这货确实是有value值的啊,这货的value属性就是form组件实例啊(上上一张图)。
然后我又打印了它的value值,我擦,value的值,竟然不是不是Vue组件实例的了,恐怖。。。

在这里插入图片描述
真是惨绝人寰,让人无言以对。
好好的一个value值,上一行还是一个VueComponent,下一行就变成了最开始的初始值5。
我能怎么理解?我只能理解成,这特喵的是Vue的bug,或者是浏览器的bug,汗…
出现这种现象,只有在子组件第一次初始化的时候,所以,对项目中大量出现的这种写法,只要保证,在首次渲染完成之前,没有使用通过这种方式拿到的引用,去搞事情,倒是并没有太大的影响。
我擦,又又又涨知识了,这一天天的,都是嘛呀!所以总结为:不要过分相信console打印出的结果,还是要结合底层的逻辑,去设计自己的代码

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
集成学习是一种通过结合多个模型的预测结果来提升分类器或预测系统的效果的方法。在CIFAR-10数据集中,可以使用集成学习来提高图像分类的准确性。 引用中提到了CIFAR-10数据集是由10个类的60000个图像组成的,每个类有6000个图像。数据集被划分为5个训练批次和1个测试批次,每个批次包含10000个图像。其中测试批次包含了每个类别的1000个随机选择的图像,训练批次则以随机顺序包含剩余图像。因为每个批次中来自每个类别的图像数量可能不同,所以总体来看,5个训练批次包含了来自每个类别的5000张图像。 引用中提到了一种多Lora权值集成切换Zero-Finetune增强的跨模型技术方案,该方案旨在使语言模型能够以低能耗且广泛适用的方式进行集成。 引用中提到了模型集成的原理,类似于盲人摸象的比喻。每个盲人只能摸到大象的一部分,但是综合每个人摸到的部分,就能形成一个比较完整、复合实际的图像。在实际应用中,可以考虑各个模型之间的差异性和性能差异。如果模型的性能相差不大,可以取各个模型预测结果的平均值;如果模型性能相差较大,可以采用加权平均法。通过集成多个模型,可以得到一个强于单个模型的模型。 因此,在CIFAR-10数据集中,可以使用集成学习方法,如模型集成或权值集成,来提升分类器对图像的准确性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [pytorch实现CIFAR-10多分类](https://blog.csdn.net/W1517055683/article/details/105863128)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [实现一种多Lora权值集成切换+Zero-Finetune零微调增强的跨模型技术方案,LLM-Base+LLM-X+Alpaca](https://download.csdn.net/download/qq_35831906/88238087)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值