setting javascript object properties from constructor default values using parameter destructuring - javascript

This is a bit of a tricky question regarding ES6 destructuring with default usage in a javascript object constructor.
I would like to receive a destructured parameters object with default values for my object constructor
so what i did was this
function bla({a=3,b=6}={}){
this.a=a;
this.b=b;
console.log(`this.a::'${this.a}' this.b::'${this.b}' a::'${a}' b::'${b}'`);
}
let myObject= new bla({a:1});
console.log(`myObject.a::'${myObject.a}' myObject.b::'${myObject.b}'`); // only a got overriden with value "1" and b remained its defauly value "6"
I know that what i did works. However, you can see that this is a bit of a code smell, because every time i need to add a new parameter to the constructor (for example {newParameter=3}) i also need to go down and add a matching line like this in the constructor body
this.newParameter=newParameter;
Is there any more elegant way to add a destructured parameter with default value which automatically is attached to "this."

I personally think your current approach is the most readable, but you can technically also do
function bla(obj = {}){
({
a: this.a = 3,
b: this.b = 6,
} = obj);
console.log(`this.a::'${this.a}' this.b::'${this.b}'`);
}

Don't know if this is best, but you could use Object.assign.
function bla(props={}) {
Object.assign(this, {a:3,b:6}, props);
console.log(`this.a::'${this.a}' this.b::'${this.b}'`);
}
let myObject= new bla({a:1});
console.log(`myObject.a::'${myObject.a}' myObject.b::'${myObject.b}'`); // only a got overriden with value "1" and b remained its defauly value "6"
You lose the parameter names, but it could be argued that this is better so that you don't accidentally mutate the parameter when you meant to mutate the object property.

I follow more a functional style to avoid the new on object creation and this keyword.
Explanation
You could simply write a function that retuns an object and takes several arguments with default values.
Thanks of the object literal property value shorthand you have less to write.
Code
function returnObject(a = 1, b = 2, c = 3) {
return {
a,
b,
c
}
}
console.log(returnObject())

If the objective is to use the variable names exactly once then this is what I'd do:
const foo = new Foo({ a: 1 });
console.log(`foo { a: ${foo.a}, b: ${foo.b} }`);
function Foo(config = {}) {
const defaults = { a: 3, b: 6 };
for (const [key, val] of Object.entries(defaults))
({ [key]: this[key] = val } = config);
}
Now, you only need to update the defaults object and you're done.
Actually, let's make a constructor constructor by abstracting this pattern:
const Foo = defcons({ a: 3, b: 6 });
const foo = new Foo({ a: 1 });
console.log(`foo { a: ${foo.a}, b: ${foo.b} }`);
function defcons(defaults) {
return function (config = {}) {
for (const [key, val] of Object.entries(defaults))
({ [key]: this[key] = val } = config);
};
}
Now, you can easily create as many such constructors as you want.

Related

spread in object definition causing undefined properties in "this"

I have an object which I initialize with bunch of properties in node.js, spreading another object in, and at the end defining a getter.
The problem is the the getter uses this and all the properties defined on the object before the spread don't exist on this.
If I move the spread to the end or start of the object initialization, it works fine.
const obj = { a: 1 }
const obj2 = {
prop: 'a',
...obj,
prop2: 'b',
get test() {
return this.prop + this.prop2
}
}
console.log(obj2.test); // 'undefinedb'
What can possibly be the reason for that?
Thanks

Javascript object with shared name

So, I'm trying to create an object like:
var a = {
b: "object_id",
b: function(){ return c(this.b); }
}
var c = {
"object_id": {
foo: "bar"
}
}
But it only registers the last value for the key 'b'. But I think I've seen something like this used before and it would really help me if I could call a.b().foo or if I just want ID a.b
Is there any way to make this happen or will I have to rename value and/or method?
You're looking for the Object Getter/Setter notation.
var o = {
_b: 7,
get b() {
return this._b + 1;
},
}
That being the case, you CAN'T use the same object id, and should store the internal variable for b in a closure, if you need it to be totally private.

ES6 Generators and Object Destructuring

According to ES6, it is possible to use array destructuring returned from custom generators. Now however I couldn't figure a way to do the same with simple object destructuring as I thought this should work (using Babel and Polyfill):
class Test {
constructor () { this.props = {a: 1, b: 2}; }
*[Symbol.iterator]() { yield* this.props; }
}
const {a, b} = new Test();
This should actually work no? Because it always simply returns undefined for a and b.
Array destructuring is tied to iterable/iterator objects. Object destructuring does not. If you want
const {a, b} = foo
to pull values for a and b, then foo needs to actually return a value for foo.a and foo.b. So you'd either want to just store the properties on the instance itself instead of .props, or use a getter like
get a() {
return this.props.a;
}
According to ES6, it is possible to use array destructuring returned from custom generators.
Yes.
This should actually work?
No - you were not using arrays here. By destructuring onto an object literal, the iterator was never invoked, and if it was it would have thrown an exception about the this.props object not being iterable.
Now however I couldn't figure a way to do the same with simple object destructuring as I thought this should work (using Babel and Polyfill):
class Test {
constructor () {
this.propA = 1;
this.propB = 2;
this.propArr = [];
}
*[Symbol.iterator]() {
yield this.propA; // yield the single value
yield this.propB; // yield another value
yield* this.propArr; // yield every from an iterable
}
}
const [a, b] = new Test();
// ^ ^ *array* destructuring!
Object destructuring could be used here as
const {propA: a, propB: b} = new Test();

ES6 Named Object Parameter Destructuring

I am currently using the object destructuring pattern with default parameters described in that answer to ES6 Object Destructuring Default Parameters.
(function test({a = "foo", b = "bar"} = {}) {
console.log(a + " " + b);
})();
I would like to be able to access the object parameter without assigning it to a variable in the function body and explicitly listing each key.
(function test({a = "foo", b = "bar"} = {}) {
const options = {a, b};
console.log(options);
})();
I tried naming the object argument, but the function looses the ability to resolve missing keys to their default value.
(function test(options = {a = "foo", b = "bar"} = {}) {
console.log(options);
})();
It seems to be ignoring the default parameters when destructuring into a named argument.
Is this part of the ES6 spec? Is there a way to achieve the desired behavior without additional code in the function body?
Edit: I removed a superfluous example that did not add context to the question.
Honestly, I think you're overcomplicating this. Default parameters are not compulsory -- in this case your code can be cleaner without it.
I would simply take the object options as the parameter and do the destructuring within the body of the function, after assigning default values.
function test(options) {
options = Object.assign({a: 'foo', b: 'bar'}, options);
let {a, b} = options;
console.log(options, a, b);
}
test(); // foo bar
test({a: 'baz'}); // baz bar
test({b: 'fuz'}); // foo fuz
test({c: 'fiz'}); // foo bar
With particular regard to your final snippet:
(function test(options = {a: "foo", b: "bar"}) {
console.log(options);
})({a: "baz"});
The problem is that a default parameter is used when the value passed is undefined. Here, the value passed is {a: "baz"}. That is not undefined, so the default parameter is ignored. Objects are not merged automatically.
More broadly in answer to your question: there is no way of getting both an object and destructuring some of its properties in the parameters of a method. Frankly, I'm grateful, because function signatures can be hard enough to read at first glance as it is.

javascript declaring key value pair in a function

let us say i have a object in which there is a function and inside the function i have declared some key values.
if every function is an function object in javascript then it is totally legal to declare key value pair in it.
var a ={
a: "shiv",
b: "shiv1",
c: function(){
L:"shiv1",
console.log(L);
}
}
how can i access these keys. in what scenarios i need to add key value pairs to a function. what does this signify. For Example in this function, how can i access L key.
Edit 1:
Console.log line will through err.
let say we have only this code
var a ={
a: "shiv",
b: "shiv1",
c: function(){
L:"shiv1",
}
}
what does declaring a key in function signify. if i need to access L key how can i
You every function is also an object, meaning that you can indeed set properties to it. In fact every function has length property, which denotes the number of formal arguments this function accepts.
However the syntax you are using to set function properties is not how you should do it. Even though you are using perfectly valid syntax, this is label statement, not property definition syntax. If you wanted to set a property to a function object in your case you would do it like this:
function c() {
console.log(c.L) // => "I'm a property of c function"
}
c.L = "I'm a property of c function";
var a = {
a: "shiv",
b: "shiv1",
c: c
}
When it can be useful? Like I said there is a limited use for it, like length property of the function, but in many cases you would not need setting properties on a function level directly.
This has to be throwing errors:
L:"shiv1",
console.log(l);
You probably want:
c: function(){
return {L:"shiv1"};
}
And then access it as:
a.c().L;
Full example here:
var a ={
a: "shiv",
b: "shiv1",
c: function(){
return {L:"shiv1"}
}
}
alert(a.c().L);
You can't declare keys like you did inside the function.
This doesn't work:
c: function(){
L:"shiv1", //Declaration don't work in this context
console.log(l); //Don't work
}
Try this (Please, remove the "function" statement):
c: {
L:"shiv1"
}
Also, you can do this:
c: function() {
var test = "shiv1";
return test;
}
If you want to work with parameters:
c: function(a, b) {
var test = a + " shiv1 " + b;
return test;
}
Or:
c: function(a, b) {
var total = a + b;
return total;
}

Categories

Resources