ITKarma picture

Good day, friends! I bring to your attention a small interactive - a kind of quiz on JavaScript, currently consisting of 50 questions.

In my opinion, solving such problems is the best way to determine your skill level.

Foreword


This part is based on this repository . Its author, Lydia Hallie, positions his project as a list of advanced questions and, indeed, there are some among them that, it seems to me, even to an experienced JavaScript developer, will seem difficult. However, among these questions there are those for which it is sufficient to have basic knowledge to answer. There is a Russian translation in the repository, but, to put it mildly, it leaves much to be desired, so most of the answers (explanations) had to be translated again.

It should be noted that the cited explanations (answers) do not always fully reveal the essence of the problem. This is explained by the form of the project - it is a checklist, not a textbook. The answers are rather a hint for further searches on MDN or Javascript.ru . However, many of the explanations contain comprehensive answers.

Despite the fact that the code has been repeatedly tested, no one is immune from errors, of course, except for those who do nothing. Therefore, if you find errors, typos, inaccuracies, incorrect wording, etc., as well as if you want to improve the translation, please write in PM, I will be grateful (activity on GitHub is also welcome).

Actually, that’s all I wanted to say as a preface.

Rules


The rules are simple: 50 questions, 3-4 answer options, rating: the number of right and wrong answers, progress: number and number of questions.

Based on the results, the percentage of correct answers is determined and a conclusion is made on the level of JavaScript knowledge: more than 80% is excellent, more than 50% is not bad, less than 50%... well, you understand.

An explanation is attached to each question. If the answer is incorrect, this explanation is disclosed.

Due to the fact that the number of correct and incorrect answers, as well as the serial number of the question are recorded in the local storage, you have the opportunity to pause, take a break and continue at any time from where you left off.

But enough words, it's time to get down to business.

Quiz



The project code is here .

Share the results in the comments.

Mechanics


A few words about how the quiz is implemented for those who are interested.

The markup looks like this:

<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> 

Add minimal styles:

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; } 


Sources (assets) are an array of objects, where each object has the properties question (question), answers (answers), rightAnswer (correct answer) and explanation (explanation):

[ { 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. ` },... ] 

Main script:

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) 


Thank you for your attention, friends.

To be continued….

Source