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