원리에 대한 자세한 설명: Vue3의 반응성과 참조의 차이점
이 글은 vue3에서 가장 중요한 API인 ref와 반응형을 이해하는 데 도움이 될 것입니다. 아직도 어떤 것을 사용해야 할지 헷갈리시나요? Vue3를 잘 활용하고 싶다면 곧 vue2의 반응성을 살펴보세요.
Object.defineProperty 메소드를 통해 객체의 getter
및 setter
를 하이재킹하고 getter
에서 종속성을 수집하고 에서 종속성을 트리거합니다. setter
이지만 이 방법에는 몇 가지 단점이 있습니다.
- 속성을 순회하고 재귀적으로 모니터링하기 때문에 속성이 너무 많거나 중첩 수준이 너무 깊어 성능에 영향을 미칩니다
-
getter
和setter
,在getter
中收集依赖,在setter
中触发依赖,但是这种方式存在一些缺点:由于是遍历递归监听属性,当属性过多或嵌套层级过深时会影响性能
无法监听对象新增的属性和删除属性,只能监听对象本身存在的属性,所以设计了
$set
和$delete
-
如果监听数组的话,无法监听数组元素的增减,只能监听通过下标可以访问到的数组中已有的属性,由于使用
객체 자체에 존재하는 속성만 모니터링할 수 있으므로Object.defineProperty
遍历监听数组原有元素过于消耗性能,vue放弃使用Object.defineProperty
监听数组,而采用了重写数组原型方法的方式来监听对数组数据的操作,并用$set
和splice
方法来更新数组,$set
和splice
객체의 새 속성과 삭제된 속성은 모니터링할 수 없습니다$를 설계했습니다. set
및$delete
-
배열을 모니터링하면 배열 요소의 증가 또는 감소를 모니터링할 수 없습니다. 배열의 기존 속성만 모니터링할 수 있습니다.
Object.defineProperty
순회 모니터링을 통해 액세스할 수 있습니다. Vue는 모니터링을 위해Object.defineProperty
사용을 포기했습니다. 배열 데이터의 동작을 모니터링하기 위해 배열 프로토타입 메서드를 재정의하는 방법을 채택하고$set
및splice
메서드를 사용하여 배열을 업데이트했습니다. >$set 및splice
는 재정의된 배열 메서드를 호출합니다.【관련 추천: vuejs 동영상 튜토리얼
】vue3 반응형 구현
프록시 객체
새로운 객체인 Object.defineProperty의 단점을 겨냥 - ES6에서 프록시가 도입되었습니다(객체 프록시 ) 프록시 개체: 는 개체에 대한 프록시를 만드는 데 사용되며 주로 개체의 일부 기본 동작을 변경하는 데 사용됩니다. 프록시는 대상 개체 앞에 "가로채기" 계층을 설정하는 것으로 이해될 수 있습니다. 모든 액세스는 먼저 이 차단 계층을 통과해야 하므로 외부 액세스를 필터링하고 다시 작성할 수 있는 메커니즘을 제공해야 합니다. 기본 구문은 다음과 같습니다.Intercept get, value 연산/* * target: 目标对象 * handler: 配置对象,用来定义拦截的行为 * proxy: Proxy构造器的实例 */ var proxy = new Proxy(target,handler)
로그인 후 복사var proxy = new Proxy({}, { get: function(target, propKey) { return 35; } }); proxy.time // 35 proxy.name // 35 proxy.title // 35
로그인 후 복사중단할 수 있는 연산은 다음과 같습니다. operation get 값 읽기 set has in 연산자 deleteProperty Object.getPrototypeOf() getPrototypeOf Object.getPrototypeOf () setPrototypeOf Object.setPrototypeOf ( ) isExtensible Object.isExtensible() preventExtensions Object.preventExtensions() getOwnPropertyDescriptor Object.getOwnProperty 설명자() defineProperty Object.defineProperty ownKeys Object.keys() Object.getOwnPropertyNames() 및 Object.getOwnPropertySymbols() apply construct함수 호출 那么使用
Proxy
可以解决Vue2
中的哪些问题,总结一下:- Proxy是对整个对象的代理,而Object.defineProperty只能代理某个属性。
- 对象上新增属性,Proxy可以监听到,Object.defineProperty不能。
- 数组新增修改,Proxy可以监听到,Object.defineProperty不能。
- 若对象内部属性要全部递归代理,Proxy可以只在调用的时候递归,而Object.definePropery需要一次完成所有递归,Proxy相对更灵活,提高性能。
递归代理
var target = { a:1, b:{ c:2, d:{e:3} } } var handler = { get:function(target, prop, receiver){ console.log('触发get:',prop) return Reflect.get(target,prop) }, set:function(target,key,value,receiver){ console.log('触发set:',key,value) return Reflect.set(target,key,value,receiver) } } var proxy = new Proxy(target,handler) proxy.b.d.e = 4 // 输出 触发get:b , 由此可见Proxy仅代理了对象外层属性。
로그인 후 복사以上写法只代理了对象的外层属性,所以要想深层代理整个对象的所有属性,需要进行递归处理:
var target = { a:1, b:{ c:2, d:{e:3} }, f: {z: 3} } var handler = { get:function(target, prop, receiver){ var val = Reflect.get(target,prop) console.log('触发get:',prop) if(val !== null && typeof val==='object') { return new Proxy(val,handler) // 代理内层属性 } return Reflect.get(target,prop) }, set:function(target,key,value,receiver){ console.log('触发set:',key,value) return Reflect.set(target,key,value,receiver) } } var proxy = new Proxy(target,handler) proxy.b.d.e = 4 // 输出 触发get b,get d, get e
로그인 후 복사从递归代理可以看出,如果要代理对象的内部属性,Proxy可以只在属性被调用时去设置代理(惰性),访问了
e
,就仅递归代理b
下面的属性,不会额外代理其他没有用到的深层属性,如z
。关于
Reflect
的作用和意义- 规范语言内部方法的所属对象,不全都堆放在Object对象或Function等对象的原型上。如
Function.prototype.apply Object.defineProperty
로그인 후 복사修改某些
Object
方法的返回结果,让其变得更合理。比如,Object.defineProperty(obj, name, desc)
在无法定义属性时,会抛出一个错误,而Reflect.defineProperty(obj, name, desc)
则会返回false
。让
Object
操作都变成函数行为。某些Object
操作是命令式,比如name in obj
和delete obj[name]
,而Reflect.has(obj, name)
和Reflect.deleteProperty(obj, name)
让它们变成了函数行为。Reflect
对象的方法与Proxy
对象的方法一一对应,只要是Proxy
对象的方法,就能在Reflect
对象上找到对应的方法。这就让Proxy
对象可以方便地调用对应的Reflect
方法,完成默认行为,作为修改行为的基础。也就是说,不管Proxy
怎么修改默认行为,你总可以在Reflect
上获取默认行为。
vue3的
reative
和ref
Vue3 的 reactive 和 ref 正是借助了Proxy来实现。
reactive
作用:创建原始对象的响应式副本,即将「引用类型」数据转换为「响应式」数据
参数: reactive参数必须是对象或数组
reative函数实现:
// 判断是否为对象 const isObject = val => val !== null && typeof val === 'object'; // 判断key是否存在 const hasOwn = (target, key) => Object.prototype.hasOwnProperty.call(target, key); export function reactive(target) { // 首先先判断是否为对象 if (!isObject(target)) return target; const handler = { get(target, key, receiver) { console.log(`获取对象属性${key}值`) // 收集依赖 ... const result = Reflect.get(target, key, receiver) // 深度监听(惰性) if (isObject(result)) { return reactive(result); } return result; }, set(target, key, value, receiver) { console.log(`设置对象属性${key}值`) // 首先先获取旧值 const oldValue = Reflect.get(target, key, reactive) let result = Reflect.set(target, key, value, receiver); if (result && oldValue !== value) { // 更新操作 ... } return result }, deleteProperty(target, key) { console.log(`删除对象属性${key}值`) // 先判断是否有key const hadKey = hasOwn(target, key) const result = Reflect.deleteProperty(target, key) if (hadKey && result) { // 更新操作 ... } return result }, // 其他方法 // ... } return new Proxy(target, handler) } const obj = { a: { b: { c: 6 } } }; const proxy = reactive(obj); proxy.a.b.c = 77; // 获取对象属性a值 // 获取对象属性b值 // 设置对象属性c值 77
로그인 후 복사至此,引用类型的对象我们已经可以把它转化成响应式对象了,Proxy对象只能代理引用类型的对象,对于基本数据类型如何实现响应式呢?
vue的解决方法是把基本数据类型变成一个对象:这个对象只有一个value属性,value属性的值就等于这个基本数据类型的值。然后,就可以用
reative
方法将这个对象,变成响应式的Proxy对象。实际上就是:
ref(0) --> reactive( { value:0 })
ref
作用:把基本类型的数据变为响应式数据。
参数:
1.基本数据类型
2.引用类型
3.DOM的ref属性值
ref 实现 Vue3 源码
export function ref(value?: unknown) { return createRef(value, false) } function createRef(rawValue: unknown, shallow: boolean) { if (isRef(rawValue)) { return rawValue } return new RefImpl(rawValue, shallow) } class RefImpl<T> { private _value: T private _rawValue: T public dep?: Dep = undefined public readonly __v_isRef = true constructor(value: T, public readonly __v_isShallow: boolean) { this._rawValue = __v_isShallow ? value : toRaw(value) this._value = __v_isShallow ? value : toReactive(value) } get value() { trackRefValue(this) return this._value } set value(newVal) { const useDirectValue = this.__v_isShallow || isShallow(newVal) || isReadonly(newVal) newVal = useDirectValue ? newVal : toRaw(newVal) if (hasChanged(newVal, this._rawValue)) { this._rawValue = newVal this._value = useDirectValue ? newVal : toReactive(newVal) triggerRefValue(this, newVal) } } }
로그인 후 복사大体思路就是,调用ref函数时会new 一个类,这个类监听了value属性的 get 和 set ,实现了在get中收集依赖,在set中触发依赖,而如果需要对传入参数深层监听的话,就会调用我们上面提到的
reactive
方法。即:
ref(0); // 通过监听对象(类)的value属性实现响应式 ref({a: 6}); // 调用reactive方法对对象进行深度监听
로그인 후 복사根据上面的思路我们可以自己来简单实现下:
// 自定义ref function ref(target) { const result = { // 这里在源码中体现为一个类 RefImpl _value: reactive(target), // target传给reactive方法做响应式处理,如果是对象的话就变成响应式 get value () { return this._value }, set value (val) { this._value = val console.log('set value 数据已更新, 去更新界面') } } return result } // 测试 const ref = ref(9); ref.value = 6; const ref = ref({a: 4}); ref.value.a = 6;
로그인 후 복사ref 方法包装的数据,需要使用
.value
来访问,但在模板中不需要,Vue解析时会自动添加。总结
-
reactive
将引用类型值变为响应式,使用Proxy
实现 -
ref
可将基本类型和引用类型都变成响应式,通过监听类的value属性的get
和set
实现,但是当传入的值为引用类型时实际上内部还是使用reactive
方法进行的处理 - 推荐基本类型使用
ref
,引用类型使用reactive
위 내용은 원리에 대한 자세한 설명: Vue3의 반응성과 참조의 차이점의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











vue.js에서 bootstrap 사용은 5 단계로 나뉩니다 : Bootstrap 설치. main.js.의 부트 스트랩 가져 오기 부트 스트랩 구성 요소를 템플릿에서 직접 사용하십시오. 선택 사항 : 사용자 정의 스타일. 선택 사항 : 플러그인을 사용하십시오.

HTML 템플릿의 버튼을 메소드에 바인딩하여 VUE 버튼에 함수를 추가 할 수 있습니다. 메소드를 정의하고 VUE 인스턴스에서 기능 로직을 작성하십시오.

vue.js의 시계 옵션을 사용하면 개발자가 특정 데이터의 변경 사항을들을 수 있습니다. 데이터가 변경되면 콜백 기능을 트리거하여 업데이트보기 또는 기타 작업을 수행합니다. 구성 옵션에는 즉시 콜백을 실행할지 여부와 DEEP를 지정하는 즉시 포함되며, 이는 객체 또는 어레이에 대한 변경 사항을 재귀 적으로 듣는 지 여부를 지정합니다.

VUE 멀티 페이지 개발은 vue.js 프레임 워크를 사용하여 응용 프로그램을 구축하는 방법입니다. 여기서 응용 프로그램은 별도의 페이지로 나뉩니다. 코드 유지 보수 : 응용 프로그램을 여러 페이지로 분할하면 코드를보다 쉽게 관리하고 유지 관리 할 수 있습니다. 모듈 식 : 각 페이지는 쉬운 재사용 및 교체를 위해 별도의 모듈로 사용할 수 있습니다. 간단한 라우팅 : 페이지 간의 탐색은 간단한 라우팅 구성을 통해 관리 할 수 있습니다. SEO 최적화 : 각 페이지에는 자체 URL이있어 SEO가 도움이됩니다.

vue.js에서 JS 파일을 참조하는 세 가지 방법이 있습니다. & lt; script & gt; 꼬리표;; mounted () 라이프 사이클 후크를 사용한 동적 가져 오기; Vuex State Management Library를 통해 수입.

vue.js는 이전 페이지로 돌아갈 수있는 네 가지 방법이 있습니다. $ router.go (-1) $ router.back () 사용 & lt; router-link to = & quot;/quot; Component Window.history.back () 및 메소드 선택은 장면에 따라 다릅니다.

vue.js가 트래버스 어레이 및 객체에 대한 세 가지 일반적인 방법이 있습니다. V- 결합 지시문은 V-FOR와 함께 사용하여 각 요소의 속성 값을 동적으로 설정할 수 있습니다. .MAP 메소드는 배열 요소를 새 배열로 변환 할 수 있습니다.

VUE에서 DIV 요소를 점프하는 두 가지 방법이 있습니다. VUE 라우터를 사용하고 라우터 링크 구성 요소를 추가하십시오. @Click 이벤트 리스너를 추가하고 이것을 호출하십시오. $ router.push () 메소드를 점프하십시오.
