Автоматически создавать объект, если 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 это та же проблема, что и для объектов.
Ответы
Ответ 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).
Обратите внимание, что здесь есть некоторые неявные предположения:
- Промежуточные свойства являются объектами или не существуют. Например, он захлебнется, если
test.hello
является строкой. - То, что вы всегда хотите делать это до тех пор, пока вы используете прокси вместо исходного объекта.
Они довольно легко смягчаются, если вы используете его только в ограниченных контекстах (например, в корпусе редуктора), где существует небольшая вероятность случайного возврата 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);