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

Lee*_*e D 695 javascript

在JavaScript中,我创建了一个像这样的对象:

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};
Run Code Online (Sandbox Code Playgroud)

如果在运行时之前未确定属性名称,是否可以在初始创建后为此对象添加更多属性?即

var propName = 'Property' + someUserInput
//imagine someUserInput was 'Z', how can I now add a 'PropertyZ' property to 
//my object?
Run Code Online (Sandbox Code Playgroud)

Geo*_*lly 1135

是.

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

data["PropertyD"] = 4;

// dialog box with 4 in it
alert(data.PropertyD);
alert(data["PropertyD"]);
Run Code Online (Sandbox Code Playgroud)

  • @thedz:data.PropertyD需要知道属性名称,这个名称不够动态. (135认同)
  • @Qantas:我们说它没有直接回答.但是从`data ["PropertyD"]`到`data [function_to_get_property_name()]`似乎是微不足道的. (16认同)
  • @Bondye:这是javascript奇怪设计的一部分.在这种情况下,`object ["property"]`与`array [4]`不完全相同,前者不是作为真正的数组创建的. (9认同)
  • +1因为这有助于我.但我不明白为什么对象属性像数组一样处理. (6认同)
  • 仅仅是我还是这篇文章在获得195票时却没有回答这个问题?我以为它是在询​​问如何定义名称未知的属性,直到它在JavaScript代码中生成为止. (2认同)
  • 我认为data [function_to_get_property_name()]可以清除问题,值得添加答案:D (2认同)

Mau*_*res 129

ES6获胜!

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

const data = {
    a: true,
    [b]: true, // dynamic property
    [`interpolated-${c}`]: true, // dynamic property + interpolation
    [`${b}-${c}`]: true
}
Run Code Online (Sandbox Code Playgroud)

如果你记录data你得到这个:

{
  a: true,
  b: true,
  interpolated-c: true,
  b-c: true
}
Run Code Online (Sandbox Code Playgroud)

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

  • 这非常好{... state,[prop]:val} (3认同)
  • 当我希望我的代码完全发挥作用时,这就是我所需要的(例如,没有命令性语句说“obj[propname]”)。相反,我能够将其与对象扩展语法一起使用。 (2认同)
  • 尚不清楚此代码片段对尚未看到或理解新语法的人正在做什么。我建议进行编辑以显示带有'a'常量的输出/预期属性。 (2认同)

cle*_*tus 82

对的,这是可能的.假设:

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};
var propertyName = "someProperty";
var propertyValue = "someValue";
Run Code Online (Sandbox Code Playgroud)

或者:

data[propertyName] = propertyValue;
Run Code Online (Sandbox Code Playgroud)

要么

eval("data." + propertyName + " = '" + propertyValue + "'");
Run Code Online (Sandbox Code Playgroud)

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

您可以参考:

alert(data.someProperty);
Run Code Online (Sandbox Code Playgroud)

要么

data(data["someProperty"]);
Run Code Online (Sandbox Code Playgroud)

要么

alert(data[propertyName]);
Run Code Online (Sandbox Code Playgroud)

  • 使用eval真的很危险. (38认同)
  • 更不用说慢了. (10认同)

art*_*ohe 57

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

你可以使用这个功能 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
Run Code Online (Sandbox Code Playgroud)

  • @Trevor:完全可配置性和添加getter和setter的能力; 另外,能够使用[`defineProperties`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties)(复数)一次添加多个属性. (5认同)
  • 这种方法的优缺点是什么? (4认同)

Max*_*yko 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'
Run Code Online (Sandbox Code Playgroud)


Ana*_*awa 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"
Run Code Online (Sandbox Code Playgroud)

参考:了解ECMAScript 6 - Nickolas Zakas


Gab*_*ley 16

您只需使用点表示法即可添加任意数量的属性:

var data = {
    var1:'somevalue'
}
data.newAttribute = 'newvalue'
Run Code Online (Sandbox Code Playgroud)

或者:

data[newattribute] = somevalue
Run Code Online (Sandbox Code Playgroud)

用于动态键.

  • 如果属性名称直到运行时才确定" - 那么除非你使用eval,否则这将不起作用,这不是一个好的选择 (3认同)

Rus*_*sty 13

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

let a = 'key'
let myObj = {[a]: 10};
// output will be {key:10}
Run Code Online (Sandbox Code Playgroud)


Sar*_*esh 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 );
Run Code Online (Sandbox Code Playgroud)

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


Fab*_*cio 7

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

在你的例子中:

var data = {
    'PropertyA': 1,
    'PropertyB': 2,
    'PropertyC': 3
};
Run Code Online (Sandbox Code Playgroud)

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

data.key = value;
Run Code Online (Sandbox Code Playgroud)

要么

data['key'] = value;
Run Code Online (Sandbox Code Playgroud)

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

Object.defineProperty(data, key, withValue(value));
Run Code Online (Sandbox Code Playgroud)

其中data是您的对象,key是存储键名的变量,value是存储值的变量.

我希望这有帮助!


Edp*_*per 7

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

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

 let Person = [{id:1, Name: "John"}, {id:2, Name: "Susan"}, {id:3, Name: "Jet"}]
Run Code Online (Sandbox Code Playgroud)

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

Person.map((obj)=>({...obj,['Language']:"EN"}))
Run Code Online (Sandbox Code Playgroud)

人士阵列现在会变成这个样子:

Person = [{id:1, Name: "John", Language:"EN"}, 
{id:2, Name: "Susan", Language:"EN"}, {id:3, Name: "Jet", Language:"EN"}]
Run Code Online (Sandbox Code Playgroud)

  • 您说对了,应该是“ Person = Person.map(此处为代码)”。但是关键是您可以使用ES6轻松地向现有对象添加属性。 (2认同)

Phi*_*ipp 7

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

这是我想出的:

var obj = (obj = {}, obj[field] = 123, obj)
Run Code Online (Sandbox Code Playgroud)

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

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

此语法可以在函数参数中使用,而无需显式声明obj变量:

var obj = (obj = {}, obj[field] = 123, obj)
Run Code Online (Sandbox Code Playgroud)

一些变化

“严格模式”解决方法:

上面的代码不起作用,strict mode因为没有声明变量“obj”。

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

在初始化程序中使用计算属性名称的ES2015代码:

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

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

超级hacky方式使用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}') );
Run Code Online (Sandbox Code Playgroud)

允许在键中使用特殊字符

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

var field = 'my dynamic field :)';
showObject( {[field] = 123} );
// result: { "my dynamic field :)": 123 }
Run Code Online (Sandbox Code Playgroud)

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


Syd*_*ell 6

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

var varFieldName = "good";
var ob = {};
Object.defineProperty(ob, varFieldName , { value: "Fresh Value" });
Run Code Online (Sandbox Code Playgroud)

基于#abeing 答案!


Sri*_*tha 5

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

仅当您事先知道“键时才应使用向对象添加属性的(.dot)方法,否则请使用[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 }
Run Code Online (Sandbox Code Playgroud)

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


Moh*_*sen 5

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

data = { ...data, newPropery: value}
Run Code Online (Sandbox Code Playgroud)

然而,spread 操作符使用浅拷贝,但这里我们将数据分配给自己,所以应该不会丢失任何东西