>  기사  >  웹 프론트엔드  >  JS Proxy의 장점 및 사용 시나리오

JS Proxy의 장점 및 사용 시나리오

Guanhui
Guanhui앞으로
2020-06-15 09:22:414547검색

JS Proxy의 장점 및 사용 시나리오

자동차를 운전하는 사람들은 자동차의 구조를 제대로 이해하지 못하는 경우가 많지만, 자동차의 구조에 대한 깊은 이해는 더욱 강력한 효과를 가져올 수도 있습니다

서문

vue3.x 점점 더 많은 뉴스가 나오고 프록시에 대한 토론도 있습니다. Object.defineProperty와 비교했을 때 차이점은 무엇인지, 프록시의 장점은 무엇이며, 어디에 적용할 수 있는지 알아보세요. 이번 글에서는 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

Object.defineProperty

JS Proxy의 장점 및 사용 시나리오에 대해 간략하게 소개하겠습니다. proxy에 대해 이야기하기 전에 Object .defineProperty를 살펴보겠습니다. . 우리 모두 알고 있듯이 vue2.x 및 이전 버전에서는 Object.defineProperty를 사용하여 데이터의 양방향 바인딩을 구현합니다. 간단하게 구현해 볼까요

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)

브라우저 콘솔에서 실행해 보면 정상적으로 실행되는 것 같습니다

JS Proxy의 장점 및 사용 시나리오JS Proxy의 장점 및 사용 시나리오

그러나 실제로 Object.defineProperty에는 다음과 같은 문제가 있습니다

문제 1. 개체 속성 삭제 또는 추가를 모니터링할 수 없습니다

Object.defineProperty  劫持对象的属性,如果遍历的对象层级比较深,花的时间比较久,甚至有性能的问题

proxy

对于 proxy ,在 mdn 上的描述是: 对象用于定义基本操作的自定义行为(如属性查找、赋值、枚举、函数调用等)

简单来说就是,可以在对目标对象设置一层拦截。无论对目标对象进行什么操作,都要经过这层拦截

听上去似乎,proxyObject.defineProperty 要好用,并且简单很多,实际上就是如此。下面用 proxy 对上面的代码进行改写试下

<br>

也是一样的效果

JS Proxy의 장점 및 사용 시나리오

而且,能做到 Object.defineProperty 做不到的事情,比如增加一个属性 gender,能够监听到

JS Proxy의 장점 및 사용 시나리오

操作数组,也能监听到

JS Proxy의 장점 및 사용 시나리오

最后敲一下黑板,简单总结一下两者的区别

1.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예를 들어 추가 gender 속성이 하나인데, observer(obj) 실행 시 해당 속성이 없어 모니터링할 수 없기 때문입니다. 삭제된 속성은 모니터링할 수 없습니다. 속성을 추가할 때 $set를 사용해야 작동하며, $set도 내부적으로 사용됩니다. >Object.defineProperty가 동작합니다

JS Proxy의 장점 및 사용 시나리오

🎜🎜문제 2. 배열의 변경 사항을 모니터링할 수 없습니다🎜🎜🎜🎜🎜위 그림에서 볼 수 있듯이 실제로는 배열 속성이 성공적으로 수정되었지만, 모니터링이 안되네요🎜🎜질문 3. 객체를 재귀적으로 순회하므로 Object.defineProperty를 사용하여 객체의 속성을 탈취합니다. 순회하는 객체 수준이 상대적으로 깊을 경우 시간이 오래 걸리고 성능 문제가 발생할 수도 있습니다🎜🎜proxy🎜🎜🎜 proxy의 경우 mdn에 대한 설명은 다음과 같습니다. 객체는 기본 작업에 대한 사용자 정의 동작을 정의하는 데 사용됩니다(예: 속성 조회, 할당, 열거(예: 함수 호출 등) 🎜🎜간단히 말하면 대상 객체에 차단 계층을 설정할 수 있습니다. 대상 개체에 대해 어떤 작업이 수행되든 이 차단 계층을 통과해야 합니다🎜🎜proxyObject.defineProperty보다 사용하기 쉽고 훨씬 더 많은 것처럼 들립니다. 실제로는 이렇습니다. 프록시를 사용하여 위 코드를 다시 작성하여 사용해 보겠습니다🎜
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의 장점 및 사용 시나리오🎜🎜또한 gender 속성을 ​​추가하고 🎜🎜JS Proxy의 장점 및 사용 시나리오🎜🎜연산 배열도 모니터링 가능🎜🎜JS Proxy의 장점 및 사용 시나리오🎜🎜마지막으로 칠판을 두드리며 간략한 요약 둘의 차이점🎜🎜1.Object.defineProperty은 개체의 속성을 가로채서 원래 개체를 변경합니다. proxy는 전체 객체를 가로채서 원래 객체를 변경하지 않고 new를 통해 새 객체를 생성합니다. 🎜🎜2. 위의 get 및 set 외에도 프록시에 대한 11가지 차단 방법이 있습니다. 배열 모니터링, 객체 속성 추가 및 삭제 모니터링 등 Object.defineProperty가 모니터링할 수 없는 일부 작업을 모니터링할 수도 있습니다. 🎜

🎜프록시 사용 시나리오🎜🎜🎜 프록시의 사용 시나리오와 관련하여 공간 제한으로 인해 다음은 몇 가지입니다. 자세한 내용은 내 github 노트 또는 mdn을 방문하세요. 🎜🎜이것을 보시면 이미 둘의 차이점과 프록시의 장점에 대해 대략적으로 아실 것입니다. 하지만 개발 중에 프록시를 사용할 수 있는 시나리오는 무엇입니까? 다음은 발생할 수 있는 몇 가지 상황입니다🎜

🎜negative Index array🎜

🎜splice(-1), slice(-1) 등의 API를 사용할 때 음수를 입력하면 배열이 위치 지정됩니다. 마지막 항목이지만 일반 배열에서는 음수를 사용할 수 없습니다. [1,2,3][-1] 이 코드는 3 을 출력하지 않습니다. 위의 코드 출력 3을 만들려면 proxy를 사용하여 구현할 수도 있습니다. 🎜
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)
🎜🎜🎜

表单校验

在对表单的值进行改动的时候,可以在 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으로 문의하시기 바랍니다. 삭제