前几天在写一个后台项目的时候使用object.assgin时出现了一个很奇怪的bug,特写了一个简单的demo探究一下。demo为一个基础表单:
后端数据中只有name和爱好有值。
此时根据后端数据将表单中的数据赋值:this.personData = res.data.userTableData
效果十分的符合预期,随便点点也没有什么其他的问题:
但如果用下面这种方式对表单数据进行赋值:Object.assign(this.personData, res.data.userTableData)
奇怪的现象发生了,刷新后表单没有初始数值,而且表单的修改不生效:
此时修改运动栏的值后发现前两栏的数据终于更新了,但是前两栏的数据依然是不能做任何的直接修改,只有运动一栏的数据修改后,前两栏数据之前做过的修改才会显示出来。让人不禁想问到底发生了什么。
为此我查询了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函数,自然也不会通知到调用其值的对象上,界面上的数据自然也没有变化。
这时第二个问题出现了,为什么在修改运动一栏的数据时会又这么反常的现象?
我认为对象在新增属性后,对其新增的属性做任何的变化也不会触发双向数据绑定,此时相当于仅仅给对象多了一个指向新属性的指针而已。只有当修改运动栏的值时真正触发了set才会导致页面数据重新载入。关于对象的双向数据绑定具体是如何实现的,我想过几天再写一篇文章记录一下(flag)。
总结一下,如果你想使用object.assgin的话,可以这么写:this.personData = object.assgin({}, res.data.userTableData)
或者你想将二者属性结合到一起:this.personData = Object.assign(Object.assign({}, this.personData), res.data.userTableData)
引用的相关文章地址:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。