{
  "assessmentTests": {
    "javascript_test": {
      "name": "JavaScript Test",
      "desc": "30 domande su scenari pratici di sintassi e coercizione di tipi, funzioni/scope/closure e this, oggetti/array e strutture dati, e loop degli eventi/async/idiomi prototipali — scopri se il tuo JavaScript rispecchia ciò che una job posting intende per competenza JavaScript.",
      "recommendation": "Il tuo profilo di competenze JavaScript",
      "results": {
        "beginner": {
          "name": "Principiante",
          "desc": "Riesci a scrivere funzioni e oggetti funzionanti, ma le domande che hai sbagliato si concentrano sulla coercizione di tipi e la semantica dei riferimenti piuttosto che sulla sintassi — == che converte silenziosamente i tipi prima di confrontarli, un assegnamento di array che condivide un oggetto piuttosto che copiarlo, perché NaN non è mai uguale a se stesso. Niente di questo riguarda essere scarsi a JavaScript; sono le regole specifiche che confondono le persone che hanno imparato il linguaggio scrivendo codice che funzionava piuttosto che imparando come i valori e i riferimenti funzionano effettivamente. Contano al lavoro perché ognuno di questi è il luogo dove il codice si esegue senza errori e tuttavia fa la cosa sbagliata.",
          "recommendation": "Inizia con tre cose, in questo ordine: perché == coercisce i tipi prima di confrontarli mentre === no, perché assegnare un array o un oggetto a una nuova variabile copia il riferimento piuttosto che il valore, e come var è sollevato e inizializzato a undefined mentre let e const rimangono nella temporal dead zone fino a quando la loro dichiarazione si esegue. La guida JavaScript di MDN copre tutti e tre con esempi eseguibili."
        },
        "intermediate": {
          "name": "Intermedio",
          "desc": "Gestisci comodamente il codice applicativo quotidiano — funzioni, metodi degli array, flusso di controllo semplice — e non saresti rallentato dal lavoro di feature routine. Il divario tra qui e Avanzato è per lo più in ciò che accade quando le regole di scoping e timing di JavaScript interagiscono: una var catturata dentro i callback di un loop tutti che leggono lo stesso valore finale, un this che smette silenziosamente di puntare all'oggetto una volta che un metodo viene staccato da esso, una copia spread che sembra profonda ma copia solo un livello. Questi sono il tipo di bug che passano una lettura veloce e appaiono solo sotto una condizione di runtime specifica.",
          "recommendation": "Concentrati su come scope e this si risolvono effettivamente al momento della chiamata piuttosto che al momento della definizione: perché un loop for basato su var passa a ogni callback lo stesso valore di counter finale mentre let no, come this è determinato da come una funzione è chiamata piuttosto che dove è scritta, e perché uno spread o Object.assign copia solo il livello superiore di un oggetto. Poi il loop degli eventi, poiché è quello che confonde le persone che conoscono già le promise individualmente."
        },
        "advanced": {
          "name": "Avanzato",
          "desc": "Questo è il livello che la maggior parte delle job posting intende con \"JavaScript forte\". Leggi una catena di filter/map/reduce e puoi prevedere esattamente cosa ritorna senza mutare l'array originale, sai perché un console.log sincrono batte sempre una microtask che batte sempre una setTimeout, e usi Promise.all sapendo che rifiuta nel momento in cui una qualsiasi promise rifiuta piuttosto che aspettare il resto. Ciò che separa questa fascia dalla cima è il lato prototipale e del modello di oggetti del lavoro: come la catena prototipale risolve un metodo ereditato rispetto a hasOwnProperty, e cosa un campo di classe privato effettivamente nasconde.",
          "recommendation": "Approfondisci le parti che proteggono lo stato che altro codice tocca anche: come la catena prototipale di JavaScript risolve le ricerche di metodi che non sono sull'istanza stessa, cosa i #fields privati di una classe effettivamente nascondono dall'accesso esterno, e come JSON.stringify tratta undefined e le funzioni diversamente dentro un oggetto piano rispetto a dentro un array. Il materiale di MDN sul loop degli eventi e la catena prototipale sono il passo naturale successivo per entrambi."
        },
        "expert": {
          "name": "Esperto",
          "desc": "Hai segnato il massimo in ogni sezione — sintassi di base, tipi e coercizione; funzioni, scope, closure e this; oggetti, array e strutture dati; e async, il loop degli eventi, prototipi e idiomi. Praticamente, questo significa che puoi ricevere la funzione di uno sconosciuto e spiegare perché ritorna quello che ritorna, non solo quello che la sintassi dice che dovrebbe fare, che è l'abilità più difficile e più preziosa. A questo livello il linguaggio stesso è raramente il fattore limitante; il limite è solitamente il flusso di controllo asincrono o la forma dei dati sottostanti.",
          "recommendation": "I rendimenti sono ora nel design e nella diagnosi: ragionare su una condizione di gara tra Promise.all e Promise.race piuttosto che recitare le loro definizioni, scegliere quando una closure è lo strumento giusto per lo stato privato rispetto a quando un #field privato di una classe lo è, e leggere un bug di ordinamento di microtask-vs-macrotask nei registri di produzione piuttosto che in un quiz. Se sei sottoposto a screening per un ruolo, descrivi un bug di timing che hai trovato — una variabile closure stantia o un callback asincrono fuori ordine — piuttosto che nominare le caratteristiche di JavaScript; dimostra il ragionamento, non solo il vocabolario."
        }
      },
      "questions": [
        {
          "question": "console.log(x);\nvar x = 5;\nCosa stampa questo?",
          "options": [
            {
              "icon": "",
              "label": "5 — le dichiarazioni var si eseguono immediatamente, prima di qualsiasi altro codice"
            },
            {
              "icon": "",
              "label": "ReferenceError: x non è definito"
            },
            {
              "icon": "",
              "label": "undefined — le dichiarazioni var sono sollevate in cima al loro scope e inizializzate a undefined, ma l'assegnamento si esegue in situ, quindi prima che si esegua la variabile esiste ma contiene undefined"
            },
            {
              "icon": "",
              "label": "null"
            }
          ]
        },
        {
          "question": "console.log(y);\nlet y = 5;\nCosa succede?",
          "options": [
            {
              "icon": "",
              "label": "Genera ReferenceError: non puoi accedere a 'y' prima dell'inizializzazione — let è sollevato in cima al suo scope ma rimane nella temporal dead zone fino a quando la linea di dichiarazione effettivamente si esegue"
            },
            {
              "icon": "",
              "label": "Stampa undefined, come farebbe var"
            },
            {
              "icon": "",
              "label": "Stampa 5"
            },
            {
              "icon": "",
              "label": "Genera un SyntaxError al momento del parse"
            }
          ]
        },
        {
          "question": "const arr = [1, 2, 3];\narr.push(4);\nconsole.log(arr.length);\nCosa stampa questo?",
          "options": [
            {
              "icon": "",
              "label": "4 — const impedisce solo di riassegnare il binding arr stesso, non di mutare l'oggetto array a cui punta, quindi push funziona ancora"
            },
            {
              "icon": "",
              "label": "Genera un TypeError, perché arr è const"
            },
            {
              "icon": "",
              "label": "3 — push è bloccato su un array const"
            },
            {
              "icon": "",
              "label": "undefined"
            }
          ]
        },
        {
          "question": "console.log('' == 0);\nconsole.log('' === 0);\nCosa stampano le due linee?",
          "options": [
            {
              "icon": "",
              "label": "true poi true"
            },
            {
              "icon": "",
              "label": "false poi false"
            },
            {
              "icon": "",
              "label": "true poi false — == coercisce la stringa vuota a 0 prima di confrontarli, mentre === confronta tipo e valore senza coercizione, e una stringa non è mai strettamente uguale a un numero"
            },
            {
              "icon": "",
              "label": "false poi true"
            }
          ]
        },
        {
          "question": "console.log(NaN === NaN);\nconsole.log(Number.isNaN(NaN));\nCosa stampano le due linee?",
          "options": [
            {
              "icon": "",
              "label": "true poi true"
            },
            {
              "icon": "",
              "label": "true poi false"
            },
            {
              "icon": "",
              "label": "false poi false"
            },
            {
              "icon": "",
              "label": "false poi true — NaN è l'unico valore in JavaScript che non è uguale a se stesso sotto ===, ma Number.isNaN() lo rileva correttamente comunque"
            }
          ]
        },
        {
          "question": "console.log(typeof null);\nCosa stampa questo?",
          "options": [
            {
              "icon": "",
              "label": "\"null\""
            },
            {
              "icon": "",
              "label": "\"object\" — un bug di lunga data nel linguaggio: typeof null ritorna \"object\" anche se null è un primitivo, ed è stato mantenuto per retrocompatibilità da allora"
            },
            {
              "icon": "",
              "label": "\"undefined\""
            },
            {
              "icon": "",
              "label": "\"boolean\""
            }
          ]
        },
        {
          "question": "Quale dei seguenti è truthy quando usato in una condizione if?",
          "options": [
            {
              "icon": "",
              "label": "0"
            },
            {
              "icon": "",
              "label": "\"\" (una stringa vuota)"
            },
            {
              "icon": "",
              "label": "null"
            },
            {
              "icon": "",
              "label": "\"0\" — una stringa non vuota è sempre truthy in JavaScript, anche quando il suo contenuto è la stringa \"0\""
            }
          ]
        },
        {
          "question": "foo();\nfunction foo() { console.log('a'); }\nbar();\nvar bar = function() { console.log('b'); };\nCosa succede?",
          "options": [
            {
              "icon": "",
              "label": "Entrambe le chiamate stampano, \"a\" poi \"b\""
            },
            {
              "icon": "",
              "label": "foo() stampa \"a\"; bar() genera TypeError: bar non è una funzione — le dichiarazioni di funzione sono completamente sollevate con il loro corpo, ma una function expression assegnata a var solleva solo la var stessa (come undefined), non l'assegnamento"
            },
            {
              "icon": "",
              "label": "Entrambe le chiamate generano ReferenceError"
            },
            {
              "icon": "",
              "label": "foo() genera un errore; bar() stampa \"b\""
            }
          ]
        },
        {
          "question": "function makeCounter() {\n  let count = 0;\n  return function() { count++; return count; };\n}\nconst counter = makeCounter();\nconsole.log(counter());\nconsole.log(counter());\nCosa stampano le due linee?",
          "options": [
            {
              "icon": "",
              "label": "1 poi 1"
            },
            {
              "icon": "",
              "label": "0 poi 1"
            },
            {
              "icon": "",
              "label": "undefined poi undefined"
            },
            {
              "icon": "",
              "label": "1 poi 2 — la funzione ritornata chiude sulla stessa variabile count dello scope di makeCounter, e quella variabile persiste tra le chiamate piuttosto che resettarsi"
            }
          ]
        },
        {
          "question": "for (var i = 0; i < 3; i++) {\n  setTimeout(() => console.log(i), 0);\n}\nCosa stampa questo?",
          "options": [
            {
              "icon": "",
              "label": "0, 1, 2"
            },
            {
              "icon": "",
              "label": "3, 3, 3 — var è function-scoped, non block-scoped, quindi tutti e tre i callback chiudono sulla stessa i, che ha già finito il loop e è uguale a 3 entro il momento in cui uno qualsiasi di loro effettivamente si esegue"
            },
            {
              "icon": "",
              "label": "0, 0, 0"
            },
            {
              "icon": "",
              "label": "undefined, undefined, undefined"
            }
          ]
        },
        {
          "question": "for (let i = 0; i < 3; i++) {\n  setTimeout(() => console.log(i), 0);\n}\nCosa stampa questo?",
          "options": [
            {
              "icon": "",
              "label": "3, 3, 3"
            },
            {
              "icon": "",
              "label": "0, 0, 0"
            },
            {
              "icon": "",
              "label": "undefined, undefined, undefined"
            },
            {
              "icon": "",
              "label": "0, 1, 2 — let crea un binding fresco di i per ogni iterazione del loop, quindi ogni callback chiude sulla sua propria copia separata piuttosto che una variabile condivisa"
            }
          ]
        },
        {
          "question": "function greet() { return `Hi, ${this.name}`; }\nconst person = { name: 'Ana' };\nconsole.log(greet.call(person));\nCosa stampa questo?",
          "options": [
            {
              "icon": "",
              "label": "\"Hi, Ana\" — Function.prototype.call invoca la funzione con this esplicitamente impostato al suo primo argomento, quindi this.name si risolve contro person"
            },
            {
              "icon": "",
              "label": "\"Hi, undefined\" — call() funziona solo su funzioni che sono già metodi di un oggetto"
            },
            {
              "icon": "",
              "label": "Genera un TypeError, perché greet non è un metodo di person"
            },
            {
              "icon": "",
              "label": "\"Hi, ${this.name}\" — call() non valuta il template literal"
            }
          ]
        },
        {
          "question": "const timer = {\n  seconds: 0,\n  start: function() {\n    setInterval(() => { this.seconds++; }, 1000);\n  },\n};\nPerché le persone preferiscono la funzione freccia a function() { this.seconds++ } dentro setInterval qui?",
          "options": [
            {
              "icon": "",
              "label": "Le funzioni freccia non hanno il loro proprio this — catturano this lessicalmente dalla funzione start racchiudente, che è timer (poiché start è stata chiamata come timer.start()), quindi this.seconds si riferisce correttamente a timer.seconds ad ogni tick"
            },
            {
              "icon": "",
              "label": "Le funzioni freccia si eseguono più velocemente delle funzioni normali a runtime"
            },
            {
              "icon": "",
              "label": "Le funzioni freccia associano automaticamente this all'oggetto globale, che capita di essere uguale a timer"
            },
            {
              "icon": "",
              "label": "Le funzioni freccia convertono automaticamente this in una variabile globale"
            }
          ]
        },
        {
          "question": "function multiply(a, b) { return a * b; }\nconst double = multiply.bind(null, 2);\nconsole.log(double(5));\nCosa stampa questo?",
          "options": [
            {
              "icon": "",
              "label": "Genera un errore, perché bind richiede entrambi gli argomenti in anticipo"
            },
            {
              "icon": "",
              "label": "10 — bind ritorna una nuova funzione con this e qualsiasi argomento iniziale pre-impostato; chiamare double(5) fornisce l'argomento rimanente b=5, quindi multiply(2, 5) si esegue"
            },
            {
              "icon": "",
              "label": "NaN"
            },
            {
              "icon": "",
              "label": "7, perché bind aggiunge i suoi argomenti alla chiamata piuttosto che sostituirli"
            }
          ]
        },
        {
          "question": "function outer() {\n  let x = 10;\n  function inner() {\n    let x = 20;\n    console.log(x);\n  }\n  inner();\n  console.log(x);\n}\nouter();\nCosa stampano le due chiamate console.log?",
          "options": [
            {
              "icon": "",
              "label": "20 poi 20"
            },
            {
              "icon": "",
              "label": "20 poi 10 — il proprio let x di inner oscura il x di outer solo dentro lo scope di inner; il proprio x di outer non è mai toccato"
            },
            {
              "icon": "",
              "label": "10 poi 10"
            },
            {
              "icon": "",
              "label": "Genera un ReferenceError, perché x è dichiarato due volte"
            }
          ]
        },
        {
          "question": "const a = [1, 2, 3];\nconst b = a;\nb.push(4);\nconsole.log(a.length);\nCosa stampa questo?",
          "options": [
            {
              "icon": "",
              "label": "3 — b è una copia separata di a"
            },
            {
              "icon": "",
              "label": "undefined"
            },
            {
              "icon": "",
              "label": "Genera un TypeError, perché a è const"
            },
            {
              "icon": "",
              "label": "4 — gli array sono oggetti, quindi const b = a copia il riferimento, non l'array; mutare b attraverso push muta lo stesso array esatto a cui a punta"
            }
          ]
        },
        {
          "question": "const original = { name: 'Ana', tags: ['x', 'y'] };\nconst copy = { ...original };\ncopy.name = 'Bea';\ncopy.tags.push('z');\nconsole.log(original.name, original.tags.length);\nCosa stampa questo?",
          "options": [
            {
              "icon": "",
              "label": "'Ana' 2 — spread deep-clona ogni oggetto e array annidato"
            },
            {
              "icon": "",
              "label": "'Ana' 3 — spread è solo una copia superficiale: una proprietà primitiva come name è copiata per valore, quindi riassegnare copy.name non tocca mai original, ma un array annidato come tags è copiato per riferimento, quindi pushare in copy.tags muta lo stesso array esatto a cui original.tags punta"
            },
            {
              "icon": "",
              "label": "'Bea' 3 — spread copia tutto per riferimento, quindi sia i cambiamenti di livello superiore che annidati si riportano a original"
            },
            {
              "icon": "",
              "label": "'Bea' 2"
            }
          ]
        },
        {
          "question": "const { a: x = 10, b: y = 20 } = { a: 5 };\nconsole.log(x, y);\nCosa stampa questo?",
          "options": [
            {
              "icon": "",
              "label": "undefined undefined"
            },
            {
              "icon": "",
              "label": "5 undefined"
            },
            {
              "icon": "",
              "label": "10 20"
            },
            {
              "icon": "",
              "label": "5 20 — a è rinominato a x ed è presente, quindi mantiene il suo valore 5; b è rinominato a y ed è assente, quindi torna al suo default 20"
            }
          ]
        },
        {
          "question": "const [first, ...rest] = [1, 2, 3, 4];\nconsole.log(rest);\nCosa stampa questo?",
          "options": [
            {
              "icon": "",
              "label": "[1, 2, 3, 4]"
            },
            {
              "icon": "",
              "label": "[2, 3, 4] — rest raccoglie ogni elemento rimanente dopo first in un array completamente nuovo"
            },
            {
              "icon": "",
              "label": "2"
            },
            {
              "icon": "",
              "label": "[1]"
            }
          ]
        },
        {
          "question": "const nums = [10, 1, 2];\nnums.sort();\nconsole.log(nums);\nCosa stampa questo?",
          "options": [
            {
              "icon": "",
              "label": "[1, 2, 10] — sort ordina sempre i numeri numericamente in ordine crescente per impostazione predefinita"
            },
            {
              "icon": "",
              "label": "[10, 1, 2] — sort non muta l'array originale"
            },
            {
              "icon": "",
              "label": "[1, 10, 2] — il comparatore predefinito di Array.prototype.sort converte gli elementi in stringhe e li confronta lessicograficamente, quindi \"10\" ordina prima di \"2\"; sort muta anche l'array in situ piuttosto che ritornare uno nuovo"
            },
            {
              "icon": "",
              "label": "[2, 1, 10]"
            }
          ]
        },
        {
          "question": "const user = { profile: { age: 0 } };\nconsole.log(user.profile?.age ?? 'unknown');\nconsole.log(user.address?.city ?? 'unknown');\nCosa stampano le due linee?",
          "options": [
            {
              "icon": "",
              "label": "'unknown' poi 'unknown' — ?? tratta 0 come mancante, lo stesso modo in cui || lo fa"
            },
            {
              "icon": "",
              "label": "0 poi 'unknown' — ?? torna indietro solo su null o undefined, non su altri valori falsy come 0, quindi age (0) viene mantenuto così com'è; user.address è undefined, quindi ?. cortocircuita l'intera catena a undefined e ?? poi fornisce 'unknown'"
            },
            {
              "icon": "",
              "label": "0 poi undefined"
            },
            {
              "icon": "",
              "label": "'unknown' poi 0"
            }
          ]
        },
        {
          "question": "const obj = { a: undefined, b: function(){}, c: NaN, d: [undefined, function(){}, 1] };\nconsole.log(JSON.stringify(obj));\nCosa stampa questo?",
          "options": [
            {
              "icon": "",
              "label": "'{\"a\":null,\"b\":null,\"c\":null,\"d\":[null,null,1]}' — ogni valore non supportato diventa null ovunque, in oggetti e array allo stesso modo"
            },
            {
              "icon": "",
              "label": "'{\"a\":undefined,\"b\":undefined,\"c\":NaN,\"d\":[undefined,null,1]}'"
            },
            {
              "icon": "",
              "label": "'{\"c\":null,\"d\":[null,null,1]}' — le proprietà degli oggetti il cui valore è undefined o una funzione sono omesse interamente, e NaN si serializza a null, ma dentro un array questi stessi valori non supportati diventano null invece di essere scartati, perché rimuovere un elemento dell'array sposterebbe ogni indice successivo"
            },
            {
              "icon": "",
              "label": "Genera un TypeError, perché NaN non può essere serializzato a JSON"
            }
          ]
        },
        {
          "question": "console.log('1');\nsetTimeout(() => console.log('2'), 0);\nPromise.resolve().then(() => console.log('3'));\nconsole.log('4');\nIn quale ordine questi stampano?",
          "options": [
            {
              "icon": "",
              "label": "1, 2, 3, 4"
            },
            {
              "icon": "",
              "label": "1, 4, 2, 3"
            },
            {
              "icon": "",
              "label": "1, 4, 3, 2 — il codice sincrono si esegue per primo (quindi 1 e 4 stampano immediatamente), poi la microtask queue (callback delle Promise) si svuota completamente prima che l'event loop vada al prossimo macrotask, quindi 3 stampa prima del callback di setTimeout di 2"
            },
            {
              "icon": "",
              "label": "1, 3, 4, 2"
            }
          ]
        },
        {
          "question": "async function foo() {\n  console.log('a');\n  await null;\n  console.log('b');\n}\nconsole.log('start');\nfoo();\nconsole.log('end');\nIn quale ordine questi stampano?",
          "options": [
            {
              "icon": "",
              "label": "start, a, end, b — foo() si esegue sincronamente fino al suo primo await, quindi 'a' si registra immediatamente quando foo() è chiamata; l'await poi sospende foo e ritorna il controllo al caller, quindi 'end' si registra prima del ripristinato 'b', che si esegue più tardi come una microtask"
            },
            {
              "icon": "",
              "label": "start, a, b, end"
            },
            {
              "icon": "",
              "label": "start, end, a, b"
            },
            {
              "icon": "",
              "label": "a, start, end, b"
            }
          ]
        },
        {
          "question": "Promise.all([\n  Promise.resolve(1),\n  Promise.reject('err'),\n  Promise.resolve(3),\n]).then(r => console.log('ok', r)).catch(e => console.log('fail', e));\nCosa stampa questo?",
          "options": [
            {
              "icon": "",
              "label": "'fail err' — Promise.all rifiuta non appena una qualsiasi delle sue promise di input rifiuta, ignorando i risultati delle altre, quindi il gestore catch si esegue con la ragione di quel rifiuto"
            },
            {
              "icon": "",
              "label": "'ok' [1, 3]"
            },
            {
              "icon": "",
              "label": "'ok' [1, undefined, 3]"
            },
            {
              "icon": "",
              "label": "Genera sincrono e nessun gestore non si esegue mai"
            }
          ]
        },
        {
          "question": "const fast = new Promise(res => setTimeout(() => res('fast'), 10));\nconst slow = new Promise(res => setTimeout(() => res('slow'), 100));\nPromise.race([fast, slow]).then(v => console.log(v));\nCosa stampa questo?",
          "options": [
            {
              "icon": "",
              "label": "'slow'"
            },
            {
              "icon": "",
              "label": "['fast', 'slow']"
            },
            {
              "icon": "",
              "label": "'fast' — Promise.race si risolve non appena la prima delle sue promise di input si risolve, e il timer di 10ms si risolve ben prima di quello di 100ms"
            },
            {
              "icon": "",
              "label": "Genera un errore, perché race richiede esattamente due promise"
            }
          ]
        },
        {
          "question": "function Animal(name) { this.name = name; }\nAnimal.prototype.speak = function() { return `${this.name} makes a sound`; };\nconst dog = new Animal('Rex');\nconsole.log(dog.speak());\nconsole.log(dog.hasOwnProperty('speak'));\nCosa stampano le due linee?",
          "options": [
            {
              "icon": "",
              "label": "'Rex makes a sound' poi true"
            },
            {
              "icon": "",
              "label": "undefined poi false"
            },
            {
              "icon": "",
              "label": "Genera un TypeError, perché dog non ha il metodo speak di suo"
            },
            {
              "icon": "",
              "label": "'Rex makes a sound' poi false — speak è definito su Animal.prototype, non sull'istanza dog stessa; dog lo trova attraverso la catena prototipale quando è chiamato, ma hasOwnProperty controlla solo le proprietà proprie dell'istanza, non niente di ereditato"
            }
          ]
        },
        {
          "question": "class Counter {\n  #count = 0;\n  increment() { this.#count++; return this.#count; }\n}\nconst c = new Counter();\nconsole.log(c.increment());\nconsole.log(c.count);\nCosa stampano le due linee?",
          "options": [
            {
              "icon": "",
              "label": "1 poi undefined — #count è un campo di classe privato, leggibile e scrivibile solo dall'interno dei metodi propri della classe; c.count (senza #) è una proprietà ordinaria completamente diversa che non è mai stata impostata, quindi è undefined"
            },
            {
              "icon": "",
              "label": "1 poi 0"
            },
            {
              "icon": "",
              "label": "1 poi 1"
            },
            {
              "icon": "",
              "label": "Genera un SyntaxError quando accedi a c.count"
            }
          ]
        },
        {
          "question": "const items = ['a', 'b'];\nconst label = `Items: ${items.length > 0 ? items.join(', ') : 'none'}`;\nconsole.log(label);\nCosa stampa questo?",
          "options": [
            {
              "icon": "",
              "label": "'Items: ${items.length > 0 ? items.join(\\', \\') : \\'none\\'}'"
            },
            {
              "icon": "",
              "label": "'Items: none'"
            },
            {
              "icon": "",
              "label": "'Items: a, b' — i template literal valutano qualsiasi espressione posizionata dentro ${...}, incluso un ternario completo, e interpolano il suo risultato direttamente nella stringa"
            },
            {
              "icon": "",
              "label": "Genera un SyntaxError, perché i ternari non sono consentiti dentro i template literal"
            }
          ]
        },
        {
          "question": "const nums = [1, 2, 3, 4, 5];\nconst result = nums.filter(n => n % 2 === 0).map(n => n * 10).reduce((sum, n) => sum + n, 0);\nconsole.log(result, nums);\nCosa stampa questo?",
          "options": [
            {
              "icon": "",
              "label": "60 [1, 2, 3, 4, 5] — filter, map e reduce ognuno ritorna un nuovo array o valore senza mutare l'array originale, quindi nums è invariato mentre result è la somma finale ridotta (2 e 4, raddoppiati a 20 e 40, sommati a 60)"
            },
            {
              "icon": "",
              "label": "60 [2, 4, 20, 40]"
            },
            {
              "icon": "",
              "label": "150 [1, 2, 3, 4, 5]"
            },
            {
              "icon": "",
              "label": "60 [20, 40]"
            }
          ]
        }
      ],
      "optionOrderVersion": "50fc0eba818f2d72"
    }
  }
}
