代码详解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 相关文章推荐
javascript cookie解码函数(兼容ff)
Mar 17 Javascript
Firebug 字幕文件JSON地址获取代码
Oct 28 Javascript
CSS+Jquery实现页面圆角框方法大全
Dec 24 Javascript
JavaScript 模式之工厂模式(Factory)应用介绍
Nov 15 Javascript
form表单只提交数据而不进行页面跳转的解决方案
Sep 18 Javascript
详解JavaScript中双等号引起的隐性类型转换
May 30 Javascript
用js制作淘宝放大镜效果
Oct 28 Javascript
利用 spin.js 生成等待效果(js 等待效果)
Jun 25 Javascript
在vue里面设置全局变量或数据的方法
Mar 09 Javascript
深入理解 JS 垃圾回收
Jun 03 Javascript
小程序实现搜索框功能
Mar 26 Javascript
JavaScript运行机制实例分析
Apr 11 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 cli 方式 在crotab中运行解决
2010/02/08 PHP
PHP XML操作的各种方法解析(比较详细)
2010/06/17 PHP
php echo, print, print_r, sprintf, var_dump, var_expor的使用区别
2013/06/20 PHP
php发送post请求函数分享
2014/03/06 PHP
PHP实现图片裁剪、添加水印效果代码
2014/10/01 PHP
PHP call_user_func和call_user_func_array函数的简单理解与应用分析
2019/11/25 PHP
一直复略了的一个问题,关于表单重复提交
2007/02/15 Javascript
location对象的属性和方法应用(解析URL)
2013/04/12 Javascript
javascript中负数算术右移、逻辑右移的奥秘探索
2013/10/17 Javascript
JS数组(Array)处理函数整理
2014/12/07 Javascript
Node.js中的缓冲与流模块详细介绍
2015/02/11 Javascript
在jQuery中处理XML数据的大致方法
2015/08/14 Javascript
js中常用的Tab切换效果(推荐)
2016/08/30 Javascript
javascript匀速动画和缓冲动画详解
2016/10/20 Javascript
AngularJS基于ngInfiniteScroll实现下拉滚动加载的方法
2016/12/14 Javascript
微信小程序 动态的设置图片的高度和宽度详解及实例代码
2017/02/24 Javascript
Vue.js 2.0中select级联下拉框实例
2017/03/06 Javascript
使用webpack打包koa2 框架app
2018/02/02 Javascript
小谈angular ng deploy的实现
2020/04/07 Javascript
基于Vue CSR的微前端实现方案实践
2020/05/27 Javascript
Python基础教程之正则表达式基本语法以及re模块
2016/03/25 Python
Python判断以什么结尾以什么开头的实例
2018/10/27 Python
PyQt5基本控件使用之消息弹出、用户输入、文件对话框的使用方法
2019/08/06 Python
Python csv文件的读写操作实例详解
2019/11/19 Python
Python字符串、列表、元组、字典、集合的补充实例详解
2019/12/20 Python
CentOS 7如何实现定时执行python脚本
2020/06/24 Python
python获取时间戳的实现示例(10位和13位)
2020/09/23 Python
使用HTML5里的classList操作CSS类
2016/06/28 HTML / CSS
Fossil美国官网:化石手表、手袋、首饰及配饰
2019/02/17 全球购物
屈臣氏俄罗斯在线商店:Watsons俄罗斯
2020/08/03 全球购物
高一新生军训方案
2014/05/12 职场文书
应急管理培训方案
2014/06/12 职场文书
学校感恩教育活动总结
2014/07/07 职场文书
工作失职检讨书(精华篇)
2014/10/15 职场文书
监理中标通知书
2015/04/16 职场文书
SpringBoot接入钉钉自定义机器人预警通知
2022/07/15 Java/Android