如何在Javascript中在对象开头添加属性

54

我有

var obj = {'b': 2, 'c': 3};

我想在该对象的开头(而不是结尾)添加一个属性:

var obj = {'a': 1, 'b': 2, 'c': 3};
有没有一种干净的方式来实现这个?

3
对象没有顺序! - epascarello
3
很幸运,我的浏览器不知道这一点,并且表现得好像它们知道一样。 - cedivad
3
不要依赖它:https://dev59.com/jW035IYBdhLWcg3wQtsgJavaScript不能保证对象属性的顺序,因为在规范中没有定义对象属性的顺序。在不同的浏览器和JavaScript引擎中,对象属性的顺序可能会有所不同。因此,在编写代码时,不应该依赖对象属性的顺序。 - epascarello
8个回答

84

你也可以在ES6(ES2015+)中使用Object.assign()

let obj = {'b': 2, 'c': 3};
const returnedTarget = Object.assign({a: 1}, obj);

// Object {a: 1, b: 2, c: 3}

6
这种方法不会改变原始对象,需要提供一个新的对象。 - Mada Aryakusumah
正确,@MadaAryakusumah,这将返回一个新对象,其中属性添加到开头。 - Justin
4
只有当键的类型是字符串时,这个方法才有效。如果键的类型是数字,并且您尝试添加一个字符串键,则它将始终添加在末尾,例如obj = {"1" : "test1","2" : "test2"},而Object.assign({"key1": "value1"}, obj)将返回{"1" : "test1","2" : "test2","key1": "value1"},它不会把新的键放在最前面。 - Manjunath M

44

现在你可以在ES6(ES2015+)中使用方便的扩展运算符(...),试试以下代码:

const obj = {'b': 2, 'c': 3};
   
const startAdded = {'a':1 , ...obj};
console.log(startAdded);

const endAdded = {...obj, 'd':4};
console.log(endAdded);

也许能帮助那些在IT领域摸索的人 :)


20
最简单的方法是使用展开运算符。
let obj = {'b': 2, 'c': 3};
let newObj = {'a': 1, ...obj};

12

JavaScript对象是无序的。没有开始或结束。如果您想要排序,请使用数组。

var arr = [
    { key: 'b', value: 2 },
    { key: 'c', value: 3 }
];

您可以使用 unshift 在其前面添加:

arr.unshift({ key: 'a', value: 1 });

我需要使用c作为数组的键来访问obj['c']。据我所知,JS数组不允许您设置任意键,这就是为什么我卡住了。 - cedivad
1
你最好维护一个对象和数组,两者都包含相同的对象。一个按顺序保留它们,另一个按字母索引它们。 - Quentin

5
这可以通过使用lodash合并函数来完成:
var myObj = _.merge({ col1: 'col 1', col2: 'col 2'}, { col3: 'col 3', col4: 'col 4' });

您的最终对象应该是这样的:
{ col1: 'col 1', col2: 'col 2', col3: 'col 3', col4: 'col 4' }

如其他人所述,无法保证对象中键的顺序是否会保持不变,这取决于您对其进行的操作。但是,如果您将合并作为最后一步执行,则应该没有问题。请注意,“合并”函数将生成一个全新的对象,它不会更改您传递给它的任何对象。


3
var obj = {'b': 2, 'c': 3};
obj = Object.assign({a: 1}, obj);
console.log(obj); // {a: 1, b: 2, c: 3}

希望这能有所帮助。


3
JavaScript本身可能不会为语言中的属性指定顺序,但至少在我的项目(也许是你的)中,它肯定表现得像有顺序一样(JSON.stringify、debug watch windows等) 。我从来没有看到 for...in 顺序不是最初添加属性的顺序。因此,在我的项目和也许你的项目中,就所有方面而言,这是非常可预测的。
虽然这不影响执行,但如果您想查看统一列表,则当不同项目的属性可能根据创建对象的方式以不同的顺序添加时,这将是一个痛点。在项目开发中,执行可能不是唯一重要的事情。快速检查对象的能力也可能很重要。
方法1(高科技)
如果您拥有spread,那么可以使用它,如果您不介意另一个对象。但是,如果您没有spread(例如在较旧的Google应用程序脚本中),或者您需要保留原始对象,则可以执行以下操作:
objects.js
// Insert Property
Object.defineProperty(
  Object.prototype, 
  'insertProperty', 
  {
  value: function(name, value, index){
    // backup my properties
    var backup = {};
    // delete all properties after index
    var propertyIndex = 0;
    for(var propertyName in this) {
      if(this.hasOwnProperty(propertyName) && propertyIndex++ >= index) {
        backup[propertyName] = this[propertyName];  
        delete this[propertyName];
      }
    }
    this[name] = value;
    // restore all properties after index
    for(var propertyName in backup) {
      if(backup.hasOwnProperty(propertyName))
        this[propertyName] = backup[propertyName];  
    }
    return this; // same object; not a new object
  },
  enumerable: false,
});

使用方法

  var obj = {'b': 2, 'c': 3};
  obj.insertProperty('a',1,0); // {a:1, b:2, c:3}

笔记

  • 您可以使用任何索引将属性放在所需位置,0表示放在最前面。
  • 如果您不喜欢将方法添加到对象原型中,您当然可以将函数提取出来并添加一个obj参数。在我的项目中,向原型添加方法对我有帮助,而不是有害。

方法2(低技术)

在某些情况下,您可能只需按照要查看其出现的顺序创建具有所有已知属性的对象,并稍后在设置属性时而不是插入属性。

// creation
var a = {Id: null, foo: 'bar'}; 

// update later
if(!a.Id)
  a.Id = '123'; 

+1 给低技术方法,这肯定是一个创新的解决方案,但允许就地修改目标对象。在我看来,当需要添加的属性是强制性的时候(例如 id 等属性)可以使用此方法。 - Renaud Pawlak

1
我的做法是使用一个临时对象来按照所需顺序存储项目。 例如:
var new_object = {}; 
new_object[name] = value; // The property we need at the start 

for (var key in old_object) { // Looping through all values of the old object 
  new_object[key] = old_object[key];
  delete old_object[key]; 
} 

old_object = new_object; // Replacing the old object with the desired one

对象没有顺序,for in 枚举它们是任意的。 - Bergi
但是...它并没有。 - Nick

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