chst365's blog chst365's blog
首页
  • Git
  • 网络
  • 操作系统
  • 浏览器
  • webpack
  • JavaScript
  • TypeScript
  • 性能
  • 工程化
  • React
  • 编程题
  • React技术揭秘
  • 算法
  • Node
  • 编码解码
  • NodeJS系列
  • Linux系列
  • JavaScript系列
  • HTTP系列
  • GIT系列
  • ES6系列
  • 设计模式系列
  • CSS系列
  • 小程序系列
  • 数据结构与算法系列
  • React系列
  • Vue3系列
  • Vue系列
  • TypeScript系列
  • Webpack系列
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

chst365

DIV工程师
首页
  • Git
  • 网络
  • 操作系统
  • 浏览器
  • webpack
  • JavaScript
  • TypeScript
  • 性能
  • 工程化
  • React
  • 编程题
  • React技术揭秘
  • 算法
  • Node
  • 编码解码
  • NodeJS系列
  • Linux系列
  • JavaScript系列
  • HTTP系列
  • GIT系列
  • ES6系列
  • 设计模式系列
  • CSS系列
  • 小程序系列
  • 数据结构与算法系列
  • React系列
  • Vue3系列
  • Vue系列
  • TypeScript系列
  • Webpack系列
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • NodeJS系列

  • Linux系列

  • JavaScript系列

  • HTTP系列

  • GIT系列

  • ES6系列

  • 设计模式系列

  • CSS系列

  • 小程序系列

  • 数据结构与算法系列

  • React系列

  • Vue3系列

  • Vue系列

    • vue项目本地开发完成后部署到服务器后报404是什么原因呢?
    • Vue项目中有封装过axios吗?主要是封装哪方面的?
    • 你了解axios的原理吗?有看过它的源码吗?
    • 双向数据绑定是什么
    • Vue组件之间的通信方式都有哪些?
    • Vue中组件和插件有什么区别?
    • Vue项目中你是如何解决跨域的呢?
    • 为什么data属性是一个函数而不是一个对象?
    • 动态给vue的data添加一个新的属性时会发生什么?怎样解决?
      • 一、直接添加属性的问题
      • 二、原理分析
      • 三、解决方案
        • Vue.set()
        • Object.assign()
        • $forceUpdate
        • 小结
      • 参考文献
    • 你了解vue的diff算法吗?说说看
    • 你有写过自定义指令吗?自定义指令的应用场景有哪些?
    • 你是怎么处理vue项目中的错误的?
    • Vue中的过滤器了解吗?过滤器的应用场景有哪些?
    • SPA首屏加载速度慢的怎么解决?
    • v-if和v-for的优先级是什么?
    • 说说你对keep-alive的理解是什么?
    • 你知道vue中key的原理吗?说说你对它的理解
    • 请描述下你对vue生命周期的理解?在created和mounted这两个生命周期中请求数据有什么区别呢?
    • 说说你对vue的mixin的理解,有什么应用场景?
    • Vue常用的修饰符有哪些有什么应用场景
    • Vue实例挂载的过程
    • Vue中的$nextTick有什么作用?
    • Vue.observable你有了解过吗?说说看
    • vue要做权限管理该怎么做?如果控制到按钮级别的权限怎么做?
    • v-show和v-if有什么区别?使用场景分别是什么?
    • 说说你对slot的理解?slot使用场景有哪些?
    • 你对SPA单页面的理解,它的优缺点分别是什么?如何实现SPA应用呢
    • SSR解决了什么问题?有做过SSR吗?你是怎么做的?
    • 说下你的vue项目的目录结构,如果是大型项目你该怎么划分结构和划分组件呢?
    • 什么是虚拟DOM?如何实现一个虚拟DOM?说说你的思路
    • 有使用过vue吗?说说你对vue的理解
    • vue3有了解过吗?能说说跟vue2的区别吗?
  • TypeScript系列

  • Webpack系列

  • 面试官
  • Vue系列
chst365
2023-06-28
目录

动态给vue的data添加一个新的属性时会发生什么?怎样解决?

# 面试官:动态给vue的data添加一个新的属性时会发生什么?怎样解决?

image.png

# 一、直接添加属性的问题

我们从一个例子开始

定义一个p标签,通过v-for指令进行遍历

然后给botton标签绑定点击事件,我们预期点击按钮时,数据新增一个属性,界面也 新增一行

<p v-for="(value,key) in item" :key="key">
    {{ value }}
</p>
<button @click="addProperty">动态添加新属性</button>
1
2
3
4

实例化一个vue实例,定义data属性和methods方法

const app = new Vue({
    el:"#app",
   	data:()=>{
       	item:{
            oldProperty:"旧属性"
        }
    },
    methods:{
        addProperty(){
            this.items.newProperty = "新属性"  // 为items添加新属性
            console.log(this.items)  // 输出带有newProperty的items
        }
    }
})
1
2
3
4
5
6
7
8
9
10
11
12
13
14

点击按钮,发现结果不及预期,数据虽然更新了(console打印出了新属性),但页面并没有更新

# 二、原理分析

为什么产生上面的情况呢?

下面来分析一下

vue2是用过Object.defineProperty实现数据响应式

const obj = {}
Object.defineProperty(obj, 'foo', {
        get() {
            console.log(`get foo:${val}`);
            return val
        },
        set(newVal) {
            if (newVal !== val) {
                console.log(`set foo:${newVal}`);
                val = newVal
            }
        }
    })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

当我们访问foo属性或者设置foo值的时候都能够触发setter与getter

obj.foo   
obj.foo = 'new'
1
2

但是我们为obj添加新属性的时候,却无法触发事件属性的拦截

obj.bar  = '新属性'
1

原因是一开始obj的foo属性被设成了响应式数据,而bar是后面新增的属性,并没有通过Object.defineProperty设置成响应式数据

# 三、解决方案

Vue 不允许在已经创建的实例上动态添加新的响应式属性

若想实现数据与视图同步更新,可采取下面三种解决方案:

  • Vue.set()
  • Object.assign()
  • $forcecUpdated()

# Vue.set()

Vue.set( target, propertyName/index, value )

参数

  • {Object | Array} target
  • {string | number} propertyName/index
  • {any} value

返回值:设置的值

通过Vue.set向响应式对象中添加一个property,并确保这个新 property同样是响应式的,且触发视图更新

关于Vue.set源码(省略了很多与本节不相关的代码)

源码位置:src\core\observer\index.js

function set (target: Array<any> | Object, key: any, val: any): any {
  ...
  defineReactive(ob.value, key, val)
  ob.dep.notify()
  return val
}
1
2
3
4
5
6

这里无非再次调用defineReactive方法,实现新增属性的响应式

关于defineReactive方法,内部还是通过Object.defineProperty实现属性拦截

大致代码如下:

function defineReactive(obj, key, val) {
    Object.defineProperty(obj, key, {
        get() {
            console.log(`get ${key}:${val}`);
            return val
        },
        set(newVal) {
            if (newVal !== val) {
                console.log(`set ${key}:${newVal}`);
                val = newVal
            }
        }
    })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# Object.assign()

直接使用Object.assign()添加到对象的新属性不会触发更新

应创建一个新的对象,合并原对象和混入对象的属性

this.someObject = Object.assign({},this.someObject,{newProperty1:1,newProperty2:2 ...})
1

# $forceUpdate

如果你发现你自己需要在 Vue中做一次强制更新,99.9% 的情况,是你在某个地方做错了事

$forceUpdate迫使Vue 实例重新渲染

PS:仅仅影响实例本身和插入插槽内容的子组件,而不是所有子组件。

# 小结

  • 如果为对象添加少量的新属性,可以直接采用Vue.set()

  • 如果需要为新对象添加大量的新属性,则通过Object.assign()创建新对象

  • 如果你实在不知道怎么操作时,可采取$forceUpdate()进行强制刷新 (不建议)

PS:vue3是用过proxy实现数据响应式的,直接动态添加新属性仍可以实现数据响应式

# 参考文献

  • https://cn.vuejs.org/v2/api/#Vue-set
  • https://vue3js.cn/docs/zh
#面试官
上次更新: 2025/04/11, 17:57:53
为什么data属性是一个函数而不是一个对象?
你了解vue的diff算法吗?说说看

← 为什么data属性是一个函数而不是一个对象? 你了解vue的diff算法吗?说说看→

最近更新
01
面试官
03-27
02
this&指针&作用域&闭包
03-27
03
前端
03-27
更多文章>
Theme by Vdoing | Copyright © 2019-2025 chst365 | 豫ICP备17031889号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式