-1

this block of code takes the values of the scored property and puts them in duplication object as a key and how many times the name got duplicated as a value using the || operator. I understand that the || operator will return the first truthy value or the last value if all of the values are falsy, however, I didn't understand duplication[x]++ what does the ++ sign do exactly? and why we put the (duplication[x]=1) between parentheses

const game = {
  score: "4:0",
  scored: ["Lewandowski", "Gnarby", "Lewandowski", "Hummels"],
}; 


const duplication = {};
for (let x of game.scored) {
 duplication[x]++ || (duplication[x]=1) // I'm confused in this line
}
 
console.log(duplication);
MrXQ
  • 465
  • 8
  • 25
  • `||` is not a "short circuit" operator. It's the logical "or" operator. It runs "a or b", so it runs `duplication[x]++` and if that's falsey, it then runs `(duplication[x]=1)`. Also, remember to write your post about the thing you actually want to know: if you don't know what `++` does, or why someone would add `()`, then [ask about that](/help/how-to-ask). But of course, only after searching the web/SO for explanations (which for `++` is trivial, there are thousands of pages that explain what that does). – Mike 'Pomax' Kamermans Nov 12 '21 at 18:14
  • 1
    "so it runs duplication[x]++ and if that's falsey, it then runs (duplication[x]=1)" - almost literally the definition of a short circuit evaluation; evaluation is stopped if evaluating the other side of the operator would not change the result, ie `true || x` or `false && x`. – msbit Nov 12 '21 at 18:33
  • @Mike'Pomax'Kamermans next time I will search more before asking, Thank you for your correction about `||` . – MrXQ Nov 12 '21 at 19:15
  • 1
    Almost literally is not literally: JS does not call it the "shortcircuit operator", so that's not what it is when we're talking about JS. It is the [logical or operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_OR), which you can _use_ to short circuit a conditional. Using the right terms, and learning the right terms, when asking a technical question always matters. – Mike 'Pomax' Kamermans Nov 12 '21 at 19:19
  • 1
    @Mike'Pomax'Kamermans I think I see the grain of sand at the centre of this pearl. I would agree that `||` is not _the_ short-circuit operator, and I imagine you would agree that `||` is _a_ short-circuit operator (if not explicitly named so in ECMA-262). If not, that's fine too ✌️ – msbit Nov 13 '21 at 03:05

3 Answers3

3

Let's see what's happing on this line :

duplication[x]++ || (duplication[x]=1)
  1. duplication[x]++ , first duplication[x] it will check if duplication has any with value of x, if yes then it it will perform duplication[x]++ else it will be undefined to moved to the other part of or condition

  2. duplication[x]=1, this is a simple assignment it will assign the value 1, duplication[x] and this will create a key if not exist in the duplication object

Now if you run the below script and check the console log for each loop, it will give you clear idea what actually happing.

const game = {
  score: "4:0",
  scored: ["Lewandowski", "Gnarby", "Lewandowski", "Hummels"],
}; 


const duplication = {};
let index = 0;

for (let x of game.scored) {

  console.log( `INDEX : ${index} ` , x , duplication[x] ? 'FOUND , INCREMENT CURRENT VALUE WITH ++' : 'NOT FOUND, SO ASSIGN VALUE 1' );
  duplication[x]++ || (duplication[x]=1)
  console.log( `INDEX : ${index} \n` , duplication);
  index++;

}
 
console.log( 'FINAL OBJECT \n' , duplication);
Vivek Doshi
  • 56,649
  • 12
  • 110
  • 122
  • 1
    "if yes then it it will perform `duplication[x]++` else it will be undefined" - very close, it will post-increment regardless of what value is currently in `duplication[x]` but test against what is in `duplication[x]` before the increment. I'm actually not sure if that qualifies as undefined behaviour; it seems possible to me that the post increment could occur after the assignment (`duplication[x] = 1`). Personally I'd consider `duplication[x] = (duplication[x] || 0) + 1` – msbit Nov 12 '21 at 18:31
  • Yes, agreed! but I am just trying to explain the current code as OP is bit confused, your approach is better and more clear. @msbit – Vivek Doshi Nov 12 '21 at 18:33
  • @VivekDoshi Thank you so much for this detailed answer, now I can understand the general idea of this line however I have two questions 1- When I was changing some stuff to understand the code I noticed that changing `duplication[x]++` to `duplication[x]+=1` returns `NaN` and I didn't understand why, It is clearly a number... 2- when I remove the parenthesesfrom `(duplication[x]=1)` it gives this error: Invalid left-hand side in assignment . Why I can't assign `duplication[x]=1` without putting it inside a parentheses – MrXQ Nov 12 '21 at 18:41
  • 2
    @MrXQ, read this one, https://stackoverflow.com/a/43414179/2349407, this might help you with your queries – Vivek Doshi Nov 12 '21 at 18:54
2

The non-descriptive variable names don't really help to explain the situation. Let's start of by rewriting the code with more descriptive variable names.

const game = {
  score: "4:0",
  scored: ["Lewandowski", "Gnarby", "Lewandowski", "Hummels"],
}; 


const goals = {};
for (const player of game.scored) {
  goals[player]++ || (goals[player] = 1);
}
 
console.log(goals);

goals[player]++ increments the goals for player by 1 and returns the old value. The tricky thing in goals[player]++ is that player might not be present in goals yet. In which case undefined is returned (which is falsy). Because the value is falsy the second operand of the OR operator will be executed. (goals[player] = 1) will set the goals for player to 1.

The code is essentially counting how often a specific name is present in the game.scored array. The presence of a name symbolises a goal made by them.

A less cryptic way of writing similar code would be:

const goals = {};
for (const player of game.scored) {
  if (player in goals) {
    goals[player] += 1; // add 1 to the current score
  } else {
    goals[player] = 1; // no score present so use 1
  }
}

However I usually prefer to set a default value, this way you don't have to split the logic into two actions:

const goals = {};
for (const player of game.scored) {
  goals[player] ||= 0; // assign 0 if the current value is falsy
  goals[player] += 1;  // add 1 to the current value
}

Note that ||= is fairly new, if you write JavaScript for older browser you can use the following instead:

if (!goals[player]) goals[player] = 0;
3limin4t0r
  • 19,353
  • 2
  • 31
  • 52
  • Thank you for your detailed answer! I have 2 more questions please : 1- When I was changing some stuff to understand the code I noticed that changing `duplication[x]++` to `duplication[x]+=`1 returns `NaN` and I didn't understand why It is clearly a number... 2- when I remove the parentheses from `(duplication[x]=1)` it gives this error: Invalid left-hand side in assignment. Why I can't assign `duplication[x]=1` without putting it inside a parentheses. – MrXQ Nov 12 '21 at 18:48
  • @MrXQ 1. If `value` is not defined yet (`undefined`) then `undefined + 1 //=> NaN`. Because `value++` returns the **old** value the return value will be `undefined`. `++value` and `value += 1` do the same thing as `value++` but they return the **new** value (`NaN`) instead of the old value. Though all three scenarios do leave `value` set to the value `NaN` (which is also falsy). (1/2) – 3limin4t0r Nov 12 '21 at 18:57
  • 1
    2. The reason you cannot remove the parentheses is because `||` has a higher [precedence](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence) than `=`. Therefore `goals[player]++ || goals[player] = 1` will be evaluated as `(goals[player]++ || goals[player]) = 1`, which causes the error because it is an invalid JavaScript expression. (2/2) – 3limin4t0r Nov 12 '21 at 18:59
1

The first part of

duplication[x]++ || (duplication[x] = 1)
^^^^^^^^^^^^^^^^

has four parts:

  1. a variable duplication with
  2. a property accessor x in bracket notation
  3. a postfix increment operator ++ and
  4. an expression for the logical OR || operator.

The second part returns undefined at the first call with an unknown property.

The try to increment this value returns NaN, because of the following operation of duplication[x] = duplication[x] + 1. The result is is a falsy value.

This forces the expression to evaluate the right hand part of logical OR.

And because the left hand part has an expression, it needs to be evaluated first with a grouping operator (). Now the assignment takes place and the result of 1 is returned to the OR.

Nina Scholz
  • 376,160
  • 25
  • 347
  • 392