Skip to content

Sync with upstream @ 540d753e #23

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 221 commits into from
Closed
Changes from all commits
Commits
Show all changes
221 commits
Select commit Hold shift + click to select a range
cd86528
Fix typo
wdscxsj Oct 3, 2022
165a3f5
typo "optimzed
joaquinelio Oct 3, 2022
f0ce7e9
IE 9
joaquinelio Oct 3, 2022
f0fa52f
Fix typo
wdscxsj Oct 4, 2022
3a5d32e
Remove typo
aki-mizu Oct 5, 2022
4573d0b
Fix typos
TevaHenry Oct 5, 2022
dca45f7
Unicode art, grammar suggestions
joaquinelio Oct 5, 2022
dc7a157
Update article.md
joaquinelio Oct 5, 2022
87c0ca9
mdn link
joaquinelio Oct 6, 2022
af4843b
👾 smth
Rnbsov Oct 8, 2022
530dc9f
👾 smth
Rnbsov Oct 8, 2022
1d999c7
👾 smth
Rnbsov Oct 8, 2022
429caba
👾 smth
Rnbsov Oct 8, 2022
306a197
Update article.md
joaquinelio Oct 10, 2022
69bfbb0
Update article.md
joaquinelio Oct 10, 2022
b89b938
Update article.md
joaquinelio Oct 10, 2022
455c57a
Update article.md
joaquinelio Oct 10, 2022
6f34912
Update article.md
joaquinelio Oct 10, 2022
bf7d8bb
Merge pull request #3220 from joaquinelio/patch-19
iliakan Oct 10, 2022
7b0f9e5
Content-Length is now a CORS-safelisted response header
wdscxsj Oct 11, 2022
fe8ed87
Fix typo
wdscxsj Oct 12, 2022
75edb67
strict-origin-when-cross-origin is now the default referrerPolicy
wdscxsj Oct 12, 2022
0c5ac0e
typo at String concatenation with binary
adam4nj Oct 13, 2022
ca42edd
Remove a redundant argument
wdscxsj Oct 13, 2022
0487c35
Remove use of error.message in onerror()
wdscxsj Oct 14, 2022
c09efa8
http to https checked links
joaquinelio Oct 14, 2022
2ca8f83
closes #3242
iliakan Oct 18, 2022
245e59e
closes #3239
iliakan Oct 18, 2022
28803aa
Merge pull request #3238 from joaquinelio/pp
iliakan Oct 18, 2022
2f37897
minor fixes
iliakan Oct 18, 2022
f6cb5e9
Merge pull request #3237 from wdscxsj/patch-9
iliakan Oct 18, 2022
321b05e
Merge pull request #3223 from joaquinelio/patch-20
iliakan Oct 18, 2022
508ca01
closes #3229
iliakan Oct 18, 2022
5f91fda
closes #3230
iliakan Oct 18, 2022
aaf3b5b
Merge pull request #3231 from wdscxsj/patch-4
iliakan Oct 18, 2022
91e8edd
Merge pull request #3232 from wdscxsj/patch-5
iliakan Oct 18, 2022
36eb3da
Merge pull request #3233 from wdscxsj/patch-6
iliakan Oct 18, 2022
b0e2e04
Merge pull request #3234 from adam4nj/patch-1
iliakan Oct 18, 2022
a4050f2
Merge pull request #3235 from wdscxsj/patch-7
iliakan Oct 18, 2022
5dff42b
closes #3222
iliakan Oct 18, 2022
0c8e883
typo *udefined
joaquinelio Oct 20, 2022
4edd6b5
Proper Polish language inflection
f6p Oct 20, 2022
094aa10
Add .at( ) to strings summary
joaquinelio Oct 20, 2022
434e637
For the completeness of example.
Vic-Bonlight Oct 28, 2022
b3c7a7f
👾 add run button and remove typo
Rnbsov Oct 29, 2022
515dc44
👾 smth
Rnbsov Oct 29, 2022
78a9566
👾 smth
Rnbsov Oct 29, 2022
9e08049
👾 smth
Rnbsov Oct 29, 2022
1bda839
fix: typo getRangesAt to getRangeAt
leviding Oct 30, 2022
55b6c5e
Update article.md
nikolai-chernolutskii Oct 30, 2022
588117e
Update index.html
Alexandre887 Oct 30, 2022
4943f21
Update article.md
alagunoff Nov 1, 2022
8d185f7
Update article.md
Alexandre887 Nov 4, 2022
c70a3dc
Merge pull request #3218 from aki-mizu/patch-1
iliakan Nov 13, 2022
1fb0500
Merge pull request #3219 from TevaHenry/localstorage-sessionstorage
iliakan Nov 13, 2022
fe3d781
Merge pull request #3227 from Rnbsov/patch-75
iliakan Nov 13, 2022
1b078d0
Merge pull request #3245 from joaquinelio/patch-19
iliakan Nov 13, 2022
294a91e
Merge pull request #3246 from f6p/patch-1
iliakan Nov 13, 2022
083de40
Merge pull request #3247 from joaquinelio/patch-20
iliakan Nov 13, 2022
a4f1afd
Merge pull request #3248 from Victor-Nikliaiev/patch-1
iliakan Nov 13, 2022
fac9385
fixes #3249
iliakan Nov 13, 2022
ffbe0f5
Merge pull request #3251 from Rnbsov/patch-77
iliakan Nov 13, 2022
f47885b
minor fixes
iliakan Nov 13, 2022
7048f44
Merge pull request #3252 from leviding/patch-7
iliakan Nov 13, 2022
2c8f0fc
Merge pull request #3253 from nikolai-chernolutskii/patch-1
iliakan Nov 13, 2022
6fc7ba3
Merge pull request #3254 from Alexandre887/master
iliakan Nov 13, 2022
121141b
minor fixes
iliakan Nov 13, 2022
a665e29
Merge pull request #3255 from alagunoff/patch-1
iliakan Nov 13, 2022
8d9ecb7
Merge pull request #3258 from Alexandre887/patch-1
iliakan Nov 13, 2022
dafc925
the output is 0
joaquinelio Nov 14, 2022
c918da4
map.delete removes the pair key/value
joaquinelio Nov 14, 2022
9f1848c
Update article.md
joaquinelio Nov 14, 2022
d52f318
fix typo on Remainder %
cerealexperiments Nov 15, 2022
e1bec69
Merge pull request #3267 from cerealexperiments/patch-1
iliakan Nov 15, 2022
e912311
Merge pull request #3265 from joaquinelio/patch-20
iliakan Nov 15, 2022
cfc0195
Merge branch 'master' into patch-19
iliakan Nov 15, 2022
33c48a4
Merge pull request #3264 from joaquinelio/patch-19
iliakan Nov 15, 2022
477cb58
Merge pull request #3214 from joaquinelio/patch-17
iliakan Nov 15, 2022
746ad80
closes #3260
iliakan Nov 16, 2022
4e26c7e
Suggestion
bogdanbacosca Nov 26, 2022
657e389
minor code formatting
bogdanbacosca Nov 26, 2022
45a2d14
other code formatting bits
bogdanbacosca Nov 26, 2022
66ad8c1
Revert "minor code formatting"
bogdanbacosca Nov 26, 2022
67fe46f
Merge pull request #3279 from bogdanbacosca/if-else-bogdan
iliakan Nov 30, 2022
cfe2249
Bezier curves: update paused demo on point move
orelby Nov 30, 2022
1ce5644
Merge pull request #3287 from orelby/animation/bezier-curve/update-de…
iliakan Nov 30, 2022
8375316
fix typo, remove pleonasm
a-v-gor Dec 6, 2022
e75f655
small format change
joaquinelio Dec 7, 2022
4a8e8e1
Update article.md
Violet-Bora-Lee Dec 7, 2022
3f305f5
Merge pull request #3292 from a-v-gor/proofreading
iliakan Dec 11, 2022
9a26eb0
Merge pull request #3293 from joaquinelio/patch-19
iliakan Dec 11, 2022
ea7738b
Merge pull request #3295 from Violet-Bora-Lee/patch-4
iliakan Dec 11, 2022
b2e7dbf
grammar & legility (to check)
joaquinelio Dec 12, 2022
88d9b3f
removed -> remove; optimzed -> optimized ;
sagarpanchal Jan 18, 2023
ccd0a11
Fix "JavaScript specials" links
odsantos Jan 22, 2023
ae7afcb
update
bogdanbacosca Jan 24, 2023
03b8f2e
Merge pull request #3278 from bogdanbacosca/work
iliakan Jan 24, 2023
cd988dd
Fix a typo
MAHIN0093 Jan 24, 2023
bbf3a44
Update 1-js/05-data-types/04-array/article.md
MAHIN0093 Jan 24, 2023
f489288
Update button to fix horizontal scroll on mobile
marcusicaro Jan 25, 2023
4baa619
fix: add missing word 'to'
JeraldVin Jan 26, 2023
a4e9ba5
Merge pull request #3336 from JeraldVin/patch-1
iliakan Jan 26, 2023
d906956
Merge pull request #3334 from marcusicaro/patch-1
iliakan Jan 26, 2023
f9afaf3
Merge pull request #3330 from odsantos/fix-javascript-specials-links
iliakan Jan 26, 2023
5a3db89
Merge pull request #3332 from MAHIN0093/change
iliakan Jan 26, 2023
9e3fa13
Merge pull request #3302 from joaquinelio/patch-19
iliakan Jan 29, 2023
968fa09
added a word
Raviikumar001 Apr 4, 2023
ea5fbfa
added word fix
Raviikumar001 Apr 6, 2023
af71856
Merge pull request #3425 from Raviikumar001/Added-a-word
iliakan Apr 17, 2023
cd8dd53
#3345 Fixed Grammar
pradeep-ramola Apr 23, 2023
733ff69
Merge pull request #3435 from pradeep-ramola/master
iliakan Apr 29, 2023
e68750e
translated Russian word into English
MSHNK1 Jul 9, 2023
023c0ec
Fixing a minor grammatical typo in the document.
rahulrao0209 Jul 16, 2023
d694e89
Merge pull request #3492 from MSHNK1/fix-typos
iliakan Jul 17, 2023
285083f
minor fixes
iliakan Aug 7, 2023
8ab6b39
Add WeakRef and FinalizationRegistry article
WOLFRIEND Nov 4, 2023
5ab1ce2
Merge pull request #3609 from WOLFRIEND/master
iliakan Nov 15, 2023
b7ebc1b
Improve awkward sentence structure
smith558 Nov 24, 2023
75bad83
Improve grammar
smith558 Nov 24, 2023
74a8a19
Fix formatting char
smith558 Nov 27, 2023
d51037a
Fix grammar and add an example
nakhodkin Dec 27, 2023
c66bace
Fix grammar and typos
nakhodkin Dec 31, 2023
bbac8a5
Fix grammar and JavaScript syntax
nakhodkin Jan 2, 2024
1b9a28b
Update article.md
JaFro96 Jan 4, 2024
4ec440f
Update article.md
JaFro96 Jan 4, 2024
d83bfb2
refactor: Updated RFC spec Safe Methods URL in Cookies chapter
alexandermirzoyan Jan 12, 2024
9ec34c6
Replace assignment with equals in Truncate the text task
CJDumbleton Jan 17, 2024
2e0d5fb
Add missing word
qadzek Jan 20, 2024
52e184c
Add missing CSS unit
qadzek Jan 20, 2024
0530c92
fix square brackets
mikayel00 Jan 24, 2024
9270fe5
Merge pull request #3639 from JaFro96/master
smith558 Jan 24, 2024
f0f1006
fix: json
mikayel00 Jan 24, 2024
c98ec82
Merge pull request #3647 from CJDumbleton/CJDumbleton-patch-1
smith558 Jan 24, 2024
9c07c5b
Merge pull request #3649 from qadzek/patch-1
smith558 Jan 24, 2024
1a6edd7
Merge pull request #3656 from mikayel00/fix-brackets
smith558 Jan 26, 2024
9d157d8
Merge pull request #3617 from smith558/patch-3
smith558 Jan 27, 2024
b6c604a
Merge branch 'master' into patch-5
smith558 Jan 27, 2024
4286703
Merge pull request #3644 from alexandermirzoyan/patch-2
smith558 Jan 27, 2024
26ac4c8
Merge pull request #3212 from wdscxsj/patch-2
smith558 Jan 27, 2024
f24e463
Merge pull request #3213 from joaquinelio/patch-15
smith558 Jan 27, 2024
774d0c1
Merge pull request #3326 from sagarpanchal/patch-2
smith558 Jan 27, 2024
aacfc93
Fixed grammar error in regex-groups article.md
eedrxs Jan 27, 2024
e2ac312
Merge pull request #3659 from eedrxs/patch-1
smith558 Jan 27, 2024
ee62307
Update article.md
nepikn Feb 2, 2024
4a20875
Update article.md
smith558 Feb 11, 2024
5ce4b3a
Merge pull request #3664 from nepikn/patch-2
smith558 Feb 11, 2024
daca277
Fix grammar
smith558 Feb 11, 2024
3e92613
Improve options description
smith558 Feb 11, 2024
b6e7472
Update samesite content
smith558 Feb 13, 2024
d134cab
Remove "surely"
smith558 Feb 13, 2024
19e62af
Update article.md
smith558 Feb 13, 2024
a7d351f
change IndexedDb to IndexedDB (#3660)
0xtpsl Feb 13, 2024
ab1db04
Fix grammar and typos (#3628)
nakhodkin Feb 14, 2024
d461a93
Merge pull request #3217 from wdscxsj/patch-3
smith558 Feb 14, 2024
00bdf88
Update LICENSE.md
iliakan Mar 8, 2024
25c9bdf
Update LICENSE.md
iliakan Mar 8, 2024
c13e707
Update LICENSE.md
iliakan Mar 8, 2024
e15f535
Update LICENSE.md
iliakan Mar 8, 2024
2f91d87
Update LICENSE.md
iliakan Mar 8, 2024
ea05aa9
Updated result visualization
Filin3 Mar 31, 2024
04b73bf
Merge pull request #3681 from Filin3/patch-1
smith558 May 5, 2024
acf339c
Merge pull request #3632 from nakhodkin/patch-2
smith558 May 5, 2024
541b7f9
Merge pull request #3636 from nakhodkin/patch-5
smith558 May 5, 2024
0b9bc2f
Merge pull request #3634 from nakhodkin/patch-4
smith558 May 5, 2024
85da6f1
Update article.md
ellie-heidari May 10, 2024
475899e
Update article.md
smith558 May 17, 2024
7e524ba
Add link
smith558 May 17, 2024
42851f4
Update task.md
pvepamb1 May 18, 2024
2092da7
Merge pull request #3694 from pvepamb1/patch-1
smith558 May 18, 2024
f684d39
change example element of multidimensional array
sneeed Jun 8, 2024
c151e11
minor fixes
iliakan Jun 13, 2024
3fd3f98
- `run`
Alexandre887 Jun 23, 2024
d1ffe5d
docs: remove eval polyfill.io
kricsleo Jul 5, 2024
262f91a
Merge pull request #3712 from kricsleo/patch-1
smith558 Jul 8, 2024
815fafa
Merge pull request #3692 from ellie-heidari/patch-1
smith558 Jul 8, 2024
d6e0376
Remove BigInt IE incompatibility part (#3709)
FloffyGarlic Jul 9, 2024
5a0df77
Update article.md
shallow-beach Jul 10, 2024
62827d8
Merge pull request #3715 from shallow-beach/master
smith558 Jul 10, 2024
4104eba
Merge pull request #3704 from Alexandre887/patch-10
smith558 Jul 10, 2024
ca72abb
Merge pull request #3700 from sneeed/patch-2
smith558 Jul 10, 2024
b258d7d
Merge pull request #3495 from rahulrao0209/patch-1
smith558 Jul 10, 2024
6f08958
minor fix to function name written in explanation
tonybishnoi Oct 9, 2024
eedc262
Grammatical fix
nikoandpiko Oct 22, 2024
34a80e7
Merge pull request #3768 from tonybishnoi/patch-1
smith558 Oct 24, 2024
67833c9
Update article.md
zakingslayerv22 Dec 11, 2024
b36823a
better wording
pj-szdm Dec 18, 2024
dc14378
Update article.md
mhi1627 Jan 22, 2025
8b2a2f2
Improve readability
AdityaGirdhar Jan 30, 2025
a2b97b5
Merge pull request #3810 from AdityaGirdhar/patch-1
smith558 Feb 4, 2025
793ad4b
Merge branch 'master' into patch-1
smith558 Feb 4, 2025
e466826
Merge pull request #3772 from nikoandpiko/patch-1
smith558 Feb 4, 2025
a087279
Merge pull request #3804 from mhi1627/patch-1
smith558 Feb 8, 2025
26daef2
Merge pull request #3794 from zakingslayerv22/patch-1
smith558 Feb 8, 2025
6236eb8
Merge pull request #3797 from pj-szdm/patch-1
smith558 Feb 8, 2025
011dd4f
Update article.md
Gleb-Pastushenko Feb 10, 2025
1dce5b7
Merge pull request #3815 from Gleb-Pastushenko/patch-6
smith558 Feb 10, 2025
4b3474b
Fixed missing closing parenthesis in 2-ui/4-forms-control/1-form-elem…
vincent-clipet Mar 10, 2025
3d7abb9
Merge pull request #3822 from vincent-clipet/fix/missing_parenthesis
smith558 Mar 10, 2025
3de63df
promise.all task
iliakan Mar 24, 2025
ef31066
minor fixes
iliakan Mar 24, 2025
de4247b
minor fixes
iliakan Mar 24, 2025
0af25bc
minor fixes
iliakan Mar 24, 2025
d932e52
minor fixes
iliakan Mar 24, 2025
f0d8abb
minor fixes
iliakan Mar 24, 2025
f775835
minor fixes
iliakan Mar 24, 2025
0760c90
minor fixes
iliakan Mar 24, 2025
5dea441
minor fixes
iliakan Mar 24, 2025
035c526
minor fixes
iliakan Mar 24, 2025
4c4598b
Fix for #3826 - Removed errorception.com from the respective md file.
Paramesh-T-S Mar 29, 2025
cde189d
Update Safari settings screenshots
dangerman Apr 2, 2025
78c6c44
Update Safari devtools instructions
dangerman Apr 2, 2025
e88c212
Update Function object, NFE article
rahulrao0209 Apr 6, 2025
a711a1f
Merge pull request #3830 from Paramesh-T-S/Issue_fix_Outdate_-link_in…
iliakan Apr 8, 2025
efaa9aa
sentry.io added as per suggestion - https://github.com/javascript-tut…
Paramesh-T-S Apr 8, 2025
6cc5077
Merge pull request #3835 from Paramesh-T-S/Issue_fix_Outdate_-link_in…
iliakan Apr 9, 2025
81cfee9
Update article.md
rahulrao0209 Apr 13, 2025
e2d8ebe
Merge pull request #3836 from rahulrao0209/patch-3
smith558 Apr 13, 2025
6bbdd0c
Merge pull request #3834 from rahulrao0209/patch-2
smith558 Apr 13, 2025
d3c395c
Merge pull request #3832 from dangerman/update-safari-devtools-screen…
smith558 Apr 13, 2025
540d753
Replace with up to date screenshots
smith558 Apr 13, 2025
eb42ed1
merging all conflicts
iliakan Jun 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/FUNDING.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
github: iliakan
19 changes: 19 additions & 0 deletions 1-js/01-getting-started/3-code-editors/article.md
Original file line number Diff line number Diff line change
@@ -29,16 +29,35 @@ Windows үчүн Visual Studio да бар (Visual Studio Code менен чат

Иш жүзүндө "жеңил" редакторлор көптөгөн плагиндерге, анын ичинде директория деңгээлиндеги синтаксис анализаторлору жана автокошумчалоолору ээ болушу мүмкүн, ошондуктан "жеңил" редактор менен IDE ортосунда катуу чеги жок.

<<<<<<< HEAD
Төмөнкү варианттар сиздин көңүлүңүздү бурууга татыктуу:
- [Atom](https://atom.io) (кроссплатформалуу, акысыз)
- [Sublime Text](http://www.sublimetext.com) (кроссплатформалуу, шарттуу акысыз).
- [Notepad++](https://notepad-plus-plus.org/) (Windows, акысыз).
- [Vim](http://www.vim.org/) жана [Emacs](https://www.gnu.org/software/emacs/) кантип колдонгонун билсеңиз, алар да жакшы.

## Жаңжалдашпайлы
=======
There are many options, for instance:

- [Sublime Text](https://www.sublimetext.com/) (cross-platform, shareware).
- [Notepad++](https://notepad-plus-plus.org/) (Windows, free).
- [Vim](https://www.vim.org/) and [Emacs](https://www.gnu.org/software/emacs/) are also cool if you know how to use them.
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
Жогоруда саналган редакторлор авторго көптөн бери белгилүү жана кесиптештеринин көптөгөн жакшы пикирлерине ээ болушкан.

Албетте, башка көптөгөн сонун редакторлор бар. Сизге эң жактырганын тандаңыз.

<<<<<<< HEAD
Башка куралды сыяктуу эле редакторду тандоо жеке иш болуп саналат жана долбоорлоруңузга, адаттарыңызга жана жеке каалоолоруңузга жараша болот.
=======
There are other great editors in our big world. Please choose the one you like the most.

The choice of an editor, like any other tool, is individual and depends on your projects, habits, and personal preferences.

The author's personal opinion:

- I'd use [Visual Studio Code](https://code.visualstudio.com/) if I develop mostly frontend.
- Otherwise, if it's mostly another language/platform and partially frontend, then consider other editors, such as XCode (Mac), Visual Studio (Windows) or Jetbrains family (Webstorm, PHPStorm, RubyMine etc, depending on the language).
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
6 changes: 5 additions & 1 deletion 1-js/01-getting-started/4-devtools/article.md
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@

Көрүнүшү:

![chrome](chrome.png)
![chrome](chrome.webp)

Иштеп чыгуучу куралдардын так көрүнүшү Chrome версияңыздан көз каранды. Анда-санда өзгөрүп турат, бирок, жалпысынан, көрүнүшү мурунку версияларга окшош бойдон калууда.

@@ -48,9 +48,13 @@
## Safari


<<<<<<< HEAD
Safari (Mac браузери, Windows/Linux тарабынан колдоого алынбайт) бул жерде бир аз өзгөчө. Адегенде "Иштеп чыгуу менюсун" ("Developer menu") күйгүзүшүбүз керек.

Орнотууларды (Preferences) ачып, "Өркүндөтүлгөндөр" (Advanced) панелине өтүңүз. Төмөндө чекбокс бар:
=======
Open Settings and go to the "Advanced" pane. There's a checkbox at the bottom:
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
![safari](safari.png)

Binary file removed 1-js/01-getting-started/4-devtools/chrome.png
Binary file not shown.
Binary file added 1-js/01-getting-started/4-devtools/chrome.webp
Binary file not shown.
Binary file added 1-js/01-getting-started/4-devtools/chrome@2.webp
Binary file not shown.
Binary file removed 1-js/01-getting-started/4-devtools/chrome@2x.png
Binary file not shown.
Binary file modified 1-js/01-getting-started/4-devtools/safari.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified 1-js/01-getting-started/4-devtools/safari@2x.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
57 changes: 57 additions & 0 deletions 1-js/02-first-steps/04-variables/article.md
Original file line number Diff line number Diff line change
@@ -88,16 +88,26 @@ let user = 'Жакыя'
*!*var*/!* message = 'Салам';
```

<<<<<<< HEAD
`var` ачкыч сөзү `let` менен *дээрлик* бирдей. Ал өзгөрмөнү жарыялайт, бирок бир аз башкача, "эскирген" жол менен.

`let` жана `var` ортосунда назик айырмачылыктар бар, бирок алар биз үчүн азырынча маанилүү эмес. Биз аларды <info:var> бөлүмүндө кененирээк карап чыгабыз.
=======
The `var` keyword is *almost* the same as `let`. It also declares a variable but in a slightly different, "old-school" way.

There are subtle differences between `let` and `var`, but they do not matter to us yet. We'll cover them in detail in the chapter <info:var>.
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
````
## Жашоодогу аналогия
Эгерде өзгөрмөнү берилмелер үчүн уникалдуу аталышы бар "куту" катары элестетсек, биз "өзгөрмө" түшүнүгүн оңой эле түшүнө алабыз.
<<<<<<< HEAD
Мисалы үчүн, `message` өзгөрмөсүн `"билдирүү"` деп аталган жана анын ичиндеги `"Салам!"` мааниси бар куту катары элестетүүгө болот.
=======
For instance, the variable `message` can be imagined as a box labelled `"message"` with the value `"Hello!"` in it:
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
![](variable.svg)
@@ -150,12 +160,21 @@ let message = "Ошол"; // SyntaxError: 'message' has already been declared
Ошондуктан, биз өзгөрмөнү бир гана жолу жарыялап, ага `let`'сиз кайрылышыбыз керек.
````

<<<<<<< HEAD
```smart header="Функционалдуу тилдер"
Өзгөрмө маанилерин өзгөртүүгө тыюу салган [Scala](http://www.scala-lang.org/) же [Erlang](http://www.erlang.org/) сыяктуу [функционалдуу](https://en.wikipedia.org/wiki/Functional_programming) программалоо тилдери бар экенин белгилей кетүү кызык.
=======
```smart header="Functional languages"
It's interesting to note that there exist so-called [pure functional](https://en.wikipedia.org/wiki/Purely_functional_programming) programming languages, such as [Haskell](https://en.wikipedia.org/wiki/Haskell), that forbid changing variable values.
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
Мындай тилдерде бир жолу "кутуда" сакталган маани түбөлүккө ошол жерде калат. Эгер башка нерсени сактоо керек болсо, тил бизди жаңы кутуча түзүүгө (жаңы өзгөрмө жарыялоого) мажбурлайт. Биз эски өзгөрмөнү колдоно албайбыз.
<<<<<<< HEAD
Бир караганда бул бир аз кызыктай көрүнгөнү менен, бул тилдер олуттуу иштеп чыгууга жөндөмдүү. Мындан тышкары, бул чектөө кээ бир артыкчылыктарды берген параллелдүү эсептөөлөр сыяктуу аймактар бар. Мындай тилди үйрөнүү (сиз аны жакында колдонууну пландабасаңыз да) акыл-эсти кеңейтүү үчүн сунушталат.
=======
Though it may seem a little odd at first sight, these languages are quite capable of serious development. More than that, there are areas like parallel computations where this limitation confers certain benefits.
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
```

## Өзгөрмөлөрдү атоо [#variable-naming]
@@ -197,15 +216,24 @@ let my-name; // атта '-' дефисти коюуга болбойт
`apple` жана `APPLE` деп аталган өзгөрмөлөр -- бул эки башка өзгөрмө.
```

<<<<<<< HEAD
````smart header="Латын эмес тамгаларга уруксат берилет, бирок сунушталбайт"
Каалаган тилди, анын ичинде кирил тамгаларын же жадаганда иероглифтерди колдонууга болот:
=======
````smart header="Non-Latin letters are allowed, but not recommended"
It is possible to use any language, including Cyrillic letters, Chinese logograms and so on, like this:
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
```js
let аталыш = '...';
let 我 = '...';
```
<<<<<<< HEAD
Техникалык жактан бул жерде ката жок. Мындай аттарга уруксат берилген, бирок өзгөрмө аттарында англис тилин колдонуу боюнча эл аралык келишим бар. Кичинекей скрипт жазып жатсак да, анын алдында өмүрү узун болушу мүмкүн. Башка өлкөлөрдөн келгендер аны бир нече жолу окууга туура келиши мүмкүн.
=======
Technically, there is no error here. Such names are allowed, but there is an international convention to use English in variable names. Even if we're writing a small script, it may have a long life ahead. People from other countries may need to read it sometime.
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
````

````warn header="Резервделген аттар"
@@ -260,11 +288,19 @@ const myBirthday = '18.04.1982';
myBirthday = '01.01.2001'; // ката, константаны өзгөртүүгө болбойт!
```
<<<<<<< HEAD
Эгерде программист өзгөрмө эч качан өзгөрбөйт деп ишенсе, ал муну кепилдей алат жана аны `const` аркылуу жарыялоо менен ар бирине так кабарлай алат.
=======
When a programmer is sure that a variable will never change, they can declare it with `const` to guarantee and communicate that fact to everyone.
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
### Баш тамгадагы константалар
<<<<<<< HEAD
Скрипт аткарылганга чейин белгилүү болгон эстеп калууга кыйын маанилер үчүн константаларды тергеме ат катары колдонуу тажрыйбасы кеңири таралган.
=======
There is a widespread practice to use constants as aliases for difficult-to-remember values that are known before execution.
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
Мындай константалардын аталыштары баш тамгалар жана ылдыйкы сызыкчалар менен жазылат.
@@ -289,15 +325,23 @@ alert(color); // #FF7F00
Качан константа үчүн баш тамгаларды колдонушубуз керек жана качан аны кадимкидей аташыбыз керек? Келгиле, бул маселени чечели.
<<<<<<< HEAD
"Константа" болуу жөн гана өзгөрмөнүн мааниси эч качан өзгөрбөй турганын билдирет. Бирок аткарылганга чейин белгилүү болгон константалар бар (кызыл түстүн он алтылык мааниси сыяктуу) жана скрипттин аткарылышы учурунда *эсептелүүчү*, бирок алар башында жарыялангандан кийин өзгөрбөй турган константалар да бар.
=======
Being a "constant" just means that a variable's value never changes. But some constants are known before execution (like a hexadecimal value for red) and some constants are *calculated* in run-time, during the execution, but do not change after their initial assignment.
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
Мисалы үчүн:
```js
const pageLoadTime = /* веб-баракчаны жүктөөгө сарпталган убакыт */;
```
<<<<<<< HEAD
`pageLoadTime` константасынын мааниси баракчаны жүктөөдөн мурун белгилүү эмес, андыктан ал кадимкидей аталат. Бирок ал дагы эле константа, анткени жарыялангандан кийин өзгөрбөйт.
=======
The value of `pageLoadTime` is not known before the page load, so it's named normally. But it's still a constant because it doesn't change after the assignment.
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
Башкача айтканда, баш тамгалар менен аталган константалар "катуу коддолгон" маанилер үчүн тергеме ат катары гана колдонулат.
@@ -307,18 +351,31 @@ const pageLoadTime = /* веб-баракчаны жүктөөгө сарпта
Өзгөрмөнүн аталышы ал сактаган берилмелерди сыпаттаган таза, анык мааниге ээ болушу керек.
<<<<<<< HEAD
Өзгөрмөлөрдү атоо -- бул программалоодогу эң маанилүү жана татаал көндүмдөрдүн бири. Өзгөрмөлөрдүн аттарына тез караш кайсы кодду башталгыч же тажрыйбалуу иштеп чыгуучу жазганын көрсөтө алат.
Чыныгы долбоордо көп убакыт нөлдөн толугу менен өзүнчө бир нерсени жазууга эмес, учурдагы код базасын өзгөртүүгө жана кеңейтүүгө жумшалат. Бир аз убакытка башка бир нерсе кылгандан кийин кодго кайтып келгенде, жакшы белгиленген маалыматты табуу далай жеңил болот. Же, башкача айтканда, өзгөрмөлөр жакшы аттарга ээ болгондо.
=======
Variable naming is one of the most important and complex skills in programming. A glance at variable names can reveal which code was written by a beginner versus an experienced developer.
In a real project, most of the time is spent modifying and extending an existing code base rather than writing something completely separate from scratch. When we return to some code after doing something else for a while, it's much easier to find information that is well-labelled. Or, in other words, when the variables have good names.
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
Сураныч, өзгөрмөнү жарыялоодон мурун анын туура аталышы жөнүндө ойлонууга убакыт бөлүңүз. Ушундай кылыңыз, ошондо сиз сыйланасыз.
Бир нече жакшы эрежелер:
<<<<<<< HEAD
- `userName` же `shoppingCart` сыяктуу окууга оңой аттарды колдонуңуз.
- Эмне кылып жатканыңызды так билбесеңиз, `a`, `b`, `c` сыяктуу кыскартуулардан же кыска аталыштардан алыс болуңуз.
- Аттарды максималдуу түрдө сыпаттоочу жана кыска кылыңыз. Жаман аттардын мисалдары: `data` жана `value`. Мындай ысымдар эч нерсени айтпайт. Аларды коддун контекстинен өзгөрмө кандай маалыматтарды сактай турганы анык болсо гана колдонсо болот.
- Колдонулган терминдер боюнча командаңыз менен макулдашыңыз. Эгер сайтка кирүүчү "user" деп аталса, анда аны менен байланышкан өзгөрмөлөрдү, мисалы, `currentVisitor` же `newManInTown` эмес, `currentUser` же `newUser` деп аташыбыз керек.
=======
- Use human-readable names like `userName` or `shoppingCart`.
- Stay away from abbreviations or short names like `a`, `b`, and `c`, unless you know what you're doing.
- Make names maximally descriptive and concise. Examples of bad names are `data` and `value`. Such names say nothing. It's only okay to use them if the context of the code makes it exceptionally obvious which data or value the variable is referencing.
- Agree on terms within your team and in your mind. If a site visitor is called a "user" then we should name related variables `currentUser` or `newUser` instead of `currentVisitor` or `newManInTown`.
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
Жөнөкөй угулабы? Чынында эле ошондой, бирок тажрыйбада түшүнүктүү жана кыска өзгөрмө аттарын түзүү -- бул сейректик. Алга.
8 changes: 8 additions & 0 deletions 1-js/02-first-steps/05-types/article.md
Original file line number Diff line number Diff line change
@@ -92,13 +92,17 @@ const bigInt = 1234567890123456789012345678901234567890n;
`BigInt` сандары сейрек талап кылынгандыктан, биз аларды бөлөк <info:bigint> бөлүмүндө караштырабыз. Ушунчалык чоң сандар керек болгондо аны окуңуз.
<<<<<<< HEAD
```smart header="Шайкештик көйгөйлөрү"
Азыркы учурда `BigInt` Firefox/Chrome/Edge/Safari браузерлеринде колдоого алынат, бирок IE'де - жок.
```

я Браузердин кайсы версиялары колдоого алынарын билүү үчүн [*MDN* BigInt шайкештик жадыбалын](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility) карап көрсөңүз болот.

## Сап (string)
=======
## String
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
JavaScript'те сап тырмакчага алынышы керек.

@@ -222,7 +226,11 @@ alert(age); // "undefined"

## typeof оператору [#type-typeof]

<<<<<<< HEAD
`typeof` оператору аргументинин түрүн кайтарат. Бул ар кандай түрдөгү маанилерди башкача иштеткибиз келгенде же жөн гана тез текшерүүнү каалаганыбызда пайдалуу.
=======
The `typeof` operator returns the type of the operand. It's useful when we want to process values of different types differently or just want to do a quick check.
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
`typeof x` чалуусу түрү аталышы менен сапты кайтарат:

4 changes: 4 additions & 0 deletions 1-js/02-first-steps/07-type-conversions/article.md
Original file line number Diff line number Diff line change
@@ -34,7 +34,11 @@ alert(typeof value); // string

## Санга айландыруу

<<<<<<< HEAD
Сандарга айландыруу математикалык функцияларда жана туюнтмаларда автоматтык түрдө ишке ашат.
=======
Numeric conversion in mathematical functions and expressions happens automatically.
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
Мисалы, бөлүү `/` сандар эместерге колдонулганда:

16 changes: 15 additions & 1 deletion 1-js/02-first-steps/08-operators/article.md
Original file line number Diff line number Diff line change
@@ -50,8 +50,14 @@
Мисалы үчүн:
```js run
<<<<<<< HEAD
alert( 5 % 2 ); // 1, 5ти 2ге бөлүүнүн калдыгы
alert( 8 % 3 ); // 2, 8ди 3кө бөлүүнүн калдыгы
=======
alert( 5 % 2 ); // 1, the remainder of 5 divided by 2
alert( 8 % 3 ); // 2, the remainder of 8 divided by 3
alert( 8 % 4 ); // 0, the remainder of 8 divided by 4
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
```
### Даражага көтөрүү **
@@ -68,7 +74,11 @@ alert( 2 ** 3 ); // 2³ = 8
alert( 2 ** 4 ); // 2⁴ = 16
```

<<<<<<< HEAD
Математикадагыдай эле, даражага көтөрүү операторун бөлчөктүк сандар үчүн да колдонууга болот.
=======
Just like in maths, the exponentiation operator is defined for non-integer numbers as well.
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b

Мисалы, чарчы тамыр бул ½ даражага көтөрүүсү:

@@ -80,7 +90,11 @@ alert( 8 ** (1/3) ); // 2 (1/3 даражасы кубдук тамыр мене

## Бинардык + менен саптарды кошуу

<<<<<<< HEAD
Келгиле, мектеп арифметикасынын алкагына кирбеген JavaScript операторлорунун өзгөчөлүктөрү менен таанышалы.
=======
Let's meet the features of JavaScript operators that are beyond school arithmetics.
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
Адатта, плюс оператору `+` сандарды кошот.
@@ -308,7 +322,7 @@ let n = 2;
n *= 3 + 5; // алгач оң бөлүгү эсептелинет, n *= 8 менен бирдей
alert( n ); // 16
alert( n ); // 16
```
## Инкремент/декремент
10 changes: 7 additions & 3 deletions 1-js/02-first-steps/10-ifelse/article.md
Original file line number Diff line number Diff line change
@@ -68,7 +68,11 @@ if (cond) {

## "else" пункту

<<<<<<< HEAD
`if` нускамасы кошумча "else" блогун камтышы мүмкүн. Шарт жалган болгондо ал аткарылат.
=======
The `if` statement may contain an optional `else` block. It executes when the condition is falsy.
>>>>>>> 540d753e90789205fc6e75c502f68382c87dea9b
Мисалы:
```js run
@@ -181,9 +185,9 @@ alert( message );
It may be difficult at first to grasp what's going on. But after a closer look, we can see that it's just an ordinary sequence of tests:

1. The first question mark checks whether `age < 3`.
2. If true -- it returns `'Hi, baby!'`. Otherwise, it continues to the expression after the colon '":"', checking `age < 18`.
3. If that's true -- it returns `'Hello!'`. Otherwise, it continues to the expression after the next colon '":"', checking `age < 100`.
4. If that's true -- it returns `'Greetings!'`. Otherwise, it continues to the expression after the last colon '":"', returning `'What an unusual age!'`.
2. If true -- it returns `'Hi, baby!'`. Otherwise, it continues to the expression after the colon ":", checking `age < 18`.
3. If that's true -- it returns `'Hello!'`. Otherwise, it continues to the expression after the next colon ":", checking `age < 100`.
4. If that's true -- it returns `'Greetings!'`. Otherwise, it continues to the expression after the last colon ":", returning `'What an unusual age!'`.

Here's how this looks using `if..else`:
Мында `if..else` колдонгондон кийинки көрүнүшү:
6 changes: 3 additions & 3 deletions 1-js/02-first-steps/12-nullish-coalescing-operator/article.md
Original file line number Diff line number Diff line change
@@ -29,15 +29,15 @@ For example, here we show `user` if its value isn't `null/undefined`, otherwise
```js run
let user;

alert(user ?? "Anonymous"); // Anonymous (user not defined)
alert(user ?? "Anonymous"); // Anonymous (user is undefined)
```
Here's the example with `user` assigned to a name:
```js run
let user = "John";

alert(user ?? "Anonymous"); // John (user defined)
alert(user ?? "Anonymous"); // John (user is not null/undefined)
```
We can also use a sequence of `??` to select the first value from a list that isn't `null/undefined`.
@@ -76,7 +76,7 @@ alert(firstName || lastName || nickName || "Anonymous"); // Supercoder
*/!*
```
Historically, the OR `||` operator was there first. It exists since the beginning of JavaScript, so developers were using it for such purposes for a long time.
Historically, the OR `||` operator was there first. It's been there since the beginning of JavaScript, so developers were using it for such purposes for a long time.
On the other hand, the nullish coalescing operator `??` was added to JavaScript only recently, and the reason for that was that people weren't quite happy with `||`.
2 changes: 1 addition & 1 deletion 1-js/02-first-steps/15-function-basics/article.md
Original file line number Diff line number Diff line change
@@ -460,7 +460,7 @@ These examples assume common meanings of prefixes. You and your team are free to
```smart header="Ultrashort function names"
Functions that are used *very often* sometimes have ultrashort names.

For example, the [jQuery](http://jquery.com) framework defines a function with `$`. The [Lodash](http://lodash.com/) library has its core function named `_`.
For example, the [jQuery](https://jquery.com/) framework defines a function with `$`. The [Lodash](https://lodash.com/) library has its core function named `_`.

These are exceptions. Generally function names should be concise and descriptive.
```
2 changes: 1 addition & 1 deletion 1-js/02-first-steps/16-function-expressions/article.md
Original file line number Diff line number Diff line change
@@ -82,7 +82,7 @@ let sayHi = function() { // (1) create
alert( "Hello" );
};

let func = sayHi;
let func = sayHi; //(2)
// ...
```

8 changes: 4 additions & 4 deletions 1-js/02-first-steps/18-javascript-specials/article.md
Original file line number Diff line number Diff line change
@@ -103,13 +103,13 @@ More in: <info:variables> and <info:types>.

We're using a browser as a working environment, so basic UI functions will be:

[`prompt(question, [default])`](mdn:api/Window/prompt)
[`prompt(question, [default])`](https://developer.mozilla.org/en-US/docs/Web/API/Window/prompt)
: Ask a `question`, and return either what the visitor entered or `null` if they clicked "cancel".

[`confirm(question)`](mdn:api/Window/confirm)
[`confirm(question)`](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm)
: Ask a `question` and suggest to choose between Ok and Cancel. The choice is returned as `true/false`.

[`alert(message)`](mdn:api/Window/alert)
[`alert(message)`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert)
: Output a `message`.

All these functions are *modal*, they pause the code execution and prevent the visitor from interacting with the page until they answer.
@@ -144,7 +144,7 @@ Assignments
: There is a simple assignment: `a = b` and combined ones like `a *= 2`.

Bitwise
: Bitwise operators work with 32-bit integers at the lowest, bit-level: see the [docs](mdn:/JavaScript/Guide/Expressions_and_Operators#bitwise_operators) when they are needed.
: Bitwise operators work with 32-bit integers at the lowest, bit-level: see the [docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#bitwise_operators) when they are needed.

Conditional
: The only operator with three parameters: `cond ? resultA : resultB`. If `cond` is truthy, returns `resultA`, otherwise `resultB`.
12 changes: 6 additions & 6 deletions 1-js/03-code-quality/05-testing-mocha/article.md
Original file line number Diff line number Diff line change
@@ -69,7 +69,7 @@ The flow of development usually looks like this:

1. An initial spec is written, with tests for the most basic functionality.
2. An initial implementation is created.
3. To check whether it works, we run the testing framework [Mocha](http://mochajs.org/) (more details soon) that runs the spec. While the functionality is not complete, errors are displayed. We make corrections until everything works.
3. To check whether it works, we run the testing framework [Mocha](https://mochajs.org/) (more details soon) that runs the spec. While the functionality is not complete, errors are displayed. We make corrections until everything works.
4. Now we have a working initial implementation with tests.
5. We add more use cases to the spec, probably not yet supported by the implementations. Tests start to fail.
6. Go to 3, update the implementation till tests give no errors.
@@ -85,9 +85,9 @@ The first step is already complete: we have an initial spec for `pow`. Now, befo

Here in the tutorial we'll be using the following JavaScript libraries for tests:

- [Mocha](http://mochajs.org/) -- the core framework: it provides common testing functions including `describe` and `it` and the main function that runs tests.
- [Chai](http://chaijs.com) -- the library with many assertions. It allows to use a lot of different assertions, for now we need only `assert.equal`.
- [Sinon](http://sinonjs.org/) -- a library to spy over functions, emulate built-in functions and more, we'll need it much later.
- [Mocha](https://mochajs.org/) -- the core framework: it provides common testing functions including `describe` and `it` and the main function that runs tests.
- [Chai](https://www.chaijs.com/) -- the library with many assertions. It allows to use a lot of different assertions, for now we need only `assert.equal`.
- [Sinon](https://sinonjs.org/) -- a library to spy over functions, emulate built-in functions and more, we'll need it much later.

These libraries are suitable for both in-browser and server-side testing. Here we'll consider the browser variant.

@@ -338,14 +338,14 @@ The newly added tests fail, because our implementation does not support them. Th
```smart header="Other assertions"
Please note the assertion `assert.isNaN`: it checks for `NaN`.
There are other assertions in [Chai](http://chaijs.com) as well, for instance:
There are other assertions in [Chai](https://www.chaijs.com/) as well, for instance:
- `assert.equal(value1, value2)` -- checks the equality `value1 == value2`.
- `assert.strictEqual(value1, value2)` -- checks the strict equality `value1 === value2`.
- `assert.notEqual`, `assert.notStrictEqual` -- inverse checks to the ones above.
- `assert.isTrue(value)` -- checks that `value === true`
- `assert.isFalse(value)` -- checks that `value === false`
- ...the full list is in the [docs](http://chaijs.com/api/assert/)
- ...the full list is in the [docs](https://www.chaijs.com/api/assert/)
```
So we should add a couple of lines to `pow`:
11 changes: 4 additions & 7 deletions 1-js/03-code-quality/06-polyfills/article.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@

# Polyfills and transpilers

The JavaScript language steadily evolves. New proposals to the language appear regularly, they are analyzed and, if considered worthy, are appended to the list at <https://tc39.github.io/ecma262/> and then progress to the [specification](http://www.ecma-international.org/publications/standards/Ecma-262.htm).
The JavaScript language steadily evolves. New proposals to the language appear regularly, they are analyzed and, if considered worthy, are appended to the list at <https://tc39.github.io/ecma262/> and then progress to the [specification](https://www.ecma-international.org/publications-and-standards/standards/ecma-262/).

Teams behind JavaScript engines have their own ideas about what to implement first. They may decide to implement proposals that are in draft and postpone things that are already in the spec, because they are less interesting or just harder to do.

So it's quite common for an engine to implement only part of the standard.

A good page to see the current state of support for language features is <https://kangax.github.io/compat-table/es6/> (it's big, we have a lot to study yet).
A good page to see the current state of support for language features is <https://compat-table.github.io/compat-table/es6/> (it's big, we have a lot to study yet).

As programmers, we'd like to use most recent features. The more good stuff - the better!

@@ -71,10 +71,7 @@ if (!Math.trunc) { // if no such function
JavaScript is a highly dynamic language. Scripts may add/modify any function, even built-in ones.
Two interesting polyfill libraries are:
- [core js](https://github.com/zloirock/core-js) that supports a lot, allows to include only needed features.
- [polyfill.io](http://polyfill.io) service that provides a script with polyfills, depending on the features and user's browser.
One interesting polyfill library is [core-js](https://github.com/zloirock/core-js), which supports a wide range of features and allows you to include only the ones you need.
## Summary
@@ -85,7 +82,7 @@ Just don't forget to use a transpiler (if using modern syntax or operators) and
For example, later when you're familiar with JavaScript, you can setup a code build system based on [webpack](https://webpack.js.org/) with the [babel-loader](https://github.com/babel/babel-loader) plugin.
Good resources that show the current state of support for various features:
- <https://kangax.github.io/compat-table/es6/> - for pure JavaScript.
- <https://compat-table.github.io/compat-table/es6/> - for pure JavaScript.
- <https://caniuse.com/> - for browser-related functions.
P.S. Google Chrome is usually the most up-to-date with language features, try it if a tutorial demo fails. Most tutorial demos work with any modern browser though.
4 changes: 2 additions & 2 deletions 1-js/04-object-basics/03-garbage-collection/article.md
Original file line number Diff line number Diff line change
@@ -205,8 +205,8 @@ Modern engines implement advanced algorithms of garbage collection.

A general book "The Garbage Collection Handbook: The Art of Automatic Memory Management" (R. Jones et al) covers some of them.

If you are familiar with low-level programming, more detailed information about V8's garbage collector is in the article [A tour of V8: Garbage Collection](http://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection).
If you are familiar with low-level programming, more detailed information about V8's garbage collector is in the article [A tour of V8: Garbage Collection](https://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection).

The [V8 blog](https://v8.dev/) also publishes articles about changes in memory management from time to time. Naturally, to learn more about garbage collection, you'd better prepare by learning about V8 internals in general and read the blog of [Vyacheslav Egorov](http://mrale.ph) who worked as one of the V8 engineers. I'm saying: "V8", because it is best covered by articles on the internet. For other engines, many approaches are similar, but garbage collection differs in many aspects.
The [V8 blog](https://v8.dev/) also publishes articles about changes in memory management from time to time. Naturally, to learn more about garbage collection, you'd better prepare by learning about V8 internals in general and read the blog of [Vyacheslav Egorov](https://mrale.ph) who worked as one of the V8 engineers. I'm saying: "V8", because it is best covered by articles on the internet. For other engines, many approaches are similar, but garbage collection differs in many aspects.

In-depth knowledge of engines is good when you need low-level optimizations. It would be wise to plan that as the next step after you're familiar with the language.
8 changes: 4 additions & 4 deletions 1-js/04-object-basics/04-object-methods/8-chain-calls/task.md
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ importance: 2

# Chaining

There's a `ladder` object that allows to go up and down:
There's a `ladder` object that allows you to go up and down:

```js
let ladder = {
@@ -21,7 +21,7 @@ let ladder = {
};
```

Now, if we need to make several calls in sequence, can do it like this:
Now, if we need to make several calls in sequence, we can do it like this:

```js
ladder.up();
@@ -32,10 +32,10 @@ ladder.down();
ladder.showStep(); // 0
```

Modify the code of `up`, `down` and `showStep` to make the calls chainable, like this:
Modify the code of `up`, `down`, and `showStep` to make the calls chainable, like this:

```js
ladder.up().up().down().showStep().down().showStep(); // shows 1 then 0
```

Such approach is widely used across JavaScript libraries.
Such an approach is widely used across JavaScript libraries.
4 changes: 2 additions & 2 deletions 1-js/04-object-basics/09-object-toprimitive/article.md
Original file line number Diff line number Diff line change
@@ -226,7 +226,7 @@ As we know already, many operators and functions perform type conversions, e.g.

If we pass an object as an argument, then there are two stages of calculations:
1. The object is converted to a primitive (using the rules described above).
2. If the necessary for further calculations, the resulting primitive is also converted.
2. If necessary for further calculations, the resulting primitive is also converted.

For instance:

@@ -253,7 +253,7 @@ let obj = {
}
};

alert(obj + 2); // 22 ("2" + 2), conversion to primitive returned a string => concatenation
alert(obj + 2); // "22" ("2" + 2), conversion to primitive returned a string => concatenation
```

## Summary
40 changes: 24 additions & 16 deletions 1-js/05-data-types/02-number/article.md
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ In modern JavaScript, there are two types of numbers:

1. Regular numbers in JavaScript are stored in 64-bit format [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754), also known as "double precision floating point numbers". These are numbers that we're using most of the time, and we'll talk about them in this chapter.

2. BigInt numbers represent integers of arbitrary length. They are sometimes needed because a regular integer number can't safely exceed <code>(2<sup>53</sup>-1)</code> or be less than <code>-(2<sup>53</sup>-1)</code>, as we mentioned earlier in the chapter <info:types>. As bigints are used in few special areas, we devote them a special chapter <info:bigint>.
2. BigInt numbers represent integers of arbitrary length. They are sometimes needed because a regular integer number can't safely exceed <code>(2<sup>53</sup>-1)</code> or be less than <code>-(2<sup>53</sup>-1)</code>, as we mentioned earlier in the chapter <info:types>. As bigints are used in a few special areas, we devote them to a special chapter <info:bigint>.

So here we'll talk about regular numbers. Let's expand our knowledge of them.

@@ -41,7 +41,7 @@ In other words, `e` multiplies the number by `1` with the given zeroes count.
1.23e6 === 1.23 * 1000000; // e6 means *1000000
```

Now let's write something very small. Say, 1 microsecond (one millionth of a second):
Now let's write something very small. Say, 1 microsecond (one-millionth of a second):

```js
let mсs = 0.000001;
@@ -103,13 +103,13 @@ alert( num.toString(16) ); // ff
alert( num.toString(2) ); // 11111111
```

The `base` can vary from `2` to `36`. By default it's `10`.
The `base` can vary from `2` to `36`. By default, it's `10`.

Common use cases for this are:

- **base=16** is used for hex colors, character encodings etc, digits can be `0..9` or `A..F`.
- **base=2** is mostly for debugging bitwise operations, digits can be `0` or `1`.
- **base=36** is the maximum, digits can be `0..9` or `A..Z`. The whole latin alphabet is used to represent a number. A funny, but useful case for `36` is when we need to turn a long numeric identifier into something shorter, for example to make a short url. Can simply represent it in the numeral system with base `36`:
- **base=36** is the maximum, digits can be `0..9` or `A..Z`. The whole Latin alphabet is used to represent a number. A funny, but useful case for `36` is when we need to turn a long numeric identifier into something shorter, for example, to make a short url. Can simply represent it in the numeral system with base `36`:

```js run
alert( 123456..toString(36) ); // 2n9c
@@ -118,7 +118,7 @@ Common use cases for this are:
```warn header="Two dots to call a method"
Please note that two dots in `123456..toString(36)` is not a typo. If we want to call a method directly on a number, like `toString` in the example above, then we need to place two dots `..` after it.
If we placed a single dot: `123456.toString(36)`, then there would be an error, because JavaScript syntax implies the decimal part after the first dot. And if we place one more dot, then JavaScript knows that the decimal part is empty and now goes the method.
If we placed a single dot: `123456.toString(36)`, then there would be an error, because JavaScript syntax implies the decimal part after the first dot. And if we place one more dot, then JavaScript knows that the decimal part is empty and now uses the method.
Also could write `(123456).toString(36)`.
@@ -137,7 +137,7 @@ There are several built-in functions for rounding:
: Rounds up: `3.1` becomes `4`, and `-1.1` becomes `-1`.

`Math.round`
: Rounds to the nearest integer: `3.1` becomes `3`, `3.6` becomes `4`, the middle case: `3.5` rounds up to `4` too.
: Rounds to the nearest integer: `3.1` becomes `3`, `3.6` becomes `4`. In the middle cases `3.5` rounds up to `4`, and `-3.5` rounds up to `-3`.

`Math.trunc` (not supported by Internet Explorer)
: Removes anything after the decimal point without rounding: `3.1` becomes `3`, `-1.1` becomes `-1`.
@@ -147,8 +147,10 @@ Here's the table to summarize the differences between them:
| | `Math.floor` | `Math.ceil` | `Math.round` | `Math.trunc` |
|---|---------|--------|---------|---------|
|`3.1`| `3` | `4` | `3` | `3` |
|`3.5`| `3` | `4` | `4` | `3` |
|`3.6`| `3` | `4` | `4` | `3` |
|`-1.1`| `-2` | `-1` | `-1` | `-1` |
|`-1.5`| `-2` | `-1` | `-1` | `-1` |
|`-1.6`| `-2` | `-1` | `-2` | `-1` |
@@ -188,7 +190,7 @@ There are two ways to do so:
alert( num.toFixed(5) ); // "12.34000", added zeroes to make exactly 5 digits
```

We can convert it to a number using the unary plus or a `Number()` call, e.g write `+num.toFixed(5)`.
We can convert it to a number using the unary plus or a `Number()` call, e.g. write `+num.toFixed(5)`.

## Imprecise calculations

@@ -222,7 +224,13 @@ But why does this happen?

A number is stored in memory in its binary form, a sequence of bits - ones and zeroes. But fractions like `0.1`, `0.2` that look simple in the decimal numeric system are actually unending fractions in their binary form.

What is `0.1`? It is one divided by ten `1/10`, one-tenth. In decimal numeral system such numbers are easily representable. Compare it to one-third: `1/3`. It becomes an endless fraction `0.33333(3)`.
```js run
alert(0.1.toString(2)); // 0.0001100110011001100110011001100110011001100110011001101
alert(0.2.toString(2)); // 0.001100110011001100110011001100110011001100110011001101
alert((0.1 + 0.2).toString(2)); // 0.0100110011001100110011001100110011001100110011001101
```

What is `0.1`? It is one divided by ten `1/10`, one-tenth. In the decimal numeral system, such numbers are easily representable. Compare it to one-third: `1/3`. It becomes an endless fraction `0.33333(3)`.

So, division by powers `10` is guaranteed to work well in the decimal system, but division by `3` is not. For the same reason, in the binary numeral system, the division by powers of `2` is guaranteed to work, but `1/10` becomes an endless binary fraction.

@@ -242,7 +250,7 @@ That's why `0.1 + 0.2` is not exactly `0.3`.
```smart header="Not only JavaScript"
The same issue exists in many other programming languages.

PHP, Java, C, Perl, Ruby give exactly the same result, because they are based on the same numeric format.
PHP, Java, C, Perl, and Ruby give exactly the same result, because they are based on the same numeric format.
```

Can we work around the problem? Sure, the most reliable method is to round the result with the help of a method [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed):
@@ -266,7 +274,7 @@ alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3
alert( (0.28 * 100 + 0.14 * 100) / 100); // 0.4200000000000001
```

So, multiply/divide approach reduces the error, but doesn't remove it totally.
So, the multiply/divide approach reduces the error, but doesn't remove it totally.

Sometimes we could try to evade fractions at all. Like if we're dealing with a shop, then we can store prices in cents instead of dollars. But what if we apply a discount of 30%? In practice, totally evading fractions is rarely possible. Just round them to cut "tails" when needed.

@@ -288,7 +296,7 @@ Another funny consequence of the internal representation of numbers is the exist

That's because a sign is represented by a single bit, so it can be set or not set for any number including a zero.

In most cases the distinction is unnoticeable, because operators are suited to treat them as the same.
In most cases, the distinction is unnoticeable, because operators are suited to treat them as the same.
```

## Tests: isFinite and isNaN
@@ -337,7 +345,7 @@ Please note that an empty or a space-only string is treated as `0` in all numeri
````smart header="`Number.isNaN` and `Number.isFinite`"
[Number.isNaN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN) and [Number.isFinite](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isFinite) methods are the more "strict" versions of `isNaN` and `isFinite` functions. They do not autoconvert their argument into a number, but check if it belongs to the `number` type instead.

- `Number.isNaN(value)` returns `true` if the argument belongs to the `number` type and it is `NaN`. In any other case it returns `false`.
- `Number.isNaN(value)` returns `true` if the argument belongs to the `number` type and it is `NaN`. In any other case, it returns `false`.

```js run
alert( Number.isNaN(NaN) ); // true
@@ -348,7 +356,7 @@ Please note that an empty or a space-only string is treated as `0` in all numeri
alert( isNaN("str") ); // true, because isNaN converts string "str" into a number and gets NaN as a result of this conversion
```

- `Number.isFinite(value)` returns `true` if the argument belongs to the `number` type and it is not `NaN/Infinity/-Infinity`. In any other case it returns `false`.
- `Number.isFinite(value)` returns `true` if the argument belongs to the `number` type and it is not `NaN/Infinity/-Infinity`. In any other case, it returns `false`.

```js run
alert( Number.isFinite(123) ); // true
@@ -367,7 +375,7 @@ In a way, `Number.isNaN` and `Number.isFinite` are simpler and more straightforw
There is a special built-in method `Object.is` that compares values like `===`, but is more reliable for two edge cases:

1. It works with `NaN`: `Object.is(NaN, NaN) === true`, that's a good thing.
2. Values `0` and `-0` are different: `Object.is(0, -0) === false`, technically that's correct, because internally the number has a sign bit that may be different even if all other bits are zeroes.
2. Values `0` and `-0` are different: `Object.is(0, -0) === false`, technically that's correct because internally the number has a sign bit that may be different even if all other bits are zeroes.

In all other cases, `Object.is(a, b)` is the same as `a === b`.

@@ -385,7 +393,7 @@ alert( +"100px" ); // NaN

The sole exception is spaces at the beginning or at the end of the string, as they are ignored.

But in real life we often have values in units, like `"100px"` or `"12pt"` in CSS. Also in many countries the currency symbol goes after the amount, so we have `"19€"` and would like to extract a numeric value out of that.
But in real life, we often have values in units, like `"100px"` or `"12pt"` in CSS. Also in many countries, the currency symbol goes after the amount, so we have `"19€"` and would like to extract a numeric value out of that.

That's what `parseInt` and `parseFloat` are for.

@@ -479,4 +487,4 @@ For fractions:

More mathematical functions:

- See the [Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) object when you need them. The library is very small, but can cover basic needs.
- See the [Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) object when you need them. The library is very small but can cover basic needs.
4 changes: 2 additions & 2 deletions 1-js/05-data-types/03-string/3-truncate/task.md
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ The result of the function should be the truncated (if needed) string.
For instance:

```js
truncate("What I'd like to tell on this topic is:", 20) = "What I'd like to te…"
truncate("What I'd like to tell on this topic is:", 20) == "What I'd like to te…"

truncate("Hi everyone!", 20) = "Hi everyone!"
truncate("Hi everyone!", 20) == "Hi everyone!"
```
4 changes: 2 additions & 2 deletions 1-js/05-data-types/03-string/article.md
Original file line number Diff line number Diff line change
@@ -505,7 +505,7 @@ This method actually has two additional arguments specified in [the documentatio
- There are 3 types of quotes. Backticks allow a string to span multiple lines and embed expressions `${…}`.
- We can use special characters, such as a line break `\n`.
- To get a character, use: `[]`.
- To get a character, use: `[]` or `at` method.
- To get a substring, use: `slice` or `substring`.
- To lowercase/uppercase a string, use: `toLowerCase/toUpperCase`.
- To look for a substring, use: `indexOf`, or `includes/startsWith/endsWith` for simple checks.
@@ -519,4 +519,4 @@ There are several other helpful methods in strings:
Strings also have methods for doing search/replace with regular expressions. But that's big topic, so it's explained in a separate tutorial section <info:regular-expressions>.
Also, as of now it's important to know that strings are based on Unicode encoding, and hence there're issues with comparisons. There's more about Unicode in the chapter <info:unicode>.
Also, as of now it's important to know that strings are based on Unicode encoding, and hence there're issues with comparisons. There's more about Unicode in the chapter <info:unicode>.
4 changes: 2 additions & 2 deletions 1-js/05-data-types/04-array/article.md
Original file line number Diff line number Diff line change
@@ -98,7 +98,7 @@ The "trailing comma" style makes it easier to insert/remove items, because all l

Let's say we want the last element of the array.

Some programming languages allow to use negative indexes for the same purpose, like `fruits[-1]`.
Some programming languages allow the use of negative indexes for the same purpose, like `fruits[-1]`.

Although, in JavaScript it won't work. The result will be `undefined`, because the index in square brackets is treated literally.

@@ -426,7 +426,7 @@ let matrix = [
[7, 8, 9]
];

alert( matrix[1][1] ); // 5, the central element
alert( matrix[0][1] ); // 2, the second value of the first inner array
```

## toString
50 changes: 24 additions & 26 deletions 1-js/05-data-types/05-array-methods/article.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Array methods

Arrays provide a lot of methods. To make things easier, in this chapter they are split into groups.
Arrays provide a lot of methods. To make things easier, in this chapter, they are split into groups.

## Add/remove items

@@ -32,11 +32,11 @@ alert( arr.length ); // 3

The element was removed, but the array still has 3 elements, we can see that `arr.length == 3`.

That's natural, because `delete obj.key` removes a value by the `key`. It's all it does. Fine for objects. But for arrays we usually want the rest of elements to shift and occupy the freed place. We expect to have a shorter array now.
That's natural, because `delete obj.key` removes a value by the `key`. It's all it does. Fine for objects. But for arrays we usually want the rest of the elements to shift and occupy the freed place. We expect to have a shorter array now.

So, special methods should be used.

The [arr.splice](mdn:js/Array/splice) method is a swiss army knife for arrays. It can do everything: insert, remove and replace elements.
The [arr.splice](mdn:js/Array/splice) method is a Swiss army knife for arrays. It can do everything: insert, remove and replace elements.

The syntax is:

@@ -62,7 +62,7 @@ alert( arr ); // ["I", "JavaScript"]

Easy, right? Starting from the index `1` it removed `1` element.

In the next example we remove 3 elements and replace them with the other two:
In the next example, we remove 3 elements and replace them with the other two:

```js run
let arr = [*!*"I", "study", "JavaScript",*/!* "right", "now"];
@@ -84,7 +84,7 @@ let removed = arr.splice(0, 2);
alert( removed ); // "I", "study" <-- array of removed elements
```

The `splice` method is also able to insert the elements without any removals. For that we need to set `deleteCount` to `0`:
The `splice` method is also able to insert the elements without any removals. For that, we need to set `deleteCount` to `0`:

```js run
let arr = ["I", "study", "JavaScript"];
@@ -114,7 +114,7 @@ alert( arr ); // 1,2,3,4,5

### slice

The method [arr.slice](mdn:js/Array/slice) is much simpler than similar-looking `arr.splice`.
The method [arr.slice](mdn:js/Array/slice) is much simpler than the similar-looking `arr.splice`.

The syntax is:

@@ -124,7 +124,7 @@ arr.slice([start], [end])

It returns a new array copying to it all items from index `start` to `end` (not including `end`). Both `start` and `end` can be negative, in that case position from array end is assumed.

It's similar to a string method `str.slice`, but instead of substrings it makes subarrays.
It's similar to a string method `str.slice`, but instead of substrings, it makes subarrays.

For instance:

@@ -206,7 +206,7 @@ The [arr.forEach](mdn:js/Array/forEach) method allows to run a function for ever
The syntax:
```js
arr.forEach(function(item, index, array) {
// ... do something with item
// ... do something with an item
});
```

@@ -239,7 +239,7 @@ The methods [arr.indexOf](mdn:js/Array/indexOf) and [arr.includes](mdn:js/Array/
- `arr.indexOf(item, from)` -- looks for `item` starting from index `from`, and returns the index where it was found, otherwise `-1`.
- `arr.includes(item, from)` -- looks for `item` starting from index `from`, returns `true` if found.

Usually these methods are used with only one argument: the `item` to search. By default, the search is from the beginning.
Usually, these methods are used with only one argument: the `item` to search. By default, the search is from the beginning.

For instance:

@@ -255,7 +255,7 @@ alert( arr.includes(1) ); // true

Please note that `indexOf` uses the strict equality `===` for comparison. So, if we look for `false`, it finds exactly `false` and not the zero.

If we want to check if `item` exists in the array, and don't need the exact index, then `arr.includes` is preferred.
If we want to check if `item` exists in the array and don't need the index, then `arr.includes` is preferred.

The method [arr.lastIndexOf](mdn:js/Array/lastIndexOf) is the same as `indexOf`, but looks for from right to left.

@@ -274,12 +274,12 @@ const arr = [NaN];
alert( arr.indexOf(NaN) ); // -1 (wrong, should be 0)
alert( arr.includes(NaN) );// true (correct)
```
That's because `includes` was added to JavaScript much later and uses the more up to date comparison algorithm internally.
That's because `includes` was added to JavaScript much later and uses the more up-to-date comparison algorithm internally.
````
### find and findIndex/findLastIndex
Imagine we have an array of objects. How do we find an object with the specific condition?
Imagine we have an array of objects. How do we find an object with a specific condition?
Here the [arr.find(fn)](mdn:js/Array/find) method comes in handy.
@@ -297,7 +297,7 @@ The function is called for elements of the array, one after another:
- `index` is its index.
- `array` is the array itself.
If it returns `true`, the search is stopped, the `item` is returned. If nothing found, `undefined` is returned.
If it returns `true`, the search is stopped, the `item` is returned. If nothing is found, `undefined` is returned.
For example, we have an array of users, each with the fields `id` and `name`. Let's find the one with `id == 1`:
@@ -313,11 +313,11 @@ let user = users.find(item => item.id == 1);
alert(user.name); // John
```
In real life arrays of objects is a common thing, so the `find` method is very useful.
In real life, arrays of objects are a common thing, so the `find` method is very useful.
Note that in the example we provide to `find` the function `item => item.id == 1` with one argument. That's typical, other arguments of this function are rarely used.
The [arr.findIndex](mdn:js/Array/findIndex) method has the same syntax, but returns the index where the element was found instead of the element itself. The value of `-1` is returned if nothing is found.
The [arr.findIndex](mdn:js/Array/findIndex) method has the same syntax but returns the index where the element was found instead of the element itself. The value of `-1` is returned if nothing is found.
The [arr.findLastIndex](mdn:js/Array/findLastIndex) method is like `findIndex`, but searches from right to left, similar to `lastIndexOf`.
@@ -338,8 +338,6 @@ alert(users.findIndex(user => user.name == 'John')); // 0
alert(users.findLastIndex(user => user.name == 'John')); // 3
```
### filter
The `find` method looks for a single (first) element that makes the function return `true`.
@@ -452,11 +450,11 @@ alert(arr); // *!*1, 2, 15*/!*
Now it works as intended.
Let's step aside and think what's happening. The `arr` can be array of anything, right? It may contain numbers or strings or objects or whatever. We have a set of *some items*. To sort it, we need an *ordering function* that knows how to compare its elements. The default is a string order.
Let's step aside and think about what's happening. The `arr` can be an array of anything, right? It may contain numbers or strings or objects or whatever. We have a set of *some items*. To sort it, we need an *ordering function* that knows how to compare its elements. The default is a string order.
The `arr.sort(fn)` method implements a generic sorting algorithm. We don't need to care how it internally works (an optimized [quicksort](https://en.wikipedia.org/wiki/Quicksort) or [Timsort](https://en.wikipedia.org/wiki/Timsort) most of the time). It will walk the array, compare its elements using the provided function and reorder them, all we need is to provide the `fn` which does the comparison.
By the way, if we ever want to know which elements are compared -- nothing prevents from alerting them:
By the way, if we ever want to know which elements are compared -- nothing prevents us from alerting them:
```js run
[1, -2, 15, 2, 0, 8].sort(function(a, b) {
@@ -528,7 +526,7 @@ Here's the situation from real life. We are writing a messaging app, and the per
The [str.split(delim)](mdn:js/String/split) method does exactly that. It splits the string into an array by the given delimiter `delim`.
In the example below, we split by a comma followed by space:
In the example below, we split by a comma followed by a space:
```js run
let names = 'Bilbo, Gandalf, Nazgul';
@@ -595,9 +593,9 @@ Arguments:
- `index` -- is its position.
- `array` -- is the array.

As function is applied, the result of the previous function call is passed to the next one as the first argument.
As the function is applied, the result of the previous function call is passed to the next one as the first argument.

So, the first argument is essentially the accumulator that stores the combined result of all previous executions. And at the end it becomes the result of `reduce`.
So, the first argument is essentially the accumulator that stores the combined result of all previous executions. And at the end, it becomes the result of `reduce`.

Sounds complicated?

@@ -666,7 +664,7 @@ arr.reduce((sum, current) => sum + current);

So it's advised to always specify the initial value.

The method [arr.reduceRight](mdn:js/Array/reduceRight) does the same, but goes from right to left.
The method [arr.reduceRight](mdn:js/Array/reduceRight) does the same but goes from right to left.

## Array.isArray

@@ -691,7 +689,7 @@ alert(Array.isArray([])); // true

Almost all array methods that call functions -- like `find`, `filter`, `map`, with a notable exception of `sort`, accept an optional additional parameter `thisArg`.

That parameter is not explained in the sections above, because it's rarely used. But for completeness we have to cover it.
That parameter is not explained in the sections above, because it's rarely used. But for completeness, we have to cover it.

Here's the full syntax of these methods:

@@ -751,7 +749,7 @@ A cheat sheet of array methods:
- `concat(...items)` -- returns a new array: copies all members of the current one and adds `items` to it. If any of `items` is an array, then its elements are taken.

- To search among elements:
- `indexOf/lastIndexOf(item, pos)` -- look for `item` starting from position `pos`, return the index or `-1` if not found.
- `indexOf/lastIndexOf(item, pos)` -- look for `item` starting from position `pos`, and return the index or `-1` if not found.
- `includes(value)` -- returns `true` if the array has `value`, otherwise `false`.
- `find/filter(func)` -- filter elements through the function, return first/all values that make it return `true`.
- `findIndex` is like `find`, but returns the index instead of a value.
@@ -797,7 +795,7 @@ These methods are the most used ones, they cover 99% of use cases. But there are

For the full list, see the [manual](mdn:js/Array).

From the first sight it may seem that there are so many methods, quite difficult to remember. But actually that's much easier.
At first sight, it may seem that there are so many methods, quite difficult to remember. But actually, that's much easier.

Look through the cheat sheet just to be aware of them. Then solve the tasks of this chapter to practice, so that you have experience with array methods.

2 changes: 1 addition & 1 deletion 1-js/05-data-types/06-iterable/article.md
Original file line number Diff line number Diff line change
@@ -174,7 +174,7 @@ When we use JavaScript for practical tasks in a browser or any other environment

For instance, strings are both iterable (`for..of` works on them) and array-like (they have numeric indexes and `length`).

But an iterable may be not array-like. And vice versa an array-like may be not iterable.
But an iterable may not be array-like. And vice versa an array-like may not be iterable.

For example, the `range` in the example above is iterable, but not array-like, because it does not have indexed properties and `length`.

77 changes: 38 additions & 39 deletions 1-js/05-data-types/07-map-set/article.md
Original file line number Diff line number Diff line change
@@ -10,17 +10,17 @@ But that's not enough for real life. That's why `Map` and `Set` also exist.

## Map

[Map](mdn:js/Map) is a collection of keyed data items, just like an `Object`. But the main difference is that `Map` allows keys of any type.
[Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) is a collection of keyed data items, just like an `Object`. But the main difference is that `Map` allows keys of any type.

Methods and properties are:

- `new Map()` -- creates the map.
- [`map.set(key, value)`](mdn:js/Map/set) -- stores the value by the key.
- [`map.get(key)`](mdn:js/Map/get) -- returns the value by the key, `undefined` if `key` doesn't exist in map.
- [`map.has(key)`](mdn:js/Map/has) -- returns `true` if the `key` exists, `false` otherwise.
- [`map.delete(key)`](mdn:js/Map/delete) -- removes the value by the key.
- [`map.clear()`](mdn:js/Map/clear) -- removes everything from the map.
- [`map.size`](mdn:js/Map/size) -- returns the current element count.
- [`new Map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/Map) -- creates the map.
- [`map.set(key, value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set) -- stores the value by the key.
- [`map.get(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get) -- returns the value by the key, `undefined` if `key` doesn't exist in map.
- [`map.has(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has) -- returns `true` if the `key` exists, `false` otherwise.
- [`map.delete(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete) -- removes the element (the key/value pair) by the key.
- [`map.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear) -- removes everything from the map.
- [`map.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size) -- returns the current element count.

For instance:

@@ -100,14 +100,13 @@ map.set('1', 'str1')
```
````
## Iteration over Map
For looping over a `map`, there are 3 methods:
- [`map.keys()`](mdn:js/Map/keys) -- returns an iterable for keys,
- [`map.values()`](mdn:js/Map/values) -- returns an iterable for values,
- [`map.entries()`](mdn:js/Map/entries) -- returns an iterable for entries `[key, value]`, it's used by default in `for..of`.
- [`map.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/keys) -- returns an iterable for keys,
- [`map.values()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/values) -- returns an iterable for values,
- [`map.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/entries) -- returns an iterable for entries `[key, value]`, it's used by default in `for..of`.
For instance:
@@ -162,7 +161,7 @@ let map = new Map([
alert( map.get('1') ); // str1
```
If we have a plain object, and we'd like to create a `Map` from it, then we can use built-in method [Object.entries(obj)](mdn:js/Object/entries) that returns an array of key/value pairs for an object exactly in that format.
If we have a plain object, and we'd like to create a `Map` from it, then we can use built-in method [Object.entries(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries) that returns an array of key/value pairs for an object exactly in that format.
So we can create a map from an object like this:
@@ -233,16 +232,16 @@ That's the same, because `Object.fromEntries` expects an iterable object as the
## Set
A `Set` is a special type collection - "set of values" (without keys), where each value may occur only once.
A [`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) is a special type collection - "set of values" (without keys), where each value may occur only once.
Its main methods are:
- `new Set(iterable)` -- creates the set, and if an `iterable` object is provided (usually an array), copies values from it into the set.
- [`set.add(value)`](mdn:js/Set/add) -- adds a value, returns the set itself.
- [`set.delete(value)`](mdn:js/Set/delete) -- removes the value, returns `true` if `value` existed at the moment of the call, otherwise `false`.
- [`set.has(value)`](mdn:js/Set/has) -- returns `true` if the value exists in the set, otherwise `false`.
- [`set.clear()`](mdn:js/Set/clear) -- removes everything from the set.
- [`set.size`](mdn:js/Set/size) -- is the elements count.
- [`new Set([iterable])`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/Set) -- creates the set, and if an `iterable` object is provided (usually an array), copies values from it into the set.
- [`set.add(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/add) -- adds a value, returns the set itself.
- [`set.delete(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/delete) -- removes the value, returns `true` if `value` existed at the moment of the call, otherwise `false`.
- [`set.has(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/has) -- returns `true` if the value exists in the set, otherwise `false`.
- [`set.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/clear) -- removes everything from the set.
- [`set.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/size) -- is the elements count.
The main feature is that repeated calls of `set.add(value)` with the same value don't do anything. That's the reason why each value appears in a `Set` only once.
@@ -272,7 +271,7 @@ for (let user of set) {
}
```
The alternative to `Set` could be an array of users, and the code to check for duplicates on every insertion using [arr.find](mdn:js/Array/find). But the performance would be much worse, because this method walks through the whole array checking every element. `Set` is much better optimized internally for uniqueness checks.
The alternative to `Set` could be an array of users, and the code to check for duplicates on every insertion using [arr.find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find). But the performance would be much worse, because this method walks through the whole array checking every element. `Set` is much better optimized internally for uniqueness checks.
## Iteration over Set
@@ -295,38 +294,38 @@ That's for compatibility with `Map` where the callback passed `forEach` has thre
The same methods `Map` has for iterators are also supported:
- [`set.keys()`](mdn:js/Set/keys) -- returns an iterable object for values,
- [`set.values()`](mdn:js/Set/values) -- same as `set.keys()`, for compatibility with `Map`,
- [`set.entries()`](mdn:js/Set/entries) -- returns an iterable object for entries `[value, value]`, exists for compatibility with `Map`.
- [`set.keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/keys) -- returns an iterable object for values,
- [`set.values()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/values) -- same as `set.keys()`, for compatibility with `Map`,
- [`set.entries()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/entries) -- returns an iterable object for entries `[value, value]`, exists for compatibility with `Map`.
## Summary
`Map` -- is a collection of keyed values.
[`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) -- is a collection of keyed values.
Methods and properties:
- `new Map([iterable])` -- creates the map, with optional `iterable` (e.g. array) of `[key,value]` pairs for initialization.
- [`map.set(key, value)`](mdn:js/Map/set) -- stores the value by the key, returns the map itself.
- [`map.get(key)`](mdn:js/Map/get) -- returns the value by the key, `undefined` if `key` doesn't exist in map.
- [`map.has(key)`](mdn:js/Map/has) -- returns `true` if the `key` exists, `false` otherwise.
- [`map.delete(key)`](mdn:js/Map/delete) -- removes the value by the key, returns `true` if `key` existed at the moment of the call, otherwise `false`.
- [`map.clear()`](mdn:js/Map/clear) -- removes everything from the map.
- [`map.size`](mdn:js/Map/size) -- returns the current element count.
- [`new Map([iterable])`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/Map) -- creates the map, with optional `iterable` (e.g. array) of `[key,value]` pairs for initialization.
- [`map.set(key, value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/set) -- stores the value by the key, returns the map itself.
- [`map.get(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/get) -- returns the value by the key, `undefined` if `key` doesn't exist in map.
- [`map.has(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/has) -- returns `true` if the `key` exists, `false` otherwise.
- [`map.delete(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/delete) -- removes the element by the key, returns `true` if `key` existed at the moment of the call, otherwise `false`.
- [`map.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/clear) -- removes everything from the map.
- [`map.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/size) -- returns the current element count.
The differences from a regular `Object`:
- Any keys, objects can be keys.
- Additional convenient methods, the `size` property.
`Set` -- is a collection of unique values.
[`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) -- is a collection of unique values.
Methods and properties:
- `new Set([iterable])` -- creates the set, with optional `iterable` (e.g. array) of values for initialization.
- [`set.add(value)`](mdn:js/Set/add) -- adds a value (does nothing if `value` exists), returns the set itself.
- [`set.delete(value)`](mdn:js/Set/delete) -- removes the value, returns `true` if `value` existed at the moment of the call, otherwise `false`.
- [`set.has(value)`](mdn:js/Set/has) -- returns `true` if the value exists in the set, otherwise `false`.
- [`set.clear()`](mdn:js/Set/clear) -- removes everything from the set.
- [`set.size`](mdn:js/Set/size) -- is the elements count.
- [`new Set([iterable])`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/Set) -- creates the set, with optional `iterable` (e.g. array) of values for initialization.
- [`set.add(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/add) -- adds a value (does nothing if `value` exists), returns the set itself.
- [`set.delete(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/delete) -- removes the value, returns `true` if `value` existed at the moment of the call, otherwise `false`.
- [`set.has(value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/has) -- returns `true` if the value exists in the set, otherwise `false`.
- [`set.clear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/clear) -- removes everything from the set.
- [`set.size`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set/size) -- is the elements count.
Iteration over `Map` and `Set` is always in the insertion order, so we can't say that these collections are unordered, but we can't reorder elements or directly get an element by its number.
24 changes: 14 additions & 10 deletions 1-js/05-data-types/08-weakmap-weakset/article.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@

# WeakMap and WeakSet

As we know from the chapter <info:garbage-collection>, JavaScript engine keeps a value in memory while it is "reachable" and can potentially be used.

For instance:

```js
let john = { name: "John" };

@@ -54,13 +56,13 @@ john = null; // overwrite the reference
*/!*
```

`WeakMap` is fundamentally different in this aspect. It doesn't prevent garbage-collection of key objects.
[`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) is fundamentally different in this aspect. It doesn't prevent garbage-collection of key objects.

Let's see what it means on examples.

## WeakMap

The first difference between `Map` and `WeakMap` is that keys must be objects, not primitive values:
The first difference between [`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) and [`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) is that keys must be objects, not primitive values:

```js run
let weakMap = new WeakMap();
@@ -94,10 +96,10 @@ Compare it with the regular `Map` example above. Now if `john` only exists as th

`WeakMap` has only the following methods:

- `weakMap.get(key)`
- `weakMap.set(key, value)`
- `weakMap.delete(key)`
- `weakMap.has(key)`
- [`weakMap.set(key, value)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/set)
- [`weakMap.get(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/get)
- [`weakMap.delete(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/delete)
- [`weakMap.has(key)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap/has)

Why such a limitation? That's for technical reasons. If an object has lost all other references (like `john` in the code above), then it is to be garbage-collected automatically. But technically it's not exactly specified *when the cleanup happens*.

@@ -182,6 +184,7 @@ function process(obj) {
let result = /* calculations of the result for */ obj;

cache.set(obj, result);
return result;
}

return cache.get(obj);
@@ -221,6 +224,7 @@ function process(obj) {
let result = /* calculate the result for */ obj;

cache.set(obj, result);
return result;
}

return cache.get(obj);
@@ -242,11 +246,11 @@ obj = null;

## WeakSet

`WeakSet` behaves similarly:
[`WeakSet`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) behaves similarly:

- It is analogous to `Set`, but we may only add objects to `WeakSet` (not primitives).
- An object exists in the set while it is reachable from somewhere else.
- Like `Set`, it supports `add`, `has` and `delete`, but not `size`, `keys()` and no iterations.
- Like `Set`, it supports [`add`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Weakset/add), [`has`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Weakset/has) and [`delete`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Weakset/delete), but not `size`, `keys()` and no iterations.

Being "weak", it also serves as additional storage. But not for arbitrary data, rather for "yes/no" facts. A membership in `WeakSet` may mean something about the object.

@@ -280,9 +284,9 @@ The most notable limitation of `WeakMap` and `WeakSet` is the absence of iterati

## Summary

`WeakMap` is `Map`-like collection that allows only objects as keys and removes them together with associated value once they become inaccessible by other means.
[`WeakMap`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap) is `Map`-like collection that allows only objects as keys and removes them together with associated value once they become inaccessible by other means.

`WeakSet` is `Set`-like collection that stores only objects and removes them once they become inaccessible by other means.
[`WeakSet`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet) is `Set`-like collection that stores only objects and removes them once they become inaccessible by other means.

Their main advantages are that they have weak reference to objects, so they can easily be removed by garbage collector.

40 changes: 20 additions & 20 deletions 1-js/05-data-types/10-destructuring-assignment/article.md
Original file line number Diff line number Diff line change
@@ -5,18 +5,18 @@ The two most used data structures in JavaScript are `Object` and `Array`.
- Objects allow us to create a single entity that stores data items by key.
- Arrays allow us to gather data items into an ordered list.

Although, when we pass those to a function, it may need not be an object/array as a whole. It may need individual pieces.
However, when we pass these to a function, we may not need all of it. The function might only require certain elements or properties.

*Destructuring assignment* is a special syntax that allows us to "unpack" arrays or objects into a bunch of variables, as sometimes that's more convenient.

Destructuring also works great with complex functions that have a lot of parameters, default values, and so on. Soon we'll see that.
Destructuring also works well with complex functions that have a lot of parameters, default values, and so on. Soon we'll see that.

## Array destructuring

Here's an example of how an array is destructured into variables:

```js
// we have an array with the name and surname
// we have an array with a name and surname
let arr = ["John", "Smith"]

*!*
@@ -40,10 +40,10 @@ alert(firstName); // John
alert(surname); // Smith
```

As you can see, the syntax is simple. There are several peculiar details though. Let's see more examples, to better understand it.
As you can see, the syntax is simple. There are several peculiar details though. Let's see more examples to understand it better.

````smart header="\"Destructuring\" does not mean \"destructive\"."
It's called "destructuring assignment," because it "destructurizes" by copying items into variables. But the array itself is not modified.
It's called "destructuring assignment," because it "destructurizes" by copying items into variables. However, the array itself is not modified.
It's just a shorter way to write:
```js
@@ -65,7 +65,7 @@ let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic
alert( title ); // Consul
```
In the code above, the second element of the array is skipped, the third one is assigned to `title`, and the rest of the array items is also skipped (as there are no variables for them).
In the code above, the second element of the array is skipped, the third one is assigned to `title`, and the rest of the array items are also skipped (as there are no variables for them).
````

````smart header="Works with any iterable on the right-side"
@@ -95,17 +95,17 @@ alert(user.surname); // Smith
````

````smart header="Looping with .entries()"
In the previous chapter we saw the [Object.entries(obj)](mdn:js/Object/entries) method.
In the previous chapter, we saw the [Object.entries(obj)](mdn:js/Object/entries) method.
We can use it with destructuring to loop over keys-and-values of an object:
We can use it with destructuring to loop over the keys-and-values of an object:
```js run
let user = {
name: "John",
age: 30
};
// loop over keys-and-values
// loop over the keys-and-values
*!*
for (let [key, value] of Object.entries(user)) {
*/!*
@@ -169,7 +169,7 @@ If we'd like also to gather all that follows -- we can add one more parameter th
let [name1, name2, *!*...rest*/!*] = ["Julius", "Caesar", *!*"Consul", "of the Roman Republic"*/!*];
*!*
// rest is array of items, starting from the 3rd one
// rest is an array of items, starting from the 3rd one
alert(rest[0]); // Consul
alert(rest[1]); // of the Roman Republic
alert(rest.length); // 2
@@ -187,7 +187,7 @@ let [name1, name2, *!*...titles*/!*] = ["Julius", "Caesar", "Consul", "of the Ro

### Default values

If the array is shorter than the list of variables at the left, there'll be no errors. Absent values are considered undefined:
If the array is shorter than the list of variables on the left, there will be no errors. Absent values are considered undefined:

```js run
*!*
@@ -418,7 +418,7 @@ alert( title ); // Menu
## Nested destructuring
If an object or an array contain other nested objects and arrays, we can use more complex left-side patterns to extract deeper portions.
If an object or an array contains other nested objects and arrays, we can use more complex left-side patterns to extract deeper portions.
In the code below `options` has another object in the property `size` and an array in the property `items`. The pattern on the left side of the assignment has the same structure to extract values from them:
@@ -449,7 +449,7 @@ alert(item1); // Cake
alert(item2); // Donut
```
All properties of `options` object except `extra` that is absent in the left part, are assigned to corresponding variables:
All properties of `options` object except `extra` which is absent in the left part, are assigned to corresponding variables:
![](destructuring-complex.svg)
@@ -459,17 +459,17 @@ Note that there are no variables for `size` and `items`, as we take their conten
## Smart function parameters
There are times when a function has many parameters, most of which are optional. That's especially true for user interfaces. Imagine a function that creates a menu. It may have a width, a height, a title, items list and so on.
There are times when a function has many parameters, most of which are optional. That's especially true for user interfaces. Imagine a function that creates a menu. It may have a width, a height, a title, an item list and so on.
Here's a bad way to write such function:
Here's a bad way to write such a function:
```js
function showMenu(title = "Untitled", width = 200, height = 100, items = []) {
// ...
}
```
In real-life, the problem is how to remember the order of arguments. Usually IDEs try to help us, especially if the code is well-documented, but still... Another problem is how to call a function when most parameters are ok by default.
In real-life, the problem is how to remember the order of arguments. Usually, IDEs try to help us, especially if the code is well-documented, but still... Another problem is how to call a function when most parameters are ok by default.
Like this?
@@ -534,7 +534,7 @@ function({
})
```

Then, for an object of parameters, there will be a variable `varName` for property `incomingProperty`, with `defaultValue` by default.
Then, for an object of parameters, there will be a variable `varName` for the property `incomingProperty`, with `defaultValue` by default.

Please note that such destructuring assumes that `showMenu()` does have an argument. If we want all values by default, then we should specify an empty object:

@@ -561,7 +561,7 @@ In the code above, the whole arguments object is `{}` by default, so there's alw
- Destructuring assignment allows for instantly mapping an object or array onto many variables.
- The full object syntax:
```js
let {prop : varName = default, ...rest} = object
let {prop : varName = defaultValue, ...rest} = object
```

This means that property `prop` should go into the variable `varName` and, if no such property exists, then the `default` value should be used.
@@ -571,9 +571,9 @@ In the code above, the whole arguments object is `{}` by default, so there's alw
- The full array syntax:

```js
let [item1 = default, item2, ...rest] = array
let [item1 = defaultValue, item2, ...rest] = array
```

The first item goes to `item1`; the second goes into `item2`, all the rest makes the array `rest`.
The first item goes to `item1`; the second goes into `item2`, and all the rest makes the array `rest`.

- It's possible to extract data from nested arrays/objects, for that the left side must have the same structure as the right one.
2 changes: 1 addition & 1 deletion 1-js/05-data-types/11-date/article.md
Original file line number Diff line number Diff line change
@@ -376,7 +376,7 @@ for (let i = 0; i < 10; i++) {
```warn header="Be careful doing microbenchmarking"
Modern JavaScript engines perform many optimizations. They may tweak results of "artificial tests" compared to "normal usage", especially when we benchmark something very small, such as how an operator works, or a built-in function. So if you seriously want to understand performance, then please study how the JavaScript engine works. And then you probably won't need microbenchmarks at all.

The great pack of articles about V8 can be found at <http://mrale.ph>.
The great pack of articles about V8 can be found at <https://mrale.ph>.
```

## Date.parse from a string
4 changes: 2 additions & 2 deletions 1-js/05-data-types/12-json/article.md
Original file line number Diff line number Diff line change
@@ -405,7 +405,7 @@ To decode a JSON-string, we need another method named [JSON.parse](mdn:js/JSON/p

The syntax:
```js
let value = JSON.parse(str, [reviver]);
let value = JSON.parse(str[, reviver]);
```

str
@@ -451,7 +451,7 @@ let json = `{

Besides, JSON does not support comments. Adding a comment to JSON makes it invalid.

There's another format named [JSON5](http://json5.org/), which allows unquoted keys, comments etc. But this is a standalone library, not in the specification of the language.
There's another format named [JSON5](https://json5.org/), which allows unquoted keys, comments etc. But this is a standalone library, not in the specification of the language.

The regular JSON is that strict not because its developers are lazy, but to allow easy, reliable and very fast implementations of the parsing algorithm.

Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@ function sum(a, b) {
alert( sum(1, 2, 3, 4, 5) );
```

There will be no error because of "excessive" arguments. But of course in the result only the first two will be counted.
There will be no error because of "excessive" arguments. But of course in the result only the first two will be counted, so the result in the code above is `3`.

The rest of the parameters can be included in the function definition by using three dots `...` followed by the name of the array that will contain them. The dots literally mean "gather the remaining parameters into an array".

4 changes: 2 additions & 2 deletions 1-js/06-advanced-functions/04-var/article.md
Original file line number Diff line number Diff line change
@@ -58,7 +58,7 @@ alert(test); // ReferenceError: test is not defined

The same thing for loops: `var` cannot be block- or loop-local:

```js
```js run
for (var i = 0; i < 10; i++) {
var one = 1;
// ...
@@ -170,7 +170,7 @@ That's best demonstrated with an example:

```js run
function sayHi() {
alert(phrase);
alert(phrase);

*!*
var phrase = "Hello";
2 changes: 1 addition & 1 deletion 1-js/06-advanced-functions/06-function-object/article.md
Original file line number Diff line number Diff line change
@@ -326,7 +326,7 @@ welcome(); // Hello, Guest (nested call works)

Now it works, because the name `"func"` is function-local. It is not taken from outside (and not visible there). The specification guarantees that it will always reference the current function.

The outer code still has its variable `sayHi` or `welcome`. And `func` is an "internal function name", the way for the function to can call itself reliably.
The outer code still has its variable `sayHi` or `welcome`. And `func` is an "internal function name", the way for the function to call itself reliably.

```smart header="There's no such thing for Function Declaration"
The "internal name" feature described here is only available for Function Expressions, not for Function Declarations. For Function Declarations, there is no syntax for adding an "internal" name.
Original file line number Diff line number Diff line change
@@ -27,7 +27,7 @@ Usually, that's a function. For historical reasons, a string of code can be pass
: The delay before run, in milliseconds (1000 ms = 1 second), by default 0.

`arg1`, `arg2`...
: Arguments for the function (not supported in IE9-)
: Arguments for the function

For instance, this code calls `sayHi()` after one second:

Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

The error occurs because `ask` gets functions `loginOk/loginFail` without the object.
The error occurs because `askPassword` gets functions `loginOk/loginFail` without the object.

When it calls them, they naturally assume `this=undefined`.

4 changes: 2 additions & 2 deletions 1-js/06-advanced-functions/10-bind/article.md
Original file line number Diff line number Diff line change
@@ -125,7 +125,7 @@ funcUser(); // John
*/!*
```

Here `func.bind(user)` as a "bound variant" of `func`, with fixed `this=user`.
Here `func.bind(user)` is a "bound variant" of `func`, with fixed `this=user`.

All arguments are passed to the original `func` "as is", for instance:

@@ -202,7 +202,7 @@ for (let key in user) {
}
```

JavaScript libraries also provide functions for convenient mass binding , e.g. [_.bindAll(object, methodNames)](http://lodash.com/docs#bindAll) in lodash.
JavaScript libraries also provide functions for convenient mass binding , e.g. [_.bindAll(object, methodNames)](https://lodash.com/docs#bindAll) in lodash.
````
## Partial functions
Original file line number Diff line number Diff line change
@@ -123,7 +123,7 @@ user.name = "Pete"; // Error: Cannot assign to read only property 'name'
Now no one can change the name of our user, unless they apply their own `defineProperty` to override ours.

```smart header="Errors appear only in strict mode"
In the non-strict mode, no errors occur when writing to non-writable properties and such. But the operation still won't succeed. Flag-violating actions are just silently ignored in non-strict.
In non-strict mode, no errors occur when writing to non-writable properties and such. But the operation still won't succeed. Flag-violating actions are just silently ignored in non-strict.
```

Here's the same example, but the property is created from scratch:
6 changes: 3 additions & 3 deletions 1-js/08-prototypes/04-prototype-methods/article.md
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@ The only usage of `__proto__`, that's not frowned upon, is as a property when cr

Although, there's a special method for this too:

- [Object.create(proto, [descriptors])](mdn:js/Object/create) -- creates an empty object with given `proto` as `[[Prototype]]` and optional property descriptors.
- [Object.create(proto[, descriptors])](mdn:js/Object/create) -- creates an empty object with given `proto` as `[[Prototype]]` and optional property descriptors.

For instance:

@@ -116,7 +116,7 @@ alert(obj[key]); // [object Object], not "some value"!

Here, if the user types in `__proto__`, the assignment in line 4 is ignored!

That could surely be surprising for a non-developer, but pretty understandable for us. The `__proto__` property is special: it must be either an object or `null`. A string can not become a prototype. That's why an assignment a string to `__proto__` is ignored.
That could surely be surprising for a non-developer, but pretty understandable for us. The `__proto__` property is special: it must be either an object or `null`. A string can not become a prototype. That's why assigning a string to `__proto__` is ignored.

But we didn't *intend* to implement such behavior, right? We want to store key/value pairs, and the key named `"__proto__"` was not properly saved. So that's a bug!

@@ -201,7 +201,7 @@ alert(Object.keys(chineseDictionary)); // hello,bye
- To create an object with the given prototype, use:

- literal syntax: `{ __proto__: ... }`, allows to specify multiple properties
- or [Object.create(proto, [descriptors])](mdn:js/Object/create), allows to specify property descriptors.
- or [Object.create(proto[, descriptors])](mdn:js/Object/create), allows to specify property descriptors.

The `Object.create` provides an easy way to shallow-copy an object with all descriptors:

2 changes: 1 addition & 1 deletion 1-js/10-error-handling/1-try-catch/article.md
Original file line number Diff line number Diff line change
@@ -632,7 +632,7 @@ For instance:
The role of the global handler `window.onerror` is usually not to recover the script execution -- that's probably impossible in case of programming errors, but to send the error message to developers.
There are also web-services that provide error-logging for such cases, like <https://errorception.com> or <http://www.muscula.com>.
There are also web-services that provide error-logging for such cases, like <https://muscula.com> or <https://www.sentry.io>.
They work like this:
2 changes: 1 addition & 1 deletion 1-js/10-error-handling/2-custom-errors/article.md
Original file line number Diff line number Diff line change
@@ -38,7 +38,7 @@ class Error {

Now let's inherit `ValidationError` from it and try it in action:

```js run untrusted
```js run
*!*
class ValidationError extends Error {
*/!*
4 changes: 2 additions & 2 deletions 1-js/11-async/02-promise-basics/article.md
Original file line number Diff line number Diff line change
@@ -46,7 +46,7 @@ Later we'll see how "fans" can subscribe to these changes.

Here's an example of a promise constructor and a simple executor function with "producing code" that takes time (via `setTimeout`):

```js run
```js
let promise = new Promise(function(resolve, reject) {
// the function is executed automatically when the promise is constructed

@@ -222,7 +222,7 @@ The idea of `finally` is to set up a handler for performing cleanup/finalizing a
E.g. stopping loading indicators, closing no longer needed connections, etc.
Think of it as a party finisher. No matter was a party good or bad, how many friends were in it, we still need (or at least should) do a cleanup after it.
Think of it as a party finisher. Irresepective of whether a party was good or bad, how many friends were in it, we still need (or at least should) do a cleanup after it.
The code may look like this:
2 changes: 1 addition & 1 deletion 1-js/11-async/03-promise-chaining/article.md
Original file line number Diff line number Diff line change
@@ -72,7 +72,7 @@ promise.then(function(result) {
});
```

What we did here is just several handlers to one promise. They don't pass the result to each other; instead they process it independently.
What we did here is just adding several handlers to one promise. They don't pass the result to each other; instead they process it independently.

Here's the picture (compare it with the chaining above):

4 changes: 2 additions & 2 deletions 1-js/11-async/06-promisify/article.md
Original file line number Diff line number Diff line change
@@ -25,7 +25,7 @@ function loadScript(src, callback) {

The function loads a script with the given `src`, and then calls `callback(err)` in case of an error, or `callback(null, script)` in case of successful loading. That's a widespread agreement for using callbacks, we saw it before.

Let's promisify it.
Let's promisify it.

We'll make a new function `loadScriptPromise(src)`, that does the same (loads the script), but returns a promise instead of using callbacks.

@@ -124,7 +124,7 @@ For more exotic callback formats, like those without `err` at all: `callback(res
There are also modules with a bit more flexible promisification functions, e.g. [es6-promisify](https://github.com/digitaldesignlabs/es6-promisify). In Node.js, there's a built-in `util.promisify` function for that.
```smart
Promisification is a great approach, especially when you use `async/await` (see the next chapter), but not a total replacement for callbacks.
Promisification is a great approach, especially when you use `async/await` (covered later in the chapter <info:async-await>), but not a total replacement for callbacks.

Remember, a promise may have only one result, but a callback may technically be called many times.

113 changes: 113 additions & 0 deletions 1-js/11-async/08-async-await/04-promise-all-failure/solution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@

The root of the problem is that `Promise.all` immediately rejects when one of its promises rejects, but it do nothing to cancel the other promises.

In our case, the second query fails, so `Promise.all` rejects, and the `try...catch` block catches this error.Meanwhile, other promises are *not affected* - they independently continue their execution. In our case, the third query throws an error of its own after a bit of time. And that error is never caught, we can see it in the console.

The problem is especially dangerous in server-side environments, such as Node.js, when an uncaught error may cause the process to crash.

How to fix it?

An ideal solution would be to cancel all unfinished queries when one of them fails. This way we avoid any potential errors.

However, the bad news is that service calls (such as `database.query`) are often implemented by a 3rd-party library which doesn't support cancellation. Then there's no way to cancel a call.

As an alternative, we can write our own wrapper function around `Promise.all` which adds a custom `then/catch` handler to each promise to track them: results are gathered and, if an error occurs, all subsequent promises are ignored.

```js
function customPromiseAll(promises) {
return new Promise((resolve, reject) => {
const results = [];
let resultsCount = 0;
let hasError = false; // we'll set it to true upon first error

promises.forEach((promise, index) => {
promise
.then(result => {
if (hasError) return; // ignore the promise if already errored
results[index] = result;
resultsCount++;
if (resultsCount === promises.length) {
resolve(results); // when all results are ready - successs
}
})
.catch(error => {
if (hasError) return; // ignore the promise if already errored
hasError = true; // wops, error!
reject(error); // fail with rejection
});
});
});
}
```

This approach has an issue of its own - it's often undesirable to `disconnect()` when queries are still in the process.

It may be important that all queries complete, especially if some of them make important updates.

So we should wait until all promises are settled before going further with the execution and eventually disconnecting.

Here's another implementation. It behaves similar to `Promise.all` - also resolves with the first error, but waits until all promises are settled.

```js
function customPromiseAllWait(promises) {
return new Promise((resolve, reject) => {
const results = new Array(promises.length);
let settledCount = 0;
let firstError = null;

promises.forEach((promise, index) => {
Promise.resolve(promise)
.then(result => {
results[index] = result;
})
.catch(error => {
if (firstError === null) {
firstError = error;
}
})
.finally(() => {
settledCount++;
if (settledCount === promises.length) {
if (firstError !== null) {
reject(firstError);
} else {
resolve(results);
}
}
});
});
});
}
```

Now `await customPromiseAllWait(...)` will stall the execution until all queries are processed.

This is a more reliable approach, as it guarantees a predictable execution flow.

Lastly, if we'd like to process all errors, we can use either use `Promise.allSettled` or write a wrapper around it to gathers all errors in a single [AggregateError](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/AggregateError) object and rejects with it.

```js
// wait for all promises to settle
// return results if no errors
// throw AggregateError with all errors if any
function allOrAggregateError(promises) {
return Promise.allSettled(promises).then(results => {
const errors = [];
const values = [];

results.forEach((res, i) => {
if (res.status === 'fulfilled') {
values[i] = res.value;
} else {
errors.push(res.reason);
}
});

if (errors.length > 0) {
throw new AggregateError(errors, 'One or more promises failed');
}

return values;
});
}
```
79 changes: 79 additions & 0 deletions 1-js/11-async/08-async-await/04-promise-all-failure/task.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@

# Dangerous Promise.all

`Promise.all` is a great way to parallelize multiple operations. It's especially useful when we need to make parallel requests to multiple services.

However, there's a hidden danger. We'll see an example in this task and explore how to avoid it.

Let's say we have a connection to a remote service, such as a database.

There're two functions: `connect()` and `disconnect()`.

When connected, we can send requests using `database.query(...)` - an async function which usually returns the result but also may throw an error.

Here's a simple implementation:

```js
let database;

function connect() {
database = {
async query(isOk) {
if (!isOk) throw new Error('Query failed');
}
};
}

function disconnect() {
database = null;
}

// intended usage:
// connect()
// ...
// database.query(true) to emulate a successful call
// database.query(false) to emulate a failed call
// ...
// disconnect()
```

Now here's the problem.

We wrote the code to connect and send 3 queries in parallel (all of them take different time, e.g. 100, 200 and 300ms), then disconnect:

```js
// Helper function to call async function `fn` after `ms` milliseconds
function delay(fn, ms) {
return new Promise((resolve, reject) => {
setTimeout(() => fn().then(resolve, reject), ms);
});
}

async function run() {
connect();

try {
await Promise.all([
// these 3 parallel jobs take different time: 100, 200 and 300 ms
// we use the `delay` helper to achieve this effect
*!*
delay(() => database.query(true), 100),
delay(() => database.query(false), 200),
delay(() => database.query(false), 300)
*/!*
]);
} catch(error) {
console.log('Error handled (or was it?)');
}

disconnect();
}

run();
```

Two of these queries happen to be unsuccessful, but we're smart enough to wrap the `Promise.all` call into a `try..catch` block.

However, this doesn't help! This script actually leads to an uncaught error in console!

Why? How to avoid it?
4 changes: 2 additions & 2 deletions 1-js/13-modules/01-modules-intro/article.md
Original file line number Diff line number Diff line change
@@ -9,8 +9,8 @@ But eventually scripts became more and more complex, so the community invented a

To name some (for historical reasons):

- [AMD](https://en.wikipedia.org/wiki/Asynchronous_module_definition) -- one of the most ancient module systems, initially implemented by the library [require.js](http://requirejs.org/).
- [CommonJS](http://wiki.commonjs.org/wiki/Modules/1.1) -- the module system created for Node.js server.
- [AMD](https://en.wikipedia.org/wiki/Asynchronous_module_definition) -- one of the most ancient module systems, initially implemented by the library [require.js](https://requirejs.org/).
- [CommonJS](https://wiki.commonjs.org/wiki/Modules/1.1) -- the module system created for Node.js server.
- [UMD](https://github.com/umdjs/umd) -- one more module system, suggested as a universal one, compatible with AMD and CommonJS.

Now these all slowly became a part of history, but we still can find them in old scripts.
4 changes: 2 additions & 2 deletions 1-js/13-modules/02-import-export/article.md
Original file line number Diff line number Diff line change
@@ -97,9 +97,9 @@ Well, there are few reasons.
2. Explicit list of imports gives better overview of the code structure: what is used and where. It makes code support and refactoring easier.

```smart header="Don't be afraid to import too much"
Modern build tools, such as [webpack](https://webpack.js.org/) and others, bundle modules together and optimize them to speedup loading. They also removed unused imports.
Modern build tools, such as [webpack](https://webpack.js.org/) and others, bundle modules together and optimize them to speedup loading. They also remove unused imports.
For instance, if you `import * as library` from a huge code library, and then use only few methods, then unused ones [will not be included](https://github.com/webpack/webpack/tree/main/examples/harmony-unused#examplejs) into the optimzed bundle.
For instance, if you `import * as library` from a huge code library, and then use only few methods, then unused ones [will not be included](https://github.com/webpack/webpack/tree/main/examples/harmony-unused#examplejs) into the optimized bundle.
```

## Import "as"
26 changes: 13 additions & 13 deletions 1-js/99-js-misc/06-unicode/article.md
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
# Unicode, String internals

```warn header="Advanced knowledge"
The section goes deeper into string internals. This knowledge will be useful for you if you plan to deal with emoji, rare mathematical or hieroglyphic characters or other rare symbols.
The section goes deeper into string internals. This knowledge will be useful for you if you plan to deal with emoji, rare mathematical or hieroglyphic characters, or other rare symbols.
```

As we already know, JavaScript strings are based on [Unicode](https://en.wikipedia.org/wiki/Unicode): each character is represented by a byte sequence of 1-4 bytes.
@@ -11,25 +11,25 @@ JavaScript allows us to insert a character into a string by specifying its hexad

- `\xXX`

`XX` must be two hexadecimal digits with value between `00` and `FF`, then it's character whose Unicode code is `XX`.
`XX` must be two hexadecimal digits with a value between `00` and `FF`, then `\xXX` is the character whose Unicode code is `XX`.

Because the `\xXX` notation supports only two digits, it can be used only for the first 256 Unicode characters.
Because the `\xXX` notation supports only two hexadecimal digits, it can be used only for the first 256 Unicode characters.

These first 256 characters include latin alphabet, most basic syntax characters and some others. For example, `"\x7A"` is the same as `"z"` (Unicode `U+007A`).
These first 256 characters include the Latin alphabet, most basic syntax characters, and some others. For example, `"\x7A"` is the same as `"z"` (Unicode `U+007A`).

```js run
alert( "\x7A" ); // z
alert( "\xA9" ); // ©, the copyright symbol
```

- `\uXXXX`
`XXXX` must be exactly 4 hex digits with the value between `0000` and `FFFF`, then `\uXXXX` is a character whose Unicode code is `XXXX` .
`XXXX` must be exactly 4 hex digits with the value between `0000` and `FFFF`, then `\uXXXX` is the character whose Unicode code is `XXXX`.
Characters with Unicode value greater than `U+FFFF` can also be represented with this notation, but in this case we will need to use a so called surrogate pair (we will talk about surrogate pairs later in this chapter).
Characters with Unicode values greater than `U+FFFF` can also be represented with this notation, but in this case, we will need to use a so called surrogate pair (we will talk about surrogate pairs later in this chapter).
```js run
alert( "\u00A9" ); // ©, the same as \xA9, using the 4-digit hex notation
alert( "\u044F" ); // я, the cyrillic alphabet letter
alert( "\u044F" ); // я, the Cyrillic alphabet letter
alert( "\u2191" ); // ↑, the arrow up symbol
```

@@ -38,13 +38,13 @@ JavaScript allows us to insert a character into a string by specifying its hexad
`XXXXXXX` must be a hexadecimal value of 1 to 6 bytes between `0` and `10FFFF` (the highest code point defined by Unicode). This notation allows us to easily represent all existing Unicode characters.
```js run
alert( "\u{20331}" ); // 佫, a rare Chinese hieroglyph (long Unicode)
alert( "\u{20331}" ); // 佫, a rare Chinese character (long Unicode)
alert( "\u{1F60D}" ); // 😍, a smiling face symbol (another long Unicode)
```

## Surrogate pairs

All frequently used characters have 2-byte codes. Letters in most european languages, numbers, and even most hieroglyphs, have a 2-byte representation.
All frequently used characters have 2-byte codes (4 hex digits). Letters in most European languages, numbers, and the basic unified CJK ideographic sets (CJK -- from Chinese, Japanese, and Korean writing systems), have a 2-byte representation.

Initially, JavaScript was based on UTF-16 encoding that only allowed 2 bytes per character. But 2 bytes only allow 65536 combinations and that's not enough for every possible symbol of Unicode.
@@ -55,7 +55,7 @@ As a side effect, the length of such symbols is `2`:
```js run
alert( '𝒳'.length ); // 2, MATHEMATICAL SCRIPT CAPITAL X
alert( '😂'.length ); // 2, FACE WITH TEARS OF JOY
alert( '𩷶'.length ); // 2, a rare Chinese hieroglyph
alert( '𩷶'.length ); // 2, a rare Chinese character
```
That's because surrogate pairs did not exist at the time when JavaScript was created, and thus are not correctly processed by the language!
@@ -75,7 +75,7 @@ Pieces of a surrogate pair have no meaning without each other. So the alerts in

Technically, surrogate pairs are also detectable by their codes: if a character has the code in the interval of `0xd800..0xdbff`, then it is the first part of the surrogate pair. The next character (second part) must have the code in interval `0xdc00..0xdfff`. These intervals are reserved exclusively for surrogate pairs by the standard.

So the methods `String.fromCodePoint` and `str.codePointAt` were added in JavaScript to deal with surrogate pairs.
So the methods [String.fromCodePoint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint) and [str.codePointAt](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt) were added in JavaScript to deal with surrogate pairs.

They are essentially the same as [String.fromCharCode](mdn:js/String/fromCharCode) and [str.charCodeAt](mdn:js/String/charCodeAt), but they treat surrogate pairs correctly.

@@ -120,7 +120,7 @@ For instance, the letter `a` can be the base character for these characters: `à

Most common "composite" characters have their own code in the Unicode table. But not all of them, because there are too many possible combinations.

To support arbitrary compositions, Unicode standard allows us to use several Unicode characters: the base character followed by one or many "mark" characters that "decorate" it.
To support arbitrary compositions, the Unicode standard allows us to use several Unicode characters: the base character followed by one or many "mark" characters that "decorate" it.

For instance, if we have `S` followed by the special "dot above" character (code `\u0307`), it is shown as Ṡ.

@@ -167,6 +167,6 @@ alert( "S\u0307\u0323".normalize().length ); // 1
alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true
```

In reality, this is not always the case. The reason being that the symbol `` is "common enough", so Unicode creators included it in the main table and gave it the code.
In reality, this is not always the case. The reason is that the symbol `` is "common enough", so Unicode creators included it in the main table and gave it the code.

If you want to learn more about normalization rules and variants -- they are described in the appendix of the Unicode standard: [Unicode Normalization Forms](https://www.unicode.org/reports/tr15/), but for most practical purposes the information from this section is enough.
Loading