3分钟了解vue数据劫持的原理实现


Posted in Javascript onMay 01, 2019

目的: 了解Object.defineProperty如何实现数据劫持

大致原理是这样的:

  1. 定义一个监听函数,对对象的每一个属性进行监听
  2. 通过Object.defineProperty对监听的每一个属性设置get 和 set 方法。
  3. 对对象实行监听
  4. 对对象内嵌对象进行处理
  5. 对数组对象进行处理

1. 先定义一个对象

let obj = {
 name: 'jw'
}

2. 定义一个监听函数

/**
* 判断监听的是否是对象
* 如果是对象,就遍历,并且对每个属性进行定义get 和 set
*/

function observer(obj) {
 if(typeof obj === 'object') {
  for (let key in obj) {
  // defineReactive 方法设置get和set,见第三步
   defineReactive(obj, key, obj[key]);
  }
 }
}

3.定义一个函数,处理每个属性

function defineReactive(obj, key, value) {
 Object.defineProperty(obj, key, {
  get() {
   return value;
  },
  set(val) {
   console.log('数据更新了')
   value = val;
  }
 })
}

ok. 到这里初版已经实现了。尝试一下吧

observer(obj);
obj.name = 'haha'

控制台输出:
//数据更新了

以上已经实现设置obj的属性的时候,被监听到,并且可以去执行一些代码了。但是,如果对象里面嵌入了对象呢?比如:

let obj = {
 name: 'jw',
 age: {
  old: 60
 }
}

执行以下代码

observer(obj);
obj.age.old = '50'

控制台输出: 空

4.对监控的obj进行迭代处理

// 修改defineReactive , 添加一行代码
function defineReactive(obj, key, value) {
 // 如果对象的属性也是一个对象。迭代处理
 observer(value);
 Object.defineProperty(obj, key, {
  //....
 })
}

再执行以下代码:

observer(obj);
obj.age.old = '50'

控制台输出:
//数据更新了

可惜的是,如果对象是一个数组,Object.defineProperty就无法起作用了,比如:

obj.skill = [1, 2, 3];
obj.age.push(4);

控制台输出:
//空

实际上,不止push,包括slice,shift,unshif...都是没有作用.

5. 重写数组的方法

let arr = ['push', 'slice', 'shift', 'unshift'];
arr.forEach(method=> {
 let oldPush = Array.prototype[method];
 Array.prototype[method] = function(value) {
  console.log('数据更新了')
  oldPush.call(this, value)
 }
})

再执行以下代码:

obj.skill = [1, 2, 3];
obj.skill.push(4);

控制台输出:
//数据更新了

但是,数组的length操作仍然是无效的。这也是为什么vue中只能通过方法去改变数组的原因了。

总结: Object.defineProperty只是解决了状态变更后,如何触发通知的问题,那要通知谁呢?谁会关心那些属性发生了变化呢?以后再说。

以下完整代码

let obj = {
 name: 'jw',
 age: {
  old: '60'
 }
}

// vue 数据劫持 Observer.defineProperty

function observer(obj) {
 if(typeof obj === 'object') {
  for (let key in obj) {
   defineReactive(obj, key, obj[key]);
  }
 }
}

function defineReactive(obj, key, value) {
 observer(value);

 Object.defineProperty(obj, key, {
  get() {
   return value;
  },
  set(val) {
   console.log('数据更新了')
   value = val;
  }
 })
}
observer(obj);


// obj.age.old = '50'


// Object.defineProperty 对 数组无效
let arr = ['push', 'slice', 'shift', 'unshift'];

arr.forEach(method=> {
 let oldPush = Array.prototype[method];
 Array.prototype[method] = function(value) {
  console.log('数据更新了')
  oldPush.call(this, value)
 }
})
obj.skill = [1, 2, 3];
obj.skill.push(4);

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Jquery利用mouseenter和mouseleave实现鼠标经过弹出层且可以点击
Feb 12 Javascript
js阻止浏览器默认行为的简单实例
May 15 Javascript
深入理解jquery跨域请求方法
May 18 Javascript
原生javascript实现读写CSS样式的方法详解
Feb 20 Javascript
使用prop解决一个checkbox选中后再次选中失效的问题
Jul 05 Javascript
JS返回顶部实例代码
Aug 09 Javascript
使用vue官方提供的模板vue-cli搭建一个helloWorld案例分析
Jan 16 Javascript
基于打包工具Webpack进行项目开发实例
May 29 Javascript
Vue中的v-for循环key属性注意事项小结
Aug 12 Javascript
jQuery实现中奖播报功能(让文本滚动起来) 简单设置数值即可
Mar 20 jQuery
react组件基本用法示例小结
Apr 27 Javascript
JS实现超级好看的鼠标小尾巴特效
Dec 01 Javascript
vue 对象添加或删除成员时无法实时更新的解决方法
May 01 #Javascript
JavaScript强制类型转换和隐式类型转换操作示例
May 01 #Javascript
Vue源码之关于vm.$delete()/Vue.use()内部原理详解
May 01 #Javascript
Vue.extend实现挂载到实例上的方法
May 01 #Javascript
JS html事件冒泡和事件捕获操作示例
May 01 #Javascript
JS实现的贪吃蛇游戏案例详解
May 01 #Javascript
javascript原型链学习记录之继承实现方式分析
May 01 #Javascript
You might like
人大复印资料处理程序_查询篇
2006/10/09 PHP
工厂模式在Zend Framework中应用介绍
2012/07/10 PHP
PHP5下$_SERVER变量不再受magic_quotes_gpc保护的弥补方法
2012/10/31 PHP
PHPer 需要了解的 5 个 Composer 小技巧
2014/08/18 PHP
PHP实现支持加盐的图片加密解密
2016/09/09 PHP
PHP中递归的实现实例详解
2017/11/14 PHP
PHP实现图片压缩
2020/09/09 PHP
PHP copy函数使用案例代码解析
2020/09/01 PHP
window.onload 加载完毕的问题及解决方案(上)
2009/07/09 Javascript
在JavaScript中获取请求的URL参数
2010/12/22 Javascript
JavaScript中的noscript元素属性位置及作用介绍
2013/04/11 Javascript
javascript实现TreeView 无刷新展开的实例代码
2013/07/13 Javascript
html页面显示年月日时分秒和星期几的两种方式
2013/08/20 Javascript
jQuery实现360°全景拖动展示
2015/03/18 Javascript
js中数组结合字符串实现查找(屏蔽广告判断url等)
2016/03/30 Javascript
微信小程序 点击控件后选中其它反选实例详解
2017/02/21 Javascript
详解Angular-Cli中引用第三方库
2017/05/21 Javascript
基于javascript中的typeof和类型判断(详解)
2017/10/27 Javascript
Vue+jquery实现表格指定列的文字收缩的示例代码
2018/01/09 jQuery
Vue引入sass并配置全局变量的方法
2018/06/27 Javascript
Python遍历指定文件及文件夹的方法
2015/05/09 Python
Python基于pillow判断图片完整性的方法
2016/09/18 Python
Python 专题一 函数的基础知识
2017/03/16 Python
python与caffe改变通道顺序的方法
2018/08/04 Python
强悍的Python读取大文件的解决方案
2019/02/16 Python
Centos7下源码安装Python3 及shell 脚本自动安装Python3的教程
2020/03/07 Python
python爬虫开发之Request模块从安装到详细使用方法与实例全解
2020/03/09 Python
canvas生成带二维码海报的踩坑记录
2019/09/11 HTML / CSS
公司请假条格式
2014/04/11 职场文书
标准毕业生自荐信
2014/06/24 职场文书
学校门卫岗位职责范本
2014/06/30 职场文书
争做文明公民倡议书
2014/08/29 职场文书
公司酒会致辞
2015/07/30 职场文书
《花钟》教学反思
2016/02/17 职场文书
Oracle更换为MySQL遇到的问题及解决
2021/05/21 Oracle
Python实现批量自动整理文件
2022/03/16 Python