Vue对象传值问题:obj1的值赋给obj2,当obj2的值改变,obj1也会随之改变

本文探讨了JavaScript中对象的引用传递与值传递的区别,通过具体示例展示了如何避免对象修改时的相互影响,强调了使用JSON.parse(JSON.stringify(obj))进行深拷贝的重要性。

场景如标题所示,上代码:

var obj1 = {
	id:1,
	name:'Jack',
	wage:'11',//工资,11表示选择了其他
	selfWage:'6000',//当wage为其他时,自己填写
	checked:true
}

var obj2 = obj1;
console.log(obj1);
console.log(obj2);

现在控制台打印出来的结果都是一样的。

Object { id: 1, name: "Jack", wage: "11", selfWage: "6000", checked: true }

Object { id: 1, name: "Jack", wage: "11", selfWage: "6000", checked: true }

此时需要对obj2进行操作:

obj2.wage=obj2.selfWage;
delete obj2.checked;
delete obj2.selfWage;
console.log(obj1);
console.log(obj2);

这时再来看控制台结果:

Object { id: 1, name: "Jack", wage: "6000" }

Object { id: 1, name: "Jack", wage: "6000" }

会发现,obj1也随着obj2的改变而改变了。这是因为这里发赋值是属于引用传递而非值传递,两者同时指向了同一内存地址。
若在操作obj2的数据时不影响到obj1的值,我们可以这样来赋值:

var obj1 = {
   id:1,
   name:'Jack',
   wage:'11',//工资,11表示选择了其他
   selfWage:'6000',//当wage为其他时,自己填写
   checked:true
}

var obj2 = JSON.parse(JSON.stringify(obj1));
obj2.wage=obj2.selfWage;
delete obj2.checked;
delete obj2.selfWage;
console.log(obj1);
console.log(obj2);

再来看打印结果:

Object { id: 1, name: "Jack", wage: "11", selfWage: "6000", checked: true }

Object { id: 1, name: "Jack", wage: "6000" }

这时,obj1还是那个obj1,obj2已经不是那个obj2了,这里赋值主要是通过JSON将obj1转为字符串,然后再解析成对象传给obj2,这样就不会有问题了,目的达成,收工。

<think>好的,用户的问题是在Vue2中,当对props中的对象进行深度监听时,即使对象没有改变,watch也会被触发。需要找出原因和解决方案。首先,我需要回顾Vue2的响应式系统是如何工作的。 Vue2使用Object.defineProperty来实现数据的响应式,但这种方式无法检测到对象属性的添加或删除,因此需要用到$set或$delete方法。用户提到的是props中的对象,而props是父组件递下来的,子组件不能直接修改。这时候,如果父组件更新了对象的属性,子组件的watch是否能正确触发? 根据引用[2],Vue2的props是单向数据流,子组件不能直接修改父组件递的。当父组件更新对象的属性时,如果子组件的watch没有设置deep:true,可能无法检测到对象内部的变化。但用户的问题是即使对象改变,watch也被触发,这可能涉及到对象的引用问题。 另外,引用[3]和[4]提到,直接修改对象的属性(比如this.obj.prop = value)不会触发响应式更新,必须使用$set或者替换整个对象。如果在子组件中,父组件递的对象被替换,即使内容相同,由于引用不同,watch会触发。例如,父组件可能每次更新时都生成一个新对象,导致子组件的watch误判为变化。 用户的情况是深度监听props对象,即使对象未变也会触发。可能的原因是父组件在更新时重新创建了对象,导致引用变化。此时,即使内容相同,watch也会因为对象的引用不同而触发。这时候需要比较新旧是否真的改变。 解决方案可能包括:在handler中比较新旧的序列化字符串,或者在父组件中避免不必要的对象重新创建。另外,使用immediate选项可能导致初始化时触发,需要确认是否合理。 还要考虑Vue的响应式限制,比如对于数组或对象的结构变更,可能需要特殊处理。用户可能需要优化父组件的数据更新方式,或者在子组件中进行深比较来避免不必要的处理。</think>### **Vue2中props对象深度监听的异常触发问题解析与解决方案** --- #### **一、问题本质原因** 1. **引用地址变更触发** - 当父组件通过`Object.assign()`或展开运算符创建新对象时,即使对象内容未变,子组件接收的props对象**内存地址已改变**,触发watch[^3] - 示例场景: ```javascript // 父组件每次更新都生成新对象 this.obj = { ...this.obj } // 地址变更但内容可能相同 ``` 2. **深层数据对比缺失** - Vue2的响应式系统通过`Object.defineProperty`实现,**深度监听默认仅对比引用地址**,不会递归对比对象内部属性[^2] - 验证公式:$$ \text{触发条件} = \begin{cases} \text{true}, & \text{对象地址变化} \\ \text{false}, & \text{地址未变且内部数据未变} \end{cases} $$ 3. **与computed的差异** - computed属性通过**依赖收集**实现精准更新,而watch的deep模式采用**递归遍历**,性能消耗更大但精度更低[^1] --- #### **二、分步解决方案** **方案1:精确数据比对** ```javascript watch: { propObj: { deep: true, handler(newVal, oldVal) { // 序列化对比避免误触发 if(JSON.stringify(newVal) !== JSON.stringify(oldVal)) { console.log('实际数据变更') } } } } ``` **原理**:通过`JSON.stringify`实现深对比,过滤引用地址变更但数据未变的场景[^4] --- **方案2:冻结对象引用** ```javascript // 父组件优化(避免地址变更) updateData() { // 仅当数据真正变化时更新对象 if (this.isDataChanged) { this.obj = Object.assign({}, this.originalObj) } } ``` **效果**:减少父组件不必要的对象重建,从源头避免地址变更[^3] --- **方案3:混合计算属性** ```javascript computed: { stableObj() { return JSON.parse(JSON.stringify(this.propObj)) } }, watch: { stableObj(newVal) { /* 精确监听 */ } } ``` **优势**:利用computed的稳定输出特性,自动过滤无意义变更[^1] --- #### **三、进阶调试技巧** 1. **内存地址追踪** ```javascript console.log('对象地址:', this._.uid, this.propObj) ``` 2. **性能优化配置** ```javascript watch: { propObj: { deep: true, immediate: false, // 关闭初始触发 flush: 'sync' // 控制触发时机 } } ``` 3. **Vue响应式原理验证** ```javascript // 检查对象是否已被Vue代理 console.log('是否响应式:', this.$data.__ob__ ? '是' : '否') ``` --- #### **四、核心原理总结** | 现象 | 技术原理 | 数学表达 | |------|----------|----------| | 对象地址变更触发watch | 指针比对机制 | $$ \frac{d(ref\_new)}{d(ref\_old)} \neq 0 $$ | | 深层数据未变更误触发 | 缺乏递归对比 | $$ \forall x \in Object, \frac{\partial x_{new}}{\partial x_{old}} = 1 $$ | | computed精准监听 | 依赖追踪系统 | $$ \sum_{i=1}^{n} \delta(dep\_i) = 0 \Rightarrow 不更新 $$ | --- #### **五、延伸问题** 1. 如何在Vue2中实现对象属性的增量监听? 2. 使用Immutable.js优化大型对象递的性能损耗? 3. Vue3的Proxy响应式系统如何解决此类问题? --- [^1]: props监听机制与computed差异 [^2]: Vue2响应式系统设计原理 [^3]: 对象引用地址变更场景 [^4]: 深度数据比对实现方案
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值