当前位置:   article > 正文

vue组件中的data为什么是一个函数_为什么vue的data要写成函数式

为什么vue的data要写成函数式

一、总结

1.vue中组件是用来复用的,为了防止data复用,将其定义为函数。

2.vue组件中的data数据都应该是相互隔离,互不影响的,组件每复用一次,data数据就应该被复制一次,之后,当某一处复用的地方组件内data数据被改变时,其他复用地方组件的data数据不受影响,就需要通过data函数返回一个对象作为组件的状态。

3.当我们将组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,拥有自己的作用域,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。

4.当我们组件的date单纯的写成对象形式,这些实例用的是同一个构造函数,由于JavaScript的特性所导致,所有的组件实例共用了一个data,就会造成一个变了全都会变的结果。

二、代码分析:

vue每次会通过组件创建出一个构造函数,每个实例都是通过这个构造函数new出来的

假如data是一个对象,将这个对象放到这个放到原型上去

  1. function VueComponent(){}
  2. VueComponent.prototype.$options = {
  3. data:{name:'three'}
  4. }
  5. let vc1 = new VueComponent();
  6. vc1.$options.data.name = 'six'; // 将vc1实例上的data修改为six
  7. let vc2 = new VueComponent(); // 在new一个新的实例vc2
  8. console.log(vc2.$options.data.name); six
  9. // 输出vc2data的值是six,这时候发现vc2中的data也被修改了,他们data相互影响

将data改为一个函数

  1. // 这样就可以保证每个组件调用data返回一个全新的对象,和外部没有关系
  2. function VueComponent(){}
  3. VueComponent.prototype.$options = {
  4. data: () => ({name:'three'})
  5. }
  6. let vc1 = new VueComponent();
  7. let objData = vc1.$options.data()
  8. objData.name = 'six'; // 调用data方法会返回一个对象,用这个对象作为它的属性
  9. console.log(objData)
  10. let vc2 = new VueComponent();
  11. console.log(vc2.$options.data());

三、源码

1.在core/global-api/extend.js中会调用mergeOptions方法

  1. const Sub = function VueComponent (options) {
  2. this._init(options)
  3. } // 创建一个子类
  4. Sub.prototype = Object.create(Super.prototype)
  5. Sub.prototype.constructor = Sub
  6. Sub.cid = cid++
  7. Sub.options = mergeOptions( // 调用mergeOptions进行合并
  8. Super.options,
  9. extendOptions
  10. )
  11. Sub.extend = Super.extend
  12. Sub.mixin = Super.mixin
  13. Sub.use = Super.use

2.mergeOptions方法(src/core/util/options.js)

  1. // 将两个对象合并到一个对象中
  2. // 包括生命周期的合并,data的合并等
  3. export function mergeOptions (
  4. parent: Object,
  5. child: Object,
  6. vm?: Component
  7. ): Object {
  8. if (process.env.NODE_ENV !== 'production') {
  9. checkComponents(child)
  10. }
  11. if (typeof child === 'function') {
  12. child = child.options
  13. }
  14. normalizeProps(child, vm)
  15. normalizeInject(child, vm)
  16. normalizeDirectives(child)
  17. if (!child._base) {
  18. //extend和mixins做合并
  19. if (child.extends) {
  20. parent = mergeOptions(parent, child.extends, vm)
  21. }
  22. if (child.mixins) {
  23. for (let i = 0, l = child.mixins.length; i < l; i++) {
  24. parent = mergeOptions(parent, child.mixins[i], vm)
  25. }
  26. }
  27. }
  28. const options = {}
  29. let key
  30. // 循环父类
  31. for (key in parent) {
  32. mergeField(key)
  33. }
  34. // 循环子类
  35. for (key in child) {
  36. if (!hasOwn(parent, key)) {
  37. mergeField(key)
  38. }
  39. }
  40. // 合并字段
  41. function mergeField (key) {
  42. const strat = strats[key] || defaultStrat
  43. options[key] = strat(parent[key], child[key], vm, key)
  44. }
  45. return options
  46. }

3.合并data(src/core/util/options.js)

  1. strats.data = function (
  2. parentVal: any,
  3. childVal: any,
  4. vm?: Component
  5. ): ?Function {
  6. if (!vm) {
  7. // 合并之前看看这个子类是不是一个函数,如果不是就告诉他这个数据应该是一个函数
  8. // 因为每一个组件都会返回一个实例
  9. if (childVal && typeof childVal !== 'function') {
  10. process.env.NODE_ENV !== 'production' && warn(
  11. 'The "data" option should be a function ' +
  12. 'that returns a per-instance value in component ' +
  13. 'definitions.',
  14. vm
  15. )
  16. return parentVal
  17. }
  18. // 如果是函数就调用mergeDataOrFn进行合并
  19. return mergeDataOrFn(parentVal, childVal)
  20. }
  21. return mergeDataOrFn(parentVal, childVal, vm)
  22. }

4.源码总结:

通过vue.extend方法创建一个子类,创建子类之后会把自己的选项和父类的选项使用mergeOptions方法做一个合并,自己的选项就包含data。在mergeOptions中会调用strats.data对子类的data进行合并,这个方法中首先会判断子类的data进行判断,要求data必须是一个函数,如果不是会报错告诉它这个data应该是一个函数定义,因为每一个组件都会返回一个实例,如果是data就会调用 mergeDataOrFn方法进行合并。然后会合并父类的extend、minin、use方法,最后extend返回的就是这个子类的方法。

补充:

为什么要合并?因为子组件也要有父组件的属性,extend方法是通过一个对象创建了一个构造函数,但是这个构造函数并没有父类的属性,因为它是一个新函数,和之前的Vue构造函数是没有关系的。通过extend产生了一个子函数,这个子函数需要拥有vue实例上的所以东西,它就要做一次合并。

四、为什么new Vue这个里面的data可以放一个对象?

因为这个类创建的实例不会被复用。它只会new一次,不用考虑复用。

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/616762
推荐阅读
相关标签
  

闽ICP备14008679号