Proxy 物件的了解與學習

hzc
發布: 2020-06-29 10:39:44
轉載
3036 人瀏覽過

1、Proxy 物件到底是什麼?

Proxy 物件到底是什麼呢? Proxy 的意思是 代理,proxy物件的功能是:透過Proxy 建立1個代理對象,然後透過操作代理對象允許你對指定的對象的某些行為進行自訂處理。

Proxy(target,handler); Proxy建構子接收2個對象,第1個參數就是要處理的對象,第2個參數就是要自訂處理的方法的集合(也就是個對象) 。

很抽象?其實就和js中的Object.defineProperty很像(也就是存取器屬性,vue2.x的底層就是用它來實現的)。

Object.defineProperty 定義存取器屬性,可以對某個屬性的讀寫行為進行控制,在Proxy中也可以做到,而且Proxy更靈活和強大,它能做到很多存取器屬性做不到的事情。

例如,監聽屬性刪除事件(delete obj.prop;),in 事件('id' in obj;), apply 呼叫等。

先來看看,proxy物件有哪些內容。

    var targetObj = {
        id : 1,
        name : 'pxh',
        age : 20,
        school : '小学'
    }
    
    var handler = {};
    
    // 此处,我们先不对targetObj的行为进行干预,所以传个空对象进去即可。
    var proxy = new Proxy(targetObj,handler);
    
    console.log(proxy);
登入後複製

看看列印的proxy是什麼鬼,如下圖。

Proxy 物件的了解與學習

可以看到,proxy物件中,包含了Handler屬性和Target屬性和IsRevoked,它們的值分別是我們傳入的handler以及 targetObj和false。

這個isRevoked表示是否可撤銷,產生可撤銷的proxy物件用Proxy.revocable()方法,可以去MDN查看文件。

2、透過Proxy 物件操作原對象

上面我們建立了1個proxy對象,現在我們嘗試透過操作proxy物件來操作原對象,操作proxy物件就跟操作原生物件一樣即可。 (其實是proxy物件內部做了映射。)

    var targetObj = {
        id : 1,
        name : 'pxh',
        age : 20,
        school : '小学'
    }
    
    var handler = {};
    
    // 此处,我们先不对targetObj的行为进行干预,所以传个空对象进去即可。
    var proxy = new Proxy(targetObj,handler);
    
    
    /**
     * 1、读取及修改属性,可以看到原来的对象的属性也被修改了
     */
    console.log(proxy.age);  // 20
    console.log(targetObj.age); // 20
    proxy.age = 22;
    console.log(proxy.age);  // 22
    console.log(targetObj.age); // 22
    
    /**
     * 2、删除proxy对象的属性,影响原来的对象的属性
     */
    console.log(proxy.school);  // 小学
    console.log(targetObj.school); // 小学
    delete proxy.age;
    console.log(proxy.school);  // undefined
    console.log(targetObj.school); // undefined
登入後複製

3、set方法和get方法

好,現在我們可以開始介入原來物件的行為了,具體我們透過實作以下方法達到介入對象行為的目的。

  • handler.apply

  • handler.construct       介入建構子的new 行為

  • #handler. defineProperty  幹預物件的資料屬性或存取器屬性定義

  • handler.deleteProperty  介入物件的屬性刪除行為

  • handler.get             介入物件的屬性讀取行為

  • handler.getOwnProperty  幹預物件的屬性的特徵值

  • handler.has             介入物件的in行為(prop in obj )

  • handler.isExtensible

  • handler.ownKeys

  • ##handler.set             介入的屬性設定行為

  • ...
先來幹預get行為(屬性讀取行為)

    var targetObj = {
        id : 1,
        name : 'pxh',
        age : 20,
        school : '小学'
    }
    
    
    var handler = {
        // 定义get方法,get方法可以接收2个参数,分别是原来的对象及属性
        get : function(target,prop){
            console.log(`${prop}属性正在被查看`);
            console.log(targetObj == target); // true
            return target[prop];
        }
    };
    
    var proxy = new Proxy(targetObj,handler);
    
    console.log(proxy.id);
    
    /**
     * 可以看到,打印顺序为:
     *  id属性正在被查看
     *  true
     *  1
     */
登入後複製
接下來把某些屬性變成“私有」 ,如不允許讀取id屬性

定義set方法,不允許修改id,name,age屬性

    var targetObj = {
        id : 1,
        name : 'pxh',
        age : 20,
        school : '小学'
    }
    
    
    var handler = {
        // 定义get方法,get方法可以接收2个参数,分别是原来的对象及属性
        get : function(target,prop){
            if(prop == 'id'){
                return undefined;
            }
            return target[prop];
        },
        // 定义set方法,set方法比get多1个参数,那就是该属性修改时的值
        set : function(target,prop,value){
            if(prop == 'id' || prop == 'name' || prop == 'age'){
                console.log(`不允许修改${prop}属性`)
            }else{
                target[prop] = value;
            }
        }
    };
    
    var proxy = new Proxy(targetObj,handler);
    
    /**
     * 修改属性,分别打印
     * 不允许修改id属性
     * 不允许修改name属性
     * 不允许修改age属性
     */
    proxy.id = 2; 
    proxy.name = 'pxh222';
    proxy.age = 23;
    
    proxy.school = '中学'; // 这个无打印
    
    /**
     * 读取属性,可以看到分别打印
     * undefined
     * pxh
     * 20
     * 中学  // 这个没有拦截,因此可以修改
     */
    console.log(proxy.id);
    console.log(proxy.name);
    console.log(proxy.age);
    console.log(proxy.school);
登入後複製
4、幹預刪除行為(對delete obj.prop語句生效)

同樣的,我們對刪除物件屬性的行為進行幹預,不允許刪除id,name,age屬性。

    var targetObj = {
        id : 1,
        name : 'pxh',
        age : 20,
        school : '小学'
    }
    
    var handler = {
        // 在handler中定义get方法,get方法可以接收2个参数,分别是原来的对象及属性
        get : function(target,prop){
            if(prop == 'id'){
                return undefined;
            }
            return target[prop];
        },
        // set方法比get多1个参数,那就是该属性修改时的值
        set : function(target,prop,value){
            if(prop == 'id' || prop == 'name' || prop == 'age'){
                console.log(`不允许修改${prop}属性`)
            }else{
                target[prop] = value;
            }
        },
        /**
         * 这个方法要求返回个boolean值,表示是否删除成功
         * 如果返回的值不是boolean值,则会进行类型转换成boolean值再返回
         */
        deleteProperty : function(target,prop){
            if(prop == 'id' || prop == 'name' || prop == 'age'){
                console.log(`不允许删除${prop}属性`);
                return false;
            }else{
                delete target[prop];
                return true;
            }
        }
    };
    
    var proxy = new Proxy(targetObj,handler);
    /**
     * 尝试删除id属性,可以看到打印顺序为:
     * 不允许删除id属性
     * false
     */
    console.log(delete proxy.id);
    
    /**
     * 删除school属性,可以看到打印
     * true
     * undefined
     */
    console.log(delete proxy.school);
    console.log(proxy.school);
登入後複製
5、幹預prop in obj行為(判斷物件是否有某個屬性)

上面我們不允許取得物件的id值,也不可以修改、刪除,現在我們把它隱藏掉。

    var targetObj = {
        id : 1,
        name : 'pxh',
        age : 20,
        school : '小学'
    }
    
    var handler = {
        // 在handler中定义get方法,get方法可以接收2个参数,分别是原来的对象及属性
        get : function(target,prop){
            if(prop == 'id'){
                return undefined;
            }
            return target[prop];
        },
        // set方法比get多1个参数,那就是该属性修改时的值
        set : function(target,prop,value){
            if(prop == 'id' || prop == 'name' || prop == 'age'){
                console.log(`不允许修改${prop}属性`)
            }else{
                target[prop] = value;
            }
        },
        /**
         * 这个方法要求返回个boolean值,表示是否删除成功
         * 如果返回的值不是boolean值,则会进行类型转换成boolean值再返回
         */
        deleteProperty : function(target,prop){
            if(prop == 'id' || prop == 'name' || prop == 'age'){
                console.log(`不允许删除${prop}属性`);
                return false;
            }else{
                delete target[prop];
                return true;
            }
        },
        /**
         * 通过has 方法来控制,返回值也是个boolean,表示对象是否拥有某个属性
         * 如果返回的值不是boolean值,则会进行类型转换成boolean值再返回
         */
        has : function(target,prop){
            if(prop == 'id'){
                return false
            }else{
                return prop in target;
            }
        }
    };
    
    var proxy = new Proxy(targetObj,handler);
    console.log('id' in proxy); // false
    console.log('name' in proxy); // true
登入後複製
6、總結

同樣的,proxy還能介入物件的行為還有很多,這裡就不一一介紹了。有興趣戳MDN文檔

推薦教學:《

微信小程式

以上是Proxy 物件的了解與學習的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:jianshu.com
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
作者最新文章
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!