This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 5 years ago.
Is there a better way to do the following. consider this code:
this.state = {
dates: [
{date: '1st', matches:[]},
{date: '2nd', matches:[]},
{date: '3rd', matches:[]},
{date: '4th', matches:[]},
{date: '5th', matches:[]}
]
}
addToDates = () => {
let dates = this.state.dates;
const matches = this.props.matches;
matches.forEach(function(match){
dates.forEach(function(date){
if (match.date == date.date){
this.setState({dates: this.state.dates.concat(match)})
}
})
})
}
what i am trying to do is iterate through 2 arrays and if i find a match that has the same date as a date then i want to add it to the matches array.
2 problems, firstly is there a better way to compare 2 arrays rather than iterating through both?
secondly i get cant read setState of undefined even though i have:
this.addToDates = this.addToDates.bind(this) bound it in my constructor. i thought arrow functions solved that scoping too?
You need to use arrow functions in your addToDate method. You don't actually have to bind addToDates in your constructor as you are using an arrow function as a class property.
The value of this when you are using this.setState is different if you don't use an arrow functions for your forEach loops.
addToDates = () => {
let dates = this.state.dates;
const matches = this.props.matches;
matches.forEach(match =>{
dates.forEach(date =>{
if (match.date == date.date){
this.setState({dates: this.state.dates.concat(match)})
}
});
});
As per MDN
Until arrow functions, every new function defined its own this value
(a new object in the case of a constructor, undefined in strict mode
function calls, the base object if the function is called as an
"object method", etc.). This proved to be annoying with an
object-oriented style of programming.
An arrow function does not create its own this, the this value of the
enclosing execution context is used.
Related
I'm looking for a better syntax for writing the following code, and I would like to know if there is an option for assigning the return value of a function by using a destructuring assignment:
const object = {
property: 10,
getFunction() {
return "getFunction value";
}
}
const {property, getFunction} = object;
console.log("Property: ", property, " getFunction: ", getFunction);
Here, this code returns the following, which is totally normal:
"Property: 10, getFunction: [Function: getFunction]"
I'd like to know if there is a syntax option to write something like: (won't work)
const {property, getFunctionValue: getFunction()} = object;
And get the "getFunction value" from the assignment.
Unfortuntely, the syntax you're looking for doesn't exist (I've also wanted to do it many, many times). You can't call a function you're retrieving as part of a destructuring operation.¹ You're not allowed to use an arbitrary expression for the "from" part of a destructuring pattern. Destructuring always does property access, not function calls.
You'll have to do it separately, e.g.:
const { property } = object;
const getFunctionValue = object.getFunction();
or similar.
¹ unless it's the getter function for an accessor property
This question already has answers here:
JavaScript set object key by variable
(8 answers)
Closed 2 years ago.
I am trying to get a static Java-like map object working in Javascript. I am not a javascript expert, but am wondering if this is possible. What I am trying to do is the following:
I am defining
const MY_CONST_1 = 'Constant 1 value';
const MY_CONST_2 = 'Constant 2 value';
and a "map-like" object like this:
const CONST_AMOUNT_MAP = {
MY_CONST_1: 30,
MY_CONST_2: 22
}
Then, in a function I define:
function getAmount(constValue) {
return CONST_AMOUNT_MAP[constValue];
}
My expectation would be that the above function when called with
getAmount('Constant 1 value')
returned the number "30". However,
CONST_AMOUNT_MAP[constValue];
returns "undefined". Only
CONST_AMOUNT_MAP[MY_CONST_1]
returns the correct amount.
Is it possible to define an Object such as CONST_AMOUNT_MAP that allows to lookup entries based on pre-defined const variables rather than based on the actual value of the consts?
Thank you
When you define an object literal, the key names are given literally - they're not evaluated. In other words:
const CONST_AMOUNT_MAP = {
MY_CONST_1: 30,
MY_CONST_2: 22
}
...makes an object with a key named MY_CONST_1, not the value of any variable you've defined with the name MY_CONST_1.
You can achieve what you're after by instead declaring your keys wrapped in [], which will force the enclosed to be evaluated.
const CONST_AMOUNT_MAP = {
[MY_CONST_1]: 30,
[MY_CONST_2]: 22
}
Or
const CONST_AMOUNT_MAP = {};
CONST_AMOUNT_MAP[MY_CONST_1] = 30;
CONST_AMOUNT_MAP[MY_CONST_2] = 22;
Note that the keys, however you add them, must be strings or symbols. Since you mention 'map', be aware that there are true maps in JS, in which the keys can be of any data type.
This question already has answers here:
In JavaScript, how to conditionally add a member to an object?
(29 answers)
Closed 2 years ago.
I'm aware with ES6 JavaScript object you can dynamically declare variables as object keys, using [], for example:
{[2 + 2]: "four!"}
gives the output {"4": "four!"}
the question is, can a similar method be done in order to add an entire property, through variables etc., inline? Meaning, like suppose I have the following test object:
var myObj = {
someProp: 2,
someOtherProp: 3 //only add this prop if a condition is met
}
is there anything I can write in the inline object for someOtherProp, to only have it be added to the object, if a certain condition is met? So for example (pseudocode), something like this
var myObj = {
someProp: 2,
[someBool ? null : "someOtherProp: 3"] //only add this prop if a condition is met
}
would give the ouput (considering someBool is true), like the above, but if someBool is false, it would give me
var myObj = {
someProp: 2
}
??
I'm aware I can simply add a property (or delete one) to (/from) the object later, using the [] indexer, like
someBool && (myObj["someOtherProp"] = 3)
as well as make some kind of helper function for this,
but I was wondering if there was a way to do it using the inline-object notation?
You could spread an object with a conditional operator.
{} is a neutral value.
var myObj = {
someProp: 2,
...(someBool ? {} : { someOtherProp: 3 })
}
This question already has answers here:
ECMAScript 6 arrow function that returns an object
(6 answers)
Closed 3 years ago.
Following is my code which is giving Parsing error -
Code -
const { dataArr, anotherDataArr } = this.props.data
const myArr1 = dataArr.map(item => {'label': item.name,'value': item.code})
const myArr2 = anotherDataArr.map(item => { 'label': item.name, 'value': item.code})
this.setState({
newArr1: myArr1,
newArr2: myArr2,
})
myArr1, myArr2 should be an array of objects but I am getting parsing error. Let me know what silly mistake I am making here.
When you need to implicitly return an object from an arrow function wrap that object in (). Wrapping with () will make make the object expression. Without () {} will considered as block.
According to Returning object literals:
The code inside braces {} is parsed as a sequence of statements
Remember to wrap the object literal in parentheses().
const myArr1 = dataArr.map(item => ({'label': item.name,'value': item.code}))
const myArr2 = anotherDataArr.map(item => ({ 'label': item.name, 'value': item.code}))
This question already has answers here:
Methods in ES6 objects: using arrow functions
(6 answers)
Closed 5 years ago.
Cannot reproduce MDN's example («Using an object in an array-like fashion») with arrow-function-based method.
> let obj = {
... length: 0,
... addEl: el => [].push.call(this, el={}) //default argument
... };
It counts something, but… what? It definitely stores the incrementing value somewhere, but where?
> obj.addEl();
1
> obj.addEl({});
2
> obj
{ length: 0, addEl: [Function: addEl] } // array function «this» problem?
The original variant increments the length the right way, but it also creates new properties. There was nothing about it in the example.
addEl: function (el) { [].push.call(this, el) }
...
// the function in work
> anotherObj.addEl();
> anotherObj.addEl('new');
> anotherObj
{ '0': undefined,
'1': 'new',
length: 2,
addEl: [Function: addEl] }
Is it ok? If so, I guess, it should be called «creating array-like object», meaning not only the length property, but the numeric keys too. Related, already answered question is here.
The incrementing value is stored in window because arrow functions don’t bind this. Their this value is that of the enclosing scope, which in this case is the global scope. For example:
let obj = {
length: 0,
addEl: el => [].push.call(this, el={}) //default argument
};
console.log(obj.addEl());
console.log(window.length);
The window.length is the incrementing value. The reason obj.addEl() returns the incrementing value is because Array#push returns the new length. And if you log window[0], you’ll get the default argument that was pushed to this, which was window:
> window[0]
< {}
The reason why regular function expressions behave differently is because they are bound to the object obj so this refers to obj in a regular function expression opposed to window in an arrow function.
It is because you are using arrow functions which does not bind this, using a normal function would give you the result.
addEl: el => [].push.call(this, el={})
this in your case refers to the global window object