• 微信公众号:美女很有趣。 工作之余,放松一下,关注即送10G+美女照片!

object.assgin导致的vue双向数据绑失效

互联网 diligentman 4周前 (01-31) 13次浏览

前几天在写一个后台项目的时候使用object.assgin时出现了一个很奇怪的bug,特写了一个简单的demo探究一下。demo为一个基础表单:

object.assgin导致的vue双向数据绑失效

后端数据中只有name和爱好有值。

此时根据后端数据将表单中的数据赋值:
this.personData = res.data.userTableData
效果十分的符合预期,随便点点也没有什么其他的问题:

object.assgin导致的vue双向数据绑失效

但如果用下面这种方式对表单数据进行赋值:
Object.assign(this.personData, res.data.userTableData)
奇怪的现象发生了,刷新后表单没有初始数值,而且表单的修改不生效:

object.assgin导致的vue双向数据绑失效

此时修改运动栏的值后发现前两栏的数据终于更新了,但是前两栏的数据依然是不能做任何的直接修改,只有运动一栏的数据修改后,前两栏数据之前做过的修改才会显示出来。让人不禁想问到底发生了什么。

为此我查询了object.assgin相关的代码,发现这篇文章:

Object.myAssign = function (target, ...src) {
  for (let i = 0; i < src.length; i++) {
    if (src[i] !== null || src[i] !== undefined) {
      // 过滤掉源对象为null和undefined的情况
      for (let key in src[i]) {
        // in运算符会查找原型对象上的可枚举属性,所以需要通过Object.prototype.hasOwnProperty方法过滤掉对象原型对象上的属性
        if (src[i].hasOwnProperty(key)) {
          target[key] = src[i][key]
        }
      } 
    }
  }
  return target
}

关键代码:target[key] = src[i][key]

到这里开始问题就初现端倪了,我又找到了下面这篇文章

关键部分:
person.name = {name: ‘tom’} =>触发了set
person.name =>{name: “tom”}
person.name.name = 123123
=>没有打印出任何信息,说明修改name的属性值并没有触发set方法。
person.name.sex = 333
=>没有打印出任何信息,说明添加name的属性值并没有触发set方法。 delete person.name.name =>没有打印出任何信息,说明删除name的属性值并没有触发set方法。
Object.defineProperty(person.name, ‘name’, {value: 4444}) =>没有打印出任何信息,说明Object.defineProperty也没有触发set方法。

我直呼好家伙,原来对象的双向数据绑定生效条件居然如此苛刻,object.assgin的赋值方法没有触发到set函数,自然也不会通知到调用其值的对象上,直到在表单中给运动栏赋值时this.personData的set被触发,之前的所有表单的数据变化才被展示出来。

这时第二个问题出现了,为什么在修改运动一栏的数据时会又这么反常的现象?

我认为是当直接修改对象里的值时,仅仅是改变了指向栈数据的指针指向,对于双向数据绑定并未产生有效影响。所以此时修改前两栏的数据时虽然this.personData里的属性的指针指向被修改了,但修改值在双向数据绑定中的指针指向还是之前的地址。这也解释了为什么在修改运动一栏的值后之前做过的变化又会展示出来,因为this.personData的值确实被改变了,但你之后无论怎么改变前两栏的数据,都是不会有任何变化展示出来的。

引用的相关文章地址:

  1. https://segmentfault.com/a/11&#8230;
  2. https://www.cnblogs.com/yanze&#8230;

程序员灯塔
转载请注明原文链接:object.assgin导致的vue双向数据绑失效
喜欢 (0)