How to implement the logical assignment in destructuring assignment in javascript? - javascript

destructuring assignment doesn't work for the field in one object holds a falsy value, as follow:
let { aaa = 123 } = { aaa: null }
console.log(aaa) // null
so, how to achive ||= in object destructuring assignment to implement such the field's destructed defalut value ? like this:
let { aaa ||= 123 } = { aaa: null }
console.log(aaa) // 123
// it equals to
// let aaa = ({ aaa: null }).aaa || 123

You can add a default value in this way
let obj = null
{ obj1 } = { obj1: obj || 123 }
OR
try assigning values to an object using a constructor. In that way the destructuring would work fine:
class Obj1 {
a: string
b: number
constructor(obj) {
this.a = obj && obj.a || 'default a'
this.b = obj && obj.b || 1
}
}
let obj = null
let obj1 = new Obj1(obj)
let {aaa} = {aaa: obj1}

So you cannot do what you are trying to do.
The destructuring assignment works as expected/specified. It is just that the default value only works when the destructured value is undefined.
You have to use the normal syntax for "falsy" values (note: this includes undefined, false, 0, NaN etc. Extensive list at https://developer.mozilla.org/en-US/docs/Glossary/Falsy).
let { aaa } = { aaa: null }
aaa ||= 123;
Quoting from MDN Destructuring assignment
for objects
Default values
A variable can be assigned a default, in the case that the value unpacked from the object is undefined.
for arrays
Default values
A variable can be assigned a default, in the case that the value unpacked from the array is undefined.

Related

Nested object assignment in Node.js

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

using optional chaining in array of object and destructing

I have an object like this
const obj = [{a: 'a'}];
I can get it like:
const { a } = obj[0]; //a
but what if obj['x'] doesn't exist?
I tried this with optional chainning but doesn't seem to work.
const { a } = obj?.[1];
You are close to it. You should make sure to fallback with an empty object, for the destructing later to make sense
const obj = [{a: 'a'}];
const { a } = obj?.[1] || {};
console.log(a)
Update
This would be even shorter if you don't use destructing in this case
const obj = [{a: 'a'}];
const a = obj?.[1]?.a; // or: obj?.[1]?.['a']
console.log(a)
You can use the Logical OR operator.
const { a } = obj[x] || {}
If obj does not have a property x, a will be set to undefined.
You could festructure with an index as computed property and a default object for a missing item of the array.
const
obj = [{ a: 'a' }],
{ [2]: { a } = {} } = obj;
console.log(a);
Take a look at the following three cases, where I've used optional chaining.
You need to first check if the first element of the array (index 0) exists and then check if there's a field a in it.
// Case 1:
const obj1 = [{ a: "a" }];
console.log(obj1?.[0]?.a); // "a"
// Case 2:
const obj2 = [{ b: "b" }];
console.log(obj2?.[0]?.a); // undefined
// Case 3:
const obj3 = [];
console.log(obj3?.[0]?.a); // undefined

How to update global object value?

I am not sure about best practice that how to deal with it:
const obj = {a: null}
function getObject(){
// I may return a, or anything that could be nested property
return obj.a
}
let v = getObject()
v = 'updated'
console.log(obj.a) // null
I expect a value co-operates with v assignment. I have seen with operator but people say avoid using it. So, what should I be using?
If a function returns the value of a field/variable then you get a reference to the object stored in that field/variable, not a reference to the variable itself. You either need to have getObject() return an object, which you then set the field value on, like so:
function getObject(){
return obj;
}
getObject().a = 'something';
Or you need to write a function that assigns the field value instead, like so:
function setValue(val) {
obj.a = val;
}
Another option would be to wrap your values in objects, so getObject never returns null, instead returning an empty object on which you set a field value, like so:
const obj = {a: {}}
function getObject(){
return obj.a
}
let v = getObject();
v.value = "foo";
// obj now equals {a: {value: "foo"}}
As written you're returning the value currently stored in a, saving that to a variable, then changing the value in the new variable. The value in obj remains unchanged.
You can access any Javascript object using dot like what you had in getObject , also you can set value to the object like this anyObject.key = value this will change the value of the key in the object.
const obj = new Object({ a : null })
Object.prototype.setA = function(a) {
this.a = a
}
obj.setA('hello world!')
console.log(obj)
If you want to update a global object values you need to access the object and assign it
const obj = {a: null}
function getObject(){
return obj.a
}
let v = getObject()
console.log(getObject()) //null
console.log(obj.a) // null
obj.a = "a" //you are now overriding what was null here
console.log(obj.a) //contains "a" now or whatever type you want it to be
I'd recommend you check this helpful tutorial: https://www.w3schools.com/js/js_objects.asp
Understanding JS variables is important:
let a = 1;
console.log(a); //1
a = 2;//overrides a
console.log(a); //2
What you are trying to achieve is not very clear but I would recommend to always mutate the global var to avoid errors and confusion.
Short answer:
you are changing the value of v and not changing the object referenced by v
Long answer:
If this was written in a class-based langauge (like C, java, or C++, etc.), this would also not change a. Because you are only changing what v points or reference to (in case of pointers).
In C :
void *v = (void*) &getObject() // v is equal to obj (or points to obj) obj
v = (void*) &some.thing.something() // v is now equal to some.thing.something() or points to some.thing.something()
// obj has not changed
print(obj.a) // null which is reasonable
// printf ("%s", obj.a); is the correct syntax in C
To actually change a you need to change the value of of the address in memory that is referenced by v
In C:
void *v = (void*) &getObject()
*v = (void *) some.thing.something()
print(obj.a) // now obj is equal to 'some.thing.something()'
// printf ("%s", obj.a); is the correct syntax in C
Now in your code why a is not changing ?
When it comes to Javascript, it is a langauge based on prototypes, rather than class-based
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Details_of_the_Object_Model
Check the link above.
It is because of the same reason explained in the first C code above. You are just changing the value of v and not changing the object referenced by v
let v = getObject()
v = 'some.thing.something()'
console.log(obj.a) // null

Javascript object computed property [duplicate]

This question already has answers here:
Why is object[key] not equal to key, if key is an object, in JavaScript?
(3 answers)
Closed 3 years ago.
Could you please explain me what happens in code bellow? Why both of the expressions have same value?
let a = {};
let b = {
value: 'b'
};
let c = {
value: 'c'
};
a[b]=123;
a[c]=456;
console.log(a[b], a[c]); // ==> 456 456
Any link to study material are welcome
Object keys may only be strings. When you put an object in a computed property, it will be stringified to [object Object], so a[b] is the same as a[c]: a['[object Object]'].
let a = {};
let b = {
value: 'b'
};
let c = {
value: 'c'
};
a[b]=123;
a[c]=456;
console.log(a);
So, the final assignment of 456 to the [object Object] key overwrites the prior assignment of 123 (and the resulting object only has that one key).
If you want to safely use objects as "keys", use a Map instead, whose keys can be of any type, not just strings:
const a = new Map();
let b = {
value: 'b'
};
let c = {
value: 'c'
};
a.set(b, 123);
a.set(c, 456);
console.log(a.get(b));
console.log(a.get(c));
Quite easy:
When you do
a[b]=123;
a[c]=456;
you set an object as a propery name of a.
The thing is, a property name is a string, so, toString() is called on b and c (which are objects), and that makes the same value. Do you get it?
let a = {};
let b = {
value: 'b'
};
let c = {
value: 'c'
};
a[b]=123;
a[c]=456;
console.log(a[b], a[c]); // ==> 456 456
console.log(a);
In a[b] = //... expression, b gets coerced to string - and the result of that conversion is a string "[object Object]". And it's the same value for c.
let a = {};
let b = {
value: 'b'
};
let c = {
value: 'c'
};
a[b]=123;
a[c]=456;
console.log(b.toString());
console.log(c.toString());
console.log(a);
Because Object's key can be string and you are trying to assign a object as the key, js typecasts the object to string and the key becomes [object Object] for both the objects. That is why the value is updated against the same key.

indexOf but for objects? [duplicate]

This question already has answers here:
What's the correct way to test for existence of a property on a JavaScript Object?
(3 answers)
Closed 6 years ago.
I want to look through an object and assign each of it's existent properties to a variable.
There are 4 possible properties. Some of the objects have all 4. Some might only have two.
How can I check if a particular property exists? Is there an equivalent of indexOf() for arrays but for objects instead?
Use the in keyword:
"key" in object
which returns true or false, depending if the object, or anything in its prototype chain, has that property.
You can also use object.hasOwnProperty("key"), which will only be true if the object has key as a property of itself, not its prototype. Example:
var object = {};
"toString" in object; // true
object.hasOwnProperty("toString"); // false
Note (as per #dandavis's comment) that if object has a custom property called hasOwnProperty, this gets thwarted; to work around this, use hasOwnProperty.call(object, "key"). Example:
var a = {hasOwnProperty: Boolean};
a.hasOwnProperty('name'); // true
hasOwnProperty.call(a, 'name'); // false
If you are only interested in properties set directly on the object (not accessible via the prototype chain) then hasOwnProperty will provide a boolean value, true, if an object has the specified property.
For example: testObject.hasOwnProperty('propertyToCheckFor') would return true if testObject.propertyToCheckFor exists, otherwise it would be false.
See the following code for a more expanded example:
var obj1 = {
a: 1
};
var obj2 = {
a: 1,
b: 2
};
var obj3 = {
b: 2,
c: 3
};
var obj4 = {
a: 1,
b: 2,
c: 3
};
// For dispaly purposes
document.write('<pre>' + JSON.stringify({
obj1: {
hasA: obj1.hasOwnProperty('a'),
hasB: obj1.hasOwnProperty('b'),
hasC: obj1.hasOwnProperty('c')
},
obj2: {
hasA: obj2.hasOwnProperty('a'),
hasB: obj2.hasOwnProperty('b'),
hasC: obj2.hasOwnProperty('c')
},
obj3: {
hasA: obj3.hasOwnProperty('a'),
hasB: obj3.hasOwnProperty('b'),
hasC: obj3.hasOwnProperty('c')
},
obj4: {
hasA: obj4.hasOwnProperty('a'),
hasB: obj4.hasOwnProperty('b'),
hasC: obj4.hasOwnProperty('c')
}
}, null, 2) + '</pre>');
var obj = {
foo: 1,
bar: 2,
baz: 3
}
Object.keys(obj).forEach(function(key) {
window[key] = obj[key]
})
console.log(foo, bar, baz)
Or in ES2015
const obj = {
foo: 1,
bar: 2,
baz: 3
}
function assignPrivateVars() {
let {foo, bar, baz} = obj;
console.log(foo, bar, baz);
}
assignPrivateVars();
You can use destructuring assignment. If value is not defined, variable will be set to undefined. You can also check if variable is defined after destructuring then delete variable by reference.
var data = {a:1, b:2, c:3};
var {a, b, c, d} = data; // `d`: `undefined`

Categories

Resources