vue2响应式缺陷

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

vue2响应式缺陷

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

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

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

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

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

  • array.pop()
  • array.push()
  • array.shift()
  • array.unshift()
  • array.sort()
  • arry.reverse()
  • array.splice()

以上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 不需要初始化的时候遍历所有属性,另外有多层属性嵌套的话,只有访问某个属性的时候,才会递归处理下一级的属性 

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

关于vue2响应式缺陷的问题的更多相关文章

  1. VUE响应式原理的实现详解

    这篇文章主要为大家详细介绍了VUE响应式原理的实现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

  2. Vue响应式原理及双向数据绑定示例分析

    这篇文章主要为大家介绍了Vue响应式原理及双向数据绑定的示例分析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

  3. vue2中组件互相调用实例methods中的方法实现详解

    vue在同一个组件内,方法之间经常需要互相调用,下面这篇文章主要给大家介绍了关于vue2中组件互相调用实例methods中的方法实现的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下

  4. vue3.0响应式函数原理详细

    这篇文章主要介绍了vue3.0响应式函数原理,Vue3的响应式系统可以监听动态添加的属性还可以监听属性的删除操作,以及数组的索引以及length属性的修改操作。另外Vue3的响应式系统还可以作为模块单独使用。下面更多介绍,需要的小伙伴可以才可以参考一下

  5. Vue3 Reactive响应式原理逻辑详解

    这篇文章主要介绍了Vue3 Reactive响应式原理逻辑详解,文章围绕主题展开详细的内容介绍,具有一定的参考价值,需要的小伙伴可以参考一下

  6. vue3和vue2中mixins的使用解析

    这篇文章主要介绍了vue3和vue2中mixins的使用解析,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  7. CSS3 media queries结合jQuery实现响应式导航

    这篇文章主要为大家详细介绍了CSS3 media queries结合jQuery实现响应式导航,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  8. Vue2 Element Schema Form 配置式生成表单的实现

    本文主要介绍了Vue2 Element Schema Form 配置式生成表单的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  9. 详解如何在Flutter中用小部件创建响应式布局

    由于Flutter的跨平台、单一代码库的能力,了解屏幕管理以防止像柔性溢出错误或糟糕的用户界面设计这样的问题是至关重要的。本文将探讨如何用灵活和扩展的小部件创建响应式布局,需要的可以参考一下

  10. vue2项目增加eslint配置代码规范示例

    这篇文章主要为大家介绍了vue2项目增加eslint配置代码规范示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部