更新 JavaScript 对象属性?

72

我有一个如下所示的结构:

skillet.person = {
  name: {
    first: '',
    last: ''
  }, 
  age: {
    current: '' 
  },
  birthday: {
    day: '',
    month: '',
    year: ''
  }
}

我在想如何更新这些数值?也就是说,我认为以下是正确的。
skillet.person.name.push({ first: 'blah', last: 'ha'});

但这是错的吗?我该如何修复这个问题?


7
MDN有一份很棒的JavaScript教程,尤其是https://developer.mozilla.org/en/JavaScript/Guide/Working_with_Objects。 - Felix Kling
9个回答

115

使用ES7+语法和函数式编程方法:

const new_obj = { ...obj, name: { first: 'blah', last: 'ha'} }

1
那么const new_obj = { ...obj, name: { first: 'blah'} }怎么办?我错过了last属性! - Pedram A. Keyvani
7
这样做,您正在删除last属性。如果您只想更新first属性(而不删除last属性),则应执行const new_obj = { ...obj, name: { ...obj.name, first: 'blah'} } - Ramon Diogo
这个带有对象的扩展运算符在React中也适用于设置状态。 - Ben in CA
在这个例子中,...obj 应该被替换为 skillet.person 吗?还是 ...skillet.person - jschmitter

39

在支持ECMAScript 2015的现代浏览器中,您可以这样做:

Object.assign(skillet.person.name, { first: 'blah', last: 'ha'});

这将保留右侧对象中未列出的任何现有属性。

参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

[编辑] 使用ES7,您甚至可以更简短地实现此操作(但是否更清晰呢?...):

{...skillet.person.name, ...{ first: 'blah', last: 'ha'}};

参考资料: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_syntax


第二个选项有一个小差别,即属性(即函数)不会在第二个选项中被保留。 - lowzhao
你不是要用第二个选择重新创建对象吗?我认为那会增加更多的开销。 - Jamie Marshall

33

如@ramon-diogo所述,使用ES7+:

我喜欢更新嵌套的值,例如:

let user = {
    name: {
        first: 'john',
        last: 'smith'
    },
    age: 18,
    city: 'new york'
}

const age = 20;

user = {...user, age}

console.log(user.age)
// output: 20


const newData ={
    age: 22,
    city: 'san francisco'
};

user = {...user,...newData}

console.log(user.name.first)
// output: john
console.log(user.age)
// output: 22
console.log(user.city)
// output: 'san francisco'

这是唯一适用于任何用例的通用答案。 - lukassos

29
skillet.person.name.first = "blah"
skillet.person.name.last = "ha"
或者
skillet.person.name = {first : "blah", last : "ha"}

谢谢回复。如果我不想替换属性,而不是列出每个值,是否有更快的更新方式,如果不是所有值都可用? - Andy
1
@Andy:你可能正在寻找一个“extend”函数。[可以查看Underscore.js的实现。] (http://documentcloud.github.com/underscore/#extend) - pimvdb
@pimvdb - 是的,目前我有很多属性,但并非所有属性都包含值。我正在用只有部分属性的对象替换它,这会导致问题 - 这是否意味着我必须像MrE一样列出每个值,还是有一种更快的方法而不需要替换? - Andy
@Andy:你有两个对象,想要将它们的属性混合在一起吗? - pimvdb
@pimvdb - 我有一个包含9个属性的对象,但通常只更新其中6个。我尝试过 { ... },但它会替换掉3个未填充的值 - 这意味着我必须像 skillet.person.name.first 等写6个属性吗? - Andy
@pimvdb Underscore.js文档的链接已更改。 - jammon

25
如果你想将一个对象混合到另一个对象中,你可以使用jQuery的深度扩展函数。 "深度"意味着它不会用新的对象覆盖"name",而是覆盖该对象内部的属性。
$.extend(true, skillet.person, {
  name: {
    first: 'updated'
  },
  birthday: {
    day: 'updated',
    year: 'updated'
  }
});

现在,skillet.person 的相关属性已更新,而其他属性则没有改变。


5

pushArray的一个方法,用于向数组中添加新项。

如果您想替换值,则:

skillet.person.name = { … };

如果您想在对象中存储多个完整姓名,那么您需要使用一个对象数组来代替单个对象的属性。


谢谢。有没有更快的更新方式,而不是列出每个值,如果我不想替换它们? - Andy
2
@Andy:您可以迭代对象属性。for(var prop in newValues) { oldValues[prop] = newValues[prop];}(在gist中)。MDN还有一个关于for...in的好页面。看一下吧。 - Felix Kling

4
我认为这更简单。
     let skillet = {
        person: {
            name    : {
                first: '',
                last : ''
            },
            age     : {
                current: ''
            },
            birthday: {
                day  : '',
                month: '',
                year : ''
            }
        }
    };

    let update = {
        person: {
            name: {
                first: 'blah',
                last : 'ha'
            }
        }
    };

    let result = Object.assign(skillet.person, update.person);

    console.log(result);

如果我只需要更新“last”而不影响“first”怎么办? - itsji10dra
1
跟 platie 的例子一样,我认为只编辑一个元素最简单的方法是这样的:..skillet.person.birthday.year = 2019 console.log({...skillet.person, ...skillet.person.birthday.year}); - Jasp402

1
skillet.person.name.first = "blah"
skillet.person.name.last = "ha"

最简单的方法。


-1
skillset.person.name = {};

这是给对象属性赋值的最简单方法。


1
它看起来几乎和Quentin在2012年的答案一样。有任何改进或变化吗? - myeongkil kim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接