非侵入性的响应式系统是 vue 最独特的特性之一. 那么非侵入性的响应式系统是什么呢?
Vue 是 mvvm 框架. 而 module 仅仅只是普通的 JavaScript 对象. 当你修改这些对象时, 视图也会进行更新. 这就是非侵入性的响应式.
那么响应式底层原理是什么呢?
简单说: 当你把一个普通的 JavaScript 对象传入 Vue 实例作为 data 时, Vue 将会遍历这个对象的所有属性. 在遍历时会使 Object.defineProperty 把这些属性全部转为 getter 或者 setter. 由于 Object.defineProperty 是 ES5 中一个无法 shim 的特性, 因此 Vue 不支持 IE8 以及更低版本的浏览器.
当然 getter/setter 对用户是不可见的, 但是 Vue 能够在内部通过它们追踪依赖. 所以当属性被读写时, Vue 也能及时的变更属性.
那么 Vue 是如何在内部追踪依赖呢?
其实每个组件实例都对应一个 watcher 实例, 它会在组件渲染的过程中把监听到的数据属性记录为依赖. 之后当该依赖的 setter 被触发时, 会反馈给 watcher, 使该依赖和相关联的组件重新渲染.
以下是图解:
当属性检测时, 应当注意如下几项:
一, 由于 Object.observe 被废弃, Vue 无法检测到对象属性的添加或删除操作. 但是 Vue 会在初始化实例 对象时执行 getter/setter 转化. 也因此属性必须写在 data 对象上, 只有如此 Vue 才会将该属性传唤成响应式.
二, 对于已经创建的实例, Vue 是 不允许动态添加根级别的响应式属性. 但是, 可以使用 Vue.set(object, propertyName, value) 方法向嵌套对象添加响应式属性. 例如,
Vue.set(vm.someObject, 'b', 2)
还可以使用 vm.$set 实例方法, 这也是全局 Vue.set 方法的别名:
this.$set(this.someObject,'b',2)
有时你可能需要为已有对象赋值多个新属性, 比如使用 Object.assign() 或 _.extend(). 但是, 这样添加到对象上的新属性不会触发更新. 在这种情况下, 你应该用原对象与要混合进去的对象的属性一起创建一个新的对象.
由于 Vue 不允许动态添加根级响应式属性, 所以你必须在初始化实例前声明所有根级响应式属性, 哪怕只是一个空值:
如果你未在 data 选项中声明 message,Vue 将警告你渲染函数正在试图访问不存在的属性.
这样的限制在背后是有其技术原因的, 它消除了在依赖项跟踪系统中的一类边界情况, 也使 Vue 实例能更好地配合类型检查系统工作. 但与此同时在代码可维护性方面也有一点重要的考虑: data 对象就像组件状态的结构 (schema).
提前声明所有的响应式属性, 可以让组件代码在未来维护时, 给其他开发人员阅读时更易于理解.
来源: http://www.bubuko.com/infodetail-3073421.html