是否还在疑惑Vue.js中组件的data为什么是函数类型而不是对象类型

简介: 要理解本篇文章,必须具备JavaScript中基本数据类型和引用数据类型的概念,大家可以花两分钟看一下,瞬间就能理解——面试题被问到再也不慌,深究JavaScript中的深拷贝与浅拷贝,看完这篇文章以后,再来看这篇文章就会很容易理解了。

正文


本文很多地方会给新手讲解一些别的概念,懂了的小伙伴可以自行跳过第一部分,从第二部分开始看。


Vue.js中data的使用


我们先来回顾一下Vue的使用


<div id="app">
  <p>{{ name }}</p>
  <p>{{ age }}</p>
</div>
var vm = new Vue({
 el: '#app',
 data: {
  name: 'Lpyexplore',
  age: '21'
 },
 components: {}
 methods: {}
})


这个例子一般是在我们刚开始学Vue.js时遇到的。我们在这创建了一个Vue的实例对象,并给该实例对象定义了一些属性,比如el 表示跟哪个标签关联 、data表示该实例对象的一些初始属性 、methods表示该实例对象具有的方法等等。一般我们会以组件化的思想去开发(别担心,马上讲解什么是组件化的思想),所以我们还会用到Vue实例对象中的另一个属性components去注册别的组件。


我们先来了解一下什么是组件化思想,我们一般会在一个页面创建Vue实例,并以该页面作为主文件,然后将其他页面作为该文件的子文件(组件),如图


e6de36d949c379e6b3800333c8264d8f.png


我们可以看到,图中的Vue实例这个页面就是我们刚开始创建的全局Vue实例对象渲染出来的页面,我们以该页面为主文件。然后想在图上添加什么东西,只需要再创建一个文件,在该文件中创建一个Vue实例,但不通过el进行挂载,而是直接通过注册的方式,注册到另一个页面,作为别的页面的一部分,例如图中的样子。正是因为没有进行挂载,所以这个Vue实例是可以被反复使用的,也就是说可以在很多个页面都注册一次。


data为对象类型


好了,回到我们的正题data,经过这样的讲解,我们明白,我们第一次创建的Vue实例只会在该页面渲染一次。


function Vue() {
 this.data= {                   
  name: '张三',
  age: '21'
 }     
}
//创建了一个Vue实例返回给vm,会调用上面的定义的函数,并创建一个对象,该对象中有data属性
let vm =new Vue()
//此时的vm应该是这样的   
vm = {
 data: {
  name: '张三', 
  age: '21'
 }
}
//在创建了Vue实例以后我们就要进行渲染页面了
//这里的name会调用vm.data.name
<div>{{ name }}</div>


data为函数


看了上面的例子,我们再来看看data为函数的例子,一般只有在可复用的Vue实例中,data才为函数


data: function() {
 return {
  name: '李四',
  age: '55'
 }
}


  • 组件中data使用函数的情况


其实当我们把组件注册到别的页面上时,也会创建一个Vue实例,就像这个样子


function Vue() {
 //此处data的值为一个函数,调用时会return返回一个对象
 this.data = function() {
  return {
   name: '李四',
   age: '55'
  }
 }
}
//创建了一个Vue实例,会调用上面的定义的函数
let vm1 =new Vue()
//此时的vm1应该是这样的
vm1 = {
 //这里的data,是先获取了函数Vue中的data(data的值为函数),然后得到了data的返回值
 this.data = {
  name: '李四',
  age: '55'
 }
}
//将数据渲染到页面上
//此处的name会调用实例对象vm1.data.name
<div>{{ name }}</div>     //会渲染成<div>李四</div>


这时我们延续上面的例子,我们再在另一个页面注册一下该组件,这时又会调用函数Vue,创建一个实例对象


//又创建了一个Vue实例,会调用上面的定义的函数
let vm2 = new Vue()
//此时vm2是这样的
vm2 = {
 //这里的data,是先获取了函数Vue中的data(data的值为函数),然后得到了data的返回值
 data: {
  name: '李四',
  age: '55'
 } 
}
//将数据渲染到页面上
//此处的name会调用实例对象vm2.data.name
<div>{{ name }}</div>     //会渲染成<div>李四</div>


如果我们此时把实例对象vm2中的data.name 改为 王五,我们来看一下两个实例对象渲染的结果如何


//此处的name会调用实例对象vm1.data.name
<div>{{ name }}</div>   //渲染成  <div>李四</div>
//此处的name会调用实例对象vm2.data.name
<div>{{ name }}</div>   //渲染成  <div>王五</div>


我们发现,当实例对象vm2改变了他的data.name值时,实例对象vm1中的data.name值并没有改变。这是因为这两个实例对象在创建时,是先获得了一个函数,将该函数的返回值作为了自己属性data的值,并且这两个实例对象中data的值在栈中对应的堆中的地址也不一样,所以他们不会互相影响。


  • 组件中data为对象的情况


接下来我们来看一下,如果组件中data使用对象类型会发生怎么样的情况。


首先先将组件注册到一个页面中,这时会创建一个实例对象vm1


function Vue() {
 //此处data的值为一个对象
 this.data = {
  name: '李四',
  age: '55'
 } 
}
//创建了一个Vue实例,会调用上面的定义的函数
let vm1 =new Vue()
//此时的vm1应该是这样的
vm1 = {
 //这里的data是获取了函数Vue中的data属性的值
 data: {
  name: '李四',
  age: '55'
 }
}
//将数据渲染到页面上
//此处的name会调用实例对象vm1.data.name
<div>{{ name }}</div>     //会渲染成<div>李四</div>


我们在将该组件注册到另一个页面上,此时会创建一个实例对象vm2


function Vue() {
 //此处data的值为一个对象
 this.data = {
  name: '李四',
  age: '55'
 } 
}
//创建了一个Vue实例,会调用上面的定义的函数
let vm2 =new Vue()
//此时的vm1应该是这样的
vm2 = {
 //这里的data是获取了函数Vue中的data属性的值
 data: {
  name: '李四',
  age: '55'
 }
}
//将数据渲染到页面上
//此处的name会调用实例对象vm2.data.name
<div>{{ name }}</div>     //会渲染成<div>李四</div>


这时,我们改变实例对象vm2中data.name的值,改为王五,我们再来看一下这个组件在两个页面中分别渲染成什么样子


//此处的name会调用实例对象vm1.data.name
<div>{{ name }}</div>   //渲染成  <div>王五</div>
//此处的name会调用实例对象vm2.data.name
<div>{{ name }}</div>   //渲染成  <div>王五</div>


我们可以看到,只改变了实例对象vm2中的data.name,为何实例对象vm1中的data.name值也改变了?这里就是要理解==引用数据类型==的概念了,如果还有不懂得,赶紧翻到引言部分,去看一下。


因为我们刚开始定义了构造函数Vue时,给他内部的data设置了一个值,该值为对象类型,对象类型在js中称为==引用数据类型==,在栈中是存储着一个指向内存中该对象的堆中的地址。当我们创建一个实例对象时,要获取函数中的data,其实只是获取了那个堆中的地址,同样的,创建第二个实例对象时,获取的也是那个地址,然而该地址指向的都是同一个数据,也就是{name: '李四', age: '55'},所以当我们改变其中一个实例对象的data.name时,其实是先顺着地址去找到内存中的那个对象,然后改变一些值,但是因为所有创建的实例都是按照地址去寻找值的,所以其中一个改变,另一个也跟着改变啦。


下面放上一个图,让大家更容易理解


42c9683df7d05fd763bfb9df9956fd07.png


所以我们在使用复用型组件时,申明data属性的值时,必须要使用函数类型,因为每次创建实例对象时,他们都是获取属于他们自己的一个对象值,并且对应的堆中的地址都不相同,所以互不影响。此时的情况用图这样表示:


49cf9630806a4f9cf4ad8f102f4ec7ae.png


结束语


所以讲了那么多,还是一个概念,引用数据类型的表现形式,如果还是有小伙伴不懂的,一定要翻到引言部分,点击链接去看一下这个概念,否则很难理解本篇文章。

相关文章
|
1月前
|
JavaScript
Vue中如何实现兄弟组件之间的通信
在Vue中,兄弟组件可通过父组件中转、事件总线、Vuex/Pinia或provide/inject实现通信。小型项目推荐父组件中转或事件总线,大型项目建议使用Pinia等状态管理工具,确保数据流清晰可控,避免内存泄漏。
200 2
|
4月前
|
人工智能 JavaScript 算法
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
Vue 中 key 属性的深入解析:改变 key 导致组件销毁与重建
636 0
|
6月前
|
JavaScript
vue实现任务周期cron表达式选择组件
vue实现任务周期cron表达式选择组件
857 4
|
4月前
|
JavaScript UED
用组件懒加载优化Vue应用性能
用组件懒加载优化Vue应用性能
|
4月前
|
机器学习/深度学习 JavaScript 前端开发
JS进阶教程:递归函数原理与篇例解析
通过对这些代码示例的学习,我们已经了解了递归的原理以及递归在JS中的应用方法。递归虽然有着理论升华,但弄清它的核心思想并不难。举个随手可见的例子,火影鸣人做的影分身,你看到的都是同一个鸣人,但他们的行为却能在全局产生影响,这不就是递归吗?雾里看花,透过其间你或许已经深入了递归的魅力之中。
185 19
|
4月前
|
JavaScript 前端开发 UED
Vue 表情包输入组件的实现代码:支持自定义表情库、快捷键发送和输入框联动的聊天表情解决方案
本文详细介绍了在 Vue 项目中实现一个功能完善、交互友好的表情包输入组件的方法,并提供了具体的应用实例。组件设计包含表情分类展示、响应式布局、与输入框的交互及样式定制等功能。通过核心技术实现,如将表情插入输入框光标位置和点击外部关闭选择器,确保用户体验流畅。同时探讨了性能优化策略,如懒加载和虚拟滚动,以及扩展性方案,如自定义主题和国际化支持。最终,展示了如何在聊天界面中集成该组件,为用户提供丰富的表情输入体验。
362 8
|
4月前
|
JavaScript 前端开发 UED
Vue 表情包输入组件实现代码及详细开发流程解析
这是一篇关于 Vue 表情包输入组件的使用方法与封装指南的文章。通过安装依赖、全局注册和局部使用,可以快速集成表情包功能到 Vue 项目中。文章还详细介绍了组件的封装实现、高级配置(如自定义表情列表、主题定制、动画效果和懒加载)以及完整集成示例。开发者可根据需求扩展功能,例如 GIF 搜索或自定义表情上传,提升用户体验。资源链接提供进一步学习材料。
226 1
|
4月前
|
JavaScript 前端开发 UED
Vue 项目中如何自定义实用的进度条组件
本文介绍了如何使用Vue.js创建一个灵活多样的自定义进度条组件。该组件可接受进度段数据数组作为输入,动态渲染进度段,支持动画效果和内容展示。当进度超出总长时,超出部分将以红色填充。文章详细描述了组件的设计目标、实现步骤(包括props定义、宽度计算、模板渲染、动画处理及超出部分的显示),并提供了使用示例。通过此组件,开发者可根据项目需求灵活展示进度情况,优化用户体验。资源地址:[https://pan.quark.cn/s/35324205c62b](https://pan.quark.cn/s/35324205c62b)。
154 0
|
6月前
|
存储 JavaScript 前端开发
基于 ant-design-vue 和 Vue 3 封装的功能强大的表格组件
VTable 是一个基于 ant-design-vue 和 Vue 3 的多功能表格组件,支持列自定义、排序、本地化存储、行选择等功能。它继承了 Ant-Design-Vue Table 的所有特性并加以扩展,提供开箱即用的高性能体验。示例包括基础表格、可选择表格和自定义列渲染等。
463 6
|
6月前
|
JavaScript
JS实现多条件搜索函数
JS封装的多条件搜索

热门文章

最新文章