摘要:數(shù)組則在對(duì)象監(jiān)聽(tīng)之外額外在數(shù)組對(duì)象上的原型鏈上加一層原型對(duì)象來(lái)攔截掉等方法然后在執(zhí)行預(yù)設(shè)的回調(diào)函數(shù)最后本文有什么不完善的地方或者流程圖有待改進(jìn)的地方敬請(qǐng)斧正。
前言
隨著前端交互復(fù)雜度的提升,各類框架如angular,react,vue等也層出不窮,這些框架一個(gè)比較重要的技術(shù)點(diǎn)就是數(shù)據(jù)綁定。數(shù)據(jù)的監(jiān)聽(tīng)有較多的實(shí)現(xiàn)方案,本文將粗略的描述一番,并對(duì)其中一個(gè)兼容性較好的深入分析。
實(shí)現(xiàn)方案簡(jiǎn)介目前對(duì)象的監(jiān)聽(tīng)可行的方案:
臟檢查: 需要遍歷scope對(duì)象樹(shù)里的$watch數(shù)組,使用不當(dāng)容易造成性能問(wèn)題
ES5 object.defineproperty: 除ie8部分支持 其他基本都完全支持
ES7 object.observe : 已經(jīng)移除(緣由)出ES7草案
gecko object.watch :目前只有基于gecko的瀏覽器如火狐支持,官方建議僅供調(diào)試用
ES6 Proxy: 目前支持較差,babel也暫不支持轉(zhuǎn)化
ES5現(xiàn)代瀏覽器基本都支持了,OK,本文將介紹目前支持度最好的object.defineproperty 的Setters 和 Getters方式
object.defineproperty介紹 簡(jiǎn)潔的介紹它屬于es5規(guī)范,有兩種定義屬性:
一種是 數(shù)據(jù)屬性 包含Writable,Enumerable,Configurable
一種是 訪問(wèn)器屬性 包含get 和set
數(shù)據(jù)屬性的例子
obj.key="static"; //等效于 Object.defineProperty(obj, "key", { enumerable: true, configurable: true, writable: true, value: "static" });
訪問(wèn)器屬性例子
var obj = { temperature:"test" }; var temperature=""; Object.defineProperty(obj, "temperature", { get: function() { return temperature+"-----after"; }, set: function(value) { temperature = value; } }) obj.temperature="Test"; //Test-----after console.log(obj.temperature);詳細(xì)的介紹
火狐開(kāi)發(fā)者
實(shí)現(xiàn)監(jiān)聽(tīng)的思路將需要監(jiān)聽(tīng)對(duì)象/數(shù)組 obj和回調(diào)函數(shù)callback傳入構(gòu)造函數(shù),this.callback = callback 存儲(chǔ)回調(diào)函數(shù)
遍歷對(duì)象/數(shù)組obj,通過(guò)Object.defineProperty將屬性全部定義一遍。在set函數(shù)里面添加callback函數(shù),設(shè)置val值。get函數(shù)返回val。
判斷對(duì)應(yīng)的obj[key]是否為對(duì)象,是則進(jìn)入第二步,否則繼續(xù)遍歷
遍歷結(jié)束之后判斷該對(duì)象是否為數(shù)組,是則對(duì)操作數(shù)組函數(shù)如push,pop,shift,unshift等進(jìn)行封裝,操作數(shù)組前調(diào)用callback函數(shù)
數(shù)組的封裝比較復(fù)雜的是數(shù)組的封裝,結(jié)構(gòu)如下:
新建一個(gè)對(duì)象newProto,繼承Array的原型,并在newProto上面封裝push,pop等數(shù)組操作方法,再將傳入的array對(duì)象的原型設(shè)置為newProto。
在獲取數(shù)據(jù)變化的同時(shí),定位該變化數(shù)據(jù)在原始根對(duì)象的位置,以數(shù)組表示如:
如[ "a", "dd", "ffffd" ] 表示對(duì)象obj.a.dd.ffffd的屬性改變
實(shí)現(xiàn):每個(gè)遍歷對(duì)象屬性都通過(guò)path.slice(0)的方式復(fù)制入?yún)?shù)組path,生成新數(shù)組tpath,給tpath數(shù)組push對(duì)應(yīng)的對(duì)象屬性key,最后在執(zhí)行set的回調(diào)函數(shù)時(shí)候?qū)path當(dāng)參數(shù)傳入
watch.js
/** * * @param obj 需要監(jiān)聽(tīng)的對(duì)象或數(shù)組 * @param callback 當(dāng)對(duì)應(yīng)屬性變化的時(shí)候觸發(fā)的回調(diào)函數(shù) * @constructor */ function Watch(obj, callback) { this.callback = callback; //監(jiān)聽(tīng)_obj對(duì)象 判斷是否為對(duì)象,如果是數(shù)組,則對(duì)數(shù)組對(duì)應(yīng)的原型進(jìn)行封裝 //path代表相應(yīng)屬性在原始對(duì)象的位置,以數(shù)組表示. 如[ "a", "dd", "ffffd" ] 表示對(duì)象obj.a.dd.ffffd的屬性改變 this.observe = function (_obj, path) { var type=Object.prototype.toString.call(_obj); if (type== "[object Object]"||type== "[object Array]") { this.observeObj(_obj, path); if (type == "[object Array]") { this.cloneArray(_obj, path); } } }; //遍歷對(duì)象obj,設(shè)置set,get屬性,set屬性能觸發(fā)callback函數(shù),并將val的值改為newVal //遍歷結(jié)束后再次調(diào)用observe函數(shù) 判斷val是否為對(duì)象,如果是則在對(duì)val進(jìn)行遍歷設(shè)置set,get this.observeObj = function (obj, path) { var t = this; Object.keys(obj).forEach(function (prop) { var val = obj[prop]; var tpath = path.slice(0); tpath.push(prop); Object.defineProperty(obj, prop, { get: function () { return val; }, set: function (newVal) { t.callback(tpath, newVal, val); val = newVal; } }); t.observe(val, tpath); }); }; //通過(guò)對(duì)特定數(shù)組的原型中間放一個(gè)newProto原型,該原型繼承于Array的原型,但是對(duì)push,pop等數(shù)組操作屬性進(jìn)行封裝 this.cloneArray = function (a_array, path) { var ORP = ["push", "pop", "shift", "unshift", "splice", "sort", "reverse"]; var arrayProto = Array.prototype; var newProto = Object.create(arrayProto); var t = this; ORP.forEach(function (prop) { Object.defineProperty(newProto, prop, { value: function (newVal) { path.push(prop); t.callback(path, newVal); arrayProto[prop].apply(a_array, arguments); }, enumerable: false, configurable: true, writable: true }); }); a_array.__proto__ = newProto; }; //開(kāi)始監(jiān)聽(tīng)obj對(duì)象,初始path為[] this.observe(obj, []); }
index.html
完整代碼地址
流程圖具體流程的復(fù)雜度基于監(jiān)聽(tīng)對(duì)象的深度,所以下圖只對(duì)父對(duì)象做流程分析
通過(guò)定義對(duì)象內(nèi)部屬性的setter和getter方法,對(duì)將要變化的屬性進(jìn)行攔截代理,在變化前執(zhí)行預(yù)設(shè)的回調(diào)函數(shù)來(lái)達(dá)到對(duì)象監(jiān)聽(tīng)的目的。
數(shù)組則在對(duì)象監(jiān)聽(tīng)之外額外在數(shù)組對(duì)象上的原型鏈上加一層原型對(duì)象,來(lái)攔截掉push,pop等方法,然后在執(zhí)行預(yù)設(shè)的回調(diào)函數(shù)
最后本文有什么不完善的地方,或者流程圖有待改進(jìn)的地方,敬請(qǐng)斧正。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/87908.html
摘要:事件模型事件模型共有兩個(gè)過(guò)程事件處理階段。事件綁定監(jiān)聽(tīng)函數(shù)的方式如下事件移除監(jiān)聽(tīng)函數(shù)的方式如下參數(shù)說(shuō)明指定事件類型注意加是事件處理函數(shù)級(jí)模型屬于標(biāo)準(zhǔn)模型,現(xiàn)代瀏覽器除之外的瀏覽器都支持該模型。 JS事件模型 觀察者模式 觀察者模式又叫做發(fā)布訂閱者模式(Publish/Subscribe),它可以讓多個(gè)觀察者對(duì)象同時(shí)監(jiān)聽(tīng)某一個(gè)主題對(duì)象,這個(gè)主題對(duì)象的狀態(tài)變化時(shí)會(huì)通知所有的訂閱者,使得它們...
摘要:事件的監(jiān)聽(tīng)與事件的觸發(fā)事件一事件機(jī)制的實(shí)現(xiàn)中大部分的模塊,都繼承自模塊。從另一個(gè)角度來(lái)看,事件偵聽(tīng)器模式也是一種事件鉤子的機(jī)制,利用事件鉤子導(dǎo)出內(nèi)部數(shù)據(jù)或狀態(tài)給外部調(diào)用者。的核心就是事件發(fā)射與事件監(jiān)聽(tīng)器功能的封裝。 nodejs事件的監(jiān)聽(tīng)與事件的觸發(fā) nodejs事件(Events)showImg(https://segmentfault.com/img/bV0Sqi?w=692&h=...
摘要:我的個(gè)人博客地址資源地址非父子組件傳值,事件總線的使用方式我的博客地址如果您對(duì)我的博客內(nèi)容有疑惑或質(zhì)疑的地方,請(qǐng)?jiān)谙路皆u(píng)論區(qū)留言,或郵件給我,共同學(xué)習(xí)進(jìn)步。 歡迎訪問(wèn)我的個(gè)人博客:http://www.xiaolongwu.cn 前言 先說(shuō)一下什么是事件總線,其實(shí)就是訂閱發(fā)布者模式; 比如有一個(gè)bus對(duì)象,這個(gè)對(duì)象上有兩個(gè)方法,一個(gè)是on(監(jiān)聽(tīng),也就是訂閱),一個(gè)是emit(觸發(fā),也就...
摘要:之前的文章里有說(shuō),在中,流是許許多多原生對(duì)象的父類,角色可謂十分重要。效率更高的從數(shù)組中去除一個(gè)元素。不過(guò)這個(gè)所提供的功能過(guò)于多了,它支持去除自定義數(shù)量的元素,還支持向數(shù)組中添加自定義的元素。 之前的文章里有說(shuō),在 Node.js 中,流(stream)是許許多多原生對(duì)象的父類,角色可謂十分重要。但是,當(dāng)我們沿著族譜往上看時(shí),會(huì)發(fā)現(xiàn) EventEmitter 類是流(stream)類的...
摘要:取消事件的默認(rèn)行為。阻止事件的派發(fā)包括了捕獲和冒泡阻止同一個(gè)事件的其他監(jiān)聽(tīng)函數(shù)被調(diào)用。 事件模型 DOM0 級(jí)事件模型 -沒(méi)有事件流,這種方式兼容所有瀏覽器 // 方式一 將事件直接通過(guò)屬性綁定在元素上 / 方式二 獲取到頁(yè)面元素后,通過(guò) onclick 等事件,將觸發(fā)的方法指定為元素的事件 var btn = document.getElementById(btn) btn....
閱讀 3597·2023-04-26 01:43
閱讀 2984·2021-10-14 09:42
閱讀 5477·2021-09-30 09:59
閱讀 2183·2021-09-04 16:40
閱讀 1220·2019-08-30 15:52
閱讀 838·2019-08-29 17:09
閱讀 2006·2019-08-26 13:37
閱讀 3440·2019-08-26 10:20