原生js實作MVVM框架的基本原理詳解
這篇文章帶給大家的內容是關於原生JS實作MVVM框架的基本原理詳解,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
在前端頁面中,把 Model 用純 JS 物件表示,View 負責顯示,兩者做到了最大化的分離
把 Model 和 View 關聯起來的就是 ViewModel。 ViewModel 負責把 Model 的資料同步到 View 中顯示出來,也負責把 View 的修改同步回 Model。
MVVM 的設計想法:專注於 Model 的變化,讓 MVVM 框架去自動更新 DOM 的狀態,從而把開發者從操作 DOM 的繁瑣步驟中解脫出來。
了解了 MVVM 想法後,自己用原生 JS 實作一個 MVVM 框架。
實作MVVM 框架前先來看幾個基本用法:
Object.defineProperty
普通宣告對象,定義和修改屬性
let obj = {} obj.name = 'zhangsan' obj.age = 20
用ObjectdefineProperty
宣告物件
語法:
Object.defineProperty(obj,prop,descriptor)
obj
#:要處理的目標物件
prop
:要定義或修改的屬性的名稱
descriptor
:將被定義或修改的屬性描述符
let obj = {} Object.defineProperty(obj,'age',{ value = 14, })
咋一看有點畫蛇添足,這不很雞肋嘛
別急,往下看
描述子
descriptor
有兩種形式:資料描述符和儲存描述符,他們兩個共有屬性:
configurable
,是否可刪除,預設為false
,定義後無法修改
enumerable
,是否可遍歷,預設為false
,定以後無法修改
共有屬性
# configurable
設定為false
時,其內部屬性無法以delete
刪除;如要刪除,需要把configurable
設定為true
。
let obj = {} Object.defineProperty(obj,'age',{ configurable:false, value:20, }) delete obj.age //false
enumerable
設定為false
時,其內部屬性無法遍歷;如需遍歷,要把enumerable
設定為true
let obj = {name:'zhangsan'} Object.defineProperty(obj,'age',{ enumerable:false, value:20, }) for(let key in obj){ console.log(key) //name }
資料描述子
value
:此屬性對應的值,預設為undefined
。 writable
:當且緊當為true
時,value
才能被賦值運算子改變。預設為false
。
let obj = {} Object.defineProperty(obj,'age',{ value:10, writable:false }) obj.age = 11 obj.age //10
writable
和configurable
的差別是前者是value
是否能修改,後者是value
能否被刪除。
儲存描述子
get()
:一個給屬性提供getter
的方法,預設為undefined
。 set()
:一個給屬性提供setter
的方法,預設為undefined
。
let obj = {} let age Object.defineProperty(obj,'age',{ get:function(){ return age }, set:function(newVal){ age = newVal } }) obj.age = 20 obj.age //20
當我呼叫obj.age
時,其實是在向obj
物件要age
這個屬性,它會幹嘛?它會呼叫obj.get()
方法,它會找到全域變數age
,得到undefined
。
當我設定obj.age = 20
時,它會呼叫obj.set()
方法,將全域變數age
設為20
。
此時在呼叫obj.age
,得到20
。
注意:資料描述子和儲存描述子不能同時存在,否則會報錯
let obj = {} let age Object.defineProperty(obj,'age',{ value:10, //报错 get:function(){ return age }, set:function(newVal){ age = newVal } })
資料攔截
##使用Object.defineProperty 來實現資料攔截,從而實現資料監聽。
let data = { name:'zhangsan', friends:[1,2,3,4] }
data物件的監聽,就可以在內部做一些事情
observe(data)
data內部的屬性都被我們監控的,當呼叫屬性時,就可以在上面做些手腳,使得傳回的值變掉;當設定屬性時,不給他設定。
observe這個函數該怎麼寫呢?
function observe(data){ if(!data || typeof data !== 'object')return //如果 data 不是对象,什么也不做,直接跳出,也就是说只对 对象 操作 for(let key in data){ //遍历这个对象 let val = data[key] //得到这个对象的每一个`value` if(typeof val === 'object'){ //如果这个 value 依然是对象,用递归的方式继续调用,直到得到基本值的`value` observe(val) } Object.defineProperty(data,key,{ //定义对象 configurable:true, //可删除,原本的对象就能删除 enumerable:true, //可遍历,原本的对象就能遍历 get:function(){ console.log('这是假的') //调用属性时,会调用 get 方法,所以调用属性可以在 get 内部做手脚 //return val //这里注释掉了,实际调用属性就是把值 return 出去 }, set:function(newVal){ console.log('我不给你设置。。。') //设置属性时,会调用 set 方法,所以设置属性可以在 set 内部做手脚 //val = newVal //这里注释掉了,实际设置属性就是这样写的。 } }) } }
- 我們在宣告
let val = data[key]
時,不能用
var,因為這裡需要對每個屬性進行監控,用
let每次遍歷都會建立一個新的
val,在進行賦值;如果用
var#,只有第一次才是聲明,後面都是對一次聲明
val進行賦值,遍歷結束後,得到的是最後一個屬性,顯然這不是我們需要的。
get
方法裡,
return就是前面宣告的
val#,這裡不能用
data[key ],會報錯。因為呼叫
data.name,就是呼叫
get方法時,得到的結果是
data.name,又繼續呼叫
get方法,就隨變成死循環,所以這裡需要用一個變數來儲存
data[key],並將這個變數回傳。
不同的用户(我们把它叫做观察者:Observer)都可以订阅同一个公众号(我们把它叫做主体:Subject)
当订阅的公众号更新时(主体),用户都能收到通知(观察者)
用代码怎么实现呢?先看逻辑:
Subject 是构造函数,new Subject()创建一个主题对象,它维护订阅该主题的一个观察者数组数组(举例来说:Subject 是腾讯推出的公众号,new Subject() 是一个某个机构的公众号——新世相,它要维护订阅这个公众号的用户群体)
主题上有一些方法,如添加观察者addObserver
、删除观察者removeObserver
、通知观察者更新notify
(举例来说:新世相将用户分为两组,一组是忠粉就是 addObserver,一组是黑名单就是:removeObserver,它在忠粉组可以添加用户,可以在黑名单里拉黑一些杠精,如果有福利发放,它就会统治忠粉里的用户:notify)
Observer 是构造函数,new Observer() 创建一个观察者对象,该对象有一个update
方法(举例来说:Observer 是忠粉用户群体,new Observer() 是某个具体的用户——小王,他必须要打开流量才能收到新世相的福利推送:updata)
当调用notify
时实际上调用全部观察者observer
自身的update
方法(举例来说:当新世相推送福利时,它会自动帮忠粉组的用户打开流量,这比较极端,只是用来举例)
ES5 写法:
function Subject(){ this.observers = [] } Subject.prototype.addObserver = function(observer){ this.observers.push(observer) } Subject.prototype.removeObserver = function(observer){ let index = this.observers.indexOf(observer) if(index > -1){ this.observers.splice(index,1) } } Subject.prototype.notify = function(){ this.observers.forEach(observer=>{ observer.update() }) } function Observer(name){ this.name = name this.update = function(){ console.log(name + ' update...') } } let subject = new Subject() //创建主题 let observer1 = new Observer('xiaowang') //创建观察者1 subject.addObserver(observer1) //主题添加观察者1 let observer2 = new Observer('xiaozhang') //创建观察者2 subject.addObserver(observer2) //主题添加观察者2 subject.notify() //主题通知观察者 /**** 输出 *****/ hunger update... valley update...
ES6 写法:
class Subject{ constructor(){ this.observers = [] } addObserver(observer){ this.observers.push(observer) } removeObserver(observer){ let index = this.observers.indexOf(observer) if(index > -1){ this.observers.splice(index,1) } } notify(){ this.observers.forEach(observer=>{ observer.update() }) } } class Observer{ constructor(name){ this.name = name this.update = function(){ console.log(name + ' update...') } } } let subject = new Subject() //创建主题 let observer1 = new Observer('xiaowang') //创建观察者1 subject.addObserver(observer1) //主题添加观察者1 let observer2 = new Observer('xiaozhang') //创建观察者2 subject.addObserver(observer2) //主题添加观察者2 subject.notify() //主题通知观察者 /**** 输出 *****/ hunger update... valley update...
ES5 和 ES6 写法效果一样,ES5 的写法更好理解,ES6 只是个语法糖
主题添加观察者的方法subject.addObserver(observer)
很繁琐,直接给观察者下方权限,给他们增加添加进忠粉组的权限
class Observer{ constructor() { this.update = function() { console.log(name + ' update...') } } subscribeTo(subject) { //只要用户订阅了主题就会自动添加进忠粉组 subject.addObserver(this) //这里的 this 是 Observer 的实例 } } let subject = new Subject() let observer = new Observer('lisi') observer.subscribeTo(subject) //观察者自己订阅忠粉分组 subject.notify() /****** 输出 *******/ lisi update...
MVVM 框架的内部基本原理就是上面这些。
相关推荐:
以上是原生js實作MVVM框架的基本原理詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

WebSocket與JavaScript:實現即時監控系統的關鍵技術引言:隨著互聯網技術的快速發展,即時監控系統在各個領域中得到了廣泛的應用。而實現即時監控的關鍵技術之一就是WebSocket與JavaScript的結合使用。本文將介紹WebSocket與JavaScript在即時監控系統中的應用,並給出程式碼範例,詳細解釋其實作原理。一、WebSocket技

如何使用WebSocket和JavaScript實現線上語音辨識系統引言:隨著科技的不斷發展,語音辨識技術已成為了人工智慧領域的重要組成部分。而基於WebSocket和JavaScript實現的線上語音辨識系統,具備了低延遲、即時性和跨平台的特點,成為了廣泛應用的解決方案。本文將介紹如何使用WebSocket和JavaScript來實現線上語音辨識系

如何利用JavaScript和WebSocket實現即時線上點餐系統介紹:隨著網路的普及和技術的進步,越來越多的餐廳開始提供線上點餐服務。為了實現即時線上點餐系統,我們可以利用JavaScript和WebSocket技術。 WebSocket是一種基於TCP協定的全雙工通訊協議,可實現客戶端與伺服器的即時雙向通訊。在即時線上點餐系統中,當使用者選擇菜餚並下訂單

如何使用WebSocket和JavaScript實現線上預約系統在當今數位化的時代,越來越多的業務和服務都需要提供線上預約功能。而實現一個高效、即時的線上預約系統是至關重要的。本文將介紹如何使用WebSocket和JavaScript來實作一個線上預約系統,並提供具體的程式碼範例。一、什麼是WebSocketWebSocket是一種在單一TCP連線上進行全雙工

JavaScript和WebSocket:打造高效的即時天氣預報系統引言:如今,天氣預報的準確性對於日常生活以及決策制定具有重要意義。隨著技術的發展,我們可以透過即時獲取天氣數據來提供更準確可靠的天氣預報。在本文中,我們將學習如何使用JavaScript和WebSocket技術,來建立一個高效的即時天氣預報系統。本文將透過具體的程式碼範例來展示實現的過程。 We

JavaScript教學:如何取得HTTP狀態碼,需要具體程式碼範例前言:在Web開發中,經常會涉及到與伺服器進行資料互動的場景。在與伺服器進行通訊時,我們經常需要取得傳回的HTTP狀態碼來判斷操作是否成功,並根據不同的狀態碼來進行對應的處理。本篇文章將教你如何使用JavaScript來取得HTTP狀態碼,並提供一些實用的程式碼範例。使用XMLHttpRequest

用法:在JavaScript中,insertBefore()方法用於在DOM樹中插入一個新的節點。這個方法需要兩個參數:要插入的新節點和參考節點(即新節點將要插入的位置的節點)。

JavaScript中的HTTP狀態碼取得方法簡介:在進行前端開發中,我們常常需要處理與後端介面的交互,而HTTP狀態碼就是其中非常重要的一部分。了解並取得HTTP狀態碼有助於我們更好地處理介面傳回的資料。本文將介紹使用JavaScript取得HTTP狀態碼的方法,並提供具體程式碼範例。一、什麼是HTTP狀態碼HTTP狀態碼是指當瀏覽器向伺服器發起請求時,服務
