以下引官网原文:当一个组件被定义,data 必须声明为返回一个初始数据对象的函数,因为组件可能被用来创建多个实例。如果 data 仍然是一个纯粹的对象,则所有的实例将共享引用同一个数据对象!通过提供 data 函数,每次创建一个新实例后,我们能够调用 data 函数,从而返回初始数据的一个全新副本数据对象。

最近来面试的很多人。我都会问这个问题“vue中,为什么data是一个方法返回一个对象,而不是直接赋给一个对象”,只有少数人会回答出是怕重复创建实例造成多实例共享一个数据对象。更多的人回答是不知道,或者是官方文档要求这么写就这么写了。

其实这个问题的考点无非就是对vue的熟悉情况,挖掘应聘者的自驱学习能力,对技术的求知欲。这样的人往往技术成长快,具备很强的独立解决问题能力。也是各个技术团队都喜欢的一种人。

首先在vue的源码中,有这样的处理:

  // vue/src/core/instance/state.jsfunction initData (vm: Component) {var data = vm.$options.data;data = vm._data = typeof data === 'function'? getData(data, vm): data || {};if (!isPlainObject(data)) {data = {};process.env.NODE_ENV !== 'production' && warn('data functions should return an object:\n'  'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',vm);}...}

显然,vue是支持将一个对象作为vue构造参数中data属性的值并且,如果data是方法的话,也会先取得内部返回的对象结果。并且在vuex中又存在这样的用法:

  // vuex/src/store.jsfunction resetStoreVM (store, state, hot) {...const silent = Vue.config.silentVue.config.silent = truestore._vm = new Vue({data: {$$state: state},computed})...}

这是怎么回事呢?既然支持,又不让我们用,而且当我们在一个vue文件中,直接给一个data赋予一个对象则会引起红色警告:

  [Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions.

这个警告来自于Vue源码中的vue/src/core/util/options.js

  strats.data = function (parentVal: any,childVal: any,vm?: Component): ?Function {if (!vm) {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)}

首先我们需要了解在vue文件的代码被实例化成vue组件的过程需要经历下面这些步骤:

  1. vue文件被loader处理,template被编译成render函数,script被编译成一个对象变量
  2. 将script编译后的对象传入render中,并在render函数中调用vue.createElement(来自vue/src/core/vdom/create-element.js)构建vue组件
  3. 在createElement中,如果是vue组件的话,通过createComponent(vue/src/core/vdom/create-component.js)构建组件
  4. 将script编译出来的对象变量通过上下文的$options中取出,并使用Vue.extends(vue/src/core/global-api/extend.js)通过该对象构建出一个新的Vue对象

在4中因为使用了mergeOptions,进而触发了对data的类型验证,也就显示了之初的那个警告。

那么为一个对象的属性赋予一个对象真的就会造成共享对象么?让我们看下面的代码:

  class A {constructor(opt) {this.opt = opt;}update() {this.opt.data.a  ;}notify() {console.log(this.opt);}}

我们用这个类来虚拟化Vue的构造。然后进行测试:

  // testlet c = new A({ data: { a: 1 }});let d = new A({ data: { a: 1 }});c.update();d.update();c.notify(); // Object data: a: 2

我们通过字面量的方式来为构造参数传入一个对象属性,然而我们惊奇的发现,其实并没有发生共享引用的问题。这是什么鬼?

哦,不对,我们通常在使用vue的时候是在vue文件中export出一个对象,然后这个对象会在vue-loader的时候被编译传入到模版编译后的render函数中。那么我们换一个方法来做一个实验:

  // test.js文件,用于虚拟vue文件导出的vue options对象export default {data: {a: 1}}// index.jslet a = new A(test);let b = new A(test);a.update();b.update();a.notify(); // Object data: a: 3

什么?在这里产生了vue文档中提到的共享引用的问题。这是为什么呢?

原因在于vue的编译过程以及引入的import过程,通过babel编译,test.js会被转化为es5语法的js文件:

  var Re = {data: {a: 1}};var Oe = function () {function e(t) {Object(i["a"])(this, e), this.opt = t}return Object(o["a"])(e, [{key: "update",value: function () {this.opt.data.a  }}, {key: "notify",value: function () {console.log(this.opt)}}]), e}(),Fe = new Oe(Re),Ne = new Oe(Re);Fe.update(), Ne.update(), Fe.notify();var $e = new Oe({data: {a: 1}}),Ve = new Oe({data: {a: 1}});$e.update(), Ve.update(), $e.notify(),

What?原来我们的每一个vue文件经过babel编译,将导出的对象直接替换成了一个对象变量,然后将这个变量传入到对应的组件构造函数中。因此,也就产生了引用共享的问题(所有js对象皆引用)。

由于vue源码并没有通读,因此如有错误请指教

Vue(ES6)中的data属性为什么不能是一个对象?相关推荐

  1. java socket中属性详解_前端开发:关于Vue组件中的data属性值是函数而不是对象的详解...

    最近在搞关于前端开发的基础知识归纳,发现了不少经典知识点,那么本篇博文就来分享一个经典的知识点:Vue组件中的data属性值为什么是函数而不是对象.首先来了解一下Vue组件的使用理念:在Vue组件使用 ...

  2. vue组件中的data为什么是一个函数

    一.总结 1.vue中组件是用来复用的,为了防止data复用,将其定义为函数. 2.vue组件中的data数据都应该是相互隔离,互不影响的,组件每复用一次,data数据就应该被复制一次,之后,当某一处 ...

  3. Vue组件中的data和props属性

    组件中数据的绑定 在vue中数据通过data属性进行绑定,如下 <!DOCTYPE html> <html lang="en"> <head>& ...

  4. vue 给标签添加data属性_vue之data属性

    培训代码 在new Vue()的时候,是可以给data直接赋值为一个对象的. 但是在组件中,data必须是一个函数,注册组件其实并不产生新的组件类,但会产生一个可以用来实例化的新方式. 因为可能在多处 ...

  5. 为什呢vue组件中的data必须是函数?

    类比引用数据类型 Object是引用数据类型,如果不用function 返回,每个组件的data 都是内存的同一个地址,一个数据改变了其他也改变了; 关于JS中的数据类型:https://blog.c ...

  6. vue组件中的样式属性:scoped,解决在父组件中无法修改子组件样式问题

    Scoped CSS规范是Web组件产生不污染其他组件,也不被其他组件污染的CSS规范. vue组件中的style标签标有scoped属性时表明style里的css样式只适用于当前组件元素,它是通过使 ...

  7. ES6中object对象属性

    //es5中定义对象属性要么字面量.要么点.要么[],变量与空格在这些方法中没有得到好的支持 /在es6中可以这么定义: let w='www'; let obj1={w};//obj1={w:'ww ...

  8. vue vue实例中的data与vue组件中的data()

    vue组件就是vue实例,可以被复用. 而在复用时,希望组件中的data应该是相互隔离的. 如果使用 data : {count: 0} 的形式,则复制的该组件会共享data中的数据,所以要使用: d ...

  9. style 里引用php变量,在VUE style中使用data中的变量的方法详解

    最近项目中的公共组件,在复用的时候,针对不同的场景,需要不断变更CSS里样式的值,而且已经有了全局的公共组件样式了 如果用vue传统的动态绑定class和style的方式去修改样式(文末会提到),需要 ...

最新文章

  1. java网络流传输,中文乱码问题。
  2. 一周一论文(翻译)—— [PVLDB 12] Distributed GraphLab A Framework for Machine Learning 分布式机器学习图计算框架
  3. mysql忘记数据库密码
  4. Jquery checkbox全选简单用法
  5. 转:Windows Phone 7 设计简介
  6. python多线程 不在main_从python线程(不是main)启动pyQt线程有什么不...
  7. C++移位得到int型最大值
  8. jmap+MAT实战内存溢出
  9. FixedThreadPool 使用方法测试
  10. 论文笔记_S2D.09-2018-ECCV_从RGB和稀疏感知估计深度
  11. ssd用HD软件测试准确吗,HDtune到底适不适合用于测试SSD
  12. 花生壳:域名诊断—客户端离线
  13. SCI文章下载网址收藏
  14. 用python做探索性因子分析(Exploratory Factor Analysis,EFA)全代码
  15. 什么是集群农场渲染?一文带你快速了解
  16. 【Matplotlib绘制图像目录】Python数据可视化之美
  17. 像玩游戏一样做游戏 | Google Play 开发者故事
  18. Django-路由Routers-SimpleRouter-DefaultRouter使用方法
  19. 43、DNS域名系统(应用层)
  20. pyinstaller 打包小坑2

热门文章

  1. Java学习、简单代码编译
  2. 安装jdk步骤rpm_jenkins rpm包方式安装
  3. linux r包默认安装位置,R-Language(R语言或称r-project)的安装
  4. ubuntu16.04+cuda9.0_cudnn7.5+tensorflow-gpu==1.12.0
  5. TCP服务端实现并发
  6. 最长子串(FZU2128)
  7. My.Ioc 代码示例——避免循环依赖
  8. 监控系统的多协议直播(RTSP RTMP HTTP Live Streaming)
  9. $(document).ready() 和 window.onload 方法比较
  10. JPDL3.1规范手册