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

Guanhui
풀어 주다: 2020-06-15 09:22:41
앞으로
4417명이 탐색했습니다.

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 对上面的代码进行改写试下


로그인 후 복사

也是一样的效果

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 === 'age') { //如果值小于0,或者不是正整数 if (value < 0 || !Number.isInteger(value)) { throw new TypeError('请输入正确的年龄'); } } return Reflect.set(target, key, value, receiver) } } let obj = new Proxy({ age: 18 }, ecValidate) obj.age = 16obj.age = '少年'
로그인 후 복사
로그인 후 복사
같은 효과 JS Proxy의 장점 및 사용 시나리오또한 gender속성을 추가하고 Object.defineProperty가 할 수 없는 작업을 수행할 수 있습니다. ://img.php.cn/upload/article/000/000/046/8f6814814e0335ec53da5d118522f108-4.png"/>연산 배열도 모니터링 가능 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 : '广东省', 46 : '海南省' } const CITY_NUMBER = { 4401 : '广州市', 4601 : '海口市' } let ecCardNumber = { set(target, key, value, receiver) { if (key === 'cardNumber') { Reflect.set(target, 'hometown', PROVINCE_NUMBER[value.substr(0, 2)] + CITY_NUMBER[value.substr(0, 4)], receiver) Reflect.set(target, 'date', value.substr(6, 8), receiver) Reflect.set(target, 'gender', value.substr( - 2, 1) % 2 === 1 ? '男': '女', receiver) } return Reflect.set(target, key, value, receiver) } } let obj = new Proxy({ cardNumber: '' }, ecCardNumber)
로그인 후 복사
로그인 후 복사

表单校验

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

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

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

增加附加属性

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

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

const PROVINCE_NUMBER = { 44 : '广东省', 46 : '海南省' } const CITY_NUMBER = { 4401 : '广州市', 4601 : '海口市' } let ecCardNumber = { set(target, key, value, receiver) { if (key === 'cardNumber') { Reflect.set(target, 'hometown', PROVINCE_NUMBER[value.substr(0, 2)] + CITY_NUMBER[value.substr(0, 4)], receiver) Reflect.set(target, 'date', value.substr(6, 8), receiver) Reflect.set(target, 'gender', value.substr( - 2, 1) % 2 === 1 ? '男': '女', receiver) } return Reflect.set(target, key, value, receiver) } } let obj = new Proxy({ cardNumber: '' }, 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의 장점 및 사용 시나리오

推荐教程:《JS教程

위 내용은 JS Proxy의 장점 및 사용 시나리오의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:juejin.im
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!