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


745

在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?

Answers:


1209

是。

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};

data["PropertyD"] = 4;

// dialog box with 4 in it
alert(data.PropertyD);
alert(data["PropertyD"]);


142
@thedz:data.PropertyD需要知道属性名称,该名称不够动态。
乔治·Schölly

6
+1,因为这对我有所帮助。但是我不明白为什么对象属性像数组那样处理。
罗恩·范·德·海登

9
@Bondye:那是javascript奇怪设计的一部分。在这种情况下,object["property"]与并不完全相同array[4],前者不是作为真正的数组创建的。
GeorgSchölly2013年

5
是我还是该帖子在获得195票支持时没有回答问题?我以为这是在询问如何在JavaScript代码中生成未知名称之前定义属性的问题。
澳洲航空94重型

20
@Qantas:假设它没有直接回答。但是从data["PropertyD"]data[function_to_get_property_name()]似乎微不足道。
GeorgSchölly2014年

154

ES6为赢!

const b = 'b';
const c = 'c';

const data = {
    a: true,
    [b]: true, // dynamic property
    [`interpolated-${c}`]: true, // dynamic property + interpolation
    [`${b}-${c}`]: true
}

如果您登录,data则会得到以下信息:

{
  a: true,
  b: true,
  interpolated-c: true,
  b-c: true
}

这利用了新的“ 计算属性”语法和“ 模板文字”


1
在我希望我的代码能够完全正常运行的情况下,这就是我所需要的(例如,没有强制性声明说obj[propname])。相反,我可以将其与对象传播语法一起使用。
intcreator

2
尚不清楚此代码片段对尚未看到或理解新语法的人正在做什么。我建议进行编辑以显示带有'a'常量的输出/预期属性。

就我个人而言,我认为ES5的方式更加var a = {}; a["dynamic-" + prop] = true;
简洁

1
@JackGiffin在某些情况下是的,但是在使用不可变结构时,此语法非常方便,因为您显示的方法是mutating a。(特别是在使用像redux这样的软件包时)
Mauricio Soares

3
这真是太好了{... state,[prop]:val}
Xipo

87

是的,有可能。假设:

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};
var propertyName = "someProperty";
var propertyValue = "someValue";

要么:

data[propertyName] = propertyValue;

要么

eval("data." + propertyName + " = '" + propertyValue + "'");

第一种方法是首选。如果您使用的是用户提供的值,则eval()具有明显的安全性问题,因此,如果可以避免使用它,则不要使用它,但是值得知道它的存在以及它可以做什么。

您可以参考以下内容:

alert(data.someProperty);

要么

data(data["someProperty"]);

要么

alert(data[propertyName]);

40
使用eval确实很危险。
乔治·Schölly

10
更不用说慢了。
Eamon Nerbonne 09年

@GeorgSchölly对。
Obinna Nwakwue

1
注意(以防有人遇到与我相同的问题):对于普通对象,此方法工作正常。但是我必须向jQuery UI对象添加一些属性以跟踪项目列表。在这种情况下,如果以这种方式添加属性,则该属性会丢失,因为jQuery始终会创建一个副本。在这里,您需要使用jQuery.extend()
马特

我想补充一下以前的评论-即使在我的情况下也无效。因此,我最终使用$("#mySelector").data("propertyname", myvalue);进行设置,并var myValue=$("#mySelector").data("propertyname");取回值。甚至可以通过这种方式添加复杂的对象(列表,数组等)。
马特

61

我知道问题已得到完美解答,但我还找到了另一种添加新属性的方法,并希望与您分享:

您可以使用该功能 Object.defineProperty()

Mozilla开发人员网络上找到

例:

var o = {}; // Creates a new object

// Example of an object property added with defineProperty with a data property descriptor
Object.defineProperty(o, "a", {value : 37,
                               writable : true,
                               enumerable : true,
                               configurable : true});
// 'a' property exists in the o object and its value is 37

// Example of an object property added with defineProperty with an accessor property descriptor
var bValue;
Object.defineProperty(o, "b", {get : function(){ return bValue; },
                               set : function(newValue){ bValue = newValue; },
                               enumerable : true,
                               configurable : true});
o.b = 38;
// 'b' property exists in the o object and its value is 38
// The value of o.b is now always identical to bValue, unless o.b is redefined

// You cannot try to mix both :
Object.defineProperty(o, "conflict", { value: 0x9f91102, 
                                       get: function() { return 0xdeadbeef; } });
// throws a TypeError: value appears only in data descriptors, get appears only in accessor descriptors

4
这种方法的优缺点?
Trevor

6
@Trevor:总体可配置性以及添加getter和setter的能力;此外,还可以使用defineProperties(多个)一次添加多个属性。
rvighne 2014年

@Thielicious Object.defineProperty并不是简单易用的工具,而是具有细粒度控制的工具。如果您不需要该其他控件,则不是正确的选择工具。
kleinfreund

Object.defineProperty(obj, prop, valueDescriptor)V8的优化比简单进行的慢和困难obj[prop] = value;
杰克·吉芬

27

ES6引入了计算属性名称,您可以使用它来执行

let a = 'key'
let myObj = {[a]: 10};
// output will be {key:10}

23

在这里,使用您的符号:

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?
data[propName] = 'Some New Property value'

18

只需使用点符号即可添加任意多的属性:

var data = {
    var1:'somevalue'
}
data.newAttribute = 'newvalue'

data[newattribute] = somevalue

用于动态键。


4
如果属性名称要等到运行时才能确定”-除非您使用eval,否则它将不起作用,这不是一个好选择
Marc Gravell

1
或使用[]语法... data [somevar] = somevalue
Gabriel Hurley

17

除了前面的所有答案之外,如果您想知道我们将来如何使用计算属性名(ECMAScript 6)编写动态属性名,请执行以下操作:

var person = "John Doe";
var personId = "person_" + new Date().getTime();
var personIndex = {
    [ personId ]: person
//  ^ computed property name
};

personIndex[ personId ]; // "John Doe"

参考:了解ECMAScript 6-Nickolas Zakas


11

只是上述安倍答案的补充。您可以定义一个函数来封装defineProperty的复杂性,如下所述。

var defineProp = function ( obj, key, value ){
  var config = {
    value: value,
    writable: true,
    enumerable: true,
    configurable: true
  };
  Object.defineProperty( obj, key, config );
};

//Call the method to add properties to any object
defineProp( data, "PropertyA",  1 );
defineProp( data, "PropertyB",  2 );
defineProp( data, "PropertyC",  3 );

参考:http : //addyosmani.com/resources/essentialjsdesignpatterns/book/#constructorpatternjavascript


9

您可以使用以下一些选项动态添加属性:

在您的示例中:

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};

您可以通过以下两种方式使用动态值定义属性:

data.key = value;

要么

data['key'] = value;

如果您的密钥也是动态的,则可以使用Object类定义以下内容:

Object.defineProperty(data, key, withValue(value));

其中data是您的对象,key是存储密钥名称的变量,value是存储值的变量。

我希望这有帮助!


8

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

为了举例说明,假设我们有一个名为person的数组,其中包含对象:

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

因此,您可以添加具有相应值的属性。假设我们要添加一种默认值为EN语言

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"}]

您实际上并没有向对象添加属性,而是使用旧对象的属性(通过传播运算符)以及新的props创建了一个新对象。
Ed Orsi

3
你是对的,应该是对的Person = Person.map(code here)。但关键是您可以使用轻松将属性添加到现有对象ES6
Edper '17

5

最简单,最便携的方法是。

var varFieldName = "good";
var ob = {};
Object.defineProperty(ob, varFieldName , { value: "Fresh Value" });

根据#abeing答案!


3

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

(.dot)向对象添加属性的方法仅应在事先知道'key'的情况下使用,否则请使用[bracket]方法。

例:

   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。因此,添加动态创建的属性的最佳方法是[bracket]方法。


1

一种从包含对象的动态字符串名称访问的好方法(例如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
正是我一直在寻找的东西,这对于响应this.setState({dynamic property:value})很有用!
凯文·丹尼科夫斯基'18

0

这是我解决问题的方法。

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"
}

0

如果在运行时添加了新属性,则可能很有用:

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

但是,散布运算符使用浅表复制,但此处我们将数据分配给自身,因此应该不会丢失任何数据


-2

完美的简便方法

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};

var newProperty = 'getThisFromUser';
data[newProperty] = 4;

console.log(data);

如果要将其应用于数据数组(ES6 / TS版)

const data = [
  { 'PropertyA': 1, 'PropertyB': 2, 'PropertyC': 3 },
  { 'PropertyA': 11, 'PropertyB': 22, 'PropertyC': 33 }
];

const newProperty = 'getThisFromUser';
data.map( (d) => d[newProperty] = 4 );

console.log(data);

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.