成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

ES6-Proxy與數(shù)據(jù)劫持(12)

li21 / 3465人閱讀

摘要:我們先以框架出發(fā),探索其中數(shù)據(jù)劫持的奧秘。針對對象在數(shù)據(jù)劫持這個(gè)問題上,可以被認(rèn)為是的升級版。技術(shù)支持監(jiān)測數(shù)組的等方法操作,支持對象屬性的動(dòng)態(tài)添加和刪除,極大的簡化了響應(yīng)化的代碼量。

隨著前端界的空前繁榮,各種框架橫空出世,包括各類mvvm框架百家爭鳴,比如Anglar、Vue、React等等,它們最大的優(yōu)點(diǎn)就是可以實(shí)現(xiàn)數(shù)據(jù)綁定,再也不需要手動(dòng)進(jìn)行DOM操作了,它們實(shí)現(xiàn)的原理也基本上是臟檢查或數(shù)據(jù)劫持。我們先以Vue框架出發(fā),探索其中數(shù)據(jù)劫持的奧秘。

Vue 2.0的版本所使用的數(shù)據(jù)劫持,說白了就是通過Object.defineProperty()來劫持對象屬性的setter和getter操作,在數(shù)據(jù)變動(dòng)時(shí)做你想要做的事情,舉個(gè)栗子:

var data = {
    name:"xiaoming"
}

Object.keys(data).forEach(function(key){
    Object.defineProperty(data,key,{
        get:function(){
            console.log("get");
        },
        set:function(){
            console.log("監(jiān)聽到數(shù)據(jù)發(fā)生了變化");
        }
    })
});
data.name //控制臺會打印出 “get”
data.name = "xiaohong" //控制臺會打印出 "監(jiān)聽到數(shù)據(jù)發(fā)生了變化"

但是有沒有比Object.defineProperty更好的實(shí)現(xiàn)方式呢?

答案是肯定的有,那就是我們今天的主人公:Proxy

1、Proxy簡介

Proxy這個(gè)詞的原意是代理,用在這里表示由它來代理某些操作,可以譯為代理器。

也可以理解成在目標(biāo)對象之前設(shè)置一層攔截,外界對該對象的訪問,都必須先通過這層攔截,因此提供了一種機(jī)制,可以對外界的訪問進(jìn)行過濾和改寫。

在生活中,代理模式的場景是十分常見的,例如我們現(xiàn)在如果有購買海外產(chǎn)品(給女朋友買一個(gè)LV的包包,前提是你要先有個(gè)女朋友,^_^)的需求,更多的是去找代購中介機(jī)構(gòu),而不是直接去國外買。此時(shí),代購起到的作用就是代理的作用。


Proxy構(gòu)造函數(shù)能夠讓我們輕松的使用代理模式:

var proxy = new Proxy(target, handler);

Proxy構(gòu)造函數(shù)中有兩個(gè)參數(shù):

target是用Proxy包裝的被代理對象(可以是任何類型的對象,包括原生數(shù)組,函數(shù),甚至另一個(gè)代理)。

handler是一個(gè)對象,其聲明了代理target 的一些操作,其屬性是當(dāng)執(zhí)行一個(gè)操作時(shí)定義代理的行為的函數(shù)。

講的通俗點(diǎn),如何讓代購幫你買LV的包包呢?

首先,你需要告訴代購你看好了哪款包包,這個(gè)款式就是Proxy里的第一個(gè)參數(shù)target。

其次就是制定購買策略,例如國外比國內(nèi)便宜20%,就買2個(gè),便宜40%,就買4個(gè),這個(gè)策略就是第二個(gè)參數(shù)handle。

2、Proxy中的處理方法

Proxy有13種數(shù)據(jù)劫持的操作,那是相當(dāng)?shù)膹?qiáng)大:

2.1 get方法

get方法是在你得到某對象屬性值時(shí)預(yù)處理的方法,接受兩個(gè)常用參數(shù)

target:得到的目標(biāo)值

key:目標(biāo)的key值,相當(dāng)于對象的屬性

可以代購來模擬handle中的get方法,如下

var Bao = {
      name: "LV",
    price:9999,
};
var proxyBao = new Proxy(Bao, {
    get: function(target, key) {
        if (target["price"]>5000) {
          return "超出客戶心理價(jià)位,不買了";
        } else {
          return "符合客戶心理預(yù)期,買買買";
        }
    }
});
proxyBao.price
//"超出客戶心理價(jià)位,不買了"

解釋一下:客戶想買一個(gè)LV的包,心理價(jià)位是5000,把購買目標(biāo)和需求都告訴了代購,代購詢問了下國外的價(jià)格,這款LV的包是9999,超出了客戶的心理價(jià)位,于是不買了。

2.2 set方法

set方法用來攔截某個(gè)屬性的賦值操作,可以接受四個(gè)參數(shù)

target:目標(biāo)值。

key:目標(biāo)的Key值。

value:要改變的值。

receiver:改變前的原始值。

假定Person對象有一個(gè)age屬性,該屬性應(yīng)該是一個(gè)不大于 200 的整數(shù),那么可以使用Proxy保證age的屬性值符合要求。

let validator = {
  set: function(target, key, value) {
    if (key === "age") {
      if (!Number.isInteger(value)) {
        throw new TypeError("The age is not an integer");
      }
      if (value > 200) {
        throw new RangeError("The age seems invalid");
      }
    }

    // 對于滿足條件的 age 屬性以及其他屬性,直接保存
    target[key] = value;
  }
};

let person = new Proxy({}, validator);

person.age = 100;

person.age // 100
person.age = "young" // 報(bào)錯(cuò) The age is not an integer
person.age = 300     // 報(bào)錯(cuò) The age seems invalid

上面代碼中,由于設(shè)置了存值函數(shù)set,任何不符合要求的age屬性賦值,都會拋出一個(gè)錯(cuò)誤,這是數(shù)據(jù)驗(yàn)證的一種實(shí)現(xiàn)方法。

3、Proxy相比Object.defineProperty的優(yōu)勢

3.1 支持?jǐn)?shù)組

let arr = [1,2,3]
let proxy = new Proxy(arr, {
    get (target, key, receiver) {
        console.log("get", key)
        return Reflect.get(target, key, receiver)
    },
    set (target, key, value, receiver) {
        console.log("set", key, value)
        return Reflect.set(target, key, value, receiver)
    }
})
proxy.push(4)
// 能夠打印出很多內(nèi)容
// get push     (尋找 proxy.push 方法)
// get length   (獲取當(dāng)前的 length)
// set 3 4      (設(shè)置 proxy[3] = 4)
// set length 4 (設(shè)置 proxy.length = 4)

Proxy 不需要對數(shù)組的方法進(jìn)行重載,省去了眾多 hack,減少代碼量等于減少了維護(hù)成本,而且標(biāo)準(zhǔn)的就是最好的。

3.2 針對對象

在數(shù)據(jù)劫持這個(gè)問題上,Proxy 可以被認(rèn)為是 Object.defineProperty() 的升級版。外界對某個(gè)對象的訪問,都必須經(jīng)過這層攔截。因此它是針對 整個(gè)對象,而不是 對象的某個(gè)屬性,所以也就不需要對 keys 進(jìn)行遍歷。

let obj = {
  name: "Eason",
  age: 30
}
let handler = {
  get (target, key, receiver) {
    console.log("get", key)
    return Reflect.get(target, key, receiver)
  },
  set (target, key, value, receiver) {
    console.log("set", key, value)
    return Reflect.set(target, key, value, receiver)
  }
}
let proxy = new Proxy(obj, handler)
proxy.name = "Zoe" // set name Zoe
proxy.age = 18 // set age 18

3.3 嵌套支持

本質(zhì)上,Proxy 也是不支持嵌套的,這點(diǎn)和 Object.defineProperty() 是一樣的。因此也需要通過逐層遍歷來解決。Proxy 的寫法是在 get 里面遞歸調(diào)用 Proxy 并返回,代碼如下:

let obj = {
  info: {
    name: "eason",
    blogs: ["webpack", "babel", "cache"]
  }
}
let handler = {
  get (target, key, receiver) {
    console.log("get", key)
    // 遞歸創(chuàng)建并返回
    if (typeof target[key] === "object" && target[key] !== null) {
      return new Proxy(target[key], handler)
    }
    return Reflect.get(target, key, receiver)
  },
  set (target, key, value, receiver) {
    console.log("set", key, value)
    return Reflect.set(target, key, value, receiver)
  }
}
let proxy = new Proxy(obj, handler)
// 以下兩句都能夠進(jìn)入 set
proxy.info.name = "Zoe"
proxy.info.blogs.push("proxy")

4、應(yīng)用實(shí)例

4.1 使用Proxy實(shí)現(xiàn)表單校驗(yàn)

let person = {
    name: "xiaoming",
    age: 30
}
let handler = {
    set (target, key, value, receiver) {
      if (key === "name" && typeof value !== "string") {
        throw new Error("用戶姓名必須是字符串類型")
      }
      if (key === "age" && typeof value !== "number") {
        throw new Error("用戶年齡必須是數(shù)字類型")
      }
      return Reflect.set(target, key, value, receiver)
    }
}
let boy = new Proxy(person, handler)
boy.name = "xiaohong" // OK
boy.age = "18" // 報(bào)錯(cuò)  用戶年齡必須是數(shù)字類型

5、總結(jié)

Proxy本質(zhì)上屬于元編程非破壞性數(shù)據(jù)劫持,在原對象的基礎(chǔ)上進(jìn)行了功能的衍生而又不影響原對象,符合松耦合高內(nèi)聚的設(shè)計(jì)理念。

通俗的說Proxy在數(shù)據(jù)外層套了個(gè)殼,然后通過這層殼訪問內(nèi)部的數(shù)據(jù),就像下面的圖:


Proxy讓JS開發(fā)者很方便的使用代理模式,使函數(shù)更加強(qiáng)大,業(yè)務(wù)邏輯更加清楚。

Proxy 不但可以取代 Object.defineProperty 并且還擴(kuò)增了非常多的功能。Proxy 技術(shù)支持監(jiān)測數(shù)組的 push 等方法操作,支持對象屬性的動(dòng)態(tài)添加和刪除,極大的簡化了響應(yīng)化的代碼量。Vue 3.0的也會使用Proxy去實(shí)現(xiàn)部分核心代碼。

在業(yè)務(wù)開發(fā)時(shí)應(yīng)該注意Proxy使用場景,當(dāng)對象的功能變得復(fù)雜或者我們需要進(jìn)行一定的訪問限制時(shí),便可以考慮使用代理。

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/109557.html

相關(guān)文章

  • 初入ES6-Proxy和Reflect

    摘要:用于修改某些操作的默認(rèn)行為和訪問器屬性的行為類似在對象的前面多一層代理,對象字面量中定義屬性的特性方法,訪問器屬性此時(shí)屬性被定義為訪問器屬性不一樣的寫法中是用代理的寫法第一個(gè)參數(shù)是對象,第二個(gè)是要操作的方法對象也有兩個(gè)屬性,一個(gè)是目標(biāo)對象, 1,Proxy用于修改某些操作的默認(rèn)行為和訪問器屬性的行為類似,在對象的前面多一層代理, const obj = { ...

    BakerJ 評論0 收藏0
  • 全球HTTPS時(shí)代已來,你跟上了嗎?

    摘要:而未來的互聯(lián)網(wǎng)網(wǎng)絡(luò)鏈路日趨復(fù)雜,加重了安全事件發(fā)生。蘋果強(qiáng)制開啟標(biāo)準(zhǔn)蘋果宣布年月日起,所有提交到的必須強(qiáng)制開啟安全標(biāo)準(zhǔn),所有連接必須使用加密。最后是安全意識。 互聯(lián)網(wǎng)發(fā)展20多年,大家都習(xí)慣了在瀏覽器地址里輸入HTTP格式的網(wǎng)址。但前兩年,HTTPS逐漸取代HTTP,成為傳輸協(xié)議界的新寵。?早在2014年,由網(wǎng)際網(wǎng)路安全研究組織Internet Security Research Gr...

    hss01248 評論0 收藏0
  • 從函數(shù)劫持角度看開發(fā)調(diào)試工具AlloyLever

    摘要:第四行是為了保存當(dāng)前語境下的,事實(shí)上在瀏覽器的調(diào)試工具中直接運(yùn)行這些代碼的時(shí)候,這個(gè)指向的就是全局對象,所以去掉這一行,將下面的改成,程序的運(yùn)行結(jié)果是一模一樣的。 在騰訊的AlloyTeam的Blog上發(fā)現(xiàn)了這樣的一款工具:AlloyLever(原blog地址:http://www.alloyteam.com/2016...),覺得非常有趣且實(shí)用。尤其是其實(shí)現(xiàn)的原理也并不復(fù)雜,卻可以給...

    xiongzenghui 評論0 收藏0
  • 淺談前端安全

    摘要:安全問題的分類按照所發(fā)生的區(qū)域分類后端安全問題所有發(fā)生在后端服務(wù)器應(yīng)用服務(wù)當(dāng)中的安全問題前端安全問題所有發(fā)生在瀏覽器單頁面應(yīng)用頁面當(dāng)中的安全問題按照團(tuán)隊(duì)中哪個(gè)角色最適合來修復(fù)安全問題分類后端安全問題針對這個(gè)安全問題,后端最適合來修復(fù)前端安全 安全問題的分類 按照所發(fā)生的區(qū)域分類 后端安全問題:所有發(fā)生在后端服務(wù)器、應(yīng)用、服務(wù)當(dāng)中的安全問題 前端安全問題:所有發(fā)生在瀏覽器、單頁面應(yīng)用、...

    Cympros 評論0 收藏0

發(fā)表評論

0條評論

最新活動(dòng)
閱讀需要支付1元查看
<