Sebelum memahami pelaksanaan sistem responsif dengan nilai asal, mari kita semak dahulu keupayaan proksi !
const obj = { name: 'win' } const handler = { get: function(target, key){ console.log('get--', key) return Reflect.get(...arguments) }, set: function(target, key, value){ console.log('set--', key, '=', value) return Reflect.set(...arguments) } } const data = new Proxy(obj, handler) data.name = 'ten' console.log(data.name,'data.name22')
Dalam kod di atas, kami mendapati bahawa penggunaan proksi itu sendiri adalah pemintasan objek Melalui nilai pulangan new Proxy
, objek obj dipintas dengan cara ini, apabila anda mengakses nilai dalam objek, Ia akan mencetuskan kaedah get
Apabila anda mengubah suai nilai dalam objek, ia akan mencetuskan kaedah set
Tetapi apabila ia mencapai nilai asal, ia tidak mempunyai objek. new proxy
tidak berguna lagi. Dalam keadaan terdesak, kami hanya boleh membungkusnya, jadi kami perlu menggunakan .value
untuk mengakses
Mari kita lihat pelaksanaan khusus:
import { reactive } from "./reactive"; import { trackEffects, triggerEffects } from './effect' export const isObject = (value) => { return typeof value === 'object' && value !== null } // 将对象转化为响应式的 function toReactive(value) { return isObject(value) ? reactive(value) : value } class RefImpl { public _value; public dep = new Set; // 依赖收集 public __v_isRef = true; // 是ref的标识 // rawValue 传递进来的值 constructor(public rawValue, public _shallow) { // 1、判断如果是对象 使用reactive将对象转为响应式的 // 浅ref不需要再次代理 this._value = _shallow ? rawValue : toReactive(rawValue); } get value() { // 取值的时候依赖收集 trackEffects(this.dep) return this._value; } set value(newVal) { if (newVal !== this.rawValue) { // 2、set的值不等于初始值 判断新值是否是对象 进行赋值 this._value = this._shallow ? newVal : toReactive(newVal); // 赋值完 将初始值变为本次的 this.rawValue = newVal triggerEffects(this.dep) } } }
Kod di atas , Ia adalah pembungkusan nilai asal Ia dibungkus sebagai objek, dan nilai asal diakses melalui kaedah get value
dan set value
, yang membawa kepada keperluan .value
operasi ini sebenarnya tidak berdaya pilihan
Ia bersamaan dengan dua botol racun, anda perlu memilih satu Anda tidak boleh memiliki kek anda dan memakannya juga
Pertama Masalahnya akhirnya jelas, jadi mari kita lihat soalan kedua paling penting, mengapa tugasan struktur memusnahkan ciri responsif
Sebelum ini kita mulakan, mari mula-mula Bincangkan mengapa penyelesaian responsif perlu diubah
vue2 adalah berdasarkan Object.defineProperty, tetapi ia mempunyai banyak kecacatan, seperti tidak boleh memantau pengubahsuaian tatasusunan berdasarkan subskrip, dan tidak menyokong Map, Set, WeakMap dan WeakSet Defects seperti ,
sebenarnya tidak melambatkan pembangunan kami masih menjadi aliran utama pemahaman ialah
,, walaupun 与时俱进
Terdapat banyak penambahbaikan berbanding Object.defineProperty, tetapi ia bukan tanpa sebarang kekurangan Contohnya, 新一代的版本,一定要紧跟语言的特性,一定要符合新时代的书写风格
proxy
不兼容IE
Bagaimana apa-apa dalam dunia menjadi sempurna? Keberanian Youda terletak pada melepaskan sedikit masa kini dan mendapatkan masa depan!
Prinsip Pelaksanaan
proxy
Walau bagaimanapun, apa yang penting semasa menulis hidrologi: dua perkataan - koherensi
const obj = { count: 1 }; const proxy = new Proxy(obj, { get(target, key, receiver) { console.log("这里是get"); return Reflect.get(target, key, receiver); }, set(target, key, value, receiver) { console.log("这里是set"); return Reflect.set(target, key, value, receiver); } }); console.log(proxy) console.log(proxy.count)
Kod di atas ialah penggunaan Proksi khusus Dengan bekerjasama dengan Reflect, pemintasan objek boleh dicapai
Dengan pergantungan sedemikian, responsif boleh dicapai Anda boleh mendapati bahawa keseluruhan objek obj dipintas, tetapi anda mendapati objek itu bersarang satu tahap lebih dalam
< 🎜. >Contohnya:
const obj = { count: 1, b: { c: 2 } }; console.log(proxy.b) console.log(proxy.b.c)
const obj = { a: { count: 1 } }; function reactive(obj) { return new Proxy(obj, { get(target, key, receiver) { console.log("这里是get"); // 判断如果是个对象在包装一次,实现深层嵌套的响应式 if (typeof target[key] === "object") { return reactive(target[key]); }; return Reflect.get(target, key, receiver); }, set(target, key, value, receiver) { console.log("这里是set"); return Reflect.set(target, key, value, receiver); } }); }; const proxy = reactive(obj);
props
<. 🎜> 2. Penugasan langsung
reactive
3. akan Kehilangan responsif
const obj = { a: { count: 1 }, b: 1 }; //reactive 是上文中的reactive const proxy = reactive(obj); const { a, b } = proxy; console.log(a) console.log(b) console.log(a.count)
vuex
Dalam kod di atas, kami mendapati tugasan yang memusnahkan,
Penugasan jenis primitif adalah bersamaan dengan nilai lulus dan nilai jenis rujukan adalah bersamaan dengan rujukan lulus<🎜. >
b 不会触发响应式
bersamaan dengan: a如果你访问的时候
// 假设a是个响应式对象 const a={ b:1} // c 此时就是一个值跟当前的a 已经不沾边了 const c=a.b // 你直接访问c就相当于直接访问这个值 也就绕过了 a 对象的get ,也就像原文中说的失去响应式
Kalau begitu kenapa
responsif? Keranaialah jenis rujukan, kita masih ingat? Adakah terdapat penghakiman dalam kod di atas? Jika ia adalahDisebabkan ciri semasa, jika ia adalah jenis rujukan, anda tidak akan kehilangan responsif apabila mengakses kandunganmaka bungkusnya semula sebagai responsif
// 假设a是个响应式对象 const a={ b:{c:3}} // 当你访问a.b的时候就已经重新初始化响应式了,此时的c就已经是个代理的对象 const c=a.b // 你直接访问c就相当于访问一个响应式对象,所以并不会失去响应式
dan ubah tabiat penggunaan pengguna terlebih dahulu! Tidak biasa dengan a
a
Apabila kami mula-mula menggunakan vue3, kami menyatakan bahawa kami akan menulis kod berikut object
const vue = reactive({ a: 1 }) vue = { b: 2 }
然后就发出疑问reactive
不是响应式的吗? 为啥我赋值了以后,他的响应式就没了 ,接着破口大骂,垃圾vue
其实啊,这就是您对于js 原生的概念不清除,其实尤大
已经做了最大的努力,来防止你进行错误操作了
比如,由于解构赋值的问题, 他直接禁止了reactive的解构赋值
当你用解构赋值操作的时候,他直接禁用了那有人又问了, 为啥props 不给禁用了呢?因为你的props 的数据可能不是响应式的啊,不是响应式的,我得能啊,尤大他也不能干涉用户使用新语法啊
所以还是那句话:框架现在的呈现,其实充满了取舍,有时候真是两瓶毒药,挑一瓶!
回归正题,我们再来说说 原生js 语法,首先需要确认的是,原生js 的引用类型的赋值,其实是 按照引用地址赋值!
// 当reactive 之后返回一个代理对象的地址被vue 存起来, // 用一个不恰当的比喻来说,就是这个地址具备响应式的能力 const vue = reactive({ a: 1 }) // 而当你对于vue重新赋值的时候不是将新的对象赋值给那个地址,而是将vue 换了个新地址 // 而此时新地址不具备响应式,可不就失去响应式了吗 vue = { b: 2 }
在这里我要替,尤大说句公道话,人家又没收你钱,还因为他,你有口饭吃,您自己不能与时俱进,拥抱新事物,那是您没能耐
,这是典型的端起碗吃肉,放下筷子骂娘
在vuex 用赋值也可能会失去响应式:
import { computed } from 'vue' import { useStore } from 'vuex' export default { setup () { const store = useStore() return { // 在 computed 函数中访问 state count: computed(() => store.state.count), // 在 computed 函数中访问 getter double: computed(() => store.getters.double) } } }
以上代码中我们发现store.getters.double
必须用computed
包裹起来,其实道理是一样的,也是变量赋值的原因,在这里我们就不再赘述!
Atas ialah kandungan terperinci Bagaimana untuk menyelesaikan masalah yang disebabkan oleh kehilangan responsif dalam tugasan struktur dalam Vue3. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!