предисловие
Прошло некоторое время с тех пор, как вышел vue3, и несомненно говорят, что перехват данных vue был переписан с прокси (ранее использовался Object.defineProperty) и Composition API. В этой статье давайте проверим, насколько хороша способность прокси к перехвату.
Сравнение перехвата данных Object.defineProperty и перехвата данных прокси
здесь черезvue1.x,vue2.x
Поговорим о перехвате данныхObject.defineProperty
.
Объясните заранее, перехват данных здесь не включает в себя сбор vue зависимостей и обновление представления, иначе его будут ругать милые друзья-копатели.
Object.defineProperty
использовать сначалаObject.defineProperty
Реализовать перехват объекта.
let data = {
m:234,
n:[1,34,4,5676],
h:{
c:34
}
}
function observer(data){
if(typeof data === 'object'){
Object.keys(data).forEach(key=>{
defineReactive(data,key,data[key])
})
}
}
function defineReactive(obj,key,val){
Object.defineProperty(obj,key,{
get(){
console.log('get')
return val
},
set(newVal){
console.log('set')
if(newVal !== val ) val = newVal
}
})
}
выше, пересекаяdata
, сделал простой перехват, вроде все нормально, но если мы изменимdata.h.c
не сработаетset钩子的
,Зачем? Потому что это еще не реализовано递归
, так что только перехватил最表面的一层
, который не заблокирован.
объект рекурсивного перехвата
function defineReactive(obj,key,val){
observer(val)
Object.defineProperty(obj,key,{
get(){
console.log('get')
return val
},
set(newVal){
console.log('set')
if(newVal !== val ) val = newVal
}
})
}
Рекурсивный перехват, покаdefineReactive函数
настройтесь сноваobserver函数
Просто передайте ему значение, которое вы хотите перехватить. Таким образом реализуется многоуровневый перехват объектов. Но теперь массив не может быть перехвачен, когда мы вызываемpush,pop等方法
это не сработаетset钩子的
,Зачем? потому чтоObject.defineProperty
Перехват массива вообще не поддерживается. Поскольку он его не поддерживает, мы можем перехватывать только эти('push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse')
Как изменить свои данные.
Перехват массивов Object.defineProperty
function arrayMethods(){
const arrProto = Array.prototype
const arrayMethods = Object.create(arrProto)
const methods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']
methods.forEach(function (method) {
const original = arrProto[method]
Object.defineProperty(arrayMethods, method, {
value: function v(...args) {
console.log('set arrayMethods')
return original.apply(this, args)
}
})
})
return arrayMethods
}
Вышеупомянутое перехватывает метод прототипа этих массивов, а затем перезаписывает прототип перехватываемого массива.Давайте просто изменим наблюдателя.
function observer(data){
if(typeof data === 'object'){
if(Array.isArray(data)){
data.__proto__ = arrayMethods()
}else{
Object.keys(data).forEach(key=>{
defineReactive(data,key,data[key])
})
}
}
}
существуетvue
, также будет судить оkey
У вас есть__proto__
, если нет, то поместите эти методы прямо на сам ключ, если есть, то прямо перезапишите этот__proto__
.
полный код
function arrayMethods(){
const arrProto = Array.prototype
const arrayMethods = Object.create(arrProto)
const methods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse']
methods.forEach(function (method) {
const original = arrProto[method]
Object.defineProperty(arrayMethods, method, {
value: function v(...args) {
console.log('set arrayMethods')
return original.apply(this, args)
}
})
})
return arrayMethods
}
function observer(data){
if(typeof data === 'object'){
if(Array.isArray(data)){
data.__proto__ = arrayMethods()
}else{
Object.keys(data).forEach(key=>{
defineReactive(data,key,data[key])
})
}
}
}
function defineReactive(obj,key,val){
observer(val)
Object.defineProperty(obj,key,{
get(){
console.log('get')
return val
},
set(newVal){
console.log('set')
if(newVal !== val ) val = newVal
}
})
}
observer(data)
выше, это сделано对象和数组
перехват(说明:vue2.x中的实现会比这里复杂,但大概思路和大概实现是这样)
, Казалось бы, трудно, в обмен на отличный результат довольно хорошо. Но действительно ли это то, что вы думаете? попробуй позвонитьdata.n[1] = xxx
, он не запускаетсяset钩子的
, который также находится вproxy
До появления он был бессилен, поэтому был предусмотрен во вуе$set,$delete
API.
Дебютный прокси-дебют
Я не буду вводить прокси здесь, просто примите это так, как вы его знаете. код напрямую
let data = {
m:234,
n:[1,34,4,5676],
h:{
c:34
}
}
function defineReactive(obj){
Object.keys(obj).forEach((key) => {
if(typeof obj[key] === 'object'){
obj[key] = defineReactive(obj[key])
}
})
return new Proxy(obj,{
get(target,key){
console.log('get')
return target[key]
},
set(target,key,val){
console.log('set')
return target[key] = val
}
})
}
data = defineReactive(data)
Просто немного кода, чтобы сделать это对象和数组
перехват(说明:这里不是vue3的实现方法,vue3怎么实现的,我还不知道,还没看过它的源码,有兴趣自己去看一下,然后顺便告诉我一下怎么实现的,哈哈哈)
,Object.defineProperty
Чего нельзя достичь, того можно достичь;Object.defineProperty
Это можно сделать, и это можно сделать. все, что вы настраиваетеpush,pop等方法
Он может перехватить, вы регулируетеdata.n[1] = xxx
Его также можно перехватить, так что не будьте слишком круты Реализация этих двух версий дает мне личное ощущение, что это корейская красная версия (более мясистые и короткие ноги), версия Дилиреба (стройные и длинные ноги), хахаха, на мой вкус.
наконец
здесь только что对象和数组
чтобы испытать силу прокси; прокси может сделать гораздо больше.
-
Чтобы понять больше возможностей прокси, вы можете посмотреть мое предыдущее сравнение основ«Введение в прокси»
-
Чтобы лучше понять использование прокси-сервера, вы можете взглянуть на внешний интерфейс Xiaozhi.«Умелое использование прокси»
Если вы хотите узнать больше о возможностях прокси и других вариантах использования, вы можете прочитать две статьи выше (прочитайте, пожалуйста, добровольно, я не хочу ругать, говорить рекламу, рекомендовать слепые jbs и т. д., 🐶 спасите свою жизнь) .