Just started to learn react.js and javascript. I'm going through all the documentation on facebook's github, but got stuck with this.
In the handleCelsiusChange method of Calculator class in Lifting state up chapter there is this line:
this.setState({scale: 'c', value});
So scale will get the value 'c'. Okay. But what is this value being simply there? Shouldn't it be a key-value pair?
I've checked the explanation of setState():
The first argument can be an object (containing zero or more keys to
update) or a function (of state and props) that returns an object
containing keys to update.
But it says nothing relevant about this usage.
Thanks! :)
That's actually a feature of ES6. If the key matches an existing variable name you can use this shorthand syntax. So instead of writing value: value you can simply write value as key and variable name are the same.
Example with ES6
function getCar(make, model, value) {
return {
// with property value shorthand
// syntax, you can omit the property
// value if key matches variable
// name
make,
model,
value
};
}
The equivalent of the above in ES3/ES5
function getCar(make, model, value) {
return {
make: make,
model: model,
value: value
};
}
Example taken from http://www.benmvp.com/learning-es6-enhanced-object-literals/
That is a special shorthand notation from ES6, it means value: value, look here https://ariya.io/2013/02/es6-and-object-literal-property-value-shorthand for more details
Related
I am trying to make sense of this line of code:
const loanPeriod: number = get(product, 'TermMonths', this.defaultTerm) / this.monthsInAYear;
defaultTerm and monthsInAYear are global variables. product is an object and TermMonths is a number property of product. I don't know why the product & 'TermMonths' is needed. Can't you just divide the defaultTerm by monthsInAYear?
You can find the official documentation here, with an example. Using your case, the assumption is that product may or may not have a property called TermMonths. If it does, _.get will retrieve the value of that property. If it does not, the default, this.defaultTerm, is returned.
The _.get() method is used to get the value at path of object. If the resolved value is undefined, the defaultValue is returned in its place.
Syntax:
_.get(object, path, [defaultValue])
Parameters: This method accepts three parameters as mentioned above and described below:
object: This parameter holds the object to query.
path: This parameter holds the path of the property to get. The path will be array or string.
defaultValue: This parameter holds the value returned for undefined resolved values.
Return Value: This method returns the resolved value.
src: https://www.geeksforgeeks.org/lodash-_-get-method/
In your case it gets the term of loan if not it takes default and divides it by months in years to get the total years.
I am using react. I have data I am getting from my API in the form of JSON(already converted to object). The object -
{
_id: '1',
specs: {
chip: 'H1-based',
connectivity: 'Bluetooth 5.0',
},
}
I want to display the key value pairs(on the website, this is NOT an object)
Chip: H1-based
Connectivity: Bluetooth 5.0
This is the place where I want to add the necessary logic in my code -
<ListGroup.Item className="product__detail-row">
The entire object shown above is in a variable called product.
</ListGroup.Item>
You can put text in your JSX by using a JSX expression, which looks like {valueHere}. You can get the entries of an object as [key, value] pairs via the Object.entries function, then map them to JSX elements via map. So applying that to your situation:
<ListGroup.Item className="product__detail-row">
{Object.entries(product.specs).map(([key, value]) =>
<div>{initialCap(key)}: {value}</div>
)}
</ListGroup.Item>
In that example I wrapped the display of each key/value pair in a div, but you can use whatever suits your situation.
I've used a hypothetical function initialCap there to convert your property names, which are in all lower case, to initially-capitalized strings. FWIW, a simple version of that function might be:
function initialCap(str) {
return str.charAt(0).toLocaleUpperCase() + str.substring(1);
}
...though since JavaScript characters are effectively UTF-16 code units and sometimes it takes a pair of code units to make a "character," a more general version might work in code points instead of code units:
function initialCap(str) {
const [first] = str; // Spread and destructuring work by code _points_, not code units
return first.toLocaleUpperCase() + str.substring(first.length);
}
ToolJS has an "Obj" module that holds a method which loops through an object, firing a callback for each property pair, outputting the properties key and value to the callbacks arguments for each property.
Get the library either through NPM or CDN
// require the Obj module from the package
const { Obj } = require("#redakaa/tooljs");
// use the .forEach method available to the Obj module
Obj.forEach(myObj, function(key, value){
console.log(`Current key: ${key}, Current value: ${value}`);
});
Check out the libraries full docs here
Ref: ToolJS Object Manipulation
I came across this example in a MDN doc, for example:
class Search1 {
constructor(value) {
this.value = value;
}
[Symbol.search](string) {
return string.indexOf(this.value);
}
}
If I pull up node, and run just the line included as part of the object literal, it doesn't work:
> Symbol.search
Symbol(Symbol.search)
> [Symbol.search]
[ Symbol(Symbol.search) ]
> [Symbol.search]('somthing')
TypeError: [Symbol.search] is not a function
I think I've also seen this syntax in a few other places, like e.g. in the react docs:
handleChange(event) {
this.setState({ [event.target.id]: event.target.value });
}
Is this just a use of destructuring syntax? It doesn't seem like it.
brackets are used when you have variable as key and not a plain string.
const obj = {
"someId": 'abc',
};
const e = {
target: {
id: "someId"
}
};
console.log(obj[e.target.id]);
Apart from above mentioned, it is also used to access the numeric keys (Just like array) and when key is computed. See - https://javascript.info/object#square-brackets
Turns out, that's just part of the spec.
It looks a bit like array de-structuring, but it's not.
In the case of [event.target.id], you're assigning the value that event.target.id points to be a key in the object passed to setState(). If you tried to do this without the brackets ([]), it would not work, not how you expect anyway.
In the case of [Symbol.search](string), here you're using the Symbol.search symbol (see symbols) as a key which is dynamically evaluated immediately to its actual, unique value. The dynamic evaluation is allowed because this value becomes the key in an object literal definition. The value which the key points to is a function being defined here, which takes string as its first and only parameter, and operates on that. This is a hook for allowing an object to define how it behaves when used as a parameter, in this case to the .search() function. See here.
Thanks for #randomSoul's answer, for completing it I might say that braces also make you to have a string key with spaces like below:
const myOBJ = {
'my key': 'my assigned String Value'
}
Then you can call that key value pair with this braces syntax like:
console.log(myOBJ['my key'])
This is rarely used in JavaScript, but the main purpose of using braces for getting the value from object literal is for getting dynamically computed keys of object. Like that you have an object that each key is represented user id, and you based on that you want to decide to get the specific user id that you got from your url params or somewhere else then you would be able to get user data like below:
console.log(lastFiveUserData[myUserId].age)
The code is a general toggle handler for a component state. I cant seems to figure out why the first set of code create a new key name property while the second set of code use the accepted parameter.
controlToggle = (property) => {
this.setState({property: !this.state.property})
}
controlToggle = (property) => {
this.setState({[property]: !this.state.property})
}
You make use of [] while setting or getting a dynamic object key. If you do not provide the key within [] it will use the variable name as the key within the object which in your case is property
So for instance
controlToggle = (property) => {
this.setState({property: !this.state.property})
}
The above code will set the state with key as property
While the correct way is
controlToggle = (property) => {
this.setState({[property]: !this.state[property]})
}
I think that's because in JavaScript, for a key-value pair like {XXX: YYY}, it will automatically treat the first XXX as the key/property name of the value, so you have to add the [] brackets to "escape" that pattern to use the variable's value as the key instead of treating it as a string essentially.
More specifically, the stuff inside the [] brackets will be treated as normal JavaScript code and be "calculated"
I have an observable array of objects and I want to pluck out the values using underscore.js
For example:
ko.observableArray([{
id: ko.observable(1),
name: ko.observable("name1")
},
{
id: ko.observable(2),
name: ko.observable("name2")
},
...])
And I just want to pluck the values inside of the object rather than the whole observable.
Can I do this with just one command?
I tried:
_.pluck(myArray(), "id()") and _.pluck(myArray(), "id"())
But these return an array of undefineds and "id is not a function" respectively.
Thanks!
Short answer
Use _.invoke instead of _.pluck
See this sample fiddle.
Long answer
_.pluck(list, propertyName) works as documented:
A convenient version of what is perhaps the most common use-case for map: extracting a list of property values.
Or, as better exlained on lodash docs: _.pluck(collection, path)
Gets the property value of path from all elements in collection.
So, if you do this:
_.pluck(myArray(), "id")
what you get is an array with all the id's. And all of these id's are observables, as in the objects of the original array
But you can use _.invoke(list, methodName, *arguments), which, as documented:
Calls the method named by methodName on each value in the list. Any extra arguments passed to invoke will be forwarded on to the method invocation.
or, on lodash version _.invoke(collection, path, [args])
Invokes the method at path on each element in collection, returning an array of the results of each invoked method. Any additional arguments are provided to each invoked method. If methodName is a function it is invoked for, and this bound to, each element in collection.
In this way, you execute each observable, and get its value as expected:
_.invoke(myArray(), "id")
Mind the viewmodels full of observables!
The first comment to this question has made me include this notice:
The best solution is using ko.toJS to convert all the observables in a view model into a regular JavaScript object, with regular properties. Once you do it, underscore, or any other library, will work as expected.
The _.invoke solution only works for a single level of observables, as this case. If there were several level of nested observables, it will completely fail, because it invokes a function at the end of the path, not at each step of the path, for example, _.invoke wouldn't work for this case:
var advices = [{
person: ko.observable({
name = ko.observable('John')
}),
advice: ko.observable('Beware of the observables!')
}];
In this case, you could only use _.invoke on the first level, like this:
var sentences = _.invoke(advices,'advice');
But this wouldn't work:
var names = _.invoke(advices,'person.name');
In this call, only name would be invoked, but person not, so this would fail, because person is an observable, thus it doesn't have a name property.
NOTE: lodash is another library similar, and mostly compatible with underscore, but better in some aspects
I was able to solve this by using the "map" function:
_.map(myArray(), function(item) {return item.id()});
But I was hoping to use pluck since it's the exact use-case for this type of scenario.
Because name is a function, how about pluck your original array into an array of functions, then using ko.toJS to convert it into string array?
var myArray = ko.observableArray([{
id: ko.observable(1),
name: ko.observable("name1")
},
{
id: ko.observable(2),
name: ko.observable("name2")
}]);
var names = _.pluck(myArray(), 'name');
console.log(ko.toJS(names)); // Output: ["name1", "name2"]
Unwrap it first
_.pluck(ko.toJS(myArray), 'id')
_(ko.toJS(myArray)).pluck('id)