本教程操作环境:windows7系统、vue3版,DELL G3电脑。
vue data有两种初始化的方式,function和object,但是这两种情况适用场景有哪些?能不能通用?带着这两个问题咱们一起分析下
data初始化
// 代码来源于官网示例
// 第一种定义方式
var data = { a: 1 }
// 直接创建一个实例
var vm = new Vue({
data: data
})
// Vue.extend() 中 data 必须是函数
var Component = Vue.extend({
// 第二种定义方式
data: function () {
return { a: 1 }
}
})
上述代码简单描述了data定义的两种方式
function
object
官网demo中也着重说了extend中data初始化不能用object。那么为什么呢?
源码分析
按照官网demo,Vue.extend中的data初始化不能是Object,如果我们强制写成Object会出现什么?
var Component = Vue.extend({
data: { a: 1 }
})
运行以后chrome的consolo直接报错,信息如下
vue.esm.js?efeb:591 [Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions.
通过分析源码以及报错信息,当触发Vue.extend的时候,他会做一个合并操作,把一个基础组件(里面vmode, transtion等)和你定义在extend内的信息,通过mergeField往options上合并,当合并到data的时候,他会触发strats.data,在这个里面会check data是不是一个function,这里需要注意的是filter、components等和data走的是两套合并流程,详细的请看代码注释,如下
// vue.extend 源码地址https://github.com/vuejs/vue/blob/dev/src/core/global-api/extend.js
Vue.extend = function (extendOptions: Object): Function {
...
// 在这里会触发mergeOptions方法
Sub.options = mergeOptions(
Super.options,
extendOptions
)
...
}
// mergeOptions 源码地址https://github.com/vuejs/vue/blob/dev/src/core/util/options.js
export function mergeOptions (
parent: Object,
child: Object,
vm?: Component
): Object {
...
const options = {}
let key
// parent对象内包含components、filter,、directive
for (key in parent) {
mergeField(key)
}
// child对象内对应的是Vue.extend内定义的参数
for (key in child) {
if (!hasOwn(parent, key)) {
mergeField(key)
}
}
function mergeField (key) {
// 这一步是根据传入的key找到不同的合并策略filter、components、directives用到合并策略是这个方法mergeAssets和data用到的不一样,当合并到data的时候会进入专属的合并策略方法内
const strat = strats[key] || defaultStrat
options[key] = strat(parent[key], child[key], vm, key)
}
}
// strats.data 源码地址https://github.com/vuejs/vue/blob/dev/src/core/util/options.js
strats.data = function (
parentVal,
childVal,
vm
) {
if (!vm) {
// 如果data不是function的话会直接走下面的报错信息
if (childVal && typeof childVal !== 'function') {
process.env.NODE_ENV !== 'production' && warn(
'The "data" option should be a function ' +
'that returns a per-instance value in component ' +
'definitions.',
vm
);
return parentVal
}
return mergeDataOrFn(parentVal, childVal)
}
return mergeDataOrFn(parentVal, childVal, vm)
};
其他情况
其实我们上述代码只是一个简单的流程,在实际开发中同类情况有:子组件内、路由内都不可以把data定义为一个对象,因为他们底层都调用了mergeOptions方法
什么时候可以定义成一个对象
在vue初始化的时候,如下
new Vue({
data: {
linke: '//sinker.club'
}
})
意义
ok,上面说了那么多,那么这么做的意义是什么?为什么那几种情况不可以定义为对象? 其实回答这个问题,需要回到js本身,众所周知js数据类型分为引用和基本,引用类型包含Object, Array, Function,何为引用类型就不在这里阐述了
var obj = {link: '//www.sinker.club'}
var obj2 = obj
var obj3 = obj
obj2.link = "//gitlab.sinker.club"
console.log(obj3.link) // "//gitlab.sinker.club"
上述代码反应了一个问题,由于obj3和obj2在内存中都是指向一个地址,那么obj2的修改会影响到obj3,当然处理这种问题可以用深copy来做到
JSON.parse(JSON.stringify(obj))
deepClone(obj)
但是这两种做法需要开发或者框架每一次都要深copy一次,当数据量大的时候对性能什么都不友好,那么Vue怎么做的呢?把data定义成一个function
function data() {
return {
link: '//sinker.club'
}
}
var obj = test()
var obj2 = test()
obj2.link ="//gitlab.sinker.club"
console.log(obj.link) '//sinker.club'
为什么这么做?解决的场景是什么呢?
比如我定一个子组件,data是按照对象的方式定义的,这个组件在多个地方引用,如果其中一个引用此组件的data修改了,那么就会造成其余引用此组件的data同时改变, end.
扩展知识:
vue实例的时候定义data属性既可以是一个对象,也可以是一个函数
const app = new Vue({
el:"#app",
// 对象格式
data:{
foo:"foo"
},
// 函数格式
data(){
return {
foo:"foo"
}
}
})
组件中定义data属性,只能是一个函数
如果为组件data直接定义为一个对象
Vue.component('component1',{
template:`<div>组件</div>`,
data:{
foo:"foo"
}})
则会得到警告信息
说明:
vue中组件是用来复用的,为了防止data复用,将其定义为函数。
vue组件中的data数据都应该是相互隔离,互不影响的,组件每复用一次,data数据就应该被复制一次,之后,当某一处复用的地方组件内data数据被改变时,其他复用地方组件的data数据不受影响,就需要通过data函数返回一个对象作为组件的状态。
当我们将组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,拥有自己的作用域,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。
当我们组件的date单纯的写成对象形式,这些实例用的是同一个构造函数,由于JavaScript的特性所导致,所有的组件实例共用了一个data,就会造成一个变了全都会变的结果。
【相关推荐:vuejs视频教程、web前端开发】
以上就是vue初始化data方法有哪些的详细内容,更多请关注编程网其它相关文章!