É possível adicionar propriedades nomeadas dinamicamente ao objeto JavaScript?


746

Em JavaScript, eu criei um objeto assim:

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

É possível adicionar mais propriedades a esse objeto após sua criação inicial, se o nome da propriedade não for determinado até o tempo de execução? ie

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

Respostas:


1212

Sim.

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 precisa saber o nome da propriedade, que não é suficientemente dinâmico.
Georg Schölly 26/07/2009

6
+1 porque isso me ajudou. Mas não entendo por que as propriedades de um objeto são tratadas como uma matriz.
Ron van der Heijden

9
@ Bondye: Isso faz parte do design estranho do javascript. Nesse caso, object["property"]não é exatamente o mesmo que array[4], o primeiro não foi criado como uma matriz verdadeira.
Georg Schölly 5/03

5
Sou apenas eu ou este post não responde à pergunta enquanto obtém 195 votos positivos? Eu pensei que estava perguntando como definir propriedades onde o nome é desconhecido até que seja gerado no código JavaScript.
Qantas 94 Heavy

20
@Qantas: Digamos que não responda diretamente. Mas passar de data["PropertyD"]para data[function_to_get_property_name()]parece trivial.
Georg Schölly

154

ES6 para a vitória!

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

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

Se você fizer logon, dataobtém o seguinte:

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

Isso faz uso da nova sintaxe da propriedade computada e dos literais do modelo .


1
Era disso que eu precisava no caso em que queria que meu código fosse completamente funcional (como em nenhuma declaração imperativa obj[propname]). Em vez disso, eu era capaz de usar isso com sintaxe de propagação de objeto.
Intcreator

2
Não é imediatamente óbvio o que esse trecho de código está fazendo com alguém que não viu ou compreendeu a nova sintaxe. Eu sugeriria uma edição para exibir as propriedades de saída / esperadas com a const 'a'.

Pessoalmente, acho que o caminho ES5 é muito mais limpo e mais fácil de entender:var a = {}; a["dynamic-" + prop] = true;
Jack Giffin

1
@JackGiffin em alguns casos, sim, mas ao trabalhar com estruturas imutáveis, essa sintaxe pode ser muito útil, pois a abordagem que você mostrou está mudando a. (Especialmente quando utilizar pacotes como redux)
Mauricio Soares

3
Isso é ótimo {... state, [prop]: val}
Xipo 23/08/18

87

Sim, é possível. Assumindo:

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

Ou:

data[propertyName] = propertyValue;

ou

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

O primeiro método é preferido. eval () tem as óbvias preocupações de segurança se você estiver usando valores fornecidos pelo usuário, portanto, não o utilize se puder evitá-lo, mas vale a pena saber que ele existe e o que ele pode fazer.

Você pode fazer referência a isso com:

alert(data.someProperty);

ou

data(data["someProperty"]);

ou

alert(data[propertyName]);

40
Usar eval é realmente perigoso.
Georg Schölly 26/07/2009

10
Sem mencionar lento.
Eamon Nerbonne

@ GeorgSchölly True.
Obinna Nwakwue 28/08

1
Nota (caso alguém tenha o mesmo problema que eu): para objetos normais, isso funciona bem. Mas eu tive que adicionar alguma propriedade a um objeto de UI do jQuery para acompanhar uma lista de itens. Nesse caso, a propriedade foi perdida se adicionada desta maneira porque o jQuery sempre cria uma cópia. Aqui você precisa usar jQuery.extend () .
Matt

Eu gosto de adicionar ao meu comentário anterior - mesmo que não tenha funcionado no meu caso. Então acabei usando o $("#mySelector").data("propertyname", myvalue);para definir e var myValue=$("#mySelector").data("propertyname");recuperar o valor. Mesmo objetos complexos (listas, matrizes ...) podem ser adicionados dessa maneira.
Matt

61

Sei que a pergunta foi respondida perfeitamente, mas também encontrei outra maneira de adicionar novas propriedades e queria compartilhá-la com você:

Você pode usar a função Object.defineProperty()

Encontrado na Mozilla Developer Network

Exemplo:

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
Prós e contras deste método?
Trevor

6
@Trevor: configurabilidade total e capacidade de adicionar getters e setters; também, capacidade de adicionar várias propriedades de uma só vez com defineProperties(plural).
precisa saber é o seguinte

O @Thielicious Object.definePropertynão deve ser a ferramenta de conveniência fácil, mas a ferramenta com controle refinado. Se você não precisar desse controle adicional, não é a ferramenta certa para escolher.
kleinfreund 6/09/17

Object.defineProperty(obj, prop, valueDescriptor)é muito mais lento e difícil para o V8 otimizar do que simplesmente obj[prop] = value;
Jack Giffin

27

O ES6 apresenta nomes de propriedades computados, que permitem fazer

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

23

Aqui, usando sua notação:

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

Você pode adicionar quantas propriedades quiser, simplesmente usando a notação de ponto:

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

ou :

data[newattribute] = somevalue

para chaves dinâmicas.


4
se o nome de propriedades não é determinado até que tempo de execução" - de modo que não vai funcionar a menos que você usar eval, que não é uma boa opção
Marc Gravell

1
ou usar o [] sintaxe ... Dados [somevar] = somevalue
Gabriel Hurley

17

além de todas as respostas anteriores, e caso você esteja se perguntando como escreveremos nomes de propriedades dinâmicas no futuro usando nomes de propriedades computadas (ECMAScript 6), veja como:

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

personIndex[ personId ]; // "John Doe"

Referência: Compreendendo o ECMAScript 6 - Nickolas Zakas


11

Apenas uma adição à resposta da abeing acima. Você pode definir uma função para encapsular a complexidade de defineProperty, conforme mencionado abaixo.

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

referência: http://addyosmani.com/resources/essentialjsdesignpatterns/book/#constructorpatternjavascript


9

Você pode adicionar propriedades dinamicamente usando algumas das opções abaixo:

No seu exemplo:

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

Você pode definir uma propriedade com um valor dinâmico das próximas duas maneiras:

data.key = value;

ou

data['key'] = value;

Ainda mais ... se sua chave também for dinâmica, você poderá definir usando a classe Object com:

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

onde data é seu objeto, key é a variável para armazenar o nome da chave e value é a variável para armazenar o valor.

Eu espero que isso ajude!


8

Eu sei que já existem várias respostas para este post, mas ainda não vi uma em que haja várias propriedades e elas estejam dentro de uma matriz. E esta solução, a propósito, é para ES6.

Para ilustração, digamos que temos uma matriz chamada pessoa com objetos dentro:

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

Portanto, você pode adicionar uma propriedade com o valor correspondente. Digamos que queremos adicionar um idioma com o valor padrão EN .

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

A matriz Person agora se tornaria assim:

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

Na verdade, você não está adicionando propriedades a um objeto, está criando um novo objeto com as propriedades do objeto antigo (via operador de propagação) e os novos adereços também.
Ed Orsi

3
Você está certo sobre o que deveria ter sido Person = Person.map(code here). Mas o ponto é que você pode adicionar propriedades facilmente a um objeto existente ES6.
Edper

5

A maneira mais simples e mais portátil é.

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

Com base na resposta #abeing!


3

Tenha cuidado ao adicionar uma propriedade ao objeto existente usando o método . (Ponto) .

O método (.dot) de adicionar uma propriedade ao objeto só deve ser usado se você conhecer a 'chave' anteriormente, caso contrário, use o método [bracket] .

Exemplo:

   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 }

Observe o problema no final do log do console - 'chave: 1999' em vez de Propriedade6: 6, Propriedade7: 7, ........., Propriedade1999: 1999 . Portanto, a melhor maneira de adicionar propriedades criadas dinamicamente é o método [bracket].


1

Uma ótima maneira de acessar nomes dinâmicos de cadeias que contêm objetos (por exemplo, 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;
}

Exemplo:

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

eval funciona com valor de leitura, mas o valor de gravação é um pouco mais difícil.

Uma versão mais avançada (crie subclasses se elas não existirem e permita objetos em vez de variáveis ​​globais)

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

Exemplo:

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

É o mesmo que o.object.subobject.property


1
exatamente o que eu estava procurando, isso é útil para reagir a this.setState ({dynamic property: value}) obrigado!
Kevin Danikowski

0

Aqui está como eu resolvi o 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 ) );

Gera o seguinte objeto:

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

0

Pode ser útil se uma nova propriedade mista for adicionada no tempo de execução:

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

No entanto, o operador de propagação usa cópia superficial, mas aqui atribuímos dados a si mesmo, para que não perca nada


-2

Uma maneira fácil e perfeita

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

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

console.log(data);

Se você deseja aplicá-lo em uma matriz de dados (versão 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

Definitivamente. Pense nisso como um dicionário ou matriz associativa. Você pode adicionar a qualquer momento.


1
Apenas dizendo que não vai ajudar.
Obinna Nwakwue 28/08
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.