50 preguntas de JavaScript





隆Buen dia amigos!



Traigo a su atenci贸n un peque帽o cuestionario interactivo de JavaScript, que actualmente consta de 50 preguntas.



En mi opini贸n, resolver estos problemas es la mejor manera de determinar su nivel de habilidad.



Continuado aqu铆 .



Prefacio



Esta parte se basa en este repositorio . Su autora, Lydia Hallie, posiciona su proyecto como una lista de preguntas avanzadas y, de hecho, entre ellas hay algunas que, creo, incluso un desarrollador experimentado de JavaScript encontrar谩 dif铆cil. Sin embargo, entre estas preguntas tambi茅n hay aquellas para las cuales es suficiente tener conocimientos b谩sicos para responder. Hay una traducci贸n al ruso en el repositorio, pero, por decirlo suavemente, deja mucho que desear, por lo que la mayor铆a de las respuestas (explicaciones) tuvieron que traducirse nuevamente.



Cabe se帽alar que las explicaciones (respuestas) proporcionadas no siempre revelan completamente la esencia del problema. Esto se debe a la forma del proyecto: es una lista de verificaci贸n, no un tutorial. Las respuestas son m谩s bien una pista para futuras b煤squedas en MDN oJavascript.ru . Sin embargo, muchas de las explicaciones contienen respuestas completas.



A pesar de que el c贸digo ha sido probado muchas veces, nadie es inmune a los errores, por supuesto, excepto aquellos que no hacen nada. Por lo tanto, si encuentra errores, errores tipogr谩ficos, imprecisiones, redacci贸n incorrecta, etc., as铆 como si desea mejorar la traducci贸n, escriba un mensaje personal, se lo agradecer茅 (tambi茅n se recomienda la actividad en GitHub).



En realidad, eso es todo lo que quer铆a decir como prefacio.



reglas



Las reglas son simples: 50 preguntas, 3-4 respuestas posibles, calificaci贸n: n煤mero de respuestas correctas e incorrectas, progreso: n煤mero y n煤mero de preguntas.



Seg煤n los resultados, se determina el porcentaje de respuestas correctas y se llega a una conclusi贸n sobre el nivel de dominio de JavaScript: m谩s del 80% es excelente, m谩s del 50% no es malo, menos del 50% ... bueno, ya entiendes.



Se adjunta una explicaci贸n a cada pregunta. Si la respuesta es incorrecta, se revela esta explicaci贸n.



Debido al hecho de que el n煤mero de respuestas correctas e incorrectas, as铆 como el n煤mero de serie de la pregunta, se registran en el almacenamiento local, tiene la oportunidad de hacer una pausa, tomar un descanso y en cualquier momento continuar desde el lugar donde lo dej贸.



Pasemos de la prueba en s铆.



Examen





El c贸digo del proyecto est谩 aqu铆 .



Compartimos los resultados en los comentarios.



Mec谩nica



Algunas palabras sobre c贸mo se implementa el cuestionario para aquellos que est茅n interesados.



El marcado se ve as铆:



<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>200+   JavaScript</title>
    <!--  -->
    <link href="https://fonts.googleapis.com/css2?family=Ubuntu&display=swap" rel="stylesheet">
    <!--  -->
    <link rel="stylesheet" href="style.css">
    <!--     "" -->
    <script type="module" src="script.js"></script>
</head>
<body></body>


A帽adir estilos m铆nimos:



CSS:
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    font-family: Ubuntu, sans-serif;
    font-size: 1em;
    text-align: center;
    letter-spacing: 1.05px;
    line-height: 1.5em;
    color: #111;
    user-select: none;
}

@media (max-width: 512px) {
    * {
        font-size: .95em;
    }
}

html {
    position: relative;
}

body {
    padding: 1em;
    min-height: 100vh;
    background: radial-gradient(circle, skyblue, steelblue);
    display: flex;
    flex-direction: column;
    justify-content: start;
    align-items: center;
}

h1 {
    margin: .5em;
    font-size: 1.05em;
}

output {
    margin: .5em;
    display: block;
}

.score {
    font-size: 1.25em;
}

form {
    text-align: left;
}

form p {
    text-align: left;
    white-space: pre;
}

form button {
    position: relative;
    left: 50%;
    transform: translateX(-50%);
}

button {
    margin: 2em 0;
    padding: .4em .8em;
    outline: none;
    border: none;
    background: linear-gradient(lightgreen, darkgreen);
    border-radius: 6px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, .4);
    font-size: .95em;
    cursor: pointer;
    transition: .2s;
}

button:hover {
    color: #eee;
}

label {
    cursor: pointer;
}

input {
    margin: 0 10px 0 2em;
    cursor: pointer;
}

details {
    font-size: .95em;
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 90%;
    background: #eee;
    border-radius: 4px;
    cursor: pointer;
}

details h3 {
    margin: .5em;
}

details p {
    margin: .5em 1.5em;
    text-align: justify;
    text-indent: 1.5em;
}

.right {
    color: green;
}

.wrong {
    color: red;
}




Los activos son una matriz de objetos, donde cada objeto tiene propiedades pregunta (pregunta), respuestas (respuestas), rightAnswer (respuesta correcta) y explicaci贸n (explicaci贸n):



[
{
    question: `
        function sayHi() {
            console.log(name);
            console.log(age);
            var name = "Lydia";
            let age = 21;
        }

        sayHi();
    `,
    answers: `
        A: Lydia  undefined
        B: Lydia  ReferenceError
        C: ReferenceError  21
        D: undefined  ReferenceError
    `,
    rightAnswer: `D`,
    explanation: `
              name     var.  ,  name    . Name    undefined   ,       ,     Lydia.     name,      ,    undefined. ,    let ( const),  ,     var,  .      .   "  ".         , JavaScript   ReferenceError.
    `
},
...
]


Gui贸n principal:



Javascript
//    - 
import assets from './assets.js'

// IIFE
;((D, B) => {
    //  - 
    const title = D.createElement('h1')
    B.append(title)

    // :     
    const score = D.createElement('output')
    score.className = 'score'
    B.append(score)

    // :   
    const progress = D.createElement('output')
    progress.className = 'progress'
    B.append(progress)

    //   ,       
    const div = D.createElement('div')
    B.append(div)

    //         
    //    0
    let rightAnswers = +localStorage.getItem('rightAnswers') || 0
    let wrongAnswers = +localStorage.getItem('wrongAnswers') || 0

    //      
    //    0
    let i = +localStorage.getItem('i') || 0

    //  
    showQuestion()

    //    
    updateScoreAndProgress()

    function showQuestion() {
        //      
        // ,  ,
        //  
        if (i === assets.length) {
            return showResult()
        }

        // -     -  
        const titleText = {
            4: `   ?`,
            9: ` ?`,
            12: `    `,
            13: `    ?`,
            14: `  ?`,
            20: `  sum?`,
            21: `    cool_secret?`,
            23: `  ?`,
            25: `     :    this`,
            27: `  ?`,
            29: `  ?`,
            30: `   event.target    ?`,
            33: `  ?`,
            34: `    ""?`,
            38: `  JavaScript `,
            39: `  ?`,
            40: `  ?`,
            41: `  setInterval?`,
            42: `  ?`,
            48: `  num?`,
            49: `  ?`
        }
        title.textContent = titleText[i] || `    ?`

        //     -  ,
        //    ,  ,    
        const {
            question,
            rightAnswer,
            explanation
        } = assets[i]

        //    -  input type="radio",
        //      (    - \n)
        //     -  ,
        //      slice(1, -1),
        //   
        const answers = assets[i].answers
            .split('\n')
            .slice(1, -1)
            .map(i => i.trim())

        // HTML-
        const template = `
        <form action="#">
            <p><em>:</em><br> ${question}</p>

            <p><em> :</em></p><br>
            ${answers.reduce((html, item) => html += `<label><input type="radio" name="answer" value="${item}">${item}</label><br>`, '')}

            <button type="submit"></button>
        </form>
        <details>
            <summary>  </summary>
            <section>
                <h3> : ${rightAnswer}</h3>
                <p>${explanation}</p>
            </section>
        </details>`

        //    
        div.innerHTML = template

        //  
        const form = div.querySelector('form')

        //   
        form.querySelector('input').setAttribute('checked', '')

        //   
        form.addEventListener('submit', ev => {
            //   
            ev.preventDefault()

            //    
            const chosenAnswer = form.querySelector('input:checked').value.substr(0, 1)

            //  
            checkAnswer(chosenAnswer, rightAnswer)
        })
    }

    function checkAnswer(chosenAnswer, rightAnswer) {
        //   
        let isRight = true

        //      ,
        //    ,
        //       ,
        //     ,
        //       
        //    false
        if (chosenAnswer === rightAnswer) {
            rightAnswers++
            localStorage.setItem('rightAnswers', rightAnswers)
        } else {
            wrongAnswers++
            localStorage.setItem('wrongAnswers', wrongAnswers)
            isRight = false
        }

        //  
        const button = div.querySelector('button')

        //    
        if (isRight) {
            //   
            title.innerHTML = `<h1 class="right">!</h1>`

            //  
            button.disabled = true

            //    
            //        
            //  
            const timer = setTimeout(() => {
                updateScoreAndProgress()
                showQuestion()
                clearTimeout(timer)
            }, 1000)

            //    
        } else {
            //   
            title.innerHTML = `<h1 class="wrong">!</h1>`

            //  
            div.querySelectorAll('input').forEach(input => input.disabled = true)

            //  
            div.querySelector('details').setAttribute('open', '')

            //   
            button.textContent = ''

            //      
            //        
            //  
            button.addEventListener('click', () => {
                updateScoreAndProgress()
                showQuestion()
            }, {
                once: true
            })
        }

        //   
        i++

        //      
        localStorage.setItem('i', i)
    }

    function updateScoreAndProgress() {
        //  
        score.innerHTML = `<span class="right">${rightAnswers}</span> - <span class="wrong">${wrongAnswers}</span>`

        //  
        progress.innerHTML = `${i + 1} / ${assets.length}`
    }

    function showResult() {
        //    
        const percent = (rightAnswers / assets.length * 100).toFixed()

        //    
        let result

        //      
        //  result  
        if (percent >= 80) {
            result = ` !    JavaScript.`
        } else if (percent > 50) {
            result = ` ,     .`
        } else {
            result = `,     JavaScript.`
        }

        //  
        B.innerHTML = `
        <h1> </h1>
        <div>
            <p> : <span class="right">${rightAnswers}</span></p>
            <p> : <span class="wrong">${wrongAnswers}</span></p>
            <p>  : ${percent}</p>
            <p>${result}</p>
            <button></button>
        </div>
        `

        //    
        //  
        //   ,
        //  
        B.querySelector('button').addEventListener('click', () => {
            localStorage.clear()
            location.reload()
        }, {
            once: true
        })
    }
})(document, document.body)




Gracias por su atenci贸n.



All Articles