Подтвердить что ты не робот

Автоматически создавать объект, если undefined

Есть ли простой способ автоматически добавлять свойства к объектам, если они еще не существуют?

Рассмотрим следующий пример:

var test = {}
test.hello.world = "Hello doesn't exist!"

Это не работает, потому что hello не определен.

Причина, по которой я спрашиваю об этом, заключается в том, что у меня есть некоторые существующие объекты, для которых я не знаю, имеют ли они allready hello или нет. У меня на самом деле много таких объектов в разных частях моего кода. Очень раздражает всегда проверять, существует ли hello, и если он не создает новый объект, например:

var test = {}
if(test.hello === undefined) test.hello = {}
test.hello.world = "Hello World!"

Есть ли способ автоматического создания объекта, такого как hello в этом примере?

Я имею в виду что-то подобное в php:

$test = array();  
$test['hello']['world'] = "Hello world";   
var_dump($test);

Выход:

array(1) {
  ["hello"]=>
  array(1) {
    ["world"]=>
    string(11) "Hello world"
  }
}

Хорошо, это массив, но в массивах js это та же проблема, что и для объектов.

4b9b3361

Ответ 1

var test = {};
test.hello = test.hello || {};
test.hello.world = "Hello world!";

Если test.hello - undefined, он получает пустой объект.

Если ранее был определен test.hello, он остается неизменным.

var test = {
  hello : {
    foobar : "Hello foobar"
  }
};

test.hello = test.hello || {};
test.hello.world = "Hello World";

console.log(test.hello.foobar); // this is still defined;
console.log(test.hello.world); // as is this.

Ответ 2

Новый объект

myObj = {};

рекурсивная функция

function addProps(obj, arr, val) {

    if (typeof arr == 'string')
        arr = arr.split(".");

    obj[arr[0]] = obj[arr[0]] || {};

    var tmpObj = obj[arr[0]];

    if (arr.length > 1) {
        arr.shift();
        addProps(tmpObj, arr, val);
    }
    else
        obj[arr[0]] = val;

    return obj;

}

Назовите его с помощью нотной строки с точкой

addProps(myObj, 'sub1.sub2.propA', 1);

или с массивом

addProps(myObj, ['sub1', 'sub2', 'propA'], 1);

и ваш объект будет выглядеть следующим образом

myObj = {
  "sub1": {
    "sub2": {
      "propA": 1
    }
  }
};

Он также работает с непустыми объектами!

Ответ 3

Ну, вы можете расширить прототип Object с помощью функции, возвращающей свойство, но сначала добавляет ее, если она не существует:

Object.prototype.getOrCreate = function (prop) {
    if (this[prop] === undefined) {
        this[prop] = {};
    }
    return this[prop];
};

var obj = {};

obj.getOrCreate("foo").getOrCreate("bar").val = 1;

Ответ 4

Вы не сможете сделать это без какой-либо функции, так как JavaScript не имеет общего метода getter/setter для объектов (например, у Python есть __getattr__). Вот один из способов сделать это:

function add_property(object, key, value) {
    var keys = key.split('.');

    while (keys.length > 1) {
        var k = keys.shift();

        if (!object.hasOwnProperty(k)) {
            object[k] = {};
        }

        object = object[k];
    }

    object[keys[0]] = value;
}

Если вы действительно этого захотите, вы можете добавить его к прототипу Object. Вы можете вызвать его так:

> var o = {}
> add_property(o, 'foo.bar.baz', 12)
> o.foo.bar.baz
12

Ответ 5

Это добавит свойство hello, значение которого {world: 'Hello world!'} для тестового объекта, если оно не существует. Если у вас много таких объектов, вы можете просто перебрать их и применить эту функцию. Примечание: использует lodash.js

var test = {};
_.defaults(test, { hello: {world: 'Hello world!'} });    

На самом деле это удобный способ:

var defaults = _.partialRight(_.assign, function(a, b) {
  return typeof a == 'undefined' ? b : a;
});        
defaults(test, { hello: {world: 'Hello world!'} });

Примечание: _.defaults использует петли для достижения того же, что и второй блок.

P.S. Оформить заказ fooobar.com/questions/156013/...

Ответ 6

Вот классная версия с прокси:

const myUpsert = (input) => {
    const handler = {
        get: (obj, prop) => {
            obj[prop] = obj[prop] || {};
            return myUpsert(obj[prop]);
        }
    };
    return new Proxy(input, handler);
};

И вы используете это так:

myUpsert(test).hello.world = '42';

Это добавит все отсутствующие свойства как пустые объекты и оставит существующие нетронутыми. Это действительно просто прокси версия классического test.hello = test.hello || {} test.hello = test.hello || {}, хотя и намного медленнее (см. тест здесь.) Но на это также гораздо приятнее смотреть, особенно если вы будете делать это на глубине более одного уровня. Я бы не выбрал его для обработки данных с высокой производительностью, но он, вероятно, достаточно быстр для обновления внешнего интерфейса (как в Redux).

Обратите внимание, что здесь есть некоторые неявные предположения:

  1. Промежуточные свойства являются объектами или не существуют. Например, он захлебнется, если test.hello является строкой.
  2. То, что вы всегда хотите делать это до тех пор, пока вы используете прокси вместо исходного объекта.

Они довольно легко смягчаются, если вы используете его только в ограниченных контекстах (например, в корпусе редуктора), где существует небольшая вероятность случайного возврата Proxy, и не так много, что вы хотели бы сделать с объектом.

Ответ 7

var test = {}
if(!test.hasOwnProperty('hello')) {
    test.hello = {};
}
test.hello.world = "Hello World!"

Ответ 8

Я придумал что-то, действительно обычай, но он работает, насколько я тестировал.

function dotted_put_var(str,val) {
    var oper=str.split('.');
    var p=window;
    for (var i=0;i<oper.length-1;i++) {
        var x=oper[i];
        p[x]=p[x]||{};
        p=p[x];
    }
    p[oper.pop()]=val;
}

Затем сложная переменная может быть установлена ​​так, чтобы гарантировать, что все ссылки будут созданы, если они еще не были:

dotter_put_var('test.hello.world', 'testvalue'); // test.hello.world="testvalue";

Посмотрите, как работает FIDDLE.

Ответ 9

var test = {}
test.hello.world = "Hello doesn't exist!"

Это вызовет ошибку, очевидно, поскольку вы не определили test.hello

Во-первых, вам нужно определить ключ приветствия, тогда внутри вы можете назначить любой ключ. Но если вы хотите создать ключ, если он не существует, вы можете сделать следующее:

test.hello = test.hello || {};

Вышеприведенный оператор создаст объект test.hello, если он не определен, и если он определен, то он присвоит то же значение, что и ранее

Теперь вы можете назначить любой новый ключ внутри test.hello

test.hello.world = "Everything works perfect";

test.hello.world2 = 'With another key too, it works perfect';

Ответ 10

Я использую это:

Object.prototype.initProperty = function(name, defaultValue) {
  if (!(name in this)) this[name] = defaultValue;
};

Вы можете позже сделать f.e.:

var x = {a: 1};
x.initProperty("a", 2); // will not change property a
x.initProperty("b", 3); // will define property b
console.log(x); // => {a: 1, b: 3}

Ответ 11

let test = {};
test = {...test, hello: {...test.hello, world: 'Hello does exist!'}};
console.log(test);