代码详解Vuejs响应式原理


Posted in Javascript onDecember 20, 2017

响应式原理

> vuejs中的模型(model)和视图(view)是保持同步的,在修改数据的时候会自动更新视图,这其实依赖于Object.defineProperty方法,所以vuejs不支持IE8及以下版本,vuejs通过劫持getter/setter方法来监听数据的变化,通过getter进行依赖收集,在数据变更执行setter的时候通知视图更新。

Object.defineProperty

> Object.defineProperty可以定义对象的属性或修改对象的属性
> 目前可以通过 Object.defineProperty描述的属性分为两种:数据属性和访问器属性

// obj: 对象
// prop: 对象中的属性
// descriptor: 对象中的属性的特性
Object.defineProperty(obj,prop,descriptor);

数据属性 > 数据属性的descriptor包含四种:value、writable、enumerable、configurable

var person = {
  name: 'json',
  age: 18
}

Object.defineProperty(person, 'name', {
  value: 'John',     // 属性的值,默认为undefined
  writable: false,    // 是否可以重写属性的值,设为false便是只读的
  enumerable: false,   // 是否可枚举(for in或Object.keys),默认为false
  configurable: true   // 是否可以删除或者重新设定上述配置,默认为false
})

person.name = 'new name';
console.log(person.name); // 'John'

for(key in person) console.log(person[key]);  // 18

Object.defineProperty(person, 'name', {
  writable: true,    
  enumerable: true,   
  configurable: false   
})

person.name = 'new name';
console.log(person.name); // 'new name'

for(key in person) console.log(person[key]);  // 'new name',18

访问器属性 > 访问器属性的desciptor包含四种:get、set、enumerable、configurable

var person = { _age: 20 };

Object.defineProperty(person, 'age',{
  get: function(){
    return this._age;
  },
  set: function(age){
    this._age = age < 0 ? 0 : age;
  }
});

person.age = 5;   // _age == 5
person.age = -3;  // _age == 0
person._age = -3;  // _age == -3

Vuejs劫持数据的做法

function observer(value, cb) {
  // 遍历对象的所有属性并为对象添加对应的访问器属性
  Object.keys(value).forEach((key) => defineReactive(value, key, value[key] , cb))
}
function defineReactive (obj, key, val, cb) {
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: ()=>{
      /*....依赖收集等....*/
    },
    set:newVal=> {
      cb();/*订阅者收到消息的回调,这里为render函数,即重新渲染*/
    }
  })
}
class Vue {
  constructor(options) {
    this._data = options.data;
    observer(this._data, options.render)  /*把所有数据变成可观察的*/
  }
}
let app = new Vue({
  el: '#app',
  data: {
    text: 'text',
    text2: 'text2'
  },
  render(){
    console.log("render");
  }
})

残留问题 > 上述实现只有通过app._data_text才会触发set,那么怎样才能做到app.text就能触发set呢
代理

> 通过在this对象中添加访问器属性即可实现代理,然后就可以用app.text来代替app._data.text了

_proxy(options.data);/*构造函数中*/

/*代理*/
function _proxy (data) {
  const that = this;
  Object.keys(data).forEach(key => {
    Object.defineProperty(that, key, {
      configurable: true,
      enumerable: true,
      get: function proxyGetter () {
        return that._data[key];
      },
      set: function proxySetter (val) {
        that._data[key] = val;
      }
    })
  });
}

以上就是本次文章的全部内容,大家如果还有任何不明白的地方可以在下方的留言区讨论。

Javascript 相关文章推荐
一个js封装的不错的选项卡效果代码
Feb 15 Javascript
angularjs实现与服务器交互分享
Jun 24 Javascript
使用jsonp完美解决跨域问题
Nov 27 Javascript
使用jQuery简单实现模拟浏览器搜索功能
Dec 21 Javascript
jQuery动画显示和隐藏效果实例演示(附demo源码下载)
Dec 31 Javascript
详解Vue.js 2.0 如何使用axios
Apr 21 Javascript
第一次记录Bootstrap table学习笔记(1)
May 18 Javascript
用vue的双向绑定简单实现一个todo-list的示例代码
Aug 03 Javascript
微信小程序textarea层级过高的解决方法
Mar 04 Javascript
js实现自动播放匀速轮播图
Feb 06 Javascript
浅谈vue权限管理实现及流程
Apr 23 Javascript
javascript+Canvas实现画板功能
Jun 23 Javascript
详解Javascript 中的 class、构造函数、工厂函数
Dec 20 #Javascript
在一个页面实现两个zTree联动的方法
Dec 20 #Javascript
浅谈基于Vue.js的移动组件库cube-ui
Dec 20 #Javascript
Angular2+如何去除url中的#号详解
Dec 20 #Javascript
JS基于递归实现网页版计算器的方法分析
Dec 20 #Javascript
JS小球抛物线轨迹运动的两种实现方法详解
Dec 20 #Javascript
JavaScript实现二叉树定义、遍历及查找的方法详解
Dec 20 #Javascript
You might like
PHP 最大运行时间 max_execution_time修改方法
2010/03/08 PHP
PHP实现登录搜狐广告获取广告联盟数据的方法【附demo源码】
2016/10/14 PHP
php 根据自增id创建唯一编号类
2017/04/06 PHP
javascript开发技术大全 第4章 直接量与字符集
2011/07/03 Javascript
原生js实现查找/添加/删除/指定元素的class
2013/04/12 Javascript
javaScript(JS)替换节点实现思路介绍
2013/04/17 Javascript
jQuery的ajax下载blob文件
2016/07/21 Javascript
Bootstrap分页插件之Bootstrap Paginator实例详解
2016/10/15 Javascript
原生JavaScript实现AJAX、JSONP
2017/02/07 Javascript
JavaScript 中Date对象的格式化代码方法汇总
2017/09/06 Javascript
vue2.0自定义指令示例代码详解
2019/04/25 Javascript
vue swipe自定义组件实现轮播效果
2019/07/03 Javascript
nodejs使用node-xlsx生成excel的方法示例
2019/08/22 NodeJs
vue中@change兼容问题详解
2019/10/25 Javascript
Vue如何使用混合Mixins和插件开发详解
2020/02/05 Javascript
Bootstrap简单实用的表单验证插件BootstrapValidator用法实例详解
2020/03/29 Javascript
vue组件讲解(is属性的用法)模板标签替换操作
2020/09/04 Javascript
javascript前端实现多视频上传
2020/12/13 Javascript
[50:27]OG vs LGD 2018国际邀请赛淘汰赛BO3 第一场 8.26
2018/08/30 DOTA
python字符串排序方法
2014/08/29 Python
Python基本语法经典教程
2016/03/11 Python
Python直接赋值、浅拷贝与深度拷贝实例分析
2019/06/18 Python
Python进程间通信 multiProcessing Queue队列实现详解
2019/09/23 Python
Python解释器以及PyCharm的安装教程图文详解
2020/02/26 Python
解决ROC曲线画出来只有一个点的问题
2020/02/28 Python
浅谈matplotlib.pyplot与axes的关系
2020/03/06 Python
Django Path转换器自定义及正则代码实例
2020/05/29 Python
推荐技术人员一款Python开源库(造数据神器)
2020/07/08 Python
HTML5实时语音通话聊天MP3压缩传输3KB每秒
2019/08/28 HTML / CSS
程序设计HTML5 Canvas API
2013/04/08 HTML / CSS
韩国现代百货官网:Hmall
2018/03/21 全球购物
AT&T Wireless:手机、无限数据计划和配件
2018/06/03 全球购物
公共场所禁烟倡议书
2014/08/30 职场文书
2015国际残疾人日活动总结
2015/03/24 职场文书
python 爬取哔哩哔哩up主信息和投稿视频
2021/06/07 Python
Python编程源码报错解决方法总结经验分享
2021/10/05 Python