文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

关于vue2响应式缺陷的问题

2024-04-02 19:55

关注

vue2响应式缺陷

响应式 : 数据改变 ==> 视图跟着改变

vue2响应式缺陷

1.对象新增的属性没有响应式

对象,新增属性b,修改b的值,值改变但视图并未更新

解决方案 : 使用vue提供的 api $set(对象,属性名,值) 效果如属性c

2.数组的部分操作没有响应式

数组中有7种操作有响应式

以上7中API会修改原数组(vue2的内部重写了这7个API)

其他的操作都不会有响应式

示例:

1.修改数组的第一个元素的值

// 直接通过下标来修改,没有响应式
fn1() {
    this.arr[0] = 100
}

通过下标直接赋值,没有响应式

2.修改数组的长度为0

//修改数组的length
fn2 () {
    this.arr.length = 0
}

修改数组的length,没有响应式

如何修改数组的值有响应式

fn1 () {
    // 方法1: 先删除,再添加
    this.arr.splice(0,1,100)
},
fn2 () {
    // 方法2: $set
    this.$set(this.arr, "0", 100)
}

vue2与vue3的响应式原理

给大家分享一下Vue2和Vue3的响应式原理;说到响应式无非就是监听属性的获取,修改及删除...,了解逻辑之后再去实现底层代码岂不是快了许多=_=

vue2响应式

原理:利用defineReactive方法,通过defineProperty对属性进行劫持,数组则是通过重写其方法来进行劫持,每个属性值都拥有自己的dep属性,用来存取所依赖的watch,当数据发生改变时,触发相应的watch去更新数据

代码实现:

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.通过数组下标修改数组内容界面不会更新

原因:1.Vue 无法检测 property 的添加或移除。由于 Vue 会在初始化实例时对 property 执行 getter/setter 转化,所以 property 必须在 data 对象上存在才能让 Vue 将它转换为响应式的

2.通过数组下标修改数组不会触发响应,因为尤雨溪用了重写数组的方法来实现数据的响应绑定,当vue遇到push pop shift unshift splice sort reverse 的时候数组才会改变

 解决方案:1.对象:对象新增属性无法更新视图,通过Vue.$set(obj,key,value),组件中通过this.$set(obj,key,value)

2.数组:通过数组下标修改数组不会触发视图更新,可以通过Vue.$set(obj,key,value),也可以通过push pop shift unshift splice sort reverse方法来实现响应

 Vue3的响应式弥补了Vue2响应式的缺陷,并且还带来了许多优化,下面让我们来了解一下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指的是新值。

运行结果:

vue3的响应式相较于vue2的优势

用 Proxy 和 Reflect 来代替 vue2 中的 Object.definepeoperty()方法来重写响应式

vue3 中可以监听动态新增的属性

vue3 中可以监听删除的属性

vue3 中可以监听数组的索引和 length 属性

代码的执行效果更快

Proxy 可以直接监听对象而非属性

Proxy 可以直接监听数组的变化

Proxy 有多达 13 种拦截方法,不限于 apply、ownKeys、deleteProperty、has 等等是 Object.defineProperty 不具备的

Proxy 返回的是一个新对象,我们可以只操作新的对象达到目的,而 Object.defineProperty 只能遍历对象属性直接修改

Proxy 不需要初始化的时候遍历所有属性,另外有多层属性嵌套的话,只有访问某个属性的时候,才会递归处理下一级的属性 

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯