国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

js對象監(jiān)聽實現(xiàn)

iamyoung001 / 513人閱讀

摘要:數(shù)組則在對象監(jiān)聽之外額外在數(shù)組對象上的原型鏈上加一層原型對象來攔截掉等方法然后在執(zhí)行預設的回調(diào)函數(shù)最后本文有什么不完善的地方或者流程圖有待改進的地方敬請斧正。

前言

隨著前端交互復雜度的提升,各類框架如angular,react,vue等也層出不窮,這些框架一個比較重要的技術點就是數(shù)據(jù)綁定。數(shù)據(jù)的監(jiān)聽有較多的實現(xiàn)方案,本文將粗略的描述一番,并對其中一個兼容性較好的深入分析。

實現(xiàn)方案簡介

目前對象的監(jiān)聽可行的方案:

臟檢查: 需要遍歷scope對象樹里的$watch數(shù)組,使用不當容易造成性能問題

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介紹 簡潔的介紹

它屬于es5規(guī)范,有兩種定義屬性:

一種是 數(shù)據(jù)屬性 包含Writable,Enumerable,Configurable

一種是 訪問器屬性 包含get 和set

數(shù)據(jù)屬性的例子

obj.key="static";
//等效于
Object.defineProperty(obj, "key", {
  enumerable: true,
  configurable: true,
  writable: true,
  value: "static"
});

訪問器屬性例子

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);
詳細的介紹

火狐開發(fā)者

實現(xiàn)監(jiān)聽的思路

將需要監(jiān)聽對象/數(shù)組 obj和回調(diào)函數(shù)callback傳入構造函數(shù),this.callback = callback 存儲回調(diào)函數(shù)

遍歷對象/數(shù)組obj,通過Object.defineProperty將屬性全部定義一遍。在set函數(shù)里面添加callback函數(shù),設置val值。get函數(shù)返回val。

判斷對應的obj[key]是否為對象,是則進入第二步,否則繼續(xù)遍歷

遍歷結(jié)束之后判斷該對象是否為數(shù)組,是則對操作數(shù)組函數(shù)如push,pop,shift,unshift等進行封裝,操作數(shù)組前調(diào)用callback函數(shù)

數(shù)組的封裝

比較復雜的是數(shù)組的封裝,結(jié)構如下:
新建一個對象newProto,繼承Array的原型,并在newProto上面封裝push,pop等數(shù)組操作方法,再將傳入的array對象的原型設置為newProto。

對應圖

路徑的定位

在獲取數(shù)據(jù)變化的同時,定位該變化數(shù)據(jù)在原始根對象的位置,以數(shù)組表示如:
如[ "a", "dd", "ffffd" ] 表示對象obj.a.dd.ffffd的屬性改變
實現(xiàn):每個遍歷對象屬性都通過path.slice(0)的方式復制入?yún)?shù)組path,生成新數(shù)組tpath,給tpath數(shù)組push對應的對象屬性key,最后在執(zhí)行set的回調(diào)函數(shù)時候?qū)path當參數(shù)傳入

帶注釋代碼

watch.js

/**
 *
 * @param obj 需要監(jiān)聽的對象或數(shù)組
 * @param callback 當對應屬性變化的時候觸發(fā)的回調(diào)函數(shù)
 * @constructor
 */
function Watch(obj, callback) {
    this.callback = callback;
    //監(jiān)聽_obj對象 判斷是否為對象,如果是數(shù)組,則對數(shù)組對應的原型進行封裝
    //path代表相應屬性在原始對象的位置,以數(shù)組表示. 如[ "a", "dd", "ffffd" ] 表示對象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);
            }
        }
    };

    //遍歷對象obj,設置set,get屬性,set屬性能觸發(fā)callback函數(shù),并將val的值改為newVal
    //遍歷結(jié)束后再次調(diào)用observe函數(shù) 判斷val是否為對象,如果是則在對val進行遍歷設置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);
        });
    };

    //通過對特定數(shù)組的原型中間放一個newProto原型,該原型繼承于Array的原型,但是對push,pop等數(shù)組操作屬性進行封裝
    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;
    };

    //開始監(jiān)聽obj對象,初始path為[]
    this.observe(obj, []);
}

index.html




效果圖

代碼地址

完整代碼地址

流程圖

具體流程的復雜度基于監(jiān)聽對象的深度,所以下圖只對父對象做流程分析

歸納

通過定義對象內(nèi)部屬性的setter和getter方法,對將要變化的屬性進行攔截代理,在變化前執(zhí)行預設的回調(diào)函數(shù)來達到對象監(jiān)聽的目的。

數(shù)組則在對象監(jiān)聽之外額外在數(shù)組對象上的原型鏈上加一層原型對象,來攔截掉push,pop等方法,然后在執(zhí)行預設的回調(diào)函數(shù)

最后

本文有什么不完善的地方,或者流程圖有待改進的地方,敬請斧正。

文章版權歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/87908.html

相關文章

  • JS事件模型

    摘要:事件模型事件模型共有兩個過程事件處理階段。事件綁定監(jiān)聽函數(shù)的方式如下事件移除監(jiān)聽函數(shù)的方式如下參數(shù)說明指定事件類型注意加是事件處理函數(shù)級模型屬于標準模型,現(xiàn)代瀏覽器除之外的瀏覽器都支持該模型。 JS事件模型 觀察者模式 觀察者模式又叫做發(fā)布訂閱者模式(Publish/Subscribe),它可以讓多個觀察者對象同時監(jiān)聽某一個主題對象,這個主題對象的狀態(tài)變化時會通知所有的訂閱者,使得它們...

    mylxsw 評論0 收藏0
  • Node事件機制小記

    摘要:事件的監(jiān)聽與事件的觸發(fā)事件一事件機制的實現(xiàn)中大部分的模塊,都繼承自模塊。從另一個角度來看,事件偵聽器模式也是一種事件鉤子的機制,利用事件鉤子導出內(nèi)部數(shù)據(jù)或狀態(tài)給外部調(diào)用者。的核心就是事件發(fā)射與事件監(jiān)聽器功能的封裝。 nodejs事件的監(jiān)聽與事件的觸發(fā) nodejs事件(Events)showImg(https://segmentfault.com/img/bV0Sqi?w=692&h=...

    airborne007 評論0 收藏0
  • vue -- 非父子組件傳值,事件總線(eventbus)的使用方式

    摘要:我的個人博客地址資源地址非父子組件傳值,事件總線的使用方式我的博客地址如果您對我的博客內(nèi)容有疑惑或質(zhì)疑的地方,請在下方評論區(qū)留言,或郵件給我,共同學習進步。 歡迎訪問我的個人博客:http://www.xiaolongwu.cn 前言 先說一下什么是事件總線,其實就是訂閱發(fā)布者模式; 比如有一個bus對象,這個對象上有兩個方法,一個是on(監(jiān)聽,也就是訂閱),一個是emit(觸發(fā),也就...

    zone 評論0 收藏0
  • 通過源碼解析 Node.js 中 events 模塊里的優(yōu)化小細節(jié)

    摘要:之前的文章里有說,在中,流是許許多多原生對象的父類,角色可謂十分重要。效率更高的從數(shù)組中去除一個元素。不過這個所提供的功能過于多了,它支持去除自定義數(shù)量的元素,還支持向數(shù)組中添加自定義的元素。 之前的文章里有說,在 Node.js 中,流(stream)是許許多多原生對象的父類,角色可謂十分重要。但是,當我們沿著族譜往上看時,會發(fā)現(xiàn) EventEmitter 類是流(stream)類的...

    cloud 評論0 收藏0
  • 詳解JS事件 - 事件模型/事件流/事件代理/事件對象/自定義事件

    摘要:取消事件的默認行為。阻止事件的派發(fā)包括了捕獲和冒泡阻止同一個事件的其他監(jiān)聽函數(shù)被調(diào)用。 事件模型 DOM0 級事件模型 -沒有事件流,這種方式兼容所有瀏覽器 // 方式一 將事件直接通過屬性綁定在元素上 / 方式二 獲取到頁面元素后,通過 onclick 等事件,將觸發(fā)的方法指定為元素的事件 var btn = document.getElementById(btn) btn....

    URLOS 評論0 收藏0

發(fā)表評論

0條評論

iamyoung001

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<