關于vue2響應式缺陷的問題
vue2響應式缺陷
響應式 : 數(shù)據(jù)改變 ==> 視圖跟著改變
vue2響應式缺陷
1.對象新增的屬性沒有響應式

對象,新增屬性b,修改b的值,值改變但視圖并未更新
解決方案 : 使用vue提供的 api $set(對象,屬性名,值) 效果如屬性c
2.數(shù)組的部分操作沒有響應式
數(shù)組中有7種操作有響應式
array.pop()array.push()array.shift()array.unshift()array.sort()arry.reverse()array.splice()
以上7中API會修改原數(shù)組(vue2的內(nèi)部重寫了這7個API)
其他的操作都不會有響應式
示例:
1.修改數(shù)組的第一個元素的值
// 直接通過下標來修改,沒有響應式
fn1() {
this.arr[0] = 100
}
通過下標直接賦值,沒有響應式
2.修改數(shù)組的長度為0
//修改數(shù)組的length
fn2 () {
this.arr.length = 0
}
修改數(shù)組的length,沒有響應式
如何修改數(shù)組的值有響應式
fn1 () {
// 方法1: 先刪除,再添加
this.arr.splice(0,1,100)
},
fn2 () {
// 方法2: $set
this.$set(this.arr, "0", 100)
}vue2與vue3的響應式原理
給大家分享一下Vue2和Vue3的響應式原理;說到響應式無非就是監(jiān)聽屬性的獲取,修改及刪除...,了解邏輯之后再去實現(xiàn)底層代碼豈不是快了許多=_=
vue2響應式
原理:利用defineReactive方法,通過defineProperty對屬性進行劫持,數(shù)組則是通過重寫其方法來進行劫持,每個屬性值都擁有自己的dep屬性,用來存取所依賴的watch,當數(shù)據(jù)發(fā)生改變時,觸發(fā)相應的watch去更新數(shù)據(jù)
代碼實現(xiàn):
const { arrayMethods } = require('./array')
class Observer {
constructor(value) {
Object.defineProperty(value, '__ob__', {
value: this,
enumerable: false,
writable: true,
configurable: true
})
if(Array.isArray(value)) {
value.__proto__ = arrayMethods
this.observeArray(value)
} else {
this.walk(value)
}
}
walk(data) {
let keys = Object.keys(data)
for(let i = 0; i < keys.length; i++) {
const key = keys[i]
const value = data[key]
defineReactive(data, key, value)
}
}
observeArray(items) {
for(let i = 0; i < items.length; i++) {
observe(items[i])
}
}
}
function defineReactive(data, key, value) {
const childOb = observe(value)
const dep = new Dep()
Object.defineProperty(data, key, {
get() {
console.log('獲取值')
if (Dep.target) {
dep.depend()
if (childOb) {
childOb.dep.depend()
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
set(newVal) {
if (newVal === value) return
observe(newVal)
value = newVal
dep.notify()
}
})
}
function observe(value) {
if (Object.prototype.toString.call(value) === '[object Object]' || Array.isArray(value)) {
return new Observer(value)
}
}
function dependArray(value) {
for(let e, i = 0, l = value.length; i < l; i++) {
e = value[i]
e && e.__ob__ && e.__ob__.dep.depend()
if (Array.isArray(e)) {
dependArray(e)
}
}
}
// array.js
const arrayProto = Array.prototype
const arrayMethods = Object.create(arrayProto)
const methodsToPatch = [
'push',
'pop',
'shift',
'unshift',
'splice',
'reverse',
'sort'
]
methodsToPatch.forEach(method => {
arrayMethods[method] = function (...args) {
const result = arrayProto[method].apply(this, args)
const ob = this.__ob__
var inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break;
case 'splice':
inserted = args.slice(2)
default:
break;
}
if (inserted) ob.observeArray(inserted)
ob.dep.notify()
return result
}
})
但是呢,Vue2的響應式還存在一些缺陷:1.對象新增屬性,刪除屬性界面不會更新 2.通過數(shù)組下標修改數(shù)組內(nèi)容界面不會更新
原因:1.Vue 無法檢測 property 的添加或移除。由于 Vue 會在初始化實例時對 property 執(zhí)行 getter/setter 轉(zhuǎn)化,所以 property 必須在 data 對象上存在才能讓 Vue 將它轉(zhuǎn)換為響應式的
2.通過數(shù)組下標修改數(shù)組不會觸發(fā)響應,因為尤雨溪用了重寫數(shù)組的方法來實現(xiàn)數(shù)據(jù)的響應綁定,當vue遇到push pop shift unshift splice sort reverse 的時候數(shù)組才會改變
解決方案:1.對象:對象新增屬性無法更新視圖,通過Vue.$set(obj,key,value),組件中通過this.$set(obj,key,value)
2.數(shù)組:通過數(shù)組下標修改數(shù)組不會觸發(fā)視圖更新,可以通過Vue.$set(obj,key,value),也可以通過push pop shift unshift splice sort reverse方法來實現(xiàn)響應
Vue3的響應式彌補了Vue2響應式的缺陷,并且還帶來了許多優(yōu)化,下面讓我們來了解一下Vue3響應式的基本雛形
vue3響應式雛形
原理:利用了Proxy和Reflect來代替Vue2的Object.defineProperty()方法來重寫響應式
這只是基本的代碼:
let person = {
name: '張三',
age: 18
}
const p = new Proxy(person, {
get(target, propName) {
console.log(`我的${propName}值被獲取了`);
return Reflect.get(target, propName)
},
set(target, propName, value) {
console.log(`我的${propName}值被修改了`);
Reflect.set(target, propName, value)
},
deleteProperty(target, propName) {
console.log(`我的${propName}值被刪除了`);
Reflect.deleteProperty(target, propName)
}
})target指的是整個person,propName指的是person中的某個屬性,value指的是新值。
運行結(jié)果:

vue3的響應式相較于vue2的優(yōu)勢
用 Proxy 和 Reflect 來代替 vue2 中的 Object.definepeoperty()方法來重寫響應式
vue3 中可以監(jiān)聽動態(tài)新增的屬性
vue3 中可以監(jiān)聽刪除的屬性
vue3 中可以監(jiān)聽數(shù)組的索引和 length 屬性
代碼的執(zhí)行效果更快
Proxy 可以直接監(jiān)聽對象而非屬性
Proxy 可以直接監(jiān)聽數(shù)組的變化
Proxy 有多達 13 種攔截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具備的
Proxy 返回的是一個新對象,我們可以只操作新的對象達到目的,而 Object.defineProperty 只能遍歷對象屬性直接修改
Proxy 不需要初始化的時候遍歷所有屬性,另外有多層屬性嵌套的話,只有訪問某個屬性的時候,才會遞歸處理下一級的屬性
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
詳解Vue基于vue-quill-editor富文本編輯器使用心得
這篇文章主要介紹了Vue基于vue-quill-editor富文本編輯器使用心得,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01
vue3+vite3+typescript實現(xiàn)驗證碼功能及表單驗證效果
這篇文章主要介紹了vue3+vite3+typescript實現(xiàn)驗證碼功能及表單驗證效果,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-04-04

