Чи можна додати властивості, що динамічно називають, до об’єкта JavaScript?


745

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

Відповіді:


1211

Так.

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 має знати назву властивості, яка недостатньо динамічна.
Георг Шоллі,

6
+1, тому що це мені допомогло. Але я не розумію, чому властивості об'єкта обробляються як масив.
Рон ван дер Хайден

9
@Bondye: Це частина дивного дизайну JavaScript. У цьому випадку object["property"]не зовсім так array[4], як колишній не був створений як справжній масив.
Георг Шоллі

5
Це лише я чи цей пост не відповідає на питання, отримуючи 195 оновлень? Я подумав, що задає питання, як визначити властивості, де ім'я невідоме, поки воно не згенерується в коді JavaScript.
Qantas 94 Важка

20
@Qantas: Скажімо, він не відповідає на це безпосередньо. Але перехід від data["PropertyD"]до data[function_to_get_property_name()]здається банальним.
Георг Шоллі

154

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
}

Це використовує новий синтаксис обчисленої властивості та літерали шаблону .


1
Це те, що мені було потрібно в тому випадку, коли я хотів, щоб мій код був повністю функціональним (як, наприклад, у жодних імперативних твердженнях obj[propname]). Натомість мені вдалося використати це з синтаксисом розповсюдження об'єктів.
intcreator

2
Не відразу зрозуміло, що робить цей фрагмент коду тому, хто не бачив і не зрозумів нового синтаксису. Я б запропонував редагувати, щоб відобразити вихідні / очікувані властивості з const 'a'.

Особисто я вважаю, що шлях ES5 набагато чистіший і простіший для розуміння:var a = {}; a["dynamic-" + prop] = true;
Джек Гіффін

1
@JackGiffin в деяких випадках так, але при роботі з незмінними структурами цей синтаксис може бути дуже зручним, оскільки підхід, який ви показали, мутує a. (Особливо при використанні таких пакетів, як редукс)
Маурісіо Соарес

3
Це просто чудово {... стан, [опора]: val}
Xipo

87

Так, це можливо. Припустимо:

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

40
Використовувати eval дійсно небезпечно.
Георг Шоллі

10
Не кажучи вже про повільне.
Еймон Нербонна

@ GeorgSchölly True.
Obinna Nwakwue

1
Примітка (якщо хтось стикається з тією ж проблемою, що і я): Для звичайних об'єктів це працює чудово. Але мені довелося додати деяку властивість до об’єкту інтерфейсу jQuery, щоб відслідковувати список елементів. У цьому випадку властивість втрачається, якщо її додавати таким чином, оскільки jQuery завжди створює копію. Тут вам потрібно використовувати jQuery.extend () .
Метт

Мені подобається додати до свого попереднього коментаря - навіть це не спрацювало в моєму випадку. Тож я в кінцевому підсумку скористався параметром $("#mySelector").data("propertyname", myvalue);set і var myValue=$("#mySelector").data("propertyname");повернув значення. Навіть складні об'єкти (списки, масиви ...) можна додати таким чином.
Метт

61

Я знаю, що на питання відповіли чудово, але я також знайшов інший спосіб додати нові властивості і хотів поділитися ним із вами:

Ви можете використовувати функцію 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

4
Плюси і мінуси цього методу?
Тревор

6
@Trevor: загальна налаштованість та можливість додавання геттерів та сетерів; також можливість додавання декількох властивостей одночасно за допомогою defineProperties(множини).
rvighne

@Thielicious Object.definePropertyне призначений для легкого інструменту зручності, а той, який має дрібнозернистий контроль. Якщо вам не потрібен додатковий контроль, це не правильний вибір інструменту.
kleinfreund

Object.defineProperty(obj, prop, valueDescriptor)набагато повільніше та складніше для V8 оптимізувати, ніж просто робити obj[prop] = value;
Джек Гіффін

27

ES6 представляє обчислені імена властивостей, які дозволяють вам робити

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

23

Тут, використовуючи позначення:

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

Ви можете додати ще стільки властивостей, скільки вам подобається, просто використовуючи позначення крапок:

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

або :

data[newattribute] = somevalue

для динамічних клавіш.


4
якщо ім’я властивостей не визначено до часу запуску "- так що це не буде працювати, якщо ви не використовуєте eval, що не є хорошим варіантом
Marc Gravell

1
або скористайтеся синтаксисом [] ... дані [somevar] = деяке значення
Габріель Херлі,

17

на додаток до всіх попередніх відповідей, і якщо вам цікаво, як ми будемо в майбутньому писати імена динамічних властивостей, використовуючи обчислені імена властивостей (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 - Ніколас Закас


11

Лише доповнення до відповіді на відмову вище. Ви можете визначити функцію, щоб інкапсулювати складність параметра DefPP, як зазначено нижче.

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/#constructorpatternja JavaScript


9

Ви можете додавати властивості динамічно, використовуючи деякі з наведених нижче варіантів:

У вашому прикладі:

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

Можна визначити властивість з динамічним значенням наступними двома способами:

data.key = value;

або

data['key'] = value;

Ще більше ... якщо ваш ключ також динамічний, ви можете визначитись за допомогою класу Object за допомогою:

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

де дані - ваш об’єкт, ключ - це змінна для зберігання імені ключа, а значення - змінна для зберігання значення.

Я сподіваюся, що це допомагає!


8

Я знаю, що на цю публікацію вже є кілька відповідей, але я не бачив жодної, де є декілька властивостей, і вони знаходяться в масиві. І це рішення, до речі, для 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"}]

Ви фактично не додаєте властивості до об'єкта, ви створюєте новий об’єкт із властивостями старого об'єкта (через оператор розповсюдження) та нові реквізити.
Ед Орсі

3
Ви маєте рацію на те, що це мало бути Person = Person.map(code here). Але справа в тому, що ви можете легко додати властивість до вже існуючого об'єкта ES6.
Едпер

5

Найпростіший і портативний спосіб.

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

На основі відповіді #abeing!


3

Будьте обережні , додаючи властивість до існуючого об'єкта методом . (Крапка) .

(.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" замість Properties6: 6, Properties7: 7, ........., Properties1999: 1999 . Тож найкращим способом додавання динамічно створеної властивості є метод [дужка].


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


1
саме те, що я шукав, це корисно для реакції на this.setState ({динамичне властивість: значення}) дякую!
Кевін Даниковський

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

0

Це може бути корисно, якщо змішане нове властивість додати під час виконання:

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

Однак оператор розповсюдження використовує дрібну копію, але тут ми присвоюємо дані собі, тому нічого не втрачаємо


-2

Ідеальний простий спосіб

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

-14

Безумовно. Подумайте про це як словник або асоціативний масив. Ви можете додати його в будь-який момент.


1
Просто сказати, що це не допоможе.
Obinna Nwakwue
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.