• 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'

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

  • 相关阅读:
    CMake使用心得
    vue 在线预览word
    前端页面初步开发
    freertos 内部机制
    三体系ISO认证是什么?能给企业带来哪些好处?
    特殊流&Properties属性集实例遇到的问题及解决方法
    英特尔oneAPI-用于异构计算的英特尔oneAPI
    Java String、StringBuilder、StringJoiner区别实例讲解
    安装Apache2.4
    ElasticSearch ( 一 ) 安装启动
  • 原文地址:https://blog.csdn.net/qq_42750608/article/details/133612535