JavaScript对象是否可以动态添加命名属性?

948
在JavaScript中,我创建了如下的对象:
var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};

如果属性的名称直到运行时才确定,那么在对象初始化创建后是否还可以添加其他属性呢?

var propName = 'Property' + someUserInput
//imagine someUserInput was 'Z', how can I now add a 'PropertyZ' property to 
//my object?

使用用户输入来操作数据结构中的键是最好情况下的反模式,最坏情况下是安全隐患。你真正想要通过这样做实现什么目标? - ggorlen
22个回答

13

我知道这个帖子已经有几个答案了,但是我还没有看到一个在其中有多个属性并且它们在一个数组中的答案。顺便说一下,这个解决方案适用于ES6。

为了说明,假设我们有一个名为person的数组,里面有对象:

 let Person = [{id:1, Name: "John"}, {id:2, Name: "Susan"}, {id:3, Name: "Jet"}]

那么,您可以添加相应值的属性。假设我们想要添加一个默认值为EN语言(Language)属性。

Person.map((obj)=>({...obj,['Language']:"EN"}))

现在Person数组会变成这样:

Person = [{id:1, Name: "John", Language:"EN"}, 
{id:2, Name: "Susan", Language:"EN"}, {id:3, Name: "Jet", Language:"EN"}]

你实际上并没有向一个对象添加属性,而是通过扩展运算符创建了一个新对象,该新对象具有旧对象的属性和新属性。 - Ed Orsi
3
你说得对,应该是 Person = Person.map(code here)。但重点是在 ES6 中你可以轻松地向现有对象添加属性。 - Edper

13

如果在运行时混合新属性,这将非常有用:

data = { ...data, newPropery: value}

然而,扩展运算符使用浅拷贝,但在这里我们将数据分配给它本身,所以不应该失去任何内容。


11

我正在寻找一种解决方案,可以在对象声明中使用动态键名(而不使用 ES6 特性,如 ...[key]: value)。

以下是我想出的方法:

var obj = (obj = {}, obj[field] = 123, obj)

一开始看起来有点复杂,但实际上很简单。我们使用逗号操作符来依次执行三个命令:

  1. obj = {}:创建一个新对象并将其分配给变量obj
  2. obj[field] = 123:向obj添加一个计算属性名称
  3. obj:将obj变量用作括号/逗号列表的结果

这种语法可以在函数参数中使用,而不需要显式声明obj变量:

// The test function to see the result.
function showObject(obj) {
    console.log(obj);
}

// My dynamic field name.
var field = "myDynamicField";

// Call the function with our dynamic object.
showObject( (obj = {}, obj[field] = 123, obj) );

/*
Output:

{
  "myDynamicField": true
}
*/

一些变化

"strict mode" 的解决方法:

上述代码在 strict mode 下无法工作,因为变量 "obj" 没有声明。

// This gives the same result, but declares the global variable `this.obj`!
showObject( (this.obj = {}, obj[field] = 123, obj) );

使用计算属性名初始化器的ES2015代码:

// Works in most browsers, same result as the other functions.
showObject( {[field] = 123} );

这种解决方案适用于所有现代浏览器(但如果需要提及,不适用于IE)

使用JSON.parse()的超级hacky方法:

// Create a JSON string that is parsed instantly. Not recommended in most cases.
showObject( JSON.parse( '{"' + field +'":123}') );
// read: showObject( JSON.parse( '{"myDynamicfield":123}') );

允许在键中使用特殊字符

请注意,您还可以在计算属性名称(以及JSON.parse中)使用空格和其他特殊字符。

var field = 'my dynamic field :)';
showObject( {[field] = 123} );
// result: { "my dynamic field :)": 123 }

这些字段不能使用点访问(obj.my dynamic field :)明显在语法上无效),但只能通过括号表示法访问,即 obj['my dynamic field :)']返回 123


7
最简单和最便携的方法是。
var varFieldName = "good";
var ob = {};
Object.defineProperty(ob, varFieldName , { value: "Fresh Value" });

根据 #abeing 的回答!


5

在使用(点)方法向现有对象添加属性时要小心。

如果您事先 知道 'key' ,则应仅使用(点)方法将属性添加到对象中,否则请使用[括号]方法。

例如:

   var data = {
        'Property1': 1
    };
    
    // Two methods of adding a new property [ key (Property4), value (4) ] to the
    // existing object (data)
    data['Property2'] = 2; // bracket method
    data.Property3 = 3;    // dot method
    console.log(data);     // { Property1: 1, Property2: 2, Property3: 3 }
    
    // But if 'key' of a property is unknown and will be found / calculated
    // dynamically then use only [bracket] method not a dot method    
    var key;
    for(var i = 4; i < 6; ++i) {
     key = 'Property' + i;     // Key - dynamically calculated
     data[key] = i; // CORRECT !!!!
    }
    console.log(data); 
    // { Property1: 1, Property2: 2, Property3: 3, Property4: 4, Property5: 5 }
    
    for(var i = 6; i < 2000; ++i) {
     key = 'Property' + i; // Key - dynamically calculated
     data.key = i;         // WRONG !!!!!
    }
    console.log(data); 
    // { Property1: 1, Property2: 2, Property3: 3, 
    //   Property4: 4, Property5: 5, key: 1999 }

请注意控制台日志末尾的问题 - 键为'key: 1999',而不是Property6: 6, Property7: 7,.........,Property1999: 1999。因此,使用[方括号]方法添加动态创建的属性是最佳方式。

4
一种访问包含对象的动态字符串名称(例如object.subobject.property)的简便方法:
function ReadValue(varname)
{
    var v=varname.split(".");
    var o=window;
    if(!v.length)
        return undefined;
    for(var i=0;i<v.length-1;i++)
        o=o[v[i]];
    return o[v[v.length-1]];
}

function AssignValue(varname,value)
{
    var v=varname.split(".");
    var o=window;
    if(!v.length)
        return;
    for(var i=0;i<v.length-1;i++)
        o=o[v[i]];
    o[v[v.length-1]]=value;
}

例子:

ReadValue("object.subobject.property");
WriteValue("object.subobject.property",5);

eval函数可以用于读取值,但是写入值则比较困难。

更高级的版本(如果子类不存在,则创建子类,并允许使用对象代替全局变量)

function ReadValue(varname,o=window)
{
    if(typeof(varname)==="undefined" || typeof(o)==="undefined" || o===null)
        return undefined;
    var v=varname.split(".");
    if(!v.length)
        return undefined;
    for(var i=0;i<v.length-1;i++)
    {
        if(o[v[i]]===null || typeof(o[v[i]])==="undefined") 
            o[v[i]]={};
        o=o[v[i]];
    }
    if(typeof(o[v[v.length-1]])==="undefined")    
        return undefined;
    else    
        return o[v[v.length-1]];
}

function AssignValue(varname,value,o=window)
{
    if(typeof(varname)==="undefined" || typeof(o)==="undefined" || o===null)
        return;
    var v=varname.split(".");
    if(!v.length)
        return;
    for(var i=0;i<v.length-1;i++)
    {
        if(o[v[i]]===null || typeof(o[v[i]])==="undefined")
            o[v[i]]={};
        o=o[v[i]];
    }
    o[v[v.length-1]]=value;
}

例子:

ReadValue("object.subobject.property",o);
WriteValue("object.subobject.property",5,o);

这与 o.object.subobject.property 一样


1
非常好,这对于React的this.setState({dynamic property: value})非常有用。谢谢! - Kevin Danikowski

2
这是我解决问题的方法。
var obj = {

};
var field = "someouter.someinner.someValue";
var value = 123;

function _addField( obj, field, value )
{
    // split the field into tokens
    var tokens = field.split( '.' );

    // if there's more than one token, this field is an object
    if( tokens.length > 1 )
    {
        var subObj = tokens[0];

        // define the object
        if( obj[ subObj ] !== undefined ) obj[ subObj ] = {};

        // call addfield again on the embedded object
        var firstDot = field.indexOf( '.' );
        _addField( obj[ subObj ], field.substr( firstDot + 1 ), value );

    }
    else
    {
        // no embedded objects, just field assignment
        obj[ field ] = value;
    }
}

_addField( obj, field, value );
_addField(obj, 'simpleString', 'string');

console.log( JSON.stringify( obj, null, 2 ) );

生成以下对象:
{
  "someouter": {
    "someinner": {
      "someValue": 123
    }
  },
  "simpleString": "string"
}

2
你可以像这样做:
let myObj = {
  propertyA: 1,
  propertyB: 2,
  propertyC: 3,
}

// Declaring val here, could get from the user
let val = 'D';
myObj = {...myObj, [`property${val}`]: 4}

2
是的,这是可能的。我已经使用以下实现方式实现了。因此,我在响应中获得了一个数组,我希望它作为属性列表在对象中。
response = {
  "equityMonths": [
    {
      "id": 1,
      "month": "JANUARY",
      "isEligible": false
    },
    {
      "id": 2,
      "month": "FEBRUARY",
      "isEligible": true
    },
    {
      "id": 3,
      "month": "MARCH",
      "isEligible": false
    },
    {
      "id": 4,
      "month": "APRIL",
      "isEligible": true
    },
    {
      "id": 5,
      "month": "MAY",
      "isEligible": false
    },
    {
      "id": 6,
      "month": "JUNE",
      "isEligible": true
    },
    {
      "id": 7,
      "month": "JULY",
      "isEligible": true
    },
    {
      "id": 8,
      "month": "AUGUST",
      "isEligible": false
    },
    {
      "id": 9,
      "month": "SEPTEMBER",
      "isEligible": true
    },
    {
      "id": 10,
      "month": "OCTOBER",
      "isEligible": false
    },
    {
      "id": 11,
      "month": "NOVEMBER",
      "isEligible": true
    },
    {
      "id": 12,
      "month": "DECEMBER",
      "isEligible": false
    }
  ]
}

这里,我希望equityMonths作为一个对象出现,其键为一月到十二月,值为isEligible。为此,我们需要使用Object类的defineProperty()方法,该方法允许向对象添加动态属性。 添加动态属性到对象的代码:
let equityMonth = new Object();

response.equityMonths.forEach(element => {
    Object.defineProperty(equityMonth, element['month'], {
       value: element['isEligible'],
       writable: true,
       enumerable: true,
       configurable: true
    });
});
console.log("DATA : " + JSON.stringify(equityMonth));

在上面的代码中,我们有一个equityMonths数组,我们已将其转换为对象属性。
输出:
DATA : {"JANUARY":false,"FEBRUARY":true,"MARCH":false,"APRIL":true,"MAY":false,"JUNE":true,"JULY":true,"AUGUST":false,"SEPTEMBER":true,"OCTOBER":false,"NOVEMBER":true,"DECEMBER":false}

1

向JS对象动态添加数据的最简单方法。

 // Create an object
 const data = {};
     
 // Add properties to it with a key and value
 data['key'] = value;

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