欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

初探Vue3.0 中的一大亮點(diǎn)Proxy的使用

 更新時(shí)間:2018年12月06日 10:43:53   作者:Chris威  
這篇文章主要介紹了初探Vue3.0 中的一大亮點(diǎn)Proxy的使用,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧

前言

不久前,也就是11月14日-16日于多倫多舉辦的 VueConf TO 2018 大會(huì)上,尤雨溪發(fā)表了名為 Vue3.0 Updates 的主題演講,對(duì) Vue3.0 的更新計(jì)劃、方向進(jìn)行了詳細(xì)闡述,表示已經(jīng)放棄使用了 Object.defineProperty,而選擇了使用更快的原生 Proxy !!

這將會(huì)消除了之前 Vue2.x 中基于 Object.defineProperty 的實(shí)現(xiàn)所存在的很多限制:無(wú)法監(jiān)聽(tīng) 屬性的添加和刪除、數(shù)組索引和長(zhǎng)度的變更,并可以支持 Map、Set、WeakMap 和 WeakSet!

做為一個(gè) “前端工程師” ,有必要安利一波 Proxy !!

什么是 Proxy?

MDN 上是這么描述的——Proxy對(duì)象用于定義基本操作的自定義行為(如屬性查找,賦值,枚舉,函數(shù)調(diào)用等)。

官方的描述總是言簡(jiǎn)意賅,以至于不明覺(jué)厲...

其實(shí)就是在對(duì)目標(biāo)對(duì)象的操作之前提供了攔截,可以對(duì)外界的操作進(jìn)行過(guò)濾和改寫(xiě),修改某些操作的默認(rèn)行為,這樣我們可以不直接操作對(duì)象本身,而是通過(guò)操作對(duì)象的代理對(duì)象來(lái)間接來(lái)操作對(duì)象,達(dá)到預(yù)期的目的~

什么?還沒(méi)表述清楚?下面我們看個(gè)例子,就一目了然了~

  let obj = {
   a : 1
  }
  let proxyObj = new Proxy(obj,{
    get : function (target,prop) {
      return prop in target ? target[prop] : 0
    },
    set : function (target,prop,value) {
      target[prop] = 888;
    }
  })
  
  console.log(proxyObj.a);    // 1
  console.log(proxyObj.b);    // 0

  proxyObj.a = 666;
  console.log(proxyObj.a)     // 888

上述例子中,我們事先定義了一個(gè)對(duì)象 obj , 通過(guò) Proxy 構(gòu)造器生成了一個(gè) proxyObj 對(duì)象,并對(duì)其的 set(寫(xiě)入) 和 get (讀取) 行為重新做了修改。

當(dāng)我們?cè)L問(wèn)對(duì)象內(nèi)原本存在的屬性時(shí),會(huì)返回原有屬性內(nèi)對(duì)應(yīng)的值,如果試圖訪問(wèn)一個(gè)不存在的屬性時(shí),會(huì)返回0 ,即我們?cè)L問(wèn) proxyObj.a 時(shí),原本對(duì)象中有 a 屬性,因此會(huì)返回 1 ,當(dāng)我們?cè)噲D訪問(wèn)對(duì)象中不存在的 b 屬性時(shí),不會(huì)再返回 undefined ,而是返回了 0 ,當(dāng)我們?cè)噲D去設(shè)置新的屬性值的時(shí)候,總是會(huì)返回 888 ,因此,即便我們對(duì) proxyObj.a 賦值為 666 ,但是并不會(huì)生效,依舊會(huì)返回 888!

語(yǔ)法

ES6 原生提供的 Proxy 語(yǔ)法很簡(jiǎn)單,用法如下:

let proxy = new Proxy(target, handler);

參數(shù) target 是用 Proxy 包裝的目標(biāo)對(duì)象(可以是任何類型的對(duì)象,包括原生數(shù)組,函數(shù),甚至另一個(gè)代理), 參數(shù) handler 也是一個(gè)對(duì)象,其屬性是當(dāng)執(zhí)行一個(gè)操作時(shí)定義代理的行為的函數(shù),也就是自定義的行為。

Proxy 的基本用法就如同上面這樣,不同的是 handler 對(duì)象的不同,handler 可以是空對(duì)象 {} ,則表示對(duì) proxy 操作就是對(duì)目標(biāo)對(duì)象 target 操作,即:

  let obj = {}
  
  let proxyObj = new Proxy(obj,{})
  
  proxyObj.a = 1;
  proxyObj.fn = function () {
    console.log('it is a function')
  }

  console.log(proxyObj.a); // 1
  console.log(obj.a);   // 1
  console.log(obj.fn())  // it is a function

但是要注意的是,handler 不能 設(shè)置為 null ,會(huì)拋出一個(gè)錯(cuò)誤——Cannot create proxy with a non-object as target or handler!

要想 Proxy 起作用,我們就不能去操作原來(lái)對(duì)象的對(duì)象,也就是目標(biāo)對(duì)象 target (上例是 obj 對(duì)象 ),必須針對(duì)的是 Proxy 實(shí)例(上例是 proxyObj 對(duì)象)進(jìn)行操作,否則達(dá)不到預(yù)期的效果,以剛開(kāi)始的例子來(lái)看,我們?cè)O(shè)置 get 方法后,視圖繼續(xù)從原對(duì)象 obj 中讀取一個(gè)不存在的屬性 b , 結(jié)果依舊返回 undefined :

  console.log(proxyObj.b);   // 1
  console.log(obj.b);     // undefined

對(duì)于可以設(shè)置、但沒(méi)有設(shè)置攔截的操作,則對(duì) proxy 對(duì)象的處理結(jié)果也同樣會(huì)作用于原來(lái)的目標(biāo)對(duì)象 target 上,怎么理解呢?還是以剛開(kāi)始的例子來(lái)看,我們重新定義了 set 方法,所有的屬性設(shè)置都返回了 888 , 并沒(méi)有對(duì)某個(gè)特殊的屬性(這里指的是 obj 的 a 屬性 )做特殊的攔截或處理,那么通過(guò) proxyObj.a = 666 操作后的結(jié)果同樣也會(huì)作用于原來(lái)目標(biāo)對(duì)象(obj 對(duì)象)上,因此 obj 對(duì)象的 a 的值也將會(huì)變?yōu)?888 !

  proxyObj.a = 666;
  console.log( proxyObj.a);  // 888
  console.log( obj.a);    // 888

API

ES6 中 Proxy 目前提供了 13 種可代理操作,下面我對(duì)幾個(gè)比較常用的 api 做一些歸納和整理,想要了解其他方法的同學(xué)可自行去官網(wǎng)查閱 :

--handler.get(target,property,receiver)

用于攔截對(duì)象的讀取屬性操作,target 是指目標(biāo)對(duì)象,property 是被獲取的屬性名 , receiver 是 Proxy 或者繼承 Proxy 的對(duì)象,一般情況下就是 Proxy 實(shí)例。

let proxy = new Proxy({},{
  get : function (target,prop) {
    console.log(`get ${prop}`);
    return 10;
  }
})
  
console.log(proxy.a)  // get a
            // 10

我們攔截了一個(gè)空對(duì)象的 讀取get操作, 當(dāng)獲取其內(nèi)部的屬性是,會(huì)輸出 get ${prop} , 并返回 10 ;

let proxy = new Proxy({},{
  get : function (target,prop,receiver) {
      return receiver;
    }
  })

console.log(proxy.a)  // Proxy{}
console.log(proxy.a === proxy) //true

上述 proxy 對(duì)象的 a 屬性是由 proxy 對(duì)象提供的,所以 receiver 指向 proxy 對(duì)象,因此 proxy.a === proxy 返回的是 true。

要注意,如果要訪問(wèn)的目標(biāo)屬性是不可寫(xiě)以及不可配置的,則返回的值必須與該目標(biāo)屬性的值相同,也就是不能對(duì)其進(jìn)行修改,否則會(huì)拋出異常~

let obj = {};
Object.defineProperty(obj, "a", {
 configurable: false,
 enumerable: false,
 value: 10,
 writable: false
});

let proxy = new Proxy(obj,{
  get : function (target,prop) {
    return 20;
  }
})

console.log(proxy.a)  // Uncaught TypeError

上述 obj 對(duì)象中的 a 屬性不可寫(xiě),不可配置,我們通過(guò) Proxy 創(chuàng)建了一個(gè) proxy 的實(shí)例,并攔截了它的 get 操作,當(dāng)我們輸出 proxy.a 時(shí)會(huì)拋出異常,此時(shí),如果我們將 get 方法的返回值修改跟目標(biāo)屬性的值相同時(shí),也就是 10 , 就可以消除異常~

--handler.set(target, property, value, receiver)

用于攔截設(shè)置屬性值的操作,參數(shù)于 get 方法相比,多了一個(gè) value ,即要設(shè)置的屬性值~

在嚴(yán)格模式下,set方法需要返回一個(gè)布爾值,返回 true 代表此次設(shè)置屬性成功了,如果返回false且設(shè)置屬性操作失敗,并且會(huì)拋出一個(gè)TypeError。

let proxy = new Proxy({},{
  set : function (target,prop,value) {
    if( prop === 'count' ){
      if( typeof value === 'number'){
        console.log('success')
       target[prop] = value;
      }else{
       throw new Error('The variable is not an integer')
      }
    }
  }
})
  
 proxy.count = '10';  // The variable is not an integer
 
 proxy.count = 10;   // success

上述我們通過(guò)修改 set方法,對(duì) 目標(biāo)對(duì)象中的 count 屬性賦值做了限制,我們要求 count 屬性賦值必須是一個(gè) number 類型的數(shù)據(jù),如果不是,就返回一個(gè)錯(cuò)誤 The variable is not an integer,我們第一次為 count 賦值字符串 '10' , 拋出異常,第二次賦值為數(shù)字 10 , 打印成功,因此,我們可以用 set 方法來(lái)做一些數(shù)據(jù)校驗(yàn)!

同樣,如果目標(biāo)屬性是不可寫(xiě)及不可配置的,則不能改變它的值,即賦值無(wú)效,如下:

let obj = {};
Object.defineProperty(obj, "count", {
  configurable: false,
  enumerable: false,
  value: 10,
  writable: false
});

let proxy = new Proxy(obj,{
  set : function (target,prop,value) {
    target[prop] = 20;
  }
})

proxy.count = 20 ;
console.log(proxy.count)  // 10

上述 obj 對(duì)象中的 count 屬性,我們?cè)O(shè)置它不可被修改,并且默認(rèn)值,我們給定為 10 ,那么即使給其賦值為 20 ,結(jié)果仍舊沒(méi)有變化!

--handler.apply(target, thisArg, argumentsList)

用于攔截函數(shù)的調(diào)用,共有三個(gè)參數(shù),分別是目標(biāo)對(duì)象(函數(shù))target,被調(diào)用時(shí)的上下文對(duì)象 thisArg 以及被調(diào)用時(shí)的參數(shù)數(shù)組 argumentsList,該方法可以返回任何值。

target 必須是是一個(gè)函數(shù)對(duì)象,否則將拋出一個(gè)TypeError;

function sum(a, b) {
 return a + b;
}

const handler = {
  apply: function(target, thisArg, argumentsList) {
   console.log(`Calculate sum: ${argumentsList}`); 
   return target(argumentsList[0], argumentsList[1]) * 10;
  }
};

let proxy = new Proxy(sum, handler);

console.log(sum(1, 2));   // 3
console.log(proxy(1, 2));  // Calculate sum:1,2
              // 6

實(shí)際上,apply 還會(huì)攔截目標(biāo)對(duì)象的 Function.prototype.apply() 和 Function.prototype.call(),以及 Reflect.apply() 操作,如下:

console.log(proxy.call(null, 3, 4));  // Calculate sum:3,4
                    // 14

console.log(Reflect.apply(proxy, null, [5, 6]));  // Calculate sum: 5,6
                          // 22

--handler.construct(target, argumentsList, newTarget)

construct 用于攔截 new 操作符,為了使 new 操作符在生成的 Proxy對(duì)象上生效,用于初始化代理的目標(biāo)對(duì)象自身必須具有[[Construct]]內(nèi)部方法;它接收三個(gè)參數(shù),目標(biāo)對(duì)象 target ,構(gòu)造函數(shù)參數(shù)列表 argumentsList 以及最初實(shí)例對(duì)象時(shí),new 命令作用的構(gòu)造函數(shù),即下面例子中的 p。

let p = new Proxy(function() {}, {
  construct: function(target, argumentsList, newTarget) {
   console.log(newTarget === p );             // true
   console.log('called: ' + argumentsList.join(', '));   // called:1,2
   return { value: ( argumentsList[0] + argumentsList[1] )* 10 };
  }
});

console.log(new p(1,2).value);   // 30

另外,該方法必須返回一個(gè)對(duì)象,否則會(huì)拋出異常!

var p = new Proxy(function() {}, {
  construct: function(target, argumentsList, newTarget) {
   return 2
  }
});

console.log(new p(1,2));  // Uncaught TypeError

--handler.has(target,prop)

has方法可以看作是針對(duì) in 操作的鉤子,當(dāng)我們判斷對(duì)象是否具有某個(gè)屬性時(shí),這個(gè)方法會(huì)生效,典型的操作就是 in ,改方法接收兩個(gè)參數(shù) 目標(biāo)對(duì)象 target 和 要檢查的屬性 prop,并返回一個(gè) boolean 值。

let p = new Proxy({}, {
  has: function(target, prop) {
   if( prop[0] === '_' ) {
   console.log('it is a private property')
   return false;
   }
   return true;
  }
});

console.log('a' in p);   // true
console.log('_a' in p )   // it is a private property
              // false

上述例子中,我們用 has 方法隱藏了屬性以下劃線_開(kāi)頭的私有屬性,這樣在判斷時(shí)候就會(huì)返回 false,從而不會(huì)被 in 運(yùn)算符發(fā)現(xiàn)~

要注意,如果目標(biāo)對(duì)象的某一屬性本身不可被配置,則該屬性不能夠被代理隱藏,如果目標(biāo)對(duì)象為不可擴(kuò)展對(duì)象,則該對(duì)象的屬性不能夠被代理隱藏,否則將會(huì)拋出 TypeError。

let obj = { a : 1 };

Object.preventExtensions(obj); // 讓一個(gè)對(duì)象變的不可擴(kuò)展,也就是永遠(yuǎn)不能再添加新的屬性

let p = new Proxy(obj, {
 has: function(target, prop) {
 return false;
 }
});

console.log('a' in p); // TypeError is thrown

數(shù)據(jù)綁定

上面介紹了這么多,也算是對(duì) Proxy 又來(lái)一個(gè)初步的了解,那么我們就可以利用 Proxy 手動(dòng)實(shí)現(xiàn)一個(gè)極其簡(jiǎn)單數(shù)據(jù)的雙向綁定(Object.defineProperty() 的實(shí)現(xiàn)方式可以參考我上篇文章的末尾有涉及到)~

主要看功能的實(shí)現(xiàn),所以布局方面我就隨手一揮了~

頁(yè)面結(jié)構(gòu)如下:

<!--html-->
<div id="app">
  <h3 id="paragraph"></h3>
  <input type="text" id="input"/>
</div>

主要還是得看邏輯部分:

//獲取段落的節(jié)點(diǎn)
const paragraph = document.getElementById('paragraph');
//獲取輸入框節(jié)點(diǎn)
const input = document.getElementById('input');
  
//需要代理的數(shù)據(jù)對(duì)象
const data = {
 text: 'hello world'
}

const handler = {
 //監(jiān)控 data 中的 text 屬性變化
 set: function (target, prop, value) {
   if ( prop === 'text' ) {
        //更新值
        target[prop] = value;
        //更新視圖
        paragraph.innerHTML = value;
        input.value = value;
        return true;
   } else {
   return false;
   }
 }
}

//添加input監(jiān)聽(tīng)事件
input.addEventListener('input', function (e) {
  myText.text = e.target.value;  //更新 myText 的值
}, false)

//構(gòu)造 proxy 對(duì)象
const myText = new Proxy(data,handler);

//初始化值
myText.text = data.text;  

上述我們通過(guò)Proxy 創(chuàng)建了 myText 實(shí)例,通過(guò)攔截 myText 中 text 屬性 set 方法,來(lái)更新視圖變化,實(shí)現(xiàn)了一個(gè)極為簡(jiǎn)單的 雙向數(shù)據(jù)綁定~

總結(jié)

說(shuō)了這么多 , Proxy 總算是入門(mén)了,雖然它的語(yǔ)法很簡(jiǎn)單,但是要想實(shí)際發(fā)揮出它的價(jià)值,可不是件容易的事,再加上其本身的 Proxy 的兼容性方面的問(wèn)題,所以我們實(shí)際應(yīng)用開(kāi)發(fā)中使用的場(chǎng)景的并不是很多,但不代表它不實(shí)用,在我看來(lái),可以利用它進(jìn)行數(shù)據(jù)的二次處理、可以進(jìn)行數(shù)據(jù)合法性的校驗(yàn),甚至還可以進(jìn)行函數(shù)的代理,更多有用的價(jià)值等著你去開(kāi)發(fā)呢~

況且,Vue3.0 都已經(jīng)準(zhǔn)備發(fā)布了,你還不打算讓學(xué)習(xí)一下?

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 快速解決vue在ios端下點(diǎn)擊響應(yīng)延時(shí)的問(wèn)題

    快速解決vue在ios端下點(diǎn)擊響應(yīng)延時(shí)的問(wèn)題

    今天小編就為大家分享一篇快速解決vue在ios端下點(diǎn)擊響應(yīng)延時(shí)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • Vue?Electron實(shí)現(xiàn)輸入法自動(dòng)刷字?jǐn)?shù)功能詳解

    Vue?Electron實(shí)現(xiàn)輸入法自動(dòng)刷字?jǐn)?shù)功能詳解

    這篇文章主要介紹了Vue?Electron實(shí)現(xiàn)輸入法自動(dòng)刷字?jǐn)?shù)功能,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-12-12
  • vue自定義指令限制輸入框輸入值的步驟與完整代碼

    vue自定義指令限制輸入框輸入值的步驟與完整代碼

    這篇文章主要給大家介紹了關(guān)于vue自定義指令限制輸入框輸入值的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • vue+vue-validator 表單驗(yàn)證功能的實(shí)現(xiàn)代碼

    vue+vue-validator 表單驗(yàn)證功能的實(shí)現(xiàn)代碼

    這篇文章主要介紹了vue+vue-validator 表單驗(yàn)證功能的實(shí)現(xiàn)代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2017-11-11
  • 初探Vue3.0 中的一大亮點(diǎn)Proxy的使用

    初探Vue3.0 中的一大亮點(diǎn)Proxy的使用

    這篇文章主要介紹了初探Vue3.0 中的一大亮點(diǎn)Proxy的使用,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • 詳解element-ui中form驗(yàn)證雜記

    詳解element-ui中form驗(yàn)證雜記

    這篇文章主要介紹了詳解element-ui中form驗(yàn)證雜記,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-03-03
  • Vue組件開(kāi)發(fā)技巧總結(jié)

    Vue組件開(kāi)發(fā)技巧總結(jié)

    這篇文章通過(guò)代碼示例給大家詳細(xì)分析了Vue組件開(kāi)發(fā)的相關(guān)技巧以及知識(shí)點(diǎn),對(duì)此有需要的讀者們參考下吧。
    2018-03-03
  • 詳解探索 vuex 2.0 以及使用 vuejs 2.0 + vuex 2.0 構(gòu)建記事本應(yīng)用

    詳解探索 vuex 2.0 以及使用 vuejs 2.0 + vuex 2.0 構(gòu)建記事本應(yīng)用

    本篇文章主要介紹了詳解探索 vuex 2.0 以及使用 vuejs 2.0 + vuex 2.0 構(gòu)建記事本應(yīng)用 ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • element?select必填項(xiàng)驗(yàn)證回顯問(wèn)題的解決

    element?select必填項(xiàng)驗(yàn)證回顯問(wèn)題的解決

    本文主要介紹了element?select必填項(xiàng)驗(yàn)證回顯問(wèn)題的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Vue使用axios出現(xiàn)options請(qǐng)求方法

    Vue使用axios出現(xiàn)options請(qǐng)求方法

    這篇文章主要介紹了Vue使用axios出現(xiàn)options請(qǐng)求,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-05-05

最新評(píng)論