当前位置:   article > 正文

Object.defineProperty和Proxy分别实现响应式原理的简单示例

Object.defineProperty和Proxy分别实现响应式原理的简单示例

1. 利用Object.defineProperty+递归 实现响应式原理

  1. // 监听数组, Object.defineProperty做不到, 所以需要重写数组方法!!!
  2. // 重新定义数组原型
  3. const oldArrProperty = Array.prototype
  4. // 创建新对象, 原型指向oldArrProperty, 再扩展新的方法不会影响Array原型
  5. // 使用Object.create是为了不污染全局的原型方法
  6. const arrProto = Object.create(oldArrProperty);
  7. ['push', 'pop', 'shift', 'unshift', 'splice'].forEach(element => {
  8. arrProto[element] = function () {
  9. updateView(); // 触发视图更新
  10. oldArrProperty[element].call(this, ...arguments);
  11. }
  12. });
  13. // 监听对象属性
  14. function observer(target) {
  15. if (typeof target !== 'object' || target === null) {
  16. // 不是对象或数组
  17. return target;
  18. }
  19. if (Array.isArray(target)) {
  20. target.__proto__ = arrProto
  21. }
  22. // 重新定义各个属性(for in 也可以遍历数组)
  23. for (let key in target) {
  24. defineReactive(target, key, target[key])
  25. }
  26. }
  27. // 重新定义属性, 监听起来
  28. function defineReactive(target, key, value) {
  29. // 深度监听(深层对象):
  30. observer(value);
  31. // 核心API
  32. Object.defineProperty(target, key, {
  33. get() {
  34. return value
  35. },
  36. set(newVal) {
  37. if (newVal !== value) {
  38. // 设置新值的时候也要深度监听(深层对象):
  39. observer(newVal)
  40. // 设置新值
  41. // 注意, value一直闭包中, 此处设置完之后, 再get时也是会获取最新的值
  42. value = newVal
  43. // 触发更新视图
  44. updateView();
  45. }
  46. }
  47. })
  48. }
  49. // 触发更新视图
  50. function updateView() {
  51. console.log('视图更新')
  52. }
  53. const data = {
  54. name: 'zhangsan',
  55. age: 20,
  56. info: {
  57. city: '北京', // 需要深度监听
  58. },
  59. nums: []
  60. }
  61. // 监听数据
  62. observer(data)
  63. //测试
  64. // data.name='sdhewifewfewfewf'
  65. // data.age = 21
  66. // data.info.city = 'shanghai'
  67. // data.x = '100';//新增属性, 监听不到--所以有V
  68. // delete data.name; // 删除属性, 监听不到 --所以有Vue.delete
  69. data.nums.push({ a: 1 }); // 监听数组
  70. data.nums[0].a = 222
  71. // console.log(data.name, data.age, data.info.city, data.nums)
  72. // console.log(arrProto)
  73. // console.log(arrProto.__proto__.push)
  74. // console.log(arrProto.__proto__ === oldArrProperty)
  75. // console.log(arrProto.prototype.constructor)

测试: 每次修改数据, 查看控制台有没有随着数据变化打印"视图更新"

2. 使用Proxy和Reflect实现响应式原理, 如果有深层对象和数组也需要递归

  1. var data = {
  2. name: 'zhangsan',
  3. age: 20,
  4. list: [1, 2],
  5. obj: { a: 1, b: 2, c: 2, city: {
  6. name: '北京'
  7. }}
  8. }
  9. function reactive(data) {
  10. const config = {
  11. // receiver其实指的就是Proxy
  12. get(target, key, receiver) {
  13. // Reflect.ownKeys可以获取不是原型上的属性
  14. const ownKeys = Reflect.ownKeys(target);
  15. // 只处理本身(非原型的)属性
  16. // if(ownKeys.includes(key)) {
  17. // console.log('get:', key, '本身(非原型的)属性');
  18. // }
  19. const result = Reflect.get(target, key, receiver);
  20. // 如果对象有深层的对象或者数组, 需要递归
  21. if(Array.isArray(result) || Object.prototype.toString.call(result) === '[object Object]') {
  22. return reactive(result);
  23. }
  24. console.log('get:', key, target[key], result)
  25. return result;
  26. },
  27. set(target, key, val, receiver) {
  28. // 重复的数据不处理
  29. const oldVal = target[key]
  30. if(val === oldVal) {
  31. return true
  32. }
  33. const ownKeys = Reflect.ownKeys(target);
  34. // 只处理本身(非原型的)属性
  35. if(ownKeys.includes(key)) { // push方法就不执行了
  36. console.log('get:', key, '已有的key');
  37. }
  38. else {
  39. console.log('get:', key, '新增的key');
  40. }
  41. const result = Reflect.set(target, key, val, receiver);
  42. console.log('set:', key, val, result)
  43. // 触发更新视图
  44. updateView();
  45. return result;
  46. },
  47. deleteProperty(target, key) {
  48. const result = Reflect.deleteProperty(target, key);
  49. console.log('deleteProperty:', key, result)
  50. // 触发更新视图
  51. updateView();
  52. return result;
  53. },
  54. }
  55. const proxyData = new Proxy(data, config);
  56. return proxyData
  57. }
  58. // 触发更新视图
  59. function updateView() {
  60. console.log('视图更新')
  61. }
  62. const proxyData = reactive(data)
  63. proxyData.list.push('13')
  64. proxyData.obj.a = 999
  65. proxyData.obj.b = undefined
  66. proxyData.obj.city.name = 'shanghai'
  67. Reflect.deleteProperty(proxyData.obj, 'c')
  68. proxyData.obj.d = 'ddddd'

测试: 每次修改数据, 查看控制台有没有随着数据变化打印"视图更新"

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/259086
推荐阅读
相关标签
  

闽ICP备14008679号