이 글에서는 vue2&vue3 데이터 반응형 원리 분석 및 수동 구현에 대한 관련 지식을 제공합니다. 데이터 반응형 뷰와 데이터가 자동으로 업데이트되면 뷰가 자동으로 업데이트되어 데이터의 변경 사항을 추적할 수 있기를 바랍니다. 모두가 도움이 될 것입니다.
var obj = {}var age Object.defineProperty(obj, 'age', { get: function() { consoel.log('get age ...') return age }, set: function(val) { console.log('set age ...') age = val }})obj.age =100 //set age ...console.log(obj.age)//get age ...
객체 obj는 age 속성을 가져올 때 데이터 하이재킹의 get 메서드를 호출합니다
age 속성에 값을 할당할 때 set method
그런 다음 Object.defineProperty를 사용하여 데이터 응답을 구현하는 방법
function defineReactive(data) { if (!data || Object.prototype.toString.call(data) !== '[object Object]') return; for (let key in data) { let val = data[key]; Object.defineProperty(data, key, { enumerable: true, //可枚举 configurable: true, //可配置 get: function() { track(data, key); return val; }, set: function() { trigger(val, key); }, }); if (typeof val === "object") { defineReactive(val); } }}function trigger(val, key) { console.log("sue set", val, key);}function track(val, key) { console.log("sue set", val, key);}const data = { name:'better', firends:['1','2']}defineReactive(data)console.log(data.name)console.log(data.firends[1])console.log(data.firends[0])console.log(Object.prototype.toString.call(data))
이 defineReactve
함수는 Object.defineProperty
를 캡슐화하는 데 사용됩니다. 캡슐화 후에는 데이터, 키, 값만 전달하면 됩니다defineReactve
用来对Object.defineProperty
进行封装,从函数名可以看出,起作用就是定义一个响应式数据,封装后只需要传递data,key和val就行
每当从data中读取key的时候触发track函数,往data的key中设置数据时,set函数中的trigger函数触发
我们通过Array原型上的方法来改变数组的内容不会触发getter和setter
整理发现Array原型中可以改变数组自身内容
的方法有7个,分别push
pop
shift
unshift
splice
sort
reverse
vue2 改写了这这7种方法
实现方式:
以Array.propertype为原型创建一个arrayMethods对象,再使用Object.setPropertypeOf(o, arryMethods)
将o的__proto__指向arrayMethods
使用
<template><p>{{name}}</p></template>
该模板中使用数据 name
, 我们要观察数据, 当数据的属性发生变化的时候, 可以通知哪些使用的地方,
这就是我们要先收集依赖,即把用到数据name的地方收集起来,然后等数据变化的时候,把之前收集好的依赖循环触发一遍,总结来说就是getter中收集依赖,在setter中触发依赖
Proxy对象用于创建一个对象的代理, 从而实现基本操作的拦截和定义(如属性查找、赋值、枚举、函数掉用等)
const p = new Proxy(target, handler)
target
要使用 Proxy
包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
handler
一个通常以函数作为属性的对象,各属性中的函数分别定义了在执行各种操作时代理 p
的行为。
reflect是一个内置对象, 他提供拦截javascript操作的方法, 这些方法和Proxy handlers相同
Reflect.set将值分配给属性的函数。返回一个Boolean 如果更新成功则返回true
Reflect.get获取对象身上某个属性的值,类似target[name]
如何实现劫持
const dinner = { meal:'111'}const handler = { get(target, prop) { console.log('get...', prop) return Reflect.get(...arguments) }, set(target, key, value) { console.log('get...', prop) console.log('set',key,value) return Reflect.set(...arguments) }}const proxy = new Proxy(dinner, handler)console.log(proxy.meal)console.log(proxy.meal)
代码中dinner 对象代理到handler上
跟defineProperty
区别defineProperty
데이터에서 키를 읽을 때마다 추적 기능이 트리거되고 데이터가 설정될 때 이 기능이 작동되는 것을 볼 수 있습니다. set 함수의 데이터 키에 트리거 함수는
배열의 응답성
을 트리거합니다. 우리는 배열 프로토타입의 메서드를 사용하여 배열의 내용을 변경하지만 getter 및 setter
를 트리거하지 않습니다. 배열 프로토타입에서배열 자체의 내용을 변경
할 수 있는 메서드를 구성하고 발견한 후 각각 push
pop
7개가 있습니다. Shift
unshift
splice
sort <code>reverse
vue2는 이 7가지 메서드를 다시 작성합니다
구현 방법: Array.propertype을 프로토타입으로 사용하여 arrayMethods 객체를 만든 다음 Object.setPropertypeOf(o, arryMethods)o의 __proto__를 arrayMethods<img src="https://img.php.cn/upload/article/000/000/067/acd642f4f02e97980836bd636302ac44-1.png" alt="Vue2&vue3 데이터 대응 원리 분석 및 매뉴얼 구현(상세 예시)">
function reactive(obj) { const handler = { get(target, prop, receiver) { track(target, prop); const value = Reflect.get(...arguments); if(typeof value === 'Object') { reactive(value) }else { return value } }, set(target,key, value, receiver) { trigger(target,key, value); return Reflect.set(...arguments); }, }; return new Proxy(obj,handler)}function track(data, key) { console.log("sue set", data, key);}function trigger(data, key,value) { console.log("sue set", key,':',value);}const dinner = { name:'haochi1'}const proxy =reactive(dinner)proxy.name proxy.list = []proxy.list.push(1)
이름
이 사용됩니다. 이 템플릿에서는 데이터를 관찰해야 합니다. 데이터의 속성이 변경되면 해당 데이터가 사용되는 위치에 알릴 수 있습니다.target code><li>
<li> <code>프록시
(기본 배열, 함수 또는 다른 프록시를 포함한 모든 유형의 개체일 수 있음) handler
p
의 동작을 정의합니다. rrreee
코드의 저녁 개체는 다음으로 프록시됩니다. 핸들러defineProperty
DifferencedefineProperty
의 속성을 따라 모든 속성을 감독하려면 순회해야 합니다.프록시를 사용하여 개체의 모든 속성을 프록시합니다프록시를 사용하여 구현합니다. 시뮬레이션된 응답rrreee실행 후 자동으로 인쇄
🎜🎜🎜생각: 왜 get 및 not set에서만 재귀를 사용합니까? 🎜🎜할당에도 get first가 필요합니다🎜🎜간단한 요약: 🎜🎜🎜vue2(얕은 응답)🎜🎜🎜 🎜데이터를 탐색하고 defineProperty를 사용하여 모든 속성을 가로채기🎜🎜사용자가 뷰를 조작하면 set 인터셉터가 트리거됩니다.🎜🎜set는 먼저 현재 데이터를 변경한 다음 시계에 알리고 시계가 뷰 업데이트를 알리도록 합니다.🎜🎜View redraw , 그리고 get again에서 해당 데이터를 얻습니다🎜🎜🎜 🎜vue3(깊은 응답성):🎜🎜🎜🎜🎜프록시를 위해 프록시를 사용합니다. 🎜🎜🎜🎜Reflect를 사용하면 프록시 객체의 해당 속성에 대해 특정 작업을 동적으로 수행합니다.🎜🎜🎜🎜프록시 객체(프록시)의 반사 객체(reflect)는 서로 협력해야 합니다. 응답성을 달성하기🎜🎜🎜🎜둘 사이의 차이점🎜🎜프록시 전체 객체를 하이재킹할 수 있는 반면, Object.defineProperty는 객체의 속성만 하이재킹할 수 있습니다. 전자는 해당 값의 프록시를 재귀적으로 반환하여 응답성을 달성할 수 있습니다. 후자는 각 속성을 심층적으로 탐색해야 하며 후자는 배열 작업에 매우 비우호적입니다. 🎜🎜더 많은 프로그래밍 관련 지식을 보려면 🎜프로그래밍 소개🎜를 방문하세요. ! 🎜위 내용은 Vue2&vue3 데이터 대응 원리 분석 및 매뉴얼 구현(상세 예시)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!