Nested object assignment in Node.js - javascript

Suppose I have an object (baz) of variable contents. How can I assign a sub-object (foo) with a key (baz) to that object in one line?
Examples:
var baz = {}
baz.foo.bar = 1;
console.assert(baz === { foo: { bar: 1 } });
(or, in the case where foo is already defined)
var baz = { foo: { 1: "b" } };
baz.foo.bar = 1;
console.assert(baz === { foo: { 1: "b", bar: 2 } });

It's possible to put all in one line, though personally I wouldn't recommend it. You're technically doing two pretty different things:
Assign an object as a property if the object doesn't exist yet
Assign a property if the object already exists, mutating the existing object
You can assign baz.foo or the empty object to baz.foo, then assign the bar property value to the resulting object:
const baz = {};
(baz.foo ??= {}).bar = 1;
console.log(baz.foo.bar);
const baz2 = {};
(baz2.foo ??= {}).bar = 1;
console.log(baz2.foo.bar);
I'd prefer
// Create the object if it doesn't exist yet
baz.foo ??= {};
// Assign the new nested value
baz.foo.bar = 1;
Code readability is more important than golfing in most cases.

For the first case :
baz.foo = {bar :1}
And your code works for the second case
(Note that the following code outputs false :
a = {b:1}
console.log(a==={b:1})
)

Related

Add or avoid adding a property in an object depending on a boolean within the object itself [duplicate]

This question already has answers here:
Update only non-empty fields | Object spread
(2 answers)
In JavaScript, how to conditionally add a member to an object?
(29 answers)
Closed 4 years ago.
Basically I wonder if I could avoid adding a property into an object if a variable is false but from inside the object. So let's say I have this object:
var obj = { foo: 'bar', bar: 'foo' };
Now I want to rewrite the same object but I only want to add the second property if a new variable, which is a boolean, is true.
The problem is how could I do this for example with a ternary operator like this:
var add = false;
var obj = {
foo: 'bar',
(add ? bar: 'foo': null)
};
What I want to avoid is to have this:
...
bar: ( add ? 'foo' : undefined )
Because I don't want to have the bar index in case add == false. Also the assignament must be inside to object ( that's the question about, if it's posible ) because something like this is not what I'm looking for:
...
if (!add) delete obj.bar; // This would be after the creation of the whole object
Work arounds
Obviously this can be achieved in many ways, but I haven't found any that is done inside the object itself. I could use a ternary operator and having two objects like this:
var obj = add ? {
foo: 'bar',
bar: 'foo'
} : { foo: 'bar' };
But this would lead to having duplicated code ( when the object has more properties ).
Edit I'd say that my question is slightly different from the duplicates since my question refers to do it inside the object not after its declaration nor anything that isn't between var obj = { ... }
There is an accepted answer but I would love if someone knows any other way of doing it without the use of spread operator. Thank you all
A quick way of doing it using the spread operator:
const condition = false;
const foo = {
bar: 'baz',
...(condition ? {
boz: 'bat'
} : {})
};
console.log(foo);
This works because the spread operator for object literals does nothing on objects without enumerable own properties.
To achieve expected result , use below option of adding propeter based on condition in separate line
https://codepen.io/nagasai/pen/ebQmrb?editors=1010
var add = false;
var obj = { foo: 'bar'};
if(add){
obj.bar = 'foo'
}
console.log(obj)
Option 2: Use undefined value for bar, if condition is false and use JSON.stringify and JSON.parse to remove undefined 'bar' property on condition -false
var add = false;
var obj = JSON.parse(JSON.stringify({ "foo": 'bar', "bar" : add? 'foo': undefined}));
console.log(obj);
codepen - https://codepen.io/nagasai/pen/zyMgxj?editors=1010

Why does error occur at var obj={'A':'B','C':obj['A']};?

I want to create an javascript object, which value of "C" copies value of "A" :
var obj={
'A':'some complex function returns a string',
'C':obj['A']
};
But it has errors. I try to check if key 'A' really created:
var f=function(str){
console.log(str);
return str;
};
var obj={
[f('A')]:[f('B')],
"C":obj['A']
};
which prints
B
A
and then errors. Which means 'A' created but it still says obj['A'] is not defined. Why would that happen?
Your current attempt obviously fails because by the time the code constructs new object the value of obj variable was not assigned yet.
You could check it by using
var obj = { C: typeof obj}
I want to create an javascript object, which value of "C" copies value of "A"
If you want C to always reflect the value of A you could use
var obj = {
A: 'Some value',
get C() {
return this.A;
}
}
Or split obj declaration
var obj = { A: 'Some Value' };
obj.C = obj.A
You get the error because obj was not yet defined when you attempted to acces it from inside of it.
To make your code work you could use a getter.
The get syntax binds an object property to a function that will be
called when that property is looked up. - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get
Also you do not need quotes for your object properties.
Quotes can be omitted if the property name is a numeric literal
or a valid identifier name.
var obj = {
A : 'Hello',
get C() {
return this.A;
}
};
console.log(obj.C);
You can not reference a variable that has not created yet. You can do it like this.
var obj = { 'A' : 'some complex function returns a string' }
obj['C'] = obj['A']

Destructuring declaration bug with the value

I can not understand why after destructuring assignment, items prop does not equal Gorilla.
It will be used after deleting the main prop items: "Piggi" in the origin object options. I do not understand why...
'use strict';
let options = {
size: 100,
items: "Piggi"
}
let { title="Menu", items:w="Gorilla", size } = options;
let a = title;
let b = w;
console.log(a + " - " + b); // must be "Menu - Gorilla"
In the destructuring declaration with initialization here:
let { items:w = "Gorilla" } = options;
the syntax means to declare a variable called "w", whose value should be initialized to the value of the property called "items" in the object referenced by "options", or if there is no such property then to the string "Gorilla".
In your case, then, the variable "w" is initialized to the value of the "items" property in the original object.
If you don't want to take the value from the source object, then don't:
let w = "Gorilla";
When you analyze the code, you get three techniques working here:
short hand properties
{ foo, bar }
for
{ foo: foo, bar: bar}
default values
{ foo = 42 }
which is
{ foo: foo = 42 }
change of the target in the Object Property Assignment Pattern [You Don't Know JS: ES6 & Beyond, Chapter 2: Syntax]:
The syntactic pattern here is source: target (or value: variable-alias).
{ foo: bar }
The synthesis is a new target w for the old property items with a default value of 'Gorilla'.
let options = {
size: 100,
items: "Piggi"
}
let { title="Menu", items:w="Gorilla", size } = options;
let a = title;
let b = w;
console.log(a + " - " + b);
Solution- The problem is , we are overwriting the global object. it is why you have titile as Menu but option object does not have titile property. So, when you assign global object with option,
it still has items as "piggi"
plus you cannot assign object like this, you have to reassign each property in javascript.
i hope you got your answer.

Is it necessary to create nested jSON objects before using it?

I think I've seen how to create a JSON object without first preparing it. This is how i prepare it:
obj = {
0:{
type:{}
},
1:{},
2:{}
};
Now I think I can insert a value like: obj.0.type = "type0"; But I'd like to create it while using it: obj['0']['type'] = "Type0";.
Is it possible, or do I need to prepare it? I'd like to create it "on the fly"!
EDIT
I'd like to create JS object "On the fly".
var obj = {};
obj.test = "test"; //One "layer" works fine.
obj.test.test = "test" //Two "layers" do not work... why?
obj = {
0:{
type:{}
},
1:{},
2:{}
};
Now i think i can insert value like: obj.0.type = "type0";
I guess you mean "assign" a value, not "insert". Anyway, no, you can't, at least not this way, because obj.0 is invalid syntax.
But I'd like to create it while using it: obj['0']['type'] = "Type0";
That's fine. But you need to understand you are overwriting the existing value of obj[0][type], which is an empty object ({}), with the string Type0. To put it another way, there is no requirement to provide an initialized value for a property such as type in order to assign to it. So the following would have worked equally well:
obj = {
0:{},
1:{},
2:{}
};
Now let's consider your second case:
var obj = {};
obj.test = "test"; //One "layer" works fine.
obj.test.test = "test" //Two "layers" do not work... why?
Think closely about what is happening. You are creating an empty obj. You can assign to any property on that object, without initializing that property. That is why the assignment to obj.test works. Then in your second assignment, you are attempting to set the test property of obj.test, which you just set to the string "test". Actually, this will work--because strings are objects that you can set properties on. But that's probably not what you want to do. You probably mean to say the previous, string value of obj.test is to be replaced by an object with its own property "test". To do that, you could either say
obj.test = { test: "test" };
Or
obj.test = {};
obj.test.test = "test";
You are creating a plain object in JavaScript and you need to define any internal attribute before using it.
So if you want to set to "Type0" an attribute type, inside an attribute 0 of an object obj, you cannot simply:
obj['0']['type'] = "Type0";
You get a "reference error". You need to initialize the object before using it:
var obj = {
0: {
type: ""
}
};
obj['0']['type'] = "Type0";
console.log(obj['0']['type']);
You could create your own function that takes key as string and value and creates and returns nested object. I used . as separator for object keys.
function create(key, value) {
var obj = {};
var ar = key.split('.');
ar.reduce(function(a, b, i) {
return (i != (ar.length - 1)) ? a[b] = {} : a[b] = value
}, obj)
return obj;
}
console.log(create('0.type', 'type0'))
console.log(create('lorem.ipsum.123', 'someValue'))
Is it necessary to create nested objects before using it?
Yes it is, at least the parent object must exist.
Example:
var object = {};
// need to assign object[0]['prop'] = 42;
create the first property with default
object[0] = object[0] || {};
then assign value
object[0]['prop'] = 42;
var object = {};
object[0] = object[0] || {};
object[0]['prop'] = 42;
console.log(object);
Create object with property names as array
function setValue(object, keys, value) {
var last = keys.pop();
keys.reduce(function (o, k) {
return o[k] = o[k] || {};
}, object)[last] = value;
}
var object = {};
setValue(object, [0, 'prop'], 42);
console.log(object);

Trying to add multiple properties to Javascript object using a loop

I hope the day finds you well.
So I have an object with no properties. I'm trying to add multiple properties to this object using a loop. Each property added to the loop will appear in the object multiple times depending on how many times the loop runs, with each new property incremented by 1.
So I have something like this:
myObject = { };
for(i = 0; i < 2; i++){
myObject.propA + i = foo;
myObject.propB + i = bar;
};
Which I want to yield something like this:
myObject.propA0 = foo;
myObject.propB0 = bar;
myObject.propA1 = foo;
myObject.propB2 = bar;
Giving a nice stack of objects generated on the fly depending on how many times the loop runs. But I don't seem to be getting this. So how exactly do I feed the variable from the loop to the property when it's created and assigned?
Try using square bracket notation for the names
myObject['propa' + i] = foo;
As other users said, you have to use bracket notation to refer to properties by their name strings:
myObject['propA' + i] = 'foo';
But why don't you use an array of objects, instead of a single object with similar, numbered property names? Something like this:
var myArray = [];
for(i = 0; i < 2; i++){
myArray.push({
propA: 'foo',
propB: 'bar'
});
};
This should produce:
[
{ propA: 'foo', propB: 'bar'},
{ propA: 'foo', propB: 'bar'}
]
It looks way cleaner, in my opinion.
Use the array-access method to set the properties.
myObject = { };
for(i = 0; i < 2; i++){
myObject['propA' + i] = foo;
myObject['propB' + i] = bar;
};
you might use
object['popA'+i]=...
to create a standard property or either use a getter/setter property, in this case you need to use
Object.defineProperty(object, *propertyname*, *propertyDescriptor*).
The latter gives you more options on the created property.
All details here :
https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty

Categories

Resources