您好,登錄后才能下訂單哦!
今天就跟大家聊聊有關(guān)vue2和vue3數(shù)據(jù)響應(yīng)式原理分析及如何實(shí)現(xiàn),可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
視圖跟數(shù)據(jù)是自動(dòng)更新的,數(shù)據(jù)更新的時(shí)候視圖是自動(dòng)的更新的
追蹤數(shù)據(jù)的變化,在讀取數(shù)據(jù)或者設(shè)置數(shù)據(jù)的時(shí)候能夠做一些劫持的一些操作
vue2 使用defineProperty
vue3 改用Proxy
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 ...
對(duì)象obj在取age屬性的時(shí)候會(huì)調(diào)用數(shù)據(jù)劫持的get方法
在給age屬性賦值的時(shí)候會(huì)調(diào)用set方法
那怎么使用Object.defineProperty實(shí)現(xiàn)一個(gè)數(shù)據(jù)響應(yīng)式呢
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))
這個(gè)函數(shù)defineReactve
用來(lái)對(duì)Object.defineProperty
進(jìn)行封裝,從函數(shù)名可以看出,起作用就是定義一個(gè)響應(yīng)式數(shù)據(jù),封裝后只需要傳遞data,key和val就行
每當(dāng)從data中讀取key的時(shí)候觸發(fā)track函數(shù),往data的key中設(shè)置數(shù)據(jù)時(shí),set函數(shù)中的trigger函數(shù)觸發(fā)
我們通過(guò)Array原型上的方法來(lái)改變數(shù)組的內(nèi)容不會(huì)觸發(fā)getter和setter
整理發(fā)現(xiàn)Array原型中可以改變數(shù)組自身內(nèi)容
的方法有7個(gè),分別push
pop
shift
unshift
splice
sort
reverse
vue2 改寫(xiě)了這這7種方法
實(shí)現(xiàn)方式:
以Array.propertype為原型創(chuàng)建一個(gè)arrayMethods對(duì)象,再使用Object.setPropertypeOf(o, arryMethods)
將o的__proto__指向arrayMethods
使用
<template><p>{{name}}</p></template>
該模板中使用數(shù)據(jù) name
, 我們要觀察數(shù)據(jù), 當(dāng)數(shù)據(jù)的屬性發(fā)生變化的時(shí)候, 可以通知哪些使用的地方,
這就是我們要先收集依賴,即把用到數(shù)據(jù)name的地方收集起來(lái),然后等數(shù)據(jù)變化的時(shí)候,把之前收集好的依賴循環(huán)觸發(fā)一遍,總結(jié)來(lái)說(shuō)就是getter中收集依賴,在setter中觸發(fā)依賴
Proxy對(duì)象用于創(chuàng)建一個(gè)對(duì)象的代理, 從而實(shí)現(xiàn)基本操作的攔截和定義(如屬性查找、賦值、枚舉、函數(shù)掉用等)
const p = new Proxy(target, handler)
target
要使用 Proxy
包裝的目標(biāo)對(duì)象(可以是任何類型的對(duì)象,包括原生數(shù)組,函數(shù),甚至另一個(gè)代理)。
handler
一個(gè)通常以函數(shù)作為屬性的對(duì)象,各屬性中的函數(shù)分別定義了在執(zhí)行各種操作時(shí)代理 p
的行為。
reflect是一個(gè)內(nèi)置對(duì)象, 他提供攔截javascript操作的方法, 這些方法和Proxy handlers相同
Reflect.set將值分配給屬性的函數(shù)。返回一個(gè)Boolean 如果更新成功則返回true
Reflect.get獲取對(duì)象身上某個(gè)屬性的值,類似target[name]
如何實(shí)現(xiàn)劫持
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 對(duì)象代理到handler上
跟defineProperty
區(qū)別defineProperty
的屬性需要遍歷才能監(jiān)管所有屬性
使用proxy可以將對(duì)象所有屬性進(jìn)行代理
用proxy實(shí)現(xiàn)一個(gè)模擬響應(yīng)式
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)
執(zhí)行后自動(dòng)打印
思考:為啥只在get中使用遞歸,set不使用呢?
賦值也需要先get
vue2 (淺響應(yīng)式)
遍歷data,使用defineProperty攔截所有屬性
當(dāng)用戶操作視圖,會(huì)觸發(fā)set攔截器
set先改變當(dāng)前數(shù)據(jù), 再通知wartch, 讓watch去通知視圖更新
視圖重繪, 再次從get中獲取對(duì)應(yīng)的數(shù)據(jù)
vue3 (深度響應(yīng)式) :
使用proxy 進(jìn)行代理;攔截data任意屬性的任意操作(13種), 包括屬性的讀寫(xiě), 屬性的添加, 屬性的刪除等等
使用Reflect進(jìn)行反射; 動(dòng)態(tài)對(duì)被代理的對(duì)象的相應(yīng)屬性進(jìn)行特定的操作
代理對(duì)象(proxy)的反射對(duì)象(reflect)必須相互配合才能實(shí)現(xiàn)響應(yīng)式
Proxy能劫持整個(gè)對(duì)象,而Object.defineProperty只能劫持對(duì)象的屬性; 前者遞歸返回屬性對(duì)應(yīng)的值的代理即可實(shí)現(xiàn)響應(yīng)式,后者需要深度遍歷每個(gè)屬性,后者對(duì)數(shù)組的操作很不友好.
看完上述內(nèi)容,你們對(duì)vue2和vue3數(shù)據(jù)響應(yīng)式原理分析及如何實(shí)現(xiàn)有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝大家的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。