您好,登錄后才能下訂單哦!
這篇文章主要介紹“JS監聽變量改變如何實現”,在日常操作中,相信很多人在JS監聽變量改變如何實現問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”JS監聽變量改變如何實現”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
在業務中,由于項目采用微前端架構,需要通過A應用的某個值的變化對B應用中的DOM進行改變(如彈出一個Modal),第一個想到的可能是發布訂閱模式,其實不如將問題縮小化,采用原生的能力去解決。
下面給出兩種解決方案,同時也是尤大寫Vue
時的思路
ES5 的 Object.defineProperty
ES6 的 Proxy
Object.defineProperty()
方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性,并返回此對象——MDN
Object.defineProperty(obj, prop, option)
obj:代理對象;
prop:代理對象中的key;
option:配置對象,get
、set
都在其中配置;
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 對象用于創建一個對象的代理,從而實現基本操作的攔截和自定義(如屬性查找、賦值、枚舉、函數調用等)
— 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 ,一一嘗試一下,這里不再贅述
這里展示兩段偽代碼,大概業務流程是,當點擊頁面某個按鈕(打開/關閉彈窗),觸發window.obj.showModal
的切換,從而被監聽到全局變量的變化,從而改變React
中的state
狀態,最終觸發Modal
的彈窗。
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
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監聽變量改變如何實現”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。