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

时间:2009-07-26 09:24:39

标签: javascript

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

20 个答案:

答案 0 :(得分:1067)

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

data["PropertyD"] = 4;

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

答案 1 :(得分:104)

获胜的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
}

这使用了新的Computed Property语法和Template Literals

答案 2 :(得分:81)

是的,这是可能的。假设:

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]);

答案 3 :(得分:53)

我知道这个问题得到了很好的回答,但我也找到了另一种方法来添加新属性,并希望与您分享:

您可以使用Object.defineProperty()

功能

Mozilla Developer Network

上找到

示例:

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 :(得分:20)

在这里,使用您的符号:

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'

答案 5 :(得分:17)

除了之前的所有答案,如果您想知道我们将如何使用计算属性名称(ECMAScript 6)在 Future 中编写动态属性名称,请按以下步骤操作:

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

personIndex[ personId ]; // "John Doe"

参考:Understanding ECMAScript 6 - Nickolas Zakas

答案 6 :(得分:16)

您只需使用点符号即可添加更多属性:

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

data[newattribute] = somevalue

用于动态键。

答案 7 :(得分:11)

只是上述abeing答案的补充。您可以定义一个函数来封装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

答案 8 :(得分:7)

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

在你的例子中:

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

您可以在接下来的两种方式中定义具有动态值的属性:

data.key = value;

data['key'] = value;

更多..如果您的密钥也是动态的,您可以使用Object类定义:

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

数据 是您的对象, 密钥 是存储密钥名称的变量, value 是存储值的变量。

我希望这有帮助!

答案 9 :(得分:5)

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

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

=DCount("*", "Query1")
=DCount("*", "Query2")
=DCount("*", "Query3")

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

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

Person 数组现在会变成这样:

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

答案 10 :(得分:4)

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

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

基于#abeing的答案!

答案 11 :(得分: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

相同

答案 12 :(得分:1)

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

(。dot)向对象添加属性的方法仅在您知道 “键” 时使用,否则请使用 [括号] 方法。

示例:

   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 }

请注意控制台日志末尾的问题- “键:1999” ,而不是属性6:6,属性7:7,.........,属性1999:1999 。因此,添加动态创建的属性的最佳方法是[bracket]方法。

答案 13 :(得分:1)

ES6引入了计算所得的属性名称,您可以这样做

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

答案 14 :(得分:1)

我一直在寻找一种解决方案,可以在对象声明中使用动态键名(不使用...[key]: value之类的ES6功能)

这是我想出的:

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

乍一看似乎有点复杂,但这确实很简单。我们使用逗号运算符连续运行三个命令:

  1. obj = {}:创建一个新对象并将其分配给变量obj
  2. obj[field] = 123:将computed property name添加到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中不起作用,因为未声明变量“ 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} );

此解决方案可在all modern browsers中使用(但如果需要说明,则不能在IE中使用)

使用JSON.parse()的超级黑客方式:

// 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

答案 15 :(得分: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"
}

答案 16 :(得分:0)

一种完美的简便方法

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);

答案 17 :(得分:0)

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

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

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

答案 18 :(得分:0)

是的,有可能。我已经实现了使用下面的实现。为此,我得到一个响应数组,我想要一个对象作为属性列表。

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作为对象,并将Jan到Dec用作键,并将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}

答案 19 :(得分:-10)

当然。可以将其视为字典或关联数组。你可以随时添加它。