Skip to content

Commit f8a9e9f

Browse files
leoleo
leo
authored and
leo
committed
add onMount life cycle method to fix the undefined error of localStorage method.
1 parent ff30a39 commit f8a9e9f

File tree

3 files changed

+159
-64
lines changed

3 files changed

+159
-64
lines changed

Diff for: src/routes/data/questions.js

+68
Original file line numberDiff line numberDiff line change
@@ -214,4 +214,72 @@ export default [
214214
status: 0,
215215
selected: undefined,
216216
},
217+
{
218+
question: `What's the output?`,
219+
code: `
220+
var a = 10;
221+
function foo() {
222+
console.log(a); // ??
223+
let a = 20;
224+
}
225+
226+
function boo() {
227+
console.log(a); // ??
228+
var a = 20;
229+
}
230+
foo();
231+
boo();
232+
`,
233+
selections: [
234+
{
235+
des: '10 & 20',
236+
correct: 0,
237+
},
238+
{
239+
des: '10 & 10',
240+
correct: 0,
241+
},
242+
{
243+
des: 'undefined & 20',
244+
correct: 0,
245+
},
246+
{
247+
des: 'ReferenceError & undefined',
248+
correct: 1,
249+
},
250+
],
251+
explanation: {
252+
html: `
253+
<p>The variables declared with var keywords are <a href="https://developer.mozilla.org/en-US/docs/Glossary/Hoisting" rel="noopener noreferrer">hoisted</a> in JavaScript and are assigned a value of <em>undefined</em> in the memory. But initialization happens exactly where you typed them in your code. Also, <em>var-declared</em> variables are <a href="http://2ality.com/2011/02/javascript-variable-scoping-and-its.html" rel="noopener noreferrer">function-scoped</a>, whereas <em>let</em> and <strong>const</strong> have block-scoped. So, this is how the process will look like:</p>
254+
<pre><code>
255+
var a = 10; // global scope
256+
function foo() {
257+
// Declaration of var a will be hoisted to the top of function.
258+
// Something like: var a;
259+
260+
console.log(a); // prints undefined
261+
262+
// actual initialisation of value 20 only happens here
263+
var a = 20; // local scope
264+
}
265+
</code></pre>
266+
<p><em>let</em> and <em>const</em> allows you to declare variables that are limited in scope to the block, statement, or expression on which it is used. Unlike <em>var</em>, these variables are not hoisted and have a so-called <a href="http://exploringjs.com/es6/ch_variables.html#sec_temporal-dead-zone">temporal dead zone</a> (TDZ). Trying to access these variables in <em>TDZ</em> will throw a <em>ReferenceError</em> because they can only be accessed until execution reaches the declaration. Read more about <a href="http://2ality.com/2015/02/es6-scoping.html">lexical scoping</a> and <a href="http://davidshariff.com/blog/what-is-the-execution-context-in-javascript/">Execution Context &amp; Stack</a> in JavaScript.</p>
267+
<pre><code>
268+
var a = 10; // global scope
269+
function foo() { // enter new scope, TDZ starts
270+
271+
// Uninitialised binding for 'a' is created
272+
console.log(a); // ReferenceError
273+
274+
// TDZ ends, 'a' is initialised with value of 20 here only
275+
let a = 20;
276+
}
277+
</code></pre>
278+
<script src="https://gist.github.com/singhArmani/b03765a95a488289c2ca890171a56e1d.js"></script>
279+
`,
280+
origin: 'https://dev.to/aman_singh/so-you-think-you-know-javascript-5c26',
281+
},
282+
status: 0,
283+
selected: undefined,
284+
},
217285
];

Diff for: src/routes/index.svelte

+87-64
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,29 @@
22
import Prism from 'prismjs';
33
import Normalizer from 'prismjs/plugins/normalize-whitespace/prism-normalize-whitespace.js';
44
import questionData from './data/questions';
5+
import { onMount } from 'svelte';
6+
7+
let storageQuestion;
8+
let storageStatistics;
9+
let questions = [];
10+
let statistics = {
11+
correct: [],
12+
wrong: [],
13+
last: 0,
14+
};
15+
let selected = -1;
16+
let current = 0;
17+
let modalVisible = false;
518
6-
const storageQuestion = localStorage.getItem('questions');
7-
8-
const questions = storageQuestion ? [...JSON.parse(storageQuestion), ...questionData.slice(JSON.parse(storageQuestion).length)] : questionData;
9-
const statistics = localStorage.getItem('statistics') ? JSON.parse(localStorage.getItem('statistics')) : {
10-
correct: [],
11-
wrong: [],
12-
last: 0,
13-
}
19+
onMount(() => {
20+
storageQuestion = localStorage.getItem('questions');
21+
storageStatistics = localStorage.getItem('statistics');
22+
questions = storageQuestion ? [...JSON.parse(storageQuestion), ...questionData.slice(JSON.parse(storageQuestion).length)] : questionData;
23+
storageStatistics ? statistics = JSON.parse(storageStatistics) : undefined;
24+
selected = statistics.last === questions.length - 1 ? questions[statistics.last].selected : questions[statistics.last + 1].selected ? questions[statistics.last + 1].selected : undefined;
25+
current = statistics.last === questions.length - 1 ? statistics.last : statistics.last === 0 ? 0 : statistics.last + 1;
26+
});
1427
15-
let modalVisible = false;
16-
let current = statistics.last === questions.length - 1 ? statistics.last : statistics.last === 0 ? 0 : statistics.last + 1;
17-
let selected = statistics.last === questions.length - 1 ? questions[statistics.last].selected : questions[statistics.last + 1].selected ? questions[statistics.last + 1].selected : undefined;
1828
$: done = statistics.correct.length + statistics.wrong.length;
1929
$: score = done ? parseInt((statistics.correct.length / done) * 100, 10) : 0;
2030
@@ -27,7 +37,7 @@
2737
'right-trim': true
2838
});
2939
30-
$: code = Prism.highlight(nw.normalize(questions[current].code), Prism.languages.javascript, 'javascript');
40+
$: code = questions.length > 0 ? Prism.highlight(nw.normalize(questions[current].code), Prism.languages.javascript, 'javascript') : undefined;
3141
3242
const handleOnSelection = (correct, index) => {
3343
questions[current].selected = selected = index;
@@ -89,6 +99,7 @@
8999
.question-panel {
90100
margin-top: -136px;
91101
width: 100%;
102+
max-width: calc(100% - 360px);
92103
}
93104
94105
.focus-area {
@@ -237,6 +248,16 @@
237248
color: #999;
238249
}
239250
251+
.explanation .origin a {
252+
word-break: break-all;
253+
}
254+
255+
:global(.explanation pre) {
256+
background-color: #f0f0f0;
257+
border-radius: 5px;
258+
padding: 20px 24px;
259+
}
260+
240261
.score {
241262
margin-top: 60px;
242263
cursor: pointer;
@@ -405,66 +426,68 @@
405426
</svelte:head>
406427

407428
<div class="container-fluid main">
408-
<div class="container d-flex justify-between">
409-
<div class="question-panel">
410-
<div class="focus-area">
411-
<h3>{@html questions[current].question}</h3>
412-
<pre>
413-
<code class="language-javascript">
414-
{@html code}
415-
</code>
416-
</pre>
417-
<div class="selections {questions[current].selected > -1 ? 'selected' : ''}">
418-
{#each questions[current].selections as selection, index}
419-
<div disabled class="selection d-flex justify-between align-center {selected === index ? 'selected' : ''} {selected === index && questions[current].selections[index].correct ? 'right' : 'wrong'}" on:click={() => handleOnSelection(selection.correct, index)}>
420-
<span>{@html selection.des}</span>
421-
<div class="check"></div>
422-
</div>
423-
{/each}
429+
{#if questions.length > 0}
430+
<div class="container d-flex justify-between">
431+
<div class="question-panel">
432+
<div class="focus-area">
433+
<h3>{@html questions[current].question}</h3>
434+
<pre>
435+
<code class="language-javascript">
436+
{@html code}
437+
</code>
438+
</pre>
439+
<div class="selections {questions[current].selected > -1 ? 'selected' : ''}">
440+
{#each questions[current].selections as selection, index}
441+
<div disabled class="selection d-flex justify-between align-center {selected === index ? 'selected' : ''} {selected === index && questions[current].selections[index].correct ? 'right' : 'wrong'}" on:click={() => handleOnSelection(selection.correct, index)}>
442+
<span>{@html selection.des}</span>
443+
<div class="check"></div>
444+
</div>
445+
{/each}
446+
</div>
424447
</div>
448+
{#if questions[current].selected > -1}
449+
<div class="explanation">
450+
<h4>Explanation</h4>
451+
{@html questions[current].explanation.html}
452+
<p class="origin">Origin: <a href={questions[current].explanation.origin} target="_blank" rel="noopener">{questions[current].explanation.origin}</a></p>
453+
</div>
454+
{/if}
425455
</div>
426-
{#if questions[current].selected > -1}
427-
<div class="explanation">
428-
<h4>Explanation</h4>
429-
{@html questions[current].explanation.html}
430-
<p class="origin">Origin: <a href={questions[current].explanation.origin} target="_blank" rel="noopener">{questions[current].explanation.origin}</a></p>
456+
<div class="sider">
457+
<div class="progress">
458+
<p><span>Current: </span>#{current + 1}</p>
459+
<div class="progress-bar">
460+
<div class="current-progress" style="width: {(statistics.correct.length + statistics.wrong.length) * 100 / questions.length}%"></div>
461+
</div>
431462
</div>
432-
{/if}
433-
</div>
434-
<div class="sider">
435-
<div class="progress">
436-
<p><span>Current: </span>#{current + 1}</p>
437-
<div class="progress-bar">
438-
<div class="current-progress" style="width: {(statistics.correct.length + statistics.wrong.length) * 100 / questions.length}%"></div>
463+
<div class="score d-flex justify-between align-center" on:click={() => handleModalVisible(true)}>
464+
<div class="current-score d-flex justify-center align-center {score < 60 ? 'poor' : score > 59 & score < 80 ? 'normal' : 'good'}">{score}</div>
465+
<div class="score-detail">
466+
<div class="correct d-flex justify-between align-center"><span>Correct:</span> {statistics.correct.length}</div>
467+
<div class="wrong d-flex justify-between align-center"><span>Wrong:</span> {statistics.wrong.length}</div>
468+
</div>
439469
</div>
440-
</div>
441-
<div class="score d-flex justify-between align-center" on:click={() => handleModalVisible(true)}>
442-
<div class="current-score d-flex justify-center align-center {score < 60 ? 'poor' : score > 59 & score < 80 ? 'normal' : 'good'}">{score}</div>
443-
<div class="score-detail">
444-
<div class="correct d-flex justify-between align-center"><span>Correct:</span> {statistics.correct.length}</div>
445-
<div class="wrong d-flex justify-between align-center"><span>Wrong:</span> {statistics.wrong.length}</div>
470+
<div class="process-nav d-flex justify-between align-center">
471+
<button class="previous" on:click={() => handleNavClick('previous')} disabled={current === 0}>Previous</button>
472+
<button class="next" on:click={() => handleNavClick('next')} disabled={current + 1 === questions.length}>Next</button>
446473
</div>
447-
</div>
448-
<div class="process-nav d-flex justify-between align-center">
449-
<button class="previous" on:click={() => handleNavClick('previous')} disabled={current === 0}>Previous</button>
450-
<button class="next" on:click={() => handleNavClick('next')} disabled={current + 1 === questions.length}>Next</button>
451-
</div>
452-
<div class="social-sharing d-flex justify-between align-center">
453-
<p>Social Media: </p>
454-
<div class="social-media">
455-
<a class="share-to-facebook" href="https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fjavascript-hub.dezineleo.com" target="_blank" rel="noopener" aria-label="">
456-
<img src="/icon-facebook.svg" alt="FaceBook">
457-
</a>
458-
<a class="share-to-twitter" href="https://twitter.com/intent/tweet/?text=JavaScript%20Hub%20-%20Another%20free%20JavaScript%20learning%20application.&amp;url=https%3A%2F%2Fjavascript-hub.dezineleo.com" target="_blank" rel="noopener" aria-label="">
459-
<img src="/icon-twitter.svg" alt="Twitter">
460-
</a>
461-
<a class="share-to-github" href="https://github.com/DezineLeo/javascript-hub/issues" target="_blank" rel="noopener" aria-label="">
462-
<img src="/icon-github.svg" alt="Instagram">
463-
</a>
474+
<div class="social-sharing d-flex justify-between align-center">
475+
<p>Social Media: </p>
476+
<div class="social-media">
477+
<a class="share-to-facebook" href="https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fjavascript-hub.dezineleo.com" target="_blank" rel="noopener" aria-label="">
478+
<img src="/icon-facebook.svg" alt="FaceBook">
479+
</a>
480+
<a class="share-to-twitter" href="https://twitter.com/intent/tweet/?text=JavaScript%20Hub%20-%20Another%20free%20JavaScript%20learning%20application.&amp;url=https%3A%2F%2Fjavascript-hub.dezineleo.com" target="_blank" rel="noopener" aria-label="">
481+
<img src="/icon-twitter.svg" alt="Twitter">
482+
</a>
483+
<a class="share-to-github" href="https://github.com/DezineLeo/javascript-hub/issues" target="_blank" rel="noopener" aria-label="">
484+
<img src="/icon-github.svg" alt="Instagram">
485+
</a>
486+
</div>
464487
</div>
465488
</div>
466489
</div>
467-
</div>
490+
{/if}
468491
<div class="modal-container {modalVisible ? 'visible' : ''}" on:click={() => handleModalVisible(false)}>
469492
<div class="modal-body" on:click={e => e.stopPropagation()}>
470493
<img src="/share.svg" alt="Share JavaScript Hub">

Diff for: static/global.css

+4
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,10 @@ code[class*="language-"], pre[class*="language-"] {
8484
color: hsl(53, 72%, 63%)!important;
8585
}
8686

87+
button {
88+
outline: none;
89+
}
90+
8791
@media (min-width: 400px) {
8892
body {
8993
font-size: 16px;

0 commit comments

Comments
 (0)