简体   繁体   中英

JavaScript advanced reduce function I can't get my head around {}[iteration]

I just can't understand this concept in the function below:

acc[line[0]]

I really can't get my head around that piece of code, how come it is not be an error and works perfectly? How do you interpret it in English words? In my head it is an empty object acc {} at its first iteration and according to the piece of code is trying to access the iterated line at its first value [0]. How come it works without the need of inverted commas as well? And how does line[0] ended up to be the values of the object?

Here is the full code:

let output = [["mark johansson", "waffle iron", "80", "2"], 
 ["mark johansson", "blender", "200", "1"],
 ["mark johansson", "knife", "10", "4"],
 ["Nikita Smith", "waffle iron", "80", "1"],
 ["Nikita Smith", "knife", "10", "2"],
 ["Nikita Smith", "pot", "20", "3"]]

let result =output.reduce((acc,line)=>{
            acc[line[0]] = acc[line[0]] || []
            acc[line[0]].push({
            name: line[1],
            price: line[2],
            quant: line[3]
            })
           return acc
},{})

console.log(JSON.stringify(result,null,1))

{
 "mark johansson": [
  {
   "name": "waffle iron",
   "price": "80",
   "quant": "2"
  },
  {
   "name": "blender",
   "price": "200",
   "quant": "1"
  },
  {
   "name": "knife",
   "price": "10",
   "quant": "4"
  }
 ],
 "Nikita Smith": [
  {
   "name": "waffle iron",
   "price": "80",
   "quant": "1"
  },
  {
   "name": "knife",
   "price": "10",
   "quant": "2"
  },
  {
   "name": "pot",
   "price": "20",
   "quant": "3"
  }
 ]
}

  

Maybe if we replace all the dynamic references with hard-coded values from the first array - or line - in output , it will be clearer as to what is going on. This is essentially what the very first iteration of the reducer function is doing:

output.reduce((acc, ["mark johansson", "waffle iron", "80", "2"])=>{
    acc["mark johansson"] = acc["mark johansson"] || [];
    acc["mark johansson"].push({
        name: "waffle iron",
        price: "80",
        quant: "2"
    });
    return acc
},{})

Imagine that the first line of the reducer function just said acc["mark johansson"] = acc["mark johansson"] . Since there is no key on the object acc with the name "mark johansson" , after evaluating that expression the object acc would look like:

acc = {
    "mark johansson": undefined
}

However, by adding || [] || [] onto the end of the expression, we can evaluate whether acc["mark johansson"] is truthy before we actually set the key/value pair. Since undefined is falsy, the || operater kicks in and we get this instead:

acc = {
    "mark johansson": []
}

Do you see the difference? With the OR operator we are saying: "either acc["mark johansson"] exists and is therefore truthy, and we set it as itself, OR it is falsy and we set it as a blank array". The rest of the code should be fairly self explanatory. The key/value pair is now guaranteed to exist and we can push the data object to the array. Any further lines which reference acc["mark johansson"] will target the already existing entry.

It helps if you console log after each step to see what is going on:

 let output = [ ["mark johansson", "waffle iron", "80", "2"], ["mark johansson", "blender", "200", "1"], ["mark johansson", "knife", "10", "4"], ["Nikita Smith", "waffle iron", "80", "1"], ["Nikita Smith", "knife", "10", "2"], ["Nikita Smith", "pot", "20", "3"] ] let result = output.reduce((acc, line) => { console.log("acc value at start:", acc, "current line value:", line) acc[line[0]] = acc[line[0]] || [] //either a new key will appear with an empty array as the value, or the acc will appear unchanged console.log("acc value after key configuration:", acc) acc[line[0]].push({ name: line[1], price: line[2], quant: line[3] }) //there will be one new object within one of the keys' array value; //acc will appear the same in the first console log of the next cycle console.log("acc after current line values pushed as new object:", acc) return acc }, {}) console.log(JSON.stringify(result))
The code snippet above has notes detailing what to look for in the console logs, below is the actual line by line explaination:

 //pass {} as the initial value (acc) and cycle through each inner array within output array as current value(line) let result = output.reduce((acc,line)=>{ //if line[0], which is the name in each inner array, already exists as a key //then equate key to equal its current value as to not overwrite //otherwise equate key to equal a new empty array //basically, whenever line[0] value changes to another name, a new key will be created acc[line[0]] = acc[line[0]] || [] //now push the other values of the current inner array //into the key which matches that inner arrays first value(which is the name) acc[line[0]].push({ name: line[1], price: line[2], quant: line[3] }) //pass the object to the next cycle return acc },{})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM