javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > JS监听变量改变

JS监听变量改变的实现

作者:sorryhc

本文主要介绍了JS监听变量改变的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

需求和背景

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

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

Object.defineProperty

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

——MDN

用法如下:

Object.defineProperty(obj, prop, option)

入参用法:

例子:

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的用法。

Proxy

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

— MDN

const obj = new Proxy(target, handler)

其中:

例子

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提供了更丰富的代理能力:

感兴趣的可以查看 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

总结

Proxy 相比于 defineProperty 的优势:

Proxy除了兼容性不足以外,其他方面的表示都优于Object.defineProperty

所以,建议使用 Proxy 监测变量变化

到此这篇关于JS监听变量改变的实现的文章就介绍到这了,更多相关JS监听变量改变内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文