JS监听变量改变如何实现

前端开发   发布日期:2025年02月19日   浏览次数:170

这篇文章主要介绍“JS监听变量改变如何实现”,在日常操作中,相信很多人在JS监听变量改变如何实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JS监听变量改变如何实现”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

    需求和背景

    在业务中,由于项目采用微前端架构,需要通过A应用的某个值的变化对B应用中的DOM进行改变(如弹出一个Modal),第一个想到的可能是发布订阅模式,其实不如将问题缩小化,采用原生的能力去解决。

    下面给出两种解决方案,同时也是尤大写

    1. Vue
    时的思路
    • ES5 的

      1. Object.defineProperty
    • ES6 的

      1. Proxy

    Object.defineProperty

    1. Object.defineProperty()
    方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象

    ——MDN

    用法如下:

    1. Object.defineProperty(obj, prop, option)

    入参用法:

    • obj:代理对象;

    • prop:代理对象中的key;

    • option:配置对象,

      1. get
      1. set
      都在其中配置;

    例子:

    1. var obj = {
    2. name: 'sorryhc'
    3. }
    4. var rocordName = 'sorryhc';
    5. Object.defineProperty(obj, 'name', {
    6. enumerable: true,
    7. configurable:true,
    8. set: function(newVal) {
    9. rocordName = newVal
    10. console.log('set: ' + rocordName)
    11. },
    12. get: function() {
    13. console.log('get: ' + rocordName)
    14. return rocordName
    15. }
    16. })
    17. obj.name = 'sorrycc' // set: sorrycc
    18. console.log(obj.name) // get: sorrycc

    对一个对象进行整体响应式监听:

    1. // 监视对象
    2. function observe(obj) {
    3. // 遍历对象,使用 get/set 重新定义对象的每个属性值
    4. Object.keys(obj).forEach(key => {
    5. defineReactive(obj, key, obj[key])
    6. })
    7. }
    8. function defineReactive(obj, k, v) {
    9. // 递归子属性
    10. if (typeof(v) === 'object') observe(v)
    11. // 重定义 get/set
    12. Object.defineProperty(obj, k, {
    13. enumerable: true,
    14. configurable: true,
    15. get: function reactiveGetter() {
    16. console.log('get: ' + v)
    17. return v
    18. },
    19. // 重新设置值时,触发收集器的通知机制
    20. set: function reactiveSetter(newV) {
    21. console.log('set: ' + newV)
    22. v = newV
    23. },
    24. })
    25. }
    26. let data = {a: 1}
    27. // 监视对象
    28. observe(data)
    29. data.a // get: 1
    30. data.a = 2 // set: 2

    整体思路就是遇到子对象就递归,和深拷贝一样的读参顺序。

    缺陷

    如果学习过

    1. Vue2
    源码的同学可能比较熟,基于下面的缺陷,也是出现了
    1. $set
    1. $get
    的用法。
    • IE8 及更低版本 IE 是不支持的

    • 无法检测到对象属性的新增或删除

    • 如果修改数组的

      1. length
      1. Object.defineProperty
      不能监听数组的长度),以及数组的
      1. push
      等变异方法是无法触发
      1. setter

    Proxy

    Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)

    — MDN

    1. const obj = new Proxy(target, handler)

    其中:

      1. target
      :要使用
      1. Proxy
      包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)
      1. handler
      :一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理
      1. obj
      的行为

    例子

    1. const handler = {
    2. get: function(target, name){
    3. return name in target ? target[name] : 'no prop!'
    4. },
    5. set: function(target, prop, value, receiver) {
    6. target[prop] = value;
    7. console.log('property set: ' + prop + ' = ' + value);
    8. return true;
    9. }
    10. };
    11. var user = new Proxy({}, handler)
    12. user.name = 'sorryhc' // property set: name = sorryhc
    13. console.log(user.name) // sorryhc
    14. console.log(user.age) // no prop!

    并且

    1. Proxy
    提供了更丰富的代理能力:
      1. getPrototypeOf
      /
      1. setPrototypeOf
      1. isExtensible
      /
      1. preventExtensions
      1. ownKeys
      /
      1. getOwnPropertyDescriptor
      1. defineProperty
      /
      1. deleteProperty
      1. get
      /
      1. set
      /
      1. has
      1. apply
      /
      1. construct

    感兴趣的可以查看 MDN ,一一尝试一下,这里不再赘述

    在React中的实践

    这里展示两段伪代码,大概业务流程是,当点击页面某个按钮(打开/关闭弹窗),触发

    1. window.obj.showModal
    的切换,从而被监听到全局变量的变化,从而改变
    1. React
    中的
    1. state
    状态,最终触发
    1. Modal
    的弹窗。

    Object.defineProperty

    1. window.obj = {
    2. showModal: false
    3. }
    4. const [visible, setVisible] = useState(false);
    5. useEffect(() => {
    6. visible && Modal.show({
    7. // ...
    8. })
    9. }, [visible])
    10. Object.defineProperty(window.obj, 'showModal', {
    11. enumerable: true,
    12. configurable:true,
    13. set: function(newVal) {
    14. setVisible(newVal);
    15. console.log('set: ' + newVal)
    16. },
    17. get: function() {
    18. console.log('get: ' + visible)
    19. return visible
    20. }
    21. })
    22. window.obj.showModal = !window.obj.showModal // set: true
    23. console.log(window.obj.showModal) // get: true

    Proxy

    1. const [visible, setVisible] = useState(false);
    2. useEffect(() => {
    3. visible && Modal.show({
    4. // ...
    5. })
    6. }, [visible])
    7. const handler = {
    8. get: function(target, name){
    9. return name in target ? target[name] : 'no prop!'
    10. },
    11. set: function(target, prop, value, receiver) {
    12. target[prop] = value;
    13. setVisible(value);
    14. console.log('property set: ' + prop + ' = ' + value);
    15. return true;
    16. }
    17. };
    18. window.obj = new Proxy({showModal: false}, handler)
    19. window.obj.showModal = !window.obj.showModal // property set: showModal = true
    20. console.log(window.obj.showModal) // true

    以上就是JS监听变量改变如何实现的详细内容,更多关于JS监听变量改变如何实现的资料请关注九品源码其它相关文章!