¿Es posible agregar propiedades con nombres dinámicos al objeto JavaScript?


746

En JavaScript, he creado un objeto así:

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

¿Es posible agregar más propiedades a este objeto después de su creación inicial si el nombre de las propiedades no se determina hasta el tiempo de ejecución? es decir

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

Respuestas:


1212

Si.

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 necesita saber el nombre de la propiedad, que no es lo suficientemente dinámico.
Georg Schölly

66
+1 porque esto me ayudó. Pero no entiendo por qué las propiedades de un objeto se manejan como una matriz.
Ron van der Heijden

99
@Bondye: Eso es parte del extraño diseño de javascript. En este caso object["property"]no es exactamente lo mismo array[4], el primero no se creó como una verdadera matriz.
Georg Schölly

55
¿Soy solo yo o esta publicación no responde la pregunta mientras recibo 195 votos a favor? Pensé que estaba preguntando cómo definir propiedades donde el nombre es desconocido hasta que se genera en el código JavaScript.
Qantas 94 Heavy

20
@Qantas: Digamos que no responde directamente. Pero pasar de data["PropertyD"]a data[function_to_get_property_name()]parece trivial.
Georg Schölly

154

ES6 por la victoria!

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

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

Si inicia sesión dataobtendrá esto:

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

Esto hace uso de la nueva sintaxis de Propiedad Computada y Literales de Plantilla .


1
Esto es lo que necesitaba en el caso en que quería que mi código fuera completamente funcional (como en, no hay declaraciones imperativas que digan obj[propname]). En cambio, pude usar esto con la sintaxis de propagación de objetos.
intcreator

2
No es inmediatamente obvio lo que este fragmento de código le está haciendo a alguien que no ha visto o comprendido la nueva sintaxis. Sugeriría una edición para mostrar las propiedades de salida / esperadas con la const 'a'.

Personalmente, creo que la forma ES5 es mucho más limpia y fácil de entender:var a = {}; a["dynamic-" + prop] = true;
Jack Giffin

1
@JackGiffin en algunos casos sí, pero cuando se trabaja con estructuras inmutables, esta sintaxis puede ser muy útil, ya que el enfoque que mostró es mutante a. (Especialmente cuando se usan paquetes como redux)
Mauricio Soares

3
Esto es genial {... state, [prop]: val}
Xipo

87

Sí, es posible. Asumiendo:

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

Ya sea:

data[propertyName] = propertyValue;

o

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

Se prefiere el primer método. eval () tiene las preocupaciones obvias de seguridad si está utilizando valores proporcionados por el usuario, así que no lo use si puede evitarlo, pero vale la pena saber que existe y qué puede hacer.

Puede hacer referencia a esto con:

alert(data.someProperty);

o

data(data["someProperty"]);

o

alert(data[propertyName]);

40
Usar eval es realmente peligroso.
Georg Schölly

10
Sin mencionar lento.
Eamon Nerbonne

@ GeorgSchölly Cierto.
Obinna Nwakwue

1
Nota (en caso de que alguien se encuentre con el mismo problema que yo): Para los objetos normales, esto funciona bien. Pero tuve que agregar alguna propiedad a un objeto jQuery UI para realizar un seguimiento de una lista de elementos. En ese caso, la propiedad se perdió si se agrega de esta manera porque jQuery siempre crea una copia. Aquí debe usar jQuery.extend () .
Matt

Me gusta agregar a mi comentario anterior, incluso eso no funcionó en mi caso. Así que terminé usando el $("#mySelector").data("propertyname", myvalue);para establecer y var myValue=$("#mySelector").data("propertyname");recuperar el valor. Incluso los objetos complejos (listas, matrices ...) se pueden agregar de esta manera.
Matt

61

Sé que la pregunta se responde perfectamente, pero también encontré otra forma de agregar nuevas propiedades y quería compartirla con ustedes:

Puedes usar la función Object.defineProperty()

Encontrado en la red de desarrolladores de Mozilla

Ejemplo:

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

44
Pros y contras de este método?
Trevor

66
@Trevor: Configurabilidad total y capacidad de agregar captadores y establecedores; también, capacidad de agregar múltiples propiedades a la vez con defineProperties(plural).
rvighne

@Thielicious Object.definePropertyno pretende ser la herramienta de conveniencia fácil, sino la que tiene el control preciso. Si no necesita ese control adicional, no es la herramienta adecuada para elegir.
kleinfreund

Object.defineProperty(obj, prop, valueDescriptor)es mucho más lento y más difícil de optimizar para V8 que simplemente hacerlo obj[prop] = value;
Jack Giffin

27

ES6 presenta nombres de propiedad calculados, que le permiten hacer

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

23

Aquí, usando tu notación:

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

Puede agregar tantas propiedades más como desee simplemente usando la notación de puntos:

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

o :

data[newattribute] = somevalue

para llaves dinámicas.


44
si el nombre de las propiedades no se determina hasta el tiempo de ejecución ", de modo que eso no funcionará a menos que use eval, que no es una buena opción
Marc Gravell

1
o use la sintaxis [] ... data [somevar] = somevalue
Gabriel Hurley

17

Además de todas las respuestas anteriores, y en caso de que se pregunte cómo vamos a escribir nombres de propiedades dinámicos en el futuro utilizando nombres de propiedades calculados (ECMAScript 6), aquí le mostramos cómo:

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

personIndex[ personId ]; // "John Doe"

referencia: Comprender ECMAScript 6 - Nickolas Zakas


11

Solo una adición a la respuesta anterior de abeing. Puede definir una función para encapsular la complejidad de defineProperty como se menciona a continuación.

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

referencia: http://addyosmani.com/resources/essentialjsdesignpatterns/book/#constructorpatternjavascript


9

Puede agregar propiedades dinámicamente utilizando algunas de las siguientes opciones:

En tu ejemplo:

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

Puede definir una propiedad con un valor dinámico de las siguientes dos formas:

data.key = value;

o

data['key'] = value;

Aún más ... si su clave también es dinámica, puede definirla usando la clase Object con:

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

donde los datos son su objeto, la clave es la variable para almacenar el nombre de la clave y el valor es la variable para almacenar el valor.

¡Espero que esto ayude!


8

Sé que ya hay varias respuestas a esta publicación, pero no he visto una en la que haya varias propiedades y estén dentro de una matriz. Y, por cierto, esta solución es para ES6.

Por ejemplo, supongamos que tenemos una matriz llamada persona con objetos dentro:

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

Por lo tanto, puede agregar una propiedad con el valor correspondiente. Digamos que queremos agregar un idioma con un valor predeterminado de EN .

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

La matriz de Persona ahora se volvería así:

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

En realidad, no está agregando propiedades a un objeto, está creando un nuevo objeto con las propiedades del objeto antiguo (a través del operador de propagación) y los nuevos accesorios también.
Ed Orsi

3
Tienes razón en que debería haber sido Person = Person.map(code here). Pero el punto es que puede agregar propiedades a un objeto existente fácilmente con ES6.
Edper

5

La forma más simple y portátil es.

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

Basado en la respuesta #abeing!


3

Tenga cuidado al agregar una propiedad al objeto existente utilizando el método. (Punto) .

(.dot) para agregar una propiedad al objeto solo debe usarse si conoce de antemano la 'clave'; de lo contrario, use el método [paréntesis] .

Ejemplo:

   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 }

Tenga en cuenta el problema al final del registro de la consola: 'clave: 1999' en lugar de Propiedad6: 6, Propiedad7: 7, ........., Propiedad1999: 1999 . Entonces, la mejor manera de agregar propiedades creadas dinámicamente es el método [corchete].


1

Una buena manera de acceder desde nombres de cadenas dinámicas que contienen objetos (por ejemplo, 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;
}

Ejemplo:

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

eval funciona para el valor de lectura, pero el valor de escritura es un poco más difícil.

Una versión más avanzada (crea subclases si no existen y permite objetos en lugar de variables globales)

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

Ejemplo:

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

Esto es lo mismo que o.object.subobject.property


1
exactamente lo que estaba buscando, esto es útil para reaccionar this.setState ({propiedad dinámica: valor}) ¡gracias!
Kevin Danikowski el

0

Así es como resolví el problema.

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

Genera el siguiente objeto:

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

0

Puede ser útil si la nueva propiedad mixta se agrega en tiempo de ejecución:

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

Sin embargo, el operador de propagación utiliza una copia superficial, pero aquí nos asignamos datos para que no pierda nada


-2

Una manera fácil y perfecta

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

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

console.log(data);

Si desea aplicarlo en una matriz de datos (versión 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);

-14

Seguro. Piense en ello como un diccionario o una matriz asociativa. Puedes agregarlo en cualquier momento.


1
Solo decir eso no ayudará.
Obinna Nwakwue
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.