温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

JS监听变量改变如何实现

发布时间:2023-04-15 11:12:01 来源:亿速云 阅读:80 作者:iii 栏目:开发技术

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

    需求和背景

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

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

    • ES5 的 Object.defineProperty

    • ES6 的 Proxy

    Object.defineProperty

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

    ——MDN

    用法如下:

    Object.defineProperty(obj, prop, option)

    入参用法:

    • obj:代理对象;

    • prop:代理对象中的key;

    • option:配置对象,getset都在其中配置;

    例子:

    var obj = { 
      name: 'sorryhc' 
    }
    var rocordName = 'sorryhc';
    
    Object.defineProperty(obj, 'name', {
      enumerable: true,
      configurable:true,
      set: function(newVal) {
          rocordName = newVal 
          console.log('set: ' + rocordName)
      },
      get: function() {
          console.log('get: ' + rocordName)
          return rocordName
      }
    })
    
    obj.name = 'sorrycc' // set: sorrycc
    console.log(obj.name) // get: sorrycc

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

    // 监视对象
    function observe(obj) {
      // 遍历对象,使用 get/set 重新定义对象的每个属性值
       Object.keys(obj).forEach(key => {
           defineReactive(obj, key, obj[key])
       })
    }
    
    function defineReactive(obj, k, v) {
       // 递归子属性
       if (typeof(v) === 'object') observe(v)
       
       // 重定义 get/set
       Object.defineProperty(obj, k, {
           enumerable: true,
           configurable: true,
           get: function reactiveGetter() {
               console.log('get: ' + v)
               return v
           },
           // 重新设置值时,触发收集器的通知机制
           set: function reactiveSetter(newV) {
               console.log('set: ' + newV)
               v = newV
           },
       })
    }
    
    let data = {a: 1}
    // 监视对象
    observe(data)
    data.a // get: 1
    data.a = 2 // set: 2

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

    缺陷

    如果学习过Vue2源码的同学可能比较熟,基于下面的缺陷,也是出现了$set$get的用法。

    • IE8 及更低版本 IE 是不支持的

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

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

    Proxy

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

    — MDN

    const obj = new Proxy(target, handler)

    其中:

    • target :要使用 Proxy 包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)

    • handler :一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 obj 的行为

    例子

    const handler = {
      get: function(target, name){
          return name in target ? target[name] : 'no prop!'
      },
      set: function(target, prop, value, receiver) {
          target[prop] = value;
          console.log('property set: ' + prop + ' = ' + value);
          return true;
      }
    };
    
    var user = new Proxy({}, handler)
    user.name = 'sorryhc' // property set: name = sorryhc
    
    console.log(user.name) // sorryhc
    console.log(user.age) // no prop!

    并且Proxy提供了更丰富的代理能力:

    • getPrototypeOf / setPrototypeOf

    • isExtensible / preventExtensions

    • ownKeys / getOwnPropertyDescriptor

    • defineProperty / deleteProperty

    • get / set / has

    • apply / construct

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

    在React中的实践

    这里展示两段伪代码,大概业务流程是,当点击页面某个按钮(打开/关闭弹窗),触发window.obj.showModal的切换,从而被监听到全局变量的变化,从而改变React中的state状态,最终触发Modal的弹窗。

    Object.defineProperty

    window.obj = {
      showModal: false
    }
    
    const [visible, setVisible] = useState(false);
    
    useEffect(() => {
      visible && Modal.show({
        // ...
      })
    }, [visible])
    
    Object.defineProperty(window.obj, 'showModal', {
      enumerable: true,
      configurable:true,
      set: function(newVal) {
        setVisible(newVal);
          console.log('set: ' + newVal)
      },
      get: function() {
          console.log('get: ' + visible)
          return visible
      }
    })
    
    window.obj.showModal = !window.obj.showModal // set: true
    console.log(window.obj.showModal) // get: true

    Proxy

    const [visible, setVisible] = useState(false);
    
    useEffect(() => {
      visible && Modal.show({
        // ...
      })
    }, [visible])
    
    const handler = {
      get: function(target, name){
          return name in target ? target[name] : 'no prop!'
      },
      set: function(target, prop, value, receiver) {
          target[prop] = value;
          setVisible(value);
          console.log('property set: ' + prop + ' = ' + value);
          return true;
      }
    };
    
    window.obj = new Proxy({showModal: false}, handler)
    window.obj.showModal = !window.obj.showModal // property set: showModal = true
    
    console.log(window.obj.showModal) // true

    到此,关于“JS监听变量改变如何实现”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    js
    AI