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

举报
零一01 发表于 2021/07/15 22:57:46 2021/07/15
【摘要】 分析Vue.js组件中的data为何是函数类型而非对象类型 引言正文一、Vue.js中data的使用二、data为对象类型三、data为函数 结束语 引言 要理解本篇文章,必须具备JavaScript中基本数据类型和引用数据类型的概念,大家可以花两分钟看一下,瞬间就能理解——面试题被问到再也不慌,深究JavaScript中的深拷贝与浅拷贝,看完这篇文...

分析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: {}
})

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

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

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

在这里插入图片描述
我们可以看到,图中的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>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

三、data为函数

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

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

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 组件中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>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

这时我们延续上面的例子,我们再在另一个页面注册一下该组件,这时有会调用函数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>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

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

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


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

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

我们发现,当实例对象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>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

我们在将该组件注册到另一个页面上,此时会创建一个实例对象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>

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

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

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


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

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

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

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

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

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

结束语

所以讲了那么多,还是一个概念,引用数据类型的表现形式,如果还是有小伙伴不懂的,一定要翻到引言部分,点击链接去看一下这个概念,否则很难理解本篇文章。因为本文也是说到构造函数创建实例对象的概念,如果对于JavaScript中对象的概念不理解的话,也可以翻阅我之前写的一篇文章,全面剖析了js中的对象概念——充分了解JavaScript中的对象,顺便弄懂你一直不明白的原型和原型链

希望这篇文章能解开你们心中的疑惑,喜欢的点个关注,加个收藏,谢谢各位。

文章来源: lpyexplore.blog.csdn.net,作者:「零一」,版权归原作者所有,如需转载,请联系作者。

原文链接:lpyexplore.blog.csdn.net/article/details/106673156

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。