首頁 >web前端 >js教程 >JS Proxy 的優勢以及使用場景

JS Proxy 的優勢以及使用場景

Guanhui
Guanhui轉載
2020-06-15 09:22:414569瀏覽

JS Proxy 的優勢以及使用場景

開車的人往往不了解汽車的構造,但是深入了解汽車的構造,可能會有如虎添翼的效果

前言

隨著vue3.x 的訊息越來越多,proxy 的討論也。相對於 Object.definePropertyproxy 有什麼區別,有什麼優勢,以及可以應用在什麼地方。文章就簡單的介紹下

Object.defineProperty

proxy 之前,先回顧一下Object.defineProperty# 。大家都知道,vue2.x 以及之前的版本是使用 Object.defineProperty 實作資料的雙向綁定的,至於是怎樣綁定的呢?下面簡單實作一下

function observer(obj) {
    if (typeof obj === 'object') {
        for (let key in obj) {
            defineReactive(obj, key, obj[key])
        }
    }
}
function defineReactive(obj, key, value) { //针对value是对象,递归检测
    observer(value) //劫持对象的key
    Object.defineProperty(obj, key, {
        get() {
            console.log('获取:' + key) return value
        },
        set(val) { //针对所设置的val是对象
            observer(val) console.log(key + "-数据改变了") value = val
        }
    })
}
let obj = {
    name: '守候',
    flag: {
        book: {
            name: 'js',
            page: 325
        },
        interest: ['火锅', '旅游'],
    }
}

observer(obj)

在瀏覽器的console 執行一下,似乎能正常運行

JS Proxy 的優勢以及使用場景

但是實際上,Object.defineProperty 問題有以下幾個

問題1.刪除或增加物件屬性無法監聽到

例如增加一個屬性gender ,由於在執行observer(obj) 的時候,沒有這個屬性,所以這個無法監聽到。刪除的屬性也是無法監聽到

增加屬性的時候,vue 需要使用$set 來操作,$set 的內部也是使用Object.defineProperty 來操作

JS Proxy 的優勢以及使用場景

#問題2.陣列的變化無法監聽到

JS Proxy 的優勢以及使用場景

JS Proxy 的優勢以及使用場景

JS Proxy 的優勢以及使用場景

JS Proxy 的優勢以及使用場景

#由上圖得知,雖然陣列屬性其實是修改成功了,但是不能被監聽到

#問題3. 由於是使用遞歸遍歷對象,使用

Object.defineProperty  劫持物件的屬性,如果遍歷的物件層級比較深,花的時間比較久,甚至有效能的問題# proxy

對於proxy ,在mdn 上的描述是: 物件用於定義基本操作的自訂行為(如屬性查找、賦值、枚舉、函數呼叫等)

簡單來說就是,可以在對目標物件設定一層攔截。無論對目標物件進行什麼操作,都要經過這層攔截

聽上去似乎,proxy

Object.defineProperty 要好用,並且簡單很多,實際上就是如此。下面用proxy 對上面的程式碼進行改寫試下

function observerProxy(obj) {
    let handler = {
        get(target, key, receiver) {
            console.log('获取:' + key) // 如果是对象,就递归添加 proxy 拦截
            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(key + "-数据改变了") return Reflect.set(target, key, value, receiver)
        }
    }
    return new Proxy(obj, handler)
}
let obj = {
    name: '守候',
    flag: {
        book: {
            name: 'js',
            page: 325
        },
        interest: ['火锅', '旅游'],
    }
}
let objTest = observerProxy(obj)
也是一樣的效果

而且,能做到

Object.defineProperty

做不到的事情,例如增加一個屬性gender,能夠監聽到

#操作數組,也能監聽到#最後敲一下黑板,簡單總結一下兩者的差異

1.JS Proxy 的優勢以及使用場景Object.defineProperty

攔截的是物件的屬性,會改變原始物件。 ###proxy### 是攔截整個對象,透過 new 產生一個新對象,不會改變原始對象。 ######2.###proxy### 的攔截方式,除了上面的 get 和 set ,還有 11 種。選擇的方式很多 Proxy,也可以監聽一些  ###Object.defineProperty### 監聽不到的操作,例如監聽數組,監聽物件屬性的新增,刪除等。 #########proxy 使用場景#########關於###proxy### 的使用場景,受限於篇幅,這裡就簡單列舉幾個,更多的可以移步我的github 筆記或mdn。 ######看到這裡,兩者的差別,和 ###proxy### 的優勢已經知道個大概了。但是在開發上,有哪些場景可以使用到###proxy### 呢,下面列舉個可能會遇到的情況#########負索引數組#########在使用###splice(-1)###,###slice(-1)### 等API 的時候,當輸入負數的時候,會定位到陣列的最後一項,但在普通陣列上,並不能使用負數。 ###[1,2,3][-1]### 這個程式碼並不能輸出 3 。要讓上面的程式碼輸出 3 , 也可以使用 ###proxy### 實作。 ###
<br>
##########

表单校验

在对表单的值进行改动的时候,可以在 set 里面进行拦截,判断值是否合法

let ecValidate = {
    set(target, key, value, receiver) {
        if (key === &#39;age&#39;) { //如果值小于0,或者不是正整数
            if (value < 0 || !Number.isInteger(value)) {
                throw new TypeError(&#39;请输入正确的年龄&#39;);
            }
        }
        return Reflect.set(target, key, value, receiver)
    }
}
let obj = new Proxy({
    age: 18
},
ecValidate) obj.age = 16obj.age = &#39;少年&#39;

JS Proxy 的優勢以及使用場景

增加附加属性

比如有一个需求,保证用户输入正确身份证号码之后,把出生年月,籍贯,性别都添加进用户信息里面

众所周知,身份证号码第一和第二位代表所在省(自治区,直辖市,特别行政区),第三和第四位代表所在市(地级市、自治州、盟及国家直辖市所属市辖区和县的汇总码)。第七至第十四位是出生年月日。低17位代表性别,男单女双。

const PROVINCE_NUMBER = {
    44 : &#39;广东省&#39;,
    46 : &#39;海南省&#39;
}
const CITY_NUMBER = {
    4401 : &#39;广州市&#39;,
    4601 : &#39;海口市&#39;
}
let ecCardNumber = {
    set(target, key, value, receiver) {
        if (key === &#39;cardNumber&#39;) {
            Reflect.set(target, &#39;hometown&#39;, PROVINCE_NUMBER[value.substr(0, 2)] + CITY_NUMBER[value.substr(0, 4)], receiver) Reflect.set(target, &#39;date&#39;, value.substr(6, 8), receiver) Reflect.set(target, &#39;gender&#39;, value.substr( - 2, 1) % 2 === 1 ? &#39;男&#39;: &#39;女&#39;, receiver)
        }
        return Reflect.set(target, key, value, receiver)
    }
}
let obj = new Proxy({
    cardNumber: &#39;&#39;
},
ecCardNumber)

JS Proxy 的優勢以及使用場景

数据格式化

比如有一个需求,需要传时间戳给到后端,但是前端拿到的是一个时间字符串,这个也可以用 proxy 进行拦截,当得到时间字符串之后,可以自动加上时间戳。

let ecArrayProxy = {
    get(target, key, receiver) {
        let _index = key < 0 ? target.length + Number(key) : key
        return Reflect.get(target, _index, receiver)
    }
}
let arr = new Proxy([1, 2, 3], ecArrayProxy)

JS Proxy 的優勢以及使用場景<br>

推荐教程:《JS教程》    <br>

以上是JS Proxy 的優勢以及使用場景的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.im。如有侵權,請聯絡admin@php.cn刪除