使用data()设计避免数据共享问题
vue中data为啥要用函数
理解为啥使用函数不直接使用对象的方式,简单一句话。直接对象会造成同一对象共享问题。
为什么会造成共享问题?
细探源码,下面从组件的三个过程看看整个过程。
组件的三个过程
- 创建
- 注册
- 实例化
下面这篇文章对VUE源码有比较清晰的认识https://blog.csdn.net/yolo0927/article/details/78242989
组件是如何使用的?
// 方式一
var MyComponent = Vue.extend({
name: 'my-component',
template: '<div>{{name}}</div>',
data(){
return{
name:""
}
}
});
Vue.component('my-component', MyComponent);
// 方式二
Vue.component('my-component', {
name: 'my-component',
template: '<div>{{name}}</div>',
data(){
return{
name:""
}
}
});
// 使用组件
<div id="example">
<my-component></my-component>
</div>
- 方式一是怎么处理data的?
源码位于global-api/extend.js
extend.png这里传入的参数extendOptions和Super.options都一并合并放入的Sub.options,并通过this._init将原型上的options也并入Sub.options.extend最后返回的是这个构造函数Sub;
- 方式二怎么处理data的?
具体如何定位到component源码的可以参考这篇文章的分析
https://segmentfault.com/a/1190000012004707
从上面可以看出,component做的处理就是注册这个创建的组件,如果传入的第二个参数是一个对象,则会进行一次创建操作,其实也就是内部也会执行一下extend操作,然后在注册。这里没有涉及到data的操作,也没有实例化这个组件。这里的这个definition对象是一个Sub构造函数。
- 使用时怎么处理data的?
使用是组件实例化并完成了挂载过程。组件实例化也就是new一个构造函数实例化,挂载也就是将组件指定到HTML元素中输出。new Sub则会实例化创建的这个组件。
- 那么new过程data是怎么样的呢?
new内部会创建一个新的空对象,然后将这个对象的原型指向这个构造函数的原型,并复制构造函数的属性,然后返回这个新的对象。如下:
function myNew(constructor){
return function(){
let obj={};
obj.__proto__=constructor.prototype;
constructor.apply(obj, arguments);
return obj;
}
}
所以Sub.options是构造函数的属性,最后会通过constructor.apply(obj, arguments);变成实例化对象的属性。
一般的构造函数实例化,属性被共享的情况
function initData(data){
return typeof data==='function'?data():data;
}
function Sub(data){
this.data=initData(data);
}
let data={
name:'mzz'
}
let dataFn=function(){
return{
name:'mzz'
}
}
let obj1=new Sub(data),
obj2=new Sub(data);
console.log(obj1.data===obj2.data); //true
let obj3=new Sub(dataFn),
obj4=new Sub(dataFn);
console.log(obj3.data===obj4.data); //false
上面这个一般化类实例对象结果对象属性被所有实例对象共享,VUE采取data()而不是直接对象也是这个道理。
总结
js中对象的引用造成数据被共享问题比较常见,可以学习这里传函数形式避免构造函数的对象属性被实力对象共享。大家都知道的原型继承原型会被所有实例对象共享,无论在原型上的属性是对象还是一般数据类型,通过这里的学习,也可以看到实例对象还会共享构造函数的对象类型属性。
以上仅作为个人学习参考,如有错误望批评指正;
如果有小伙伴再继续深入,有新见解的,望赐教。