是否可以向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?
949334 次浏览

是滴

var data = {'PropertyA': 1,'PropertyB': 2,'PropertyC': 3};
data["PropertyD"] = 4;
// dialog box with 4 in italert(data.PropertyD);alert(data["PropertyD"]);

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

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

要么:

data[propertyName] = propertyValue;

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

如果您使用的是用户提供的值,则有明显的安全问题,因此如果可以避免它,请不要使用它,但值得知道它的存在以及它可以做什么。

你可以参考这个:

alert(data.someProperty);

data(data["someProperty"]);

alert(data[propertyName]);

您可以添加尽可能多的属性,只要你喜欢使用点符号:

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

data[newattribute] = somevalue

对于动态键。

当然。把它想象成一个字典或关联数组。您可以随时添加到它。

在这里,使用您的符号:

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'

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

您可以使用函数Object.defineProperty()

找到Mozilla开发者网络

示例:

var o = {}; // Creates a new object
// Example of an object property added with defineProperty with a data property descriptorObject.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 descriptorvar 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

除了前面所有的答案之外,如果你想知道我们将如何使用计算属性名称(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

只是对上面阿宾答案的补充。您可以定义一个函数来封装下面提到的定义属性的复杂性。

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 objectdefineProp( data, "PropertyA",  1 );defineProp( data, "PropertyB",  2 );defineProp( data, "PropertyC",  3 );

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

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

在你的例子中:

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

您可以通过以下两种方式定义具有动态值的属性:

data.key = value;

data['key'] = value;

如果您的键也是动态的,您可以使用Object类定义:

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

其中数据是您的对象,key是存储键名的变量,是存储值的变量。

我希望这有帮助!

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}

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

最简单、最方便的方法是。

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

基于#abing答案!

我是这样解决这个问题的。

var obj = {
};var field = "someouter.someinner.someValue";var value = 123;
function _addField( obj, field, value ){// split the field into tokensvar tokens = field.split( '.' );
// if there's more than one token, this field is an objectif( tokens.length > 1 ){var subObj = tokens[0];
// define the objectif( obj[ subObj ] !== undefined ) obj[ subObj ] = {};
// call addfield again on the embedded objectvar firstDot = field.indexOf( '.' );_addField( obj[ subObj ], field.substr( firstDot + 1 ), value );
}else{// no embedded objects, just field assignmentobj[ field ] = value;}}
_addField( obj, field, value );_addField(obj, 'simpleString', 'string');
console.log( JSON.stringify( obj, null, 2 ) );

生成以下对象:

{"someouter": {"someinner": {"someValue": 123}},"simpleString": "string"}

从包含对象的动态字符串名称访问的好方法(例如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;elsereturn 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一样

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

为了说明这一点,假设我们有一个数组,名字叫人,里面有对象:

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

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

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

数组现在会变成这样:

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

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

(. 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 methoddata.Property3 = 3;    // dot methodconsole.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 methodvar key;for(var i = 4; i < 6; ++i) {key = 'Property' + i;     // Key - dynamically calculateddata[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 calculateddata.key = i;         // WRONG !!!!!}console.log(data);// { Property1: 1, Property2: 2, Property3: 3,//   Property4: 4, Property5: 5, key: 1999 }

注意控制台日志末尾的问题-'key: 1999'而不是物业6:6,物业7:7,……,物业1999:1999。所以添加动态创建的属性的最佳方法是[括号]方法。

一个完美简单的方法

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

ES6引入了计算属性名称,它允许您执行

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

如果在运行时添加混合新属性,它会很有用:

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

但是,传播运算符使用浅拷贝,但在这里我们将数据分配给自己,因此应该不会丢失任何东西

我一直在寻找一个解决方案,我可以在对象声明中使用动态键名(不使用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中不起作用,因为没有声明变量“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

是的,这是可能的。我已经使用下面的实现实现了。为此,我得到了数组作为响应,我希望在对象中作为属性列表。

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}