摘要:是一個(gè)輕巧的框架它實(shí)現(xiàn)了數(shù)據(jù)的雙向綁定并提供一些基本的指令幫助你提升效率,比如,,,,是的,如你所見,以開頭的指令是它的獨(dú)特標(biāo)識(shí)行左右的代碼量,讓應(yīng)用的開發(fā)和加載的一瞬完成倉庫訂閱清單前文說到提供了一個(gè)強(qiáng)大的接口我們就用它來劫持?jǐn)?shù)據(jù)不過在此
BiuJS
BiuJS是一個(gè)輕巧的mvvm框架訂閱清單
它實(shí)現(xiàn)了數(shù)據(jù)的雙向綁定
并提供一些基本的指令幫助你提升效率,比如$for,$model,$if,$click,$style
是的,如你所見,以$開頭的指令是它的獨(dú)特標(biāo)識(shí)
1000行左右的代碼量,讓應(yīng)用的開發(fā)和加載biu的一瞬完成
BiuJS倉庫: https://github.com/veedrin/biu
前文說到JavaScript提供了一個(gè)強(qiáng)大的接口Object.defineProperty
我們就用它來劫持?jǐn)?shù)據(jù)
不過在此之前,我們還有一點(diǎn)準(zhǔn)備工作要做
還記得前文提過的數(shù)組(訂閱清單)嗎?我們要造一個(gè)數(shù)組來裝東西
其實(shí)很簡單
function Dep() { this.subs = []; } Dep.prototype.addSub = function(sub) { this.subs.push(sub); }; Dep.prototype.notify = function(newValue) { for (let i = 0; i < this.subs.length; i++) { this.subs[i].update(newValue); } };
真的就是造個(gè)數(shù)組這么簡單
再來一個(gè)添加數(shù)組成員的方法,一個(gè)遍歷數(shù)組的方法
因?yàn)?b>Dep.prototype.notify觸發(fā)的開關(guān)在setter那里,也就是說前者依賴后者。Dep取其依賴之意
為了方便,我們還有一個(gè)取巧的地方,把訂閱者掛到Dep名下,作為Dep的靜態(tài)屬性緩存起來
function Dep() { this.subs = []; } Dep.target = null; Dep.prototype.addSub = function(sub) { this.subs.push(sub); }; Dep.prototype.notify = function(newValue) { for (let i = 0; i < this.subs.length; i++) { this.subs[i].update(newValue); } };劫持對象屬性
然后再回過頭來說劫持的事
BiuJS主方法傳進(jìn)來的data是一個(gè)對象,我們把它轉(zhuǎn)成數(shù)組再遍歷
Object.keys(data).forEach((key) => { let value = data[key]; let dep = new Dep; Object.defineProperty(data, key, { enumerable: true, configurable: true, get: function() { Dep.target && dep.addSub(Dep.target); return value; }, set: function(newValue) { if (value === newValue) { return; } value = newValue; dep.notify(newValue); } }); });
每個(gè)屬性都會(huì)得到一個(gè)訂閱清單的實(shí)例,用來放它的訂閱者
getter負(fù)責(zé)把訂閱者添加進(jìn)來,setter負(fù)責(zé)通知訂閱者更新
訂閱者是什么時(shí)候掛到Dep.target上的?這個(gè)我們暫且不表
有一個(gè)問題,data可能是嵌套的對象,而且可能嵌套的很深,所以我們要用遞歸深度劫持
Observer.prototype.observe = function(data) { if (!data || typeof data !== "object") { return; } let self = this; Object.keys(data).forEach((key) => { let value = data[key]; // do something self.observe(value); }); };
遞歸停止的條件就是(嵌套)data為空,或者(嵌套)data不是對象
劫持?jǐn)?shù)組方法問題又來了,假如(嵌套)data的值是數(shù)組呢?
我們來看一個(gè)例子
let data = { key: [1, 2] }; let value = data.key; Object.defineProperty(data, "key", { enumerable: true, configurable: true, get: function() { return value; }, set: function(newValue) { value = newValue; console.log("captured"); } }); data.key = [1, 2, 3]; // 控制臺(tái)打印"captured" data.key.push(3); // 控制臺(tái)沒有打印
數(shù)組本身變化是可以被捕捉到的,用方法操作數(shù)組,setter也很絕望啊
不要悲傷,不要絕望,數(shù)組開外掛,我們就查外掛
Object.defineProperty是對象的方法呀,難道要讓數(shù)組變性嗎?
是的
let arrayObject = Object.create(Array.prototype); console.log(arrayObject); // Array{}
有了它,我們就可以查外掛了
let arrayProto = Array.prototype; let arrayObject = Object.create(arrayProto); let methods = ["push", "pop", "unshift", "shift", "slice", "splice", "concat"]; methods.forEach((method) => { let origin = arrayProto[method]; Object.defineProperty(arrayObject, method, { enumerable: true, writable: true, configurable: true, value: function() { let args = Array.from(arguments); let result = origin.apply(this, args); dep.notify(Array.from(this)); return result; } }); });
上面的意思就是來一個(gè)偷天換日,把數(shù)組的方法名的value換成我們自己定義的函數(shù)
因?yàn)槭菙?shù)組的方法,這里的this指向的就是被操作的數(shù)組本身
在內(nèi)部還是用apply調(diào)用原方法,獲得返回值返回給我們自己定義的函數(shù)
在外面看起來是一樣的,只不過加了一條:悄悄的通知訂閱者更新
這回我們不需要?jiǎng)跓?b>setter了,數(shù)組的方法不是繞過了setter么,我們只要拿到操作完后的新數(shù)組,遞給訂閱者就好了
簡直就是碟中諜有沒有!
當(dāng)然,要達(dá)到效果,還需要最后一招:移花接木
methods.forEach((method) => { let origin = arrayProto[method]; Object.defineProperty(arrayObject, method, { // do something }); }); arr.__proto__ = arrayObject;
把我們自己定義的方法嫁接到被監(jiān)測數(shù)組的原型上
一招偷天換日,一招碟中諜,一招移花接木
殊不知,我們已經(jīng)在數(shù)組的方法身上植入了芯片,外掛game over
最后,遞歸的時(shí)候,我們要判斷一下,對象和數(shù)組走的是不同的路
if (!Array.isArray(value)) { this.observe(value); } else { this.observeArray(value, dep); }寫在后面
以上就是BiuJS劫持?jǐn)?shù)據(jù)以及添加到訂閱清單里的過程
歡迎到BiuJS倉庫: https://github.com/veedrin/biu了解詳情
更歡迎Star和Fork
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.hztianpu.com/yun/92278.html
摘要:是一個(gè)輕巧的框架它實(shí)現(xiàn)了數(shù)據(jù)的雙向綁定并提供一些基本的指令幫助你提升效率,比如,,,,是的,如你所見,以開頭的指令是它的獨(dú)特標(biāo)識(shí)行左右的代碼量,讓應(yīng)用的開發(fā)和加載的一瞬完成倉庫啟動(dòng)首先我們來看一下是如何啟動(dòng)的是的掛載點(diǎn),它決定在多大范圍的樹 showImg(https://segmentfault.com/img/remote/1460000012478667?w=1920&h=926...
摘要:是一個(gè)輕巧的框架它實(shí)現(xiàn)了數(shù)據(jù)的雙向綁定并提供一些基本的指令幫助你提升效率,比如,,,,是的,如你所見,以開頭的指令是它的獨(dú)特標(biāo)識(shí)行左右的代碼量,讓應(yīng)用的開發(fā)和加載的一瞬完成倉庫指令往下看之前,請大家沐浴更衣,因?yàn)槲乙v的指令了中的已經(jīng)被占用 showImg(https://segmentfault.com/img/remote/1460000012478667?w=1920&h=926...
摘要:如此循環(huán),直到結(jié)束如果循環(huán)結(jié)束之后,比字符串的長度要小,那說明后面還有文本匹配失敗了。 showImg(https://segmentfault.com/img/remote/1460000012478667?w=1920&h=926); BiuJS BiuJS是一個(gè)輕巧的mvvm框架它實(shí)現(xiàn)了數(shù)據(jù)的雙向綁定并提供一些基本的指令幫助你提升效率,比如$for,$model,$if,$cli...
摘要:一背景團(tuán)隊(duì)最近頻繁遭受網(wǎng)絡(luò)攻擊,引起了技術(shù)負(fù)責(zé)人的重視,筆者在團(tuán)隊(duì)中相對來說更懂安全,因此花了點(diǎn)時(shí)間編輯了一份安全開發(fā)自檢清單,覺得應(yīng)該也有不少讀者有需要,所以將其分享出來。 一、背景 團(tuán)隊(duì)最近頻繁遭受網(wǎng)絡(luò)攻擊,引起了技術(shù)負(fù)責(zé)人的重視,筆者在團(tuán)隊(duì)中相對來說更懂安全,因此花了點(diǎn)時(shí)間編輯了一份安全開發(fā)自檢清單,覺得應(yīng)該也有不少讀者有需要,所以將其分享出來。 二、編碼安全 2.1 輸入驗(yàn)證 ...
摘要:一背景團(tuán)隊(duì)最近頻繁遭受網(wǎng)絡(luò)攻擊,引起了技術(shù)負(fù)責(zé)人的重視,筆者在團(tuán)隊(duì)中相對來說更懂安全,因此花了點(diǎn)時(shí)間編輯了一份安全開發(fā)自檢清單,覺得應(yīng)該也有不少讀者有需要,所以將其分享出來。 一、背景 團(tuán)隊(duì)最近頻繁遭受網(wǎng)絡(luò)攻擊,引起了技術(shù)負(fù)責(zé)人的重視,筆者在團(tuán)隊(duì)中相對來說更懂安全,因此花了點(diǎn)時(shí)間編輯了一份安全開發(fā)自檢清單,覺得應(yīng)該也有不少讀者有需要,所以將其分享出來。 二、編碼安全 2.1 輸入驗(yàn)證 ...
閱讀 1457·2021-11-15 18:11
閱讀 2583·2021-08-19 10:56
閱讀 737·2021-08-09 13:42
閱讀 887·2019-08-30 15:53
閱讀 2142·2019-08-30 10:55
閱讀 3226·2019-08-29 17:18
閱讀 1512·2019-08-29 13:45
閱讀 624·2019-08-29 13:15