Came across these 2 notations recently. While both appear to be doing similar things, one of them uses an assignment operator while another one appears to be an object. Are they doing anything different?
const { value = "" } = this.props;
and
let { value: newValue } = newProps;
Both of these are destructing an object. When you use = you are setting a default value if the value is undefined/null. With : you are aliasing the variable. You can even combine them:
const { value : value2 = 'Hello' } = this.props;
console.log(this.props.value); // World
console.log(value2); // World (since value2 IS this.props.value aliased)
// ...or if this.props.value isn't defined
console.log(value2); // Hello
It has nothing to do with React library actually. They are ES6 destructuring assignments.
The first example will create a constant variable called value and will assign whatever is this.props.value (Object, Array, Number). If this.props.value is undefined though it will use default value = "" - empty string.
const { value = "" } = this.props;
In a second example, newValue variable will be created and it will equal to newProps.value (even if it is undefined).
let { value: newValue } = newProps;
Related
I have the following code to count the number of links in a page:
let temp = {}
for (const page of pages) {
let count = temp[page.outgoingLinks.length];
if (!count) {
count = 0;
}
count++;
temp[page.outgoingLinks.length]=count;
}
Sorry for variable names like temp as I am trying show some code which would help you understand what I am trying to do. Here, I would like to avoid the need for the if check that initializes the value.
In this example, the default value is an integer. But I would like to store even an Array there, something like defaultdict in python. Any ideas on how I can do it in JS?
There is nothing like Python's defaultdict in JavaScript, however you can have a default value when accessing the property by using the nullish-coalescing operator:
let count = temp[page.outgoingLinks.length] ?? 0;
To avoid the need for the if check that initializes the value
for (const page of pages) {
temp[page.outgoingLinks.length] = temp[page.outgoingLinks.length] ? temp[page.outgoingLinks.length]++ : 0;
}
here you can direclty use ternary operator to do so.
As you want multiple default values, you could create an object that contains the default values. This object can be defined in a helper function that takes an argument which specifies the type of default value you want and returns a function that can be called with the value.
If that value is undefined or null, this function returns the required type of default value.
function getInitializer(typeOfDefault) {
const defaults = {
arr: [0, 0, 0],
num: 0,
emptyString: ''
};
return (value) => value ?? defaults[typeOfDefault];
}
// default number
const initialize = getInitializer('num');
const a = initialize(0);
console.log(a);
// default array
const initialize2 = getInitializer('arr');
const b = initialize2(null);
console.log(b);
I have a list of array I do this:
const { id } = myArray.find(
(obj) => obj === true)
If the id is not present it will throw error. How to prevent error in the same time use destructuring? I want to keep the logic in one line.
The issue here is .find() returns undefined once there is no fulfillment for the condition:
The value of the first element in the array that satisfies the provided testing function. Otherwise, undefined is returned.
So probably you can use || operator to check if you have any value returned from .find() or you can replace with empty object {} instead on the right side of the operator.
Probably the option for one-liner is the following:
const myArray = [
{ id: 12 },
{ id: 13 },
{ id: 14 }
];
const { id } = myArray.find(e => e.id === 17) || {};
console.log(id);
So you can destructure id property even if it returned undefined in this way.
Also if you need you can add default value to your destructuring statement based on the documentation which states for Destructuring statement as follows:
A variable can be assigned a default, in the case that the value unpacked from the object is undefined.
const { id = 10 } = {};
console.log(id);
I hope this helps!
This works:
handleOnChange(e) {
this.setState({[e.target.id]: e.target.value});
}
e.target.id is wrapped in brackets ([ ]), while e.target.value is not.
I could write e.target.value in brackets too and it would work, but if I remove the brackets from e.target.id my code will not work. Why?
I did some research and believe this is because Computed Property Names (I am not sure though), but then the question arises, why does the property of e.target.id needs to be computed while e.target.value does not? Both of them are simply values I would think.
why does the property of e.target.id needs to be computed while e.target.value does not?
The right hand side is always a value (and always has been).
The left hand side is, historically, a string or identifier. The ability to put an expression there (a computed property name) is a new feature.
const foo = "bar";
// Here the property name is foo because it is an identifier
const obj = {
foo: foo
};
console.log(obj);
// Here the property name is foo because it is a string
const obj2 = {
"foo": foo
};
console.log(obj2);
// Here the property name is bar because it computed by evauating the constant
const obj3 = {
[foo]: foo
};
console.log(obj3);
// Here the property name is barbar because it computed by evauating function call that returns a template string that uses the constant twice
function blah() {
return `${foo}${foo}`;
}
const obj4 = {
[blah()]: foo
};
console.log(obj4);
//This is the same as the previous example except that because the right hand side is always a value, wrapping the code in square brackets means it is treated as an array literal (as opposed to being a computed property which is what square brackets mean on the left hand side)
function blah() {
return `${foo}${foo}`;
}
const obj5 = {
[blah()]: [foo]
};
console.log(obj5);
I could write e.target.value in brackets too and it would work, but if I remove the brackets from e.target.id my code will not work. Why?
Those two pair of brackets serve very different purpose: in
{ [keyName]: value }
you have indeed a computed property name. In
{ keyName: [value] }
however, the brackets around [value] create an array.
Because {foo.bar: "fizz"} doesn't mean the same thing as {"foo.bar": "fizz"}, in fact that isn't even syntactically correct.
const a = {b: "c"};
const foo = {a.b: "d"}; // error
console.log(foo);
also consider:
const foo = {
bar: "other"
};
const b = {
[foo.bar]: "fizz", // Computed
"foo.bar": "buzz", // String accessor
// foo.bar: "err" // Syntax error
};
console.log(b);
You want the value of foo.bar to be used as the key for the Object. The language mechanism for doing that is to either extract the value and then use brackets to dereference it:
const buzz = {};
buzz[foo.bar] = "fizz";
or you use the new language feature to make it a one-liner:
const buzz = {[foo.bar]: "fizz"};
It's difficult to explain the case by words, let me give an example:
var myObj = {
'name': 'Umut',
'age' : 34
};
var prop = 'name';
var value = 'Onur';
myObj[name] = value; // This does not work
eval('myObj.' + name) = value; //Bad coding ;)
How can I set a variable property with variable value in a JavaScript object?
myObj[prop] = value;
That should work. You mixed up the name of the variable and its value. But indexing an object with strings to get at its properties works fine in JavaScript.
myObj.name=value
or
myObj['name']=value (Quotes are required)
Both of these are interchangeable.
Edit: I'm guessing you meant myObj[prop] = value, instead of myObj[name] = value. Second syntax works fine: http://jsfiddle.net/waitinforatrain/dNjvb/1/
You can get the property the same way as you set it.
foo = {
bar: "value"
}
You set the value
foo["bar"] = "baz";
To get the value
foo["bar"]
will return "baz".
You could also create something that would be similar to a value object (vo);
SomeModelClassNameVO.js;
function SomeModelClassNameVO(name,id) {
this.name = name;
this.id = id;
}
Than you can just do;
var someModelClassNameVO = new someModelClassNameVO('name',1);
console.log(someModelClassNameVO.name);
simple as this
myObj.name = value;
When you create an object myObj as you have, think of it more like a dictionary. In this case, it has two keys, name, and age.
You can access these dictionaries in two ways:
Like an array (e.g. myObj[name]); or
Like a property (e.g. myObj.name); do note that some properties are reserved, so the first method is preferred.
You should be able to access it as a property without any problems. However, to access it as an array, you'll need to treat the key like a string.
myObj["name"]
Otherwise, javascript will assume that name is a variable, and since you haven't created a variable called name, it won't be able to access the key you're expecting.
You could do the following:
var currentObj = {
name: 'Umut',
age : 34
};
var newValues = {
name: 'Onur',
}
Option 1:
currentObj = Object.assign(currentObj, newValues);
Option 2:
currentObj = {...currentObj, ...newValues};
Option 3:
Object.keys(newValues).forEach(key => {
currentObj[key] = newValues[key];
});
Is there a known reason why passing in null as a parameter in ES6 does not use the default parameter when one is provided?
function sayHello(name = "World") {
console.log("Hello, " + name + "!");
}
sayHello("Jim"); // Hello, Jim!
sayHello(undefined); // Hello, World!
sayHello(null); // Hello, null!
This is not that obvious
I've read some comments of why undefined is completely different than null and that's why it explains the current behavior of default parameters.
One could argue that explicitly passing undefined should not trigger the default value substitution because when I have a function:
const f = (x = 'default') => console.log(x);
I would like it to print "default" when I run it as:
f();
but I would like it to print "undefined" when I explicitly run it as:
f(undefined);
because otherwise why would I use f(undefined) in the first place? Clearly my intention here is to provide some argument instead of leaving it out.
Examples to the contrary
Now, consider this function:
const g = (...a) => console.log(JSON.stringify(a));
When I use it as:
g();
I get: []
But when I use it as:
g(undefined);
I get: [null]
which clearly demonstrates that:
passing undefined is not the same as not passing an argument at all
sometimes null can be a default value instead of undefined
TC39 decision
Some background on the current behavior of the default parameters can be seen in the July 24 2012 Meeting Notes by TC39:
https://github.com/rwaldron/tc39-notes/blob/master/meetings/2012-07/july-24.md
Incidentally, it shows that explicitly passing undefined originally did not trigger the default value in the first draft and there was a discussion about whether or not it should do that. So as you can see the current behavior was not so obvious to the TC39 members as it now seems to be to people who comment here.
Other languages
That having been said, the decision of what should and what should not trigger the default value substitution is completely arbitrary at the end of the day. Even having a separate undefined and null can be though of as quite strange if you think about it. Some language have only undefined (like undef in Perl), some have only null (like Java), some languages use equivalents of false or an empty list or array for that (like Scheme where you can have an empty list or #f (false) but there is no equivalent of null that would be distinct from both an empty list and a false value) and some languages don't even have equivalents of null, false or undefined (like C which uses integers instead of true and false and a NULL pointer which is actually a normal pointer pointing to address 0 - making that address inaccessible even when mapped by any code that tests for null pointers).
What you can do
Now, I can understand your need to substitute default values for null. Unfortunately this is not a default behavior but you can make a simple function to help you:
const N = f => (...a) => f(...a.map(v => (v === null ? undefined : v)));
Now every time you want defaults substituted for null values you can use it like this. E.g. if you have this function from one of the examples above:
const f = (x = 'default') => console.log(x);
it will print "default" for f() and f(undefined) but not for f(null). But when you use the N function defined above to define the f function like this:
const f = N((x = 'default') => console.log(x));
now f() and f(undefined) but also f(null) prints "default".
If you want somewhat different behavior, e.g. substituting default values for empty strings - useful for environment variables that can sometimes be set to empty strings instead of not existing, you can use:
const N = f => (...a) => f(...a.map(v => (v === '' ? undefined : v)));
If you want all falsy values to be substituted you can use it like this:
const N = f => (...a) => f(...a.map(v => (v || undefined)));
If you wanted empty objects to be substituted you could use:
const N = f => (...a) => f(...a.map(v => (Object.keys(v).length ? v : undefined)));
and so on...
Conclusion
The point is that it's your code and you know what should be the API of your functions and how the default values should work. Fortunately JavaScript is powerful enough to let you easily achieve what you need (even if that is not the default behavior of default values, so to speak) with some higher order function magic.
That's just how default parameters are defined in the spec. See MDN: (emphasis mine)
Default function parameters allow formal parameters to be initialized with default values if no value or undefined is passed.
null is neither no value, nor undefined, so it doesn't trigger the default initialization.
null is a value that won't trigger the default value to be used, the default values will be used when the argument is undefined.
ramdajs version code
// import ramda
// infra code
const isEmptyOrNil = (value) => isEmpty(value) || isNil(value)
const nullChange = (defaultValue) => (value) => isEmptyOrNil(value)? defaultValue: value
// single null
const _somef = (value) => value
const somefWithDefault = (defaultValue) => pipe(nullChange(defaultValue), _somef)
const somef = somefWithDefault('myValue')
somef(null)
// many args
const _somef2 = (value, value2, value3) => value + value2 + value3
const nullChangeMyValue = nullChange('myValue')
const somef2 = useWith(_somef2, [nullChangeMyValue, nullChangeMyValue, nullChangeMyValue])
somef2(null, undefined, 1234)
// many args2 version2
const nullChangeWith = (defaultValue) => nullChange(defaultValue)
const arrayNullChangeWith = (defaultValue) => (array) => array.map(nullChangeWith(defaultValue))
const arg2Array = (...args) => args
const funcApplyDefaultValue = (defaultValue) => (func) => pipe(
arg2Array, arrayNullChangeWith(defaultValue), apply(func)
)
const v2somef2 = funcApplyDefaultValue(8)(_somef2)
v2somef2(1,2,null)
gits: https://gist.github.com/otwm/3a6358e53ca794cc2e57ade4af91d3bb