diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..490051876 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: iliakan diff --git a/.gitignore b/.gitignore index 6f90fd190..1a71fb7c8 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ sftp-config.json Thumbs.db +/svgs \ No newline at end of file diff --git a/1-js/01-getting-started/1-intro/article.md b/1-js/01-getting-started/1-intro/article.md index 5c6a93cff..3c940bab8 100644 --- a/1-js/01-getting-started/1-intro/article.md +++ b/1-js/01-getting-started/1-intro/article.md @@ -24,26 +24,44 @@ Browser punya engine yang tertanam didalamnya yang disebut "JavaScript virtual m Tiap engine punya *codename*-nya sendiri. Misalnya: +<<<<<<< HEAD - [V8](https://en.wikipedia.org/wiki/V8_(JavaScript_engine)) -- di Chrome dan Opera. - [SpiderMonkey](https://en.wikipedia.org/wiki/SpiderMonkey) -- di Firefox. - ...Ada juga codename lain seperti "Trident" dan "Chakra" untuk versi berbeda dari IE, "ChakraCore" untuk Microsoft Edge, "Nitro" dan "SquirrelFish" untuk Safari, dll. Istilah di atas sebaiknya diingat karena akan sering digunakan dalam artikel para developer di internet. Kita akan menggunakannya juga. Misalnya, jika "fitur X didukung V8", kemungkinan ia bisa jalan di Chrome dan Opera. +======= +- [V8](https://en.wikipedia.org/wiki/V8_(JavaScript_engine)) -- in Chrome, Opera and Edge. +- [SpiderMonkey](https://en.wikipedia.org/wiki/SpiderMonkey) -- in Firefox. +- ...There are other codenames like "Chakra" for IE, "JavaScriptCore", "Nitro" and "SquirrelFish" for Safari, etc. + +The terms above are good to remember because they are used in developer articles on the internet. We'll use them too. For instance, if "a feature X is supported by V8", then it probably works in Chrome, Opera and Edge. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```smart header="Bagaimana engine bekerja?" Engine sangat rumit. Tapi basicnya mudah. +<<<<<<< HEAD 1. Engine (tertanam jika ia sebuah browser)bisa membaca ("memparsing") script. 2. Lalu ia mengkonversi ("mengkompilasi") script tersebut menjadi bahasa mesin. 3. Dan kemudian kode mesin berjalan, lumayan cepat. +======= +1. The engine (embedded if it's a browser) reads ("parses") the script. +2. Then it converts ("compiles") the script to machine code. +3. And then the machine code runs, pretty fast. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Engine melakukan optimisasi di setiap langkah proses. Dia bahkan memperhatikan script yang telah dikompilasi saat sedang berjalan, menganalisa data yang mengalir di dalam, dan melakukan optimisasi ke kode mesin berdasarkan pengetahuan itu. ``` ## Apa yang bisa dilakukan *in-browser JavaScript*? +<<<<<<< HEAD JavaScript modern merupakan bahasa pemrograman yang "aman". Ia tidak menyebabkan akses tingkat-rendah ke memory atau CPU, karena memang awalnya dibuat untuk browser, yang tentunya tidak membutuhkan hal tersebut. +======= +Modern JavaScript is a "safe" programming language. It does not provide low-level access to memory or the CPU, because it was initially created for browsers which do not require it. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Kemampuan JavaScript sangat tergantung pada lingkungan tempat ia berjalan. Misalnya, [Node.js](https://wikipedia.org/wiki/Node.js) mendukung function yang memungkingkan JavaScript melakukan baca/tulis file apapun, melakukan permintaan jaringan, dsb. @@ -59,7 +77,11 @@ Misalnya, *in-browser JavaScript* mampu: ## Apa yang TIDAK BISA dilakukan *in-browser JavaScript*? +<<<<<<< HEAD Kemampuan JavaScript yang ada di dalam browser terbatas demi keamanan pengguna. Tujuannya supaya mencegah halaman web berbahya mengakses informasi pribadi atau merusak data pengguna. +======= +JavaScript's abilities in the browser are limited to protect the user's safety. The aim is to prevent an evil webpage from accessing private information or harming the user's data. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Contoh keterbatasan tersebut meliputi: @@ -67,6 +89,7 @@ Contoh keterbatasan tersebut meliputi: Browser-browser modern memperbolehkan JavaScript mengakses file, tapi aksesnya dibatasi dan tersedia hanya jika pengguna melakukan hal tertentu, misalnya seperti "menjatuhkan" file ke dalam jendela browser atau memilih file via tag ``. +<<<<<<< HEAD Ada beberapa cara untuk berinteraksi dengan kamera/mikrofon dan perangkat-perangkat lainnya, namun mereka butuh ijin khusus pengguna. Jadi sebuah halaman yang memiliki JavaScript tidak bisa mengaktifkan web-camera, memantau sekeliling dan mengirim informasinya ke [NSA] secara diam-diam(https://en.wikipedia.org/wiki/National_Security_Agency). - Tab/jendela yang berbeda umumnya tidak ada hubungan sama sekali. Terkadang jendela yang berbeda bisa saling berhubungan juga, misalnya ketika satu jendela menggunakan JavaScript untuk membuka jendela lainnya. Tapi meski demikian, JavaScript dari suatu halaman tak boleh mengakses halaman lainnya jika mereka berasal dari situs yang berbeda (dari domain, protokol, atau port berbeda). @@ -78,21 +101,44 @@ Contoh keterbatasan tersebut meliputi: ![](limitations.svg) Pembatasan macam ini tidak ada jika JavaScript digunakan di luar browser, misalnya di server. Browser-browser modern juga memperbolehkan plugin/ekstensi yang membutuhkan ijin tambahan. +======= + There are ways to interact with the camera/microphone and other devices, but they require a user's explicit permission. So a JavaScript-enabled page may not sneakily enable a web-camera, observe the surroundings and send the information to the [NSA](https://en.wikipedia.org/wiki/National_Security_Agency). +- Different tabs/windows generally do not know about each other. Sometimes they do, for example when one window uses JavaScript to open the other one. But even in this case, JavaScript from one page may not access the other page if they come from different sites (from a different domain, protocol or port). + + This is called the "Same Origin Policy". To work around that, *both pages* must agree for data exchange and must contain special JavaScript code that handles it. We'll cover that in the tutorial. + + This limitation is, again, for the user's safety. A page from `http://anysite.com` which a user has opened must not be able to access another browser tab with the URL `http://gmail.com`, for example, and steal information from there. +- JavaScript can easily communicate over the net to the server where the current page came from. But its ability to receive data from other sites/domains is crippled. Though possible, it requires explicit agreement (expressed in HTTP headers) from the remote side. Once again, that's a safety limitation. + +![](limitations.svg) + +Such limitations do not exist if JavaScript is used outside of the browser, for example on a server. Modern browsers also allow plugins/extensions which may ask for extended permissions. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Apa yang membuat JavaScript unik? Paling tidak ada *tiga* hal unik dari JavaScript: ```compare +<<<<<<< HEAD + Integrasi penuh dengan HTML/CSS. + Hal sederhana diselesaikan dengan sederhana. + Dukungan dari mayoritas web browser dan aktif secara default. +======= ++ Full integration with HTML/CSS. ++ Simple things are done simply. ++ Supported by all major browsers and enabled by default. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` JavaScript merupakan satu-satunya teknologi browser yang mengkombinasikan ketiga poin di atas. Itulah yang membuat JavaScript unik. Itulah kenapa JavaScript menjadi alat yang paling sering untuk membuat antarmuka browser. +<<<<<<< HEAD Katanya, JavaScript juga bisa dipakai untuk membuat aplikasi server, mobile, dsb. +======= +That said, JavaScript can be used to create servers, mobile applications, etc. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Bahasa "di atas" JavaScript @@ -100,12 +146,17 @@ Sintaks JavaScript tidak memenuhi kebutuhan setiap orang. Masing-masing orang in Itu wajar, karena proyek dan persyaratan tiap orang berbeda-beda. +<<<<<<< HEAD Akhir-akhir ini muncul banyak bahasa baru, yang *ditranspile* (dikonversi) ke JavaScript sebelum dijalankan di browser. +======= +So, recently a plethora of new languages appeared, which are *transpiled* (converted) to JavaScript before they run in the browser. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Tools modern membuat transpilasi sangat cepat dan transparan, yang memungkinkan para developer menulis kodenya dalam bahasa lain dan mengautokonversi itu "di balik layar". Contoh bahasa yang dimaksud: +<<<<<<< HEAD - [CoffeeScript](http://coffeescript.org/) merupakan "syntactic sugar" dari JavaScript. Dia memperkenalkan syntax yang lebih pendek, memungkingkan kita menulis kode lebih bersih dan lebih presisi. Biasanya, Ruby devs menyukainya. - [TypeScript](http://www.typescriptlang.org/) berfokus pada penambahan "strict data typing" yang menyederhanakan pengembangan dan dukungan sistem yang komplex. Ia dikembangkan oleh Microsoft. - [Flow](http://flow.org/) juga menambahkan data typing, tapi dalam cara berbeda. Dikembangkan oleh Facebook. @@ -114,9 +165,25 @@ Contoh bahasa yang dimaksud: - [Kotlin](https://kotlinlang.org/docs/reference/js-overview.html) adalah sebuah bahasa pemograman modern, ringkas dan aman yang dapat ditargetkan untuk browser atau Node. Masih banyak lagi. Tentunya, jika kita menggunakan salah satu bahasa yang ditranspile tersebut, kita sebaiknya juga paham JavaScript untuk mengerti apa yang mereka lakukan. +======= +- [CoffeeScript](https://coffeescript.org/) is "syntactic sugar" for JavaScript. It introduces shorter syntax, allowing us to write clearer and more precise code. Usually, Ruby devs like it. +- [TypeScript](https://www.typescriptlang.org/) is concentrated on adding "strict data typing" to simplify the development and support of complex systems. It is developed by Microsoft. +- [Flow](https://flow.org/) also adds data typing, but in a different way. Developed by Facebook. +- [Dart](https://www.dartlang.org/) is a standalone language that has its own engine that runs in non-browser environments (like mobile apps), but also can be transpiled to JavaScript. Developed by Google. +- [Brython](https://brython.info/) is a Python transpiler to JavaScript that enables the writing of applications in pure Python without JavaScript. +- [Kotlin](https://kotlinlang.org/docs/reference/js-overview.html) is a modern, concise and safe programming language that can target the browser or Node. + +There are more. Of course, even if we use one of these transpiled languages, we should also know JavaScript to really understand what we're doing. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Kesimpulan +<<<<<<< HEAD - JavaScript awalnya diciptakan sebagai bahasa khusus browser, namun sekarang banyak digunakan di lingkungan lain. - Sekarang, JavaScript mempunyai posisi unik sebagai bahasa browser paling banyak diadopsi dengan integrasi penuh dengan HTML/CSS. - Ada banyak bahasa yang "ditranspile" ke JavaScript dan menyediakan fitur tertentu. Disarankan untuk mempelajari mereka juga, minimal sebentar, setelah menguasai JavaScript. +======= +- JavaScript was initially created as a browser-only language, but it is now used in many other environments as well. +- Today, JavaScript has a unique position as the most widely-adopted browser language, fully integrated with HTML/CSS. +- There are many languages that get "transpiled" to JavaScript and provide certain features. It is recommended to take a look at them, at least briefly, after mastering JavaScript. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/1-js/01-getting-started/2-manuals-specifications/article.md b/1-js/01-getting-started/2-manuals-specifications/article.md index b725ae550..febd875b6 100644 --- a/1-js/01-getting-started/2-manuals-specifications/article.md +++ b/1-js/01-getting-started/2-manuals-specifications/article.md @@ -2,7 +2,11 @@ Buku ini adalah _tutorial_. Tujuannya membantu kamu memahami bahasa ini (Javascript) pelan-pelan. Tapi sekali kamu akrab atau familiar dengan dasarnya, kamu juga membutuhkan dari sumber-sumber lain. +<<<<<<< HEAD ## Spesifikasi +======= +This book is a *tutorial*. It aims to help you gradually learn the language. But once you're familiar with the basics, you'll need other resources. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 [Spesifikasi ECMA-262](https://www.ecma-international.org/publications/standards/Ecma-262.htm) berisi informasi formal, detil, and mendalam tentang JavaScript. Ia mendefisikan bahasa ini. @@ -10,7 +14,11 @@ Tapi karena menjadi formal, ia sulit dipahami di awal. Jadi jika kamu butuh sumb Versi spesifikasi baru dirilis tiap tahun. Di antara rilis ini, draft spesifikasi terakhir ada di . +<<<<<<< HEAD Untuk membaca tentang fitur terkini, termasuk yang "hampir menjadi standar" (disebut "stage 3"), lihat proposalnya di . +======= +A new specification version is released every year. Between these releases, the latest specification draft is at . +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Juga, jika kamu dalam pengembangan untuk peramban, maka ada spek lain yang dibahas di [bagian kedua](info:browser-environment) di tutorial ini. @@ -20,9 +28,15 @@ Juga, jika kamu dalam pengembangan untuk peramban, maka ada spek lain yang dibah Kamu bisa cari di . +<<<<<<< HEAD Meski, sering lebih bagus menggunakan pencarian internet. Pakai "MDN [term]" di query, misal untuk mencari fungsi `parseInt`. - **MSDN** – Manual Microsoft dengan banyak informasi, termasuk JavaScript (sering dirujuk sebagai JScript). Jika kamu butuh sesuatu yang spesifik ke Internet Explorer, lebih baik pergi ke: . +======= + You can find it at . + +Although, it's often best to use an internet search instead. Just use "MDN [term]" in the query, e.g. to search for the `parseInt` function. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Juga, kamu bisa menggunakan pencarian internet dengan frasa seperti "RegExp MSDN" atau "RegExp MSDN jscript". @@ -30,10 +44,17 @@ Juga, jika kamu dalam pengembangan untuk peramban, maka ada spek lain yang dibah JavaScript merupakan bahasa berkembang, fitur baru ditambah secara reguler. +<<<<<<< HEAD Untuk melihat dukungan mereka pada engine berbasis peramban dan lainnya, lihat: - - tabel dukungan per-fitur, misal untuk melihat engine mana yang mendukung fungsi kryptografi modern: . - - tabel dengan fitur dan engine bahasa yang mendukung atau yang tidak mendukung. +======= +- - per-feature tables of support, e.g. to see which engines support modern cryptography functions: . +- - a table with language features and engines that support those or don't support. + +All these resources are useful in real-life development, as they contain valuable information about language details, their support, etc. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Semua sumber ini berguna di pengembangan nyata, karena mereka berisi informasi berharga tentang detil bahasa, dukungan mereka dll. diff --git a/1-js/01-getting-started/3-code-editors/article.md b/1-js/01-getting-started/3-code-editors/article.md index 6bb78d36f..c3d44c490 100644 --- a/1-js/01-getting-started/3-code-editors/article.md +++ b/1-js/01-getting-started/3-code-editors/article.md @@ -12,8 +12,13 @@ Satu IDE meload proyek (yang bisa berupa banyak file), memungkingkan navigasi an Jika kamu belum memilih satu IDE, pertimbangkan opsi-opsi berikut: +<<<<<<< HEAD - [Visual Studio Code](https://code.visualstudio.com/) (lintas-platform, gratis). - [WebStorm](http://www.jetbrains.com/webstorm/) (lintas-platform, berbayar). +======= +- [Visual Studio Code](https://code.visualstudio.com/) (cross-platform, free). +- [WebStorm](https://www.jetbrains.com/webstorm/) (cross-platform, paid). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Untuk Windows, ada juga "Visual Studio", jangan dipusingkan dengan "Visual Studio Code." "Visual Studio" merupakan editor khusus Windows yang keren dan berbayar, sangat cocok untuk platform .NET. Ia bagus juga untuk JavaScript. Lalu ada juga versi gratisnya [Visual Studio Community](https://www.visualstudio.com/vs/community/). @@ -29,6 +34,7 @@ Perbedaan utama antara "editor ringan" dan "IDE" adalah IDE bekerja pada level p Pada praktiknya, editor ringan bisa punya banyak plugin termasuk syntax analyzers dan autocompleters level direktori, jadi tak ada batasan ketat antara editor ringan dan IDE. +<<<<<<< HEAD Opsi-opsi berikut patut anda perhatikan: - [Atom](https://atom.io/) (lintas-platform, gratis). @@ -36,6 +42,13 @@ Opsi-opsi berikut patut anda perhatikan: - [Sublime Text](http://www.sublimetext.com) (lintas-platform, shareware). - [Notepad++](https://notepad-plus-plus.org/) (Windows, gratis). - [Vim](http://www.vim.org/) dan [Emacs](https://www.gnu.org/software/emacs/) sangat keren juga jika kamu tahu cara pakainya. +======= +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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Jangan berdebat @@ -43,4 +56,13 @@ Daftar editor di atas merupakan barang yang sudah biasa saya atau teman-teman sa Ada banyak editor bagus lainnya di dunia kita yang besar ini. Silakan pilih satu yang paling kamu suka. +<<<<<<< HEAD Pilihan editor, sama seperti tool lainnya, bersifat individual dan tergantung pada proyek, kebiasaan, dan preferensi personal. +======= +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). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/1-js/02-first-steps/01-hello-world/article.md b/1-js/02-first-steps/01-hello-world/article.md index 99c41f1f3..91c043f18 100644 --- a/1-js/02-first-steps/01-hello-world/article.md +++ b/1-js/02-first-steps/01-hello-world/article.md @@ -73,7 +73,11 @@ File script ditempel ke HTML dengan atribut `src`: ``` +<<<<<<< HEAD Di sini, `/path/to/script.js` adalah jalur absolut ke file script dari root sitius. Kamu juga bisa menyediakan jalur relatif dari laman ini. Misalnya, `src="script.js"` berarti file `"script.js"` dalam folder saat ini. +======= +Here, `/path/to/script.js` is an absolute path to the script from the site root. One can also provide a relative path from the current page. For instance, `src="script.js"`, just like `src="./script.js"`, would mean a file `"script.js"` in the current folder. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Kamu bisa memasang URL penuh juga. Misalnya: diff --git a/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md b/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md index 65bc298cc..5942eb447 100644 --- a/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md +++ b/1-js/02-first-steps/04-variables/3-uppercast-constant/task.md @@ -12,13 +12,24 @@ const birthday = '18.04.1982'; const age = someCode(birthday); ``` +<<<<<<< HEAD Di sini kita punya konstan tanggal `birthday` dan `age` dikalkulasi dari `birthday` dengan batuan beberapa kode (tidak tersedia yang pendek-pendek, dan karena detail tidak masalah di sini). +======= +Here we have a constant `birthday` for the date, and also the `age` constant. + +The `age` is calculated from `birthday` using `someCode()`, which means a function call that we didn't explain yet (we will soon!), but the details don't matter here, the point is that `age` is calculated somehow based on the `birthday`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Apakah tepat menggunakan huruf kapital untuk `birthday`? Untuk `age`? Atau bahkan untuk keduanya? ```js +<<<<<<< HEAD const BIRTHDAY = '18.04.1982'; // buat huruf kapital? const AGE = someCode(BIRTHDAY); // buat huruf kapital? -``` +======= +const BIRTHDAY = '18.04.1982'; // make birthday uppercase? +const AGE = someCode(BIRTHDAY); // make age uppercase? +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 +``` diff --git a/1-js/02-first-steps/04-variables/article.md b/1-js/02-first-steps/04-variables/article.md index 0bcb35ec6..386b15566 100644 --- a/1-js/02-first-steps/04-variables/article.md +++ b/1-js/02-first-steps/04-variables/article.md @@ -24,7 +24,11 @@ Kini, kita bisa menaruh beberapa data ke dalamnya dengan menggunakan operator pe let message; *!* +<<<<<<< HEAD message = 'Hello'; // simpan string +======= +message = 'Hello'; // store the string 'Hello' in the variable named message +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 */!* ``` @@ -63,7 +67,12 @@ let age = 25; let message = 'Hello'; ``` +<<<<<<< HEAD Beberapa orang juga mendefinisi variabel ganda dalam gaya multibaris ini: +======= +Some people also define multiple variables in this multiline style: + +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js no-beautify let user = 'John', age = 25, @@ -88,22 +97,37 @@ Di script jadul, kamu mungkin juga menemukan katakunci lain: `var` ketimbang `le *!*var*/!* message = 'Hello'; ``` +<<<<<<< HEAD Katakunci `var` *hampir* sama dengan `let`. Gunanya untuk mendeklarasi variabel, tapi caranya agak sedikit beda, "jadul". Ada perbedaan halus antara `let` dan `var`, tapi itu tak masalah buat kita sekarang ini. Kita akan mengcover mereka lebih detil di bab . +======= +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 . +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```` ## Analogy kehidupan nyata Kita bisa dengan mudah memahami konsep "variabel" jika kita membayangkannya sebagai "box" untuk data, dengan stiker nama yang unik. +<<<<<<< HEAD Misalnya, variabel `message` bisa dibayangkan sebagai box berlabel `"message"` dengan nilai `"Hello!"` di dalamnya: +======= +For instance, the variable `message` can be imagined as a box labelled `"message"` with the value `"Hello!"` in it: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ![](variable.svg) Kita bisa menaruh nilai apapun di dalam box. +<<<<<<< HEAD Kita juga bisa mengubahnya sebanyak yang kita mau: +======= +We can also change it as many times as we want: + +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let message; @@ -150,12 +174,21 @@ let message = "That"; // SyntaxError: 'message' has already been declared Jadi, kita harus mendeklarasikan variabel sekali dan menggunakan variabel tersebut tanpa menggunakan 'let'. ```` +<<<<<<< HEAD ```smart header="Bahasa fungsional" Ini sangat menarik untuk diperhatikan bahwa ada bahasa pemrograman [fungsional](https://en.wikipedia.org/wiki/Functional_programming), seperti [Scala](http://www.scala-lang.org/) atau [Erlang](http://www.erlang.org/) yang melarang merubah nilai dari variabel. +======= +```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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Di dalam bahasa macam ini, sekali nilai disimpan "dalam box", ia akan di sana selamanya. Jika kita harus menyimpan sesuatu yang lain, bahasa tersebut memaksa kita membuat box baru (mendeklarasi variabel baru). Kita tak bisa menggunakan ulang yang lama. +<<<<<<< HEAD Meski kelihatan sedikit aneh saat pandangan pertama, bahasa-bahasa ini ternyata mumpuni untuk pengembangan yang serius. Lebih dari itu, ada area seperti komputasi paralel di mana keterbatasan ini memberikan keuntungan tertentu. Disarankan mempelajari bahasa macam ini (meski jika kamu tak berencana menggunakannya segera) untuk meningkatkan wawasan. +======= +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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ## Penamaan variabel [#variable-naming] @@ -193,19 +226,32 @@ let 1a; // cannot start with a digit let my-name; // hyphens '-' aren't allowed in the name ``` +<<<<<<< HEAD ```smart header="Case berpengaruh" Variabel dengan nama `apple` dan `AppLE` adalah dua variabel yang berbeda. ``` ````smart header="Huruf non-Latin diperbolehkan, namun tak direkomendasikan" Boleh menggunakan bahasa apapun, termasuk huruf cyrillic atau bahkan hieroglyphs, seperti ini: +======= +```smart header="Case matters" +Variables named `apple` and `APPLE` are two different variables. +``` + +````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: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js let имя = '...'; let 我 = '...'; ``` +<<<<<<< HEAD Secara teknis, tak ada error di sini, nama-nama begitu boleh digunakan, tapi ada tradisi internasional untuk menggunakan bahasa Inggris dalam nama variabel. Meski jika kita menulis script kecil, kemungkinan variabelnya akan digunakan terus-menerus. Dan juga orang-orang dari negara lain mungkin harus membaca beberapa kali. +======= +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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```` ````warn header="Nama-nama yang dikecualikan" @@ -260,12 +306,20 @@ const myBirthday = '18.04.1982'; myBirthday = '01.01.2001'; // error, tak bisa menetapkan-ulang konstan! ``` +<<<<<<< HEAD Ketika programmer yakin bahwa variabel tak akan berubah, mereka bisa mendeklarasikan `const` untuk menjamin hal itu dan memberitahu semua orang. +======= +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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ### Konstan huruf-besar +<<<<<<< HEAD Ada kebiasaan umum untuk menggunakan konstan sebagai alias untuk nilai yang sulit dihafal yang akan diketahui sebelum dieksekusi. +======= +There is a widespread practice to use constants as aliases for difficult-to-remember values that are known before execution. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Konstan macam ini dinamai dengan huruf kapital dan underscore. @@ -290,16 +344,29 @@ Keuntungan: Kapan kita sebaiknya menggunakan kapital untuk konstan dan kapan itu dinamai dengan normal? Ayo kita perjelas. +<<<<<<< HEAD Menjadi "konstan" hanya berarti jika nilai variable tak pernah berubah. Tapi ada konstan yang diketahui sebelum eksekusi (seperti nilai hexadecimal untuk merah) dan ada konstan yang *dikalkulasi* dalam run-time, selama eksekusi, tapi tak berubah setelah penetapan inisial mereka. Misalnya: +======= +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. + +For instance: + +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js const pageLoadTime = /* waktu yang dibutuhkan laman web untuk meload */; ``` +<<<<<<< HEAD Nilai `pageLoadTime` tidak diketahui sebelum laman diload, jadi itu dinamai dengan normal. Tapi ia masih konstan karena ia tak berubah setelah penetapan. Dengan kata lain, konstan berhuruf kapital hanya digunakan sebagai alias untuk nilai yang "dihard-code". +======= +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. + +In other words, capital-named constants are only used as aliases for "hard-coded" values. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Namai dengan benar @@ -307,18 +374,31 @@ Berbicara tentang variabel, ada satu hal yang sangat penting. Nama variabel sebaiknya punya arti yang bersih dan jelas, yang menjelaskan data yang ia simpan. +<<<<<<< HEAD Penamaan variabel adalah salah satu keahlian yang penting dan rumit dalam pemrograman. Pandangan sekilas pada nama variabel bisa menyingkap kode yang ditulis oleh pengembang pemula versus pengembang berpengalaman. Di proyek nyata, kebanyakan waktu dihabiskan untuk modifikasi dan mengextend code base ketimbang menulis sesuatu yang benar-benar baru dari awal. Ketika kita kembali ke beberapa kode setelah melakukan sesuatu yang lain untuk sementara, akan lebih mudah menemukan informasi yang labelnya tepat. Atau, dengan kata lain, ketika variabel punya nama yang baik. +======= +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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Tolong renungkan tentang nama yang baik untuk variabel sebelum mendeklarasinya. Itu baik untukmu. Beberapa aturan yang baik untuk ditiru: +<<<<<<< HEAD - Gunakan nama yang manusiawi seperti `userName` atau `shoppingCart`. - Jauhi singkatan atau nama pendek seperti `a`, `b`, `c`, kecuali jika kamu benar-benar tau apa yang kamu lakukan. - Buat nama sedeskriptif dan sejelas mungkin. Contoh nama yang jelek ialah `data` dan `value`. Nama semacam ini tidak punya makna dan hanya OK untuk menggunakannya jika data atau nilai variabel yang mengacu kontex kodenya luar biasa jelas. - Sepakat dalam hal-hal yang ada di dalam timmu dan pikiranmu. Jika pengunjung situs disebut "user" maka kita sebaiknya menamai variabel terkait `currentUser` atau `newUser` ketimbang `currentVisitor` atau `newManInTown`. +======= +- 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`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Kedengaran simpel kan? Jelas saja, tapi membuat nama variabel descriptif dan jelas pada praktiknya tidak mudah. Coba lakukan. diff --git a/1-js/02-first-steps/05-types/article.md b/1-js/02-first-steps/05-types/article.md index 114947d9a..5b87531c2 100644 --- a/1-js/02-first-steps/05-types/article.md +++ b/1-js/02-first-steps/05-types/article.md @@ -46,13 +46,23 @@ Selain angka reguler, ada yang disebut "nilai numerik spesial" yang juga bagian alert( "not a number" / 2 ); // NaN, pembagian macam ini keliru ``` +<<<<<<< HEAD `NaN` itu lengket. Operasi lanjutan apapun pada `NaN` menghasilkan `NaN`: +======= + `NaN` is sticky. Any further mathematical operation on `NaN` returns `NaN`: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run - alert( "not a number" / 2 + 5 ); // NaN + alert( NaN + 1 ); // NaN + alert( 3 * NaN ); // NaN + alert( "not a number" / 2 - 1 ); // NaN ``` +<<<<<<< HEAD Jadi, jika ada `NaN` di manapun di expresi matematika, ia mempropagasi hasil keseluruhan. +======= + So, if there's a `NaN` somewhere in a mathematical expression, it propagates to the whole result (there's only one exception to that: `NaN ** 0` is `1`). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```smart header="Operasi matematika itu aman" Melakukan matematika itu "aman" dalam JavaScript. Kita bisa melakukan apapun: pembagian dengan nol, memperlakukan string non-numerik sebagai angka, dll. @@ -66,9 +76,26 @@ Kita akan melihat lebih tentang cara bekerja dengan angka di bab . ## BigInt [#bigint-type] +<<<<<<< HEAD Didalam Javascript, tipe data "number" tidak bisa mengandung nilai lebih dari (253-1) (sama dengan `9007199254740991`) atau kurang dari -(253-1). Itu adalah batasan teknik yang dibuat. Untuk kebanyakan kebutuhan sebenarnya sudah cukup, dan terkadang kita membutuhkan nilai yang lebih besar, contohnya untuk kriptografy atau perhitungan waktu microsecond. +======= +In JavaScript, the "number" type cannot safely represent integer values larger than (253-1) (that's `9007199254740991`), or less than -(253-1) for negatives. + +To be really precise, the "number" type can store larger integers (up to 1.7976931348623157 * 10308), but outside of the safe integer range ±(253-1) there'll be a precision error, because not all digits fit into the fixed 64-bit storage. So an "approximate" value may be stored. + +For example, these two numbers (right above the safe range) are the same: + +```js +console.log(9007199254740991 + 1); // 9007199254740992 +console.log(9007199254740991 + 2); // 9007199254740992 +``` + +So to say, all odd integers greater than (253-1) can't be stored at all in the "number" type. + +For most purposes ±(253-1) range is quite enough, but sometimes we need the entire range of really big integers, e.g. for cryptography or microsecond-precision timestamps. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Tipe data `BigInt` lalu ditambahkan kedalam Javascript untuk menampilkan nilai *integer* yang sangat panjang. @@ -81,6 +108,7 @@ const bigInt = 1234567890123456789012345678901234567890n; Sebenarnya `BigInt` jarang dibutuhkan, kita tidak akan mempelajarinya disini, tetapi akan dipisahkan didalam bagian . Baca saja saat kamu membutuhkan nilai *integer* yang sangat panjang. +<<<<<<< HEAD ```smart header="Masalah Kompabilitas" Sekarang `BigInt` sudah didukung oleh Firefox/Chrome/Edge, tapi tidak didalam Safari/Internet Explorer. @@ -88,6 +116,8 @@ Sekarang `BigInt` sudah didukung oleh Firefox/Chrome/Edge, tapi tidak didalam Sa You can check [*MDN* BigInt compatibility table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#Browser_compatibility) to know which versions of a browser are supported. +======= +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## String String di JavaScript harus dikelilingi petik. @@ -211,6 +241,7 @@ Tipe `symbol` digunakan untuk menciptakan identifier unik untuk sebuah objek. Un ## Operator typeof [#type-typeof] +<<<<<<< HEAD Operator `typeof` mengembalikan tipe argumen. Berguna ketika kita ingin memproses nilai dari tipe berbeda secara berbeda atau cuma ingin mengecek sekilas. Ia mendukung dua bentuk syntax: @@ -221,6 +252,11 @@ Ia mendukung dua bentuk syntax: Dengan kata lain, ia berjalan dengan atau tanpa kurung. Hasilnya sama saja. Panggilan ke `typeof x` mengembalikan string dengan nama tipenya: +======= +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. + +A call to `typeof x` returns a string with the type name: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js typeof undefined // "undefined" @@ -250,14 +286,33 @@ typeof alert // "function" (3) Tiga baris terakhir mungkin butuh penjelasan tambahan: +<<<<<<< HEAD 1. `Math` ialah objek built-in yang menyediakan operasi matematik. Kita akan belajar itu di bab . Di sini, ia cuma sekedar contoh dari objek. 2. Hasil `typeof null` yaitu `"object"`. Itu salah. Ia merupakan error yang terkenal resmi dalam `typeof`, yang dijaga untuk kompatibilitas. Tentu saja, `null` bukanlah objek. Ia merupakan nilai spesial dengan tipe terpisah miliknya sendiri. Jadi, lagi, ini merupakan error dalam bahasa. 3. Hasil dari `typeof alert` yaitu `"function"`, karena `alert` merupakan fungsi. Kita akan belajar fungsi di bab berikutnya di mana kita juga akan melihat bahwa tak ada tipe "fungsi" spesial di JavaScript. Fungsi merupakan bagian dari tipe objek. Tapi `typeof` memperlakukan mereka secara berbeda, yang mengembalikan `"fungsi"`. Itu tak sepenuhnya benar, tapi sangat nyaman pada praktiknya. ## Kesimpulan +======= +1. `Math` is a built-in object that provides mathematical operations. We will learn it in the chapter . Here, it serves just as an example of an object. +2. The result of `typeof null` is `"object"`. That's an officially recognized error in `typeof`, coming from very early days of JavaScript and kept for compatibility. Definitely, `null` is not an object. It is a special value with a separate type of its own. The behavior of `typeof` is wrong here. +3. The result of `typeof alert` is `"function"`, because `alert` is a function. We'll study functions in the next chapters where we'll also see that there's no special "function" type in JavaScript. Functions belong to the object type. But `typeof` treats them differently, returning `"function"`. That also comes from the early days of JavaScript. Technically, such behavior isn't correct, but can be convenient in practice. + +```smart header="The `typeof(x)` syntax" +You may also come across another syntax: `typeof(x)`. It's the same as `typeof x`. + +To put it clear: `typeof` is an operator, not a function. The parentheses here aren't a part of `typeof`. It's the kind of parentheses used for mathematical grouping. + +Usually, such parentheses contain a mathematical expression, such as `(2 + 2)`, but here they contain only one argument `(x)`. Syntactically, they allow to avoid a space between the `typeof` operator and its argument, and some people like it. + +Some people prefer `typeof(x)`, although the `typeof x` syntax is much more common. +``` + +## Summary +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Ada 7 tipe data dasar dalam JavaScript. +<<<<<<< HEAD - `number` untuk nomor dengan bentuk apapun: integer ataupun nilai yang memiliki nilai desimal, batas dari integer adalah ±253. - `bigint` untuk nomor integer yang sangat panjang. - `string` untuk string. Sebuah string mungkin memiliki 0 atau lebih karakter, tidak ada tipe data untuk string yang memiliki panjang 1 karakter. @@ -266,11 +321,29 @@ Ada 7 tipe data dasar dalam JavaScript. - `undefined` untuk nilai yang tidak ada atau tidak diberikan nilai -- sebuah tipe data mandiri yang memiliki satu nilai yaitu `null`. - `object` untuk struktur data yang lebih rumit. - `symbol` untuk identifier atau pengenal yang unik. +======= +- Seven primitive data types: + - `number` for numbers of any kind: integer or floating-point, integers are limited by ±(253-1). + - `bigint` for integer numbers of arbitrary length. + - `string` for strings. A string may have zero or more characters, there's no separate single-character type. + - `boolean` for `true`/`false`. + - `null` for unknown values -- a standalone type that has a single value `null`. + - `undefined` for unassigned values -- a standalone type that has a single value `undefined`. + - `symbol` for unique identifiers. +- And one non-primitive data type: + - `object` for more complex data structures. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Operator `typeof` memungkinkan kita melihat tipe mana yang disimpan dalam variable. +<<<<<<< HEAD - Dua form: `typeof x` atau `typeof(x)`. - Mengembalikan string dengan nama tipe, seperti `"string"`. - Untuk `null` mengembalikan `"object"` -- ada error dalam bahasa, yang sebenarnya bukan objek. +======= +- Usually used as `typeof x`, but `typeof(x)` is also possible. +- Returns a string with the name of the type, like `"string"`. +- For `null` returns `"object"` -- this is an error in the language, it's not actually an object. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Di bab berikutnya, kita akan fokus pada nilai primitive dan sekali kita familiar dengan mereka, kita akan lanjut ke objek. diff --git a/1-js/02-first-steps/07-type-conversions/article.md b/1-js/02-first-steps/07-type-conversions/article.md index 3f86aff0b..1cbe1edfa 100644 --- a/1-js/02-first-steps/07-type-conversions/article.md +++ b/1-js/02-first-steps/07-type-conversions/article.md @@ -6,8 +6,13 @@ Misalnya, `alert` otomatis mengkonversi nilai apapun ke string untuk menampilkan Ada juga kasus di mana kita harus explisit mengkonversi nilai ke tipe yang diharapkan. +<<<<<<< HEAD ```smart header="Belum bicara objek dulu" Di bab ini, kita takkan mengcover objek. Daripada itu, kita akan belajar primitives dulu. +======= +```smart header="Not talking about objects yet" +In this chapter, we won't cover objects. For now, we'll just be talking about primitives. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Lalu, setelah kita belajar tentang objek, kita akan lihat cara konversi objek bekerja di bab . ``` @@ -34,7 +39,11 @@ Konversi string kebanyakan jelas. `false` menjadi `"false"`, `null` menjadi `"nu ## Konversi Numerik +<<<<<<< HEAD Konversi numerik terjadi otomatis dalam fungsi dan expresi matematis. +======= +Numeric conversion in mathematical functions and expressions happens automatically. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Misalnya, ketika pembagian `/` dilakukan ke non-angka: @@ -69,8 +78,13 @@ Aturan konversi numerik: |-------|-------------| |`undefined`|`NaN`| |`null`|`0`| +<<<<<<< HEAD |true dan false | `1` and `0` | | `string` | Whitespaces dari awal dan akhir dibuang. Jika string sisanya kosong, hasilnya `0`. Sebaliknya, angkanya "dibaca" dari stringnya. Error memberikan `NaN`. | +======= +|true and false | `1` and `0` | +| `string` | Whitespaces (includes spaces, tabs `\t`, newlines `\n` etc.) from the start and end are removed. If the remaining string is empty, the result is `0`. Otherwise, the number is "read" from the string. An error gives `NaN`. | +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Misalnya: @@ -130,7 +144,11 @@ Konversinya mengikuti aturan ini: |`undefined`|`NaN`| |`null`|`0`| |true / false | `1 / 0` | +<<<<<<< HEAD | `string` | Stringnya dibaca "apa adanya", whitespace dari kedua sisi diabaikan. String kosong menjadi `0`. Error memberikan `NaN`. | +======= +| `string` | The string is read "as is", whitespaces (includes spaces, tabs `\t`, newlines `\n` etc.) from both sides are ignored. An empty string becomes `0`. An error gives `NaN`. | +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 **`Konversi Boolean`** -- Terjadi di operasi logika. Bisa berjalan dengan `Boolean(value)`. diff --git a/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md index 5b8875c4d..38032fde6 100644 --- a/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md +++ b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md @@ -16,6 +16,7 @@ undefined + 1 = NaN // (6) " \t \n" - 2 = -2 // (7) ``` +<<<<<<< HEAD 1. Penambahan dengan string `"" + 1` mengkonversi `1` ke string: `"" + 1 = "1"`, dan kita punya `"1" + 0`, aturan yang sama berlaku. 2. Pengurangan `-` (seperti kebanyakan operasi matematika) cuma berjalan dengan angka, ia mengkonversi string kosong `""` ke `0`. 3. Penambahan dengan string mengappend angka `5` ke string. @@ -23,3 +24,12 @@ undefined + 1 = NaN // (6) 5. `null` menjadi `0` setelah konversi numerik. 6. `undefined` menjadi `NaN` setelah konversi numerik. 7. Karakter spasi, ialah string yang depan dan belakangnya ditrim ketika string dikonversi ke angka. Berikut seluruh string berisi karakter spasi, seperti `\t`, `\n` dan spasi "reguler" di antaranya. Jadi, serupa dengan string kosong, ia menjadi `0`. +======= +1. The addition with a string `"" + 1` converts `1` to a string: `"" + 1 = "1"`, and then we have `"1" + 0`, the same rule is applied. +2. The subtraction `-` (like most math operations) only works with numbers, it converts an empty string `""` to `0`. +3. The addition with a string appends the number `5` to the string. +4. The subtraction always converts to numbers, so it makes `" -9 "` a number `-9` (ignoring spaces around it). +5. `null` becomes `0` after the numeric conversion. +6. `undefined` becomes `NaN` after the numeric conversion. +7. Space characters are trimmed off string start and end when a string is converted to a number. Here the whole string consists of space characters, such as `\t`, `\n` and a "regular" space between them. So, similarly to an empty string, it becomes `0`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/1-js/02-first-steps/08-operators/article.md b/1-js/02-first-steps/08-operators/article.md index ca00ba647..9339f75d8 100644 --- a/1-js/02-first-steps/08-operators/article.md +++ b/1-js/02-first-steps/08-operators/article.md @@ -50,8 +50,14 @@ Hasil dari `a % b` adalah [nilai sisa](https://en.wikipedia.org/wiki/Remainder) Contoh ```js run +<<<<<<< HEAD alert( 5 % 2 ); // 1, sisa dari pembagian antara 5 dibagi 2 alert( 8 % 3 ); // 2, sisa dari pembagian antara 8 dibagi 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 +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ### Eksponensial ** @@ -65,7 +71,11 @@ alert( 2 ** 3 ); // 2³ = 8 alert( 2 ** 4 ); // 2⁴ = 16 ``` +<<<<<<< HEAD Sama seperti dalam matematika, operator eksponensial juga didefinisikan untuk bilangan non-bilangan bulat. +======= +Just like in maths, the exponentiation operator is defined for non-integer numbers as well. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Misalnya, akar kuadrat adalah eksponensial dengan : @@ -77,7 +87,11 @@ alert( 8 ** (1/3) ); // 2 (pangkat 1/3 sama dengan akar kubik) ## Penambahan string dengan + +<<<<<<< HEAD Ayo kita bertemu dengan fitur dari operator Javascript yang berada diatas aritmatika di sekolah. +======= +Let's meet the features of JavaScript operators that are beyond school arithmetics. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Biasanya, operator plus `+` menambah angka. @@ -193,6 +207,7 @@ Di sini adalah extrak dari [tabel presedensi](https://developer.mozilla.org/en/J | Presedensi | Nama | Tanda | |------------|------|------| | ... | ... | ... | +<<<<<<< HEAD | 17 | plus unary | `+` | | 17 | negasi unary | `-` | | 16 | akar pangkat | `**` | @@ -205,10 +220,28 @@ Di sini adalah extrak dari [tabel presedensi](https://developer.mozilla.org/en/J | ... | ... | ... | Seperti yang kita lihat, "plus unary" punya prioritas `17` yang lebih tinggi dari `13` "penambahan" (plus binary). Itulah kenapa, dalam expresi `"+apples + +oranges"`, plus unary bekerja sebelum penambahan. +======= +| 14 | unary plus | `+` | +| 14 | unary negation | `-` | +| 13 | exponentiation | `**` | +| 12 | multiplication | `*` | +| 12 | division | `/` | +| 11 | addition | `+` | +| 11 | subtraction | `-` | +| ... | ... | ... | +| 2 | assignment | `=` | +| ... | ... | ... | + +As we can see, the "unary plus" has a priority of `14` which is higher than the `11` of "addition" (binary plus). That's why, in the expression `"+apples + +oranges"`, unary pluses work before the addition. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Penetapan +<<<<<<< HEAD Mari ingat bahwa penetapan `=` juga merupakan operator. Ia terdaftar di tabel presedensi dengan prioritas sangat rendah `3`. +======= +Let's note that an assignment `=` is also an operator. It is listed in the precedence table with the very low priority of `2`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Itulah kenapa, ketika kita tetapkan variabel, seperti `x = 2 * 2 + 1`, kalkulasinya dilakukan pertama dan kemudian `=` dievaluasi, menyimpan hasilnya dalam in `x`. @@ -302,9 +335,13 @@ Operator semacam itu memiliki hak dengan tingkat yang sama dengan assignment yan ```js run let n = 2; -n *= 3 + 5; +n *= 3 + 5; // right part evaluated first, same as n *= 8 +<<<<<<< HEAD alert( n ); // 16 (bagian paling kanan dievaluasi terlebih dahulu, sama seperti n *= 8) +======= +alert( n ); // 16 +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ## Inkremen/dekremen @@ -436,7 +473,11 @@ Daftar operator: - RIGHT SHIFT ( `>>` ) - ZERO-FILL RIGHT SHIFT ( `>>>` ) +<<<<<<< HEAD Operator seperti diatas sangat jarang digunakan, ketika kita membutuhkan untuk memainkan angka di level paling rendah (bitwise). Kita tidak akan membutuhkan operator seperti ini dalam waktu dekat, sebagaimana dalam pengembangan web penggunaan operator seperti itu lebih sedikit, tetapi di area yang spesial, seperti kriptographi, operator seperti itu sangan dibutuhkan. Kamu bisa membaca artikel [Bitwise Operators](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators) di MDN ketika kamu membutuhkannya. +======= +These operators are used very rarely, when we need to fiddle with numbers on the very lowest (bitwise) level. We won't need these operators any time soon, as web development has little use of them, but in some special areas, such as cryptography, they are useful. You can read the [Bitwise Operators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#bitwise_operators) chapter on MDN when a need arises. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Koma diff --git a/1-js/02-first-steps/09-comparison/article.md b/1-js/02-first-steps/09-comparison/article.md index 8ce32da7d..889c2ceb9 100644 --- a/1-js/02-first-steps/09-comparison/article.md +++ b/1-js/02-first-steps/09-comparison/article.md @@ -4,10 +4,17 @@ Kita tahu beberapa operator pembanding dari matematika. Didalam Javascript operator-operator itu ditulis seperi ini: +<<<<<<< HEAD - Lebih besar/kurang dari: a > b, a < b. - Lebih besar/kurang dari atau sama: a >= b, a <= b. - Sama dengan: `a == b`, perhatikan tanda dua `=` digunakan untuk test persamaan, jika menggunakan satu `=` seperti `a = b` itu adalah sebuah asignment atau memasukan nilai kedalam variabel. - Tidak sama dengan: Didalam matematika notasinya seperti , tetapi didalam Javascript ditulis seperti a != b. +======= +- Greater/less than: a > b, a < b. +- Greater/less than or equals: a >= b, a <= b. +- Equals: `a == b`, please note the double equality sign `==` means the equality test, while a single one `a = b` means an assignment. +- Not equals: In maths the notation is , but in JavaScript it's written as a != b. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Didalam artikel ini kita akan belajar lebih lanjut tentang perbedaan tipe dari perbandingan, bagaimana cara Javascript membuatnya, termasuk sifat-sifat penting. diff --git a/1-js/02-first-steps/10-ifelse/article.md b/1-js/02-first-steps/10-ifelse/article.md index 284100848..800e967fb 100644 --- a/1-js/02-first-steps/10-ifelse/article.md +++ b/1-js/02-first-steps/10-ifelse/article.md @@ -69,7 +69,11 @@ if (kondisi) { ## Klausa "else" +<<<<<<< HEAD Pernyataan `if` dapat berisi blok opsional "else" opsional. Block "else" dijalankan ketika semua kondisi di atas blok "else" salah (false) semua. +======= +The `if` statement may contain an optional `else` block. It executes when the condition is falsy. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Contohnya: ```js run @@ -181,10 +185,17 @@ alert( message ); Mungkin sulit pada awalnya untuk memahami apa yang terjadi. Tetapi setelah melihat lebih dekat, kita dapat melihat bahwa itu hanya serangkaian tes biasa: +<<<<<<< HEAD 1. Tanda tanya pertama memeriksa apakah `age < 3`. 2. Jika benar -- `'Hi, baby!'` akan dikembalikan. Jika tidak, kode akan melanjutkan ke ekspresi setelah titik dua '":"', memeriksa apakah `age < 18`. 3. Jika itu benar -- `'Hello!'` akan dikembalikan. . Jika tidak, kode akan melanjutkan ke ekspresi setelah titik dua berikutnya '":"', memeriksa `age < 100`. 4. Jika itu benar -- `'Greetings!'` akan dikembalikan. Jika tidak, kode akan melanjutkan ke ekspresi setelah titik dua terakhir '":"', dan akhirnya akan mengembalikan `'What an unusual age!'`. +======= +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!'`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Kode bawah ini memperlihatkan apabila menggunakan `if..else` untuk kode di atas: diff --git a/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md b/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md index deeb75059..3c19879ce 100644 --- a/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md +++ b/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/solution.md @@ -1,6 +1,6 @@ Jawabannya: `null`, karena `null` adalah nilai falsy pertama yang ada di daftar. ```js run -alert( 1 && null && 2 ); +alert(1 && null && 2); ``` diff --git a/1-js/02-first-steps/11-logical-operators/article.md b/1-js/02-first-steps/11-logical-operators/article.md index e79a5ced8..521c47599 100644 --- a/1-js/02-first-steps/11-logical-operators/article.md +++ b/1-js/02-first-steps/11-logical-operators/article.md @@ -123,7 +123,11 @@ Hal ini menjadikan penggunaan yang menarik dibanding "OR booleanpure, classical, Itu berarti bahwa `||` memproses argumennya sampai nilai pertama bersifat truthy tercapai, lalu nilainya dikembalikan langsung, bahkan tanpa menyentuh argumen lainnya. +<<<<<<< HEAD Pentingnya dari fitur ini menjadi jelas jika sebuah operan bukan hanya sebuah nilai, tapi sebuah ekspresi yang melakukan aksi, seperti assignment sebuah variabel atau sebuah pemanggilan fungsi. +======= + The importance of this feature becomes obvious if an operand isn't just a value, but an expression with a side effect, such as a variable assignment or a function call. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Didalam contoh dibawah, hanya pesan kedua yang di jalankan: diff --git a/1-js/02-first-steps/12-nullish-coalescing-operator/article.md b/1-js/02-first-steps/12-nullish-coalescing-operator/article.md index 869e3c471..819496195 100644 --- a/1-js/02-first-steps/12-nullish-coalescing-operator/article.md +++ b/1-js/02-first-steps/12-nullish-coalescing-operator/article.md @@ -4,7 +4,11 @@ Operator penggabungan nullish ditulis sebagai dua tanda tanya `??`. +<<<<<<< HEAD Karena memperlakukan `null` dan `undefined` sama, kita akan menggunakan istilah khusus di sini, di artikel ini. Kami akan mengatakan bahwa ekspresi adalah "didefinisikan" ketika itu bukan `null` atau `undefined`. +======= +As it treats `null` and `undefined` similarly, we'll use a special term here, in this article. For brevity, we'll say that a value is "defined" when it's neither `null` nor `undefined`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Hasil dari `a?? b` adalah: - jika `a` didefinisikan, maka `a`, @@ -22,14 +26,24 @@ result = (a !== null && a !== undefined) ? a : b; Sekarang harus benar-benar jelas apa yang dilakukan `??`. Mari kita lihat di mana itu membantu. +<<<<<<< HEAD Kasus penggunaan umum untuk `??` adalah memberikan nilai default untuk variabel yang berpotensi tidak terdefinisi. Misalnya, di sini kami menampilkan `pengguna` jika didefinisikan, jika tidak `Anonim`: +======= +The common use case for `??` is to provide a default value. + +For example, here we show `user` if its value isn't `null/undefined`, otherwise `Anonymous`: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js dijalankan biarkan pengguna; +<<<<<<< HEAD alert(pengguna ?? "Anonim"); // Anonim (pengguna tidak ditentukan) +======= +alert(user ?? "Anonymous"); // Anonymous (user is undefined) +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` Berikut ini contoh dengan `pengguna` ditetapkan ke sebuah nama: @@ -37,14 +51,24 @@ Berikut ini contoh dengan `pengguna` ditetapkan ke sebuah nama: ```js dijalankan biarkan pengguna = "John"; +<<<<<<< HEAD alert(pengguna ?? "Anonim"); // John (ditentukan pengguna) +======= +alert(user ?? "Anonymous"); // John (user is not null/undefined) +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` Kita juga dapat menggunakan urutan `??` untuk memilih nilai pertama dari daftar yang bukan `null/undefined`. +<<<<<<< HEAD Katakanlah kita memiliki data pengguna dalam variabel `FirstName`, `lastName` atau `nickName`. Semuanya mungkin tidak ditentukan, jika pengguna memutuskan untuk tidak memasukkan nilai. Kami ingin menampilkan nama pengguna menggunakan salah satu variabel ini, atau menampilkan "Anonim" jika semuanya tidak ditentukan. +======= +Let's say we have a user's data in variables `firstName`, `lastName` or `nickName`. All of them may be not defined, if the user decided not to fill in the corresponding values. + +We'd like to display the user name using one of these variables, or show "Anonymous" if all of them are `null/undefined`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Mari kita gunakan operator `??` untuk itu: @@ -76,7 +100,11 @@ alert(Namadepan || Nama Belakang || Nama Panggilan || "Anonim"); // kode super */!* ``` +<<<<<<< HEAD Secara historis, operator OR `||` ada terlebih dahulu. Itu ada sejak awal JavaScript, jadi pengembang menggunakannya untuk tujuan seperti itu untuk waktu yang lama. +======= +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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Di sisi lain, operator penggabungan nullish `??` baru saja ditambahkan ke JavaScript, dan alasannya adalah karena orang-orang tidak terlalu senang dengan `||`. @@ -106,11 +134,19 @@ Dalam praktiknya, ketinggian nol seringkali merupakan nilai yang valid, yang tid ## Prioritas +<<<<<<< HEAD Prioritas operator `??` hampir sama dengan `||`, hanya sedikit lebih rendah. Ini sama dengan `5` di [tabel MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table), sedangkan `||` adalah `6` . +======= +The precedence of the `??` operator is the same as `||`. They both equal `3` in the [MDN table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Artinya, seperti halnya `||`, operator penggabungan nullish `??` dievaluasi sebelum `=` dan `?`, tetapi setelah sebagian besar operasi lain, seperti `+`, `*`. +<<<<<<< HEAD Jadi, jika kita ingin memilih nilai dengan `??` dalam ekspresi dengan operator lain, pertimbangkan untuk menambahkan tanda kurung: +======= +So we may need to add parentheses in expressions like this: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js dijalankan biarkan tinggi = nol; @@ -128,8 +164,13 @@ Jika tidak, jika kita menghilangkan tanda kurung, maka karena `*` memiliki prior // tanpa tanda kurung misal luas = tinggi?? 100 * lebar ?? 50; +<<<<<<< HEAD // ...berfungsi sama seperti ini (mungkin bukan yang kita inginkan): misal luas = tinggi?? (100 * lebar) ?? 50; +======= +// ...works this way (not what we want): +let area = height ?? (100 * width) ?? 50; +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ### Menggunakan ?? dengan && atau || diff --git a/1-js/02-first-steps/13-while-for/article.md b/1-js/02-first-steps/13-while-for/article.md index 34a529171..695a9acea 100644 --- a/1-js/02-first-steps/13-while-for/article.md +++ b/1-js/02-first-steps/13-while-for/article.md @@ -6,7 +6,24 @@ Contohnya, Mengeluarkan barang dari sebuah daftar satu per satu atau hanya menja *Perulangan* adalah sebuah cara untuk mengulangi kode yang sama beberapa kali. +<<<<<<< HEAD ## Perulangan "while" +======= +```smart header="The for..of and for..in loops" +A small announcement for advanced readers. + +This article covers only basic loops: `while`, `do..while` and `for(..;..;..)`. + +If you came to this article searching for other types of loops, here are the pointers: + +- See [for..in](info:object#forin) to loop over object properties. +- See [for..of](info:array#loops) and [iterables](info:iterable) for looping over arrays and iterable objects. + +Otherwise, please read on. +``` + +## The "while" loop +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Perulangan `while` memiliki sintaks sebagai berikut: @@ -106,10 +123,17 @@ Mari bahas pernyataan `for` bagian demi bagian: | bagian | | | |-------|----------|----------------------------------------------------------------------------| +<<<<<<< HEAD | begin | `i = 0` | Jalankan sekali masuk ke loop. | | condition | `i < 3`| Cek sebelum tiap iterasi loop. Jika salah, loop berhenti. | | body | `alert(i)`| Jalankan lagi dan lagi selama kondisi bernilai truthy. | | step | `i++` | Exekusi setelah badan di tiap iterasi. | +======= +| begin | `let i = 0` | Executes once upon entering the loop. | +| condition | `i < 3`| Checked before every loop iteration. If false, the loop stops. | +| body | `alert(i)`| Runs again and again while the condition is truthy. | +| step| `i++` | Executes after the body on each iteration. | +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Cara kerja algoritma perulangan umum seperti ini: @@ -162,11 +186,14 @@ for (i = 0; i < 3; i++) { // gunakan variabel yang sudah ada alert(i); // 3, terlihat, karena dideklarasikan diluar dari perulangan ``` - ```` +<<<<<<< HEAD ### Melewatkan bagian +======= +### Skipping parts +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Bagian apapun dari `for` dapat dilewati. @@ -268,7 +295,11 @@ for (let i = 0; i < 10; i++) { Dari sudut pandang teknis, ini identik dengan contoh diatas. Tentunya, kita dapat membungkus kode dalam sebuah blok `if` daripada menggunakan `continue`. +<<<<<<< HEAD Tapi sebagai efeknya, hal ini akan menciptakan kode lebih dalam satu tingkat (pemanggilan `alert` didalam kurung kurawal). Jika kode didalam `if` lebih panjang beberapa baris, hal itu akan membuat tingkat keterbacaan kode menjadi berkurang. +======= +But as a side effect, this created one more level of nesting (the `alert` call inside the curly braces). If the code inside of `if` is longer than a few lines, that may decrease the overall readability. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```` ````warn header="Tidak ada `break/continue` ke sisi kanan '?'" @@ -286,7 +317,6 @@ if (i > 5) { ...dan tulis ulang menggunakan sebuah tanda tanya: - ```js no-beautify (i > 5) ? alert(i) : *!*continue*/!*; // continue tidak diperbolehkan disini ``` @@ -320,7 +350,12 @@ Kita butuh cara untuk menghentikan proses jika pengguna membatalkan input. `break` biasa setelah `input` hanya akan menghentikan perulangan dalam. Itu tidak cukup--label, datang untuk menyelamatkan! +<<<<<<< HEAD Label adalah sebuah pengidentifikasi dengan sebuah titik dua sebelum perulangan: +======= +A *label* is an identifier with a colon before a loop: + +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js labelName: for (...) { ... @@ -342,6 +377,7 @@ Pernyataan `break ` di dalam loop di bawah menghentikan pada label: // lakukan sesuatu dengan nilai... } } + alert('Done!'); ``` @@ -361,14 +397,24 @@ Perintah `continue` dapat juga digunakan dengan sebuah label. pada kasus ini, ek ````warn header="Label tidak mengizinkan \"lompat\" ke manapun" Label tidak mengizinkan kita untuk lompat ke sembarang tempat dalam kode. +<<<<<<< HEAD Misalnya, mustahil melakukan ini: +======= +For example, it is impossible to do this: + +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js break label; // tidak lompak ke label di bawah label: for (...) ``` +<<<<<<< HEAD Direktif `break` harus berada di dalam blok kode. Secara teknis, setiap blok kode berlabel akan dilakukan, contoh.: +======= +A `break` directive must be inside a code block. Technically, any labelled code block will do, e.g.: + +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js label: { // ... @@ -377,7 +423,11 @@ label: { } ``` +<<<<<<< HEAD ...Meskipun, 99,9% dari waktu `break` yang digunakan adalah loop dalam, seperti yang telah kita lihat pada contoh di atas. +======= +...Although, 99.9% of the time `break` is used inside loops, as we've seen in the examples above. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 `continue` hanya dimungkinkan dari dalam loop. ```` diff --git a/1-js/02-first-steps/14-switch/article.md b/1-js/02-first-steps/14-switch/article.md index 99c67de94..6f97d6d9b 100644 --- a/1-js/02-first-steps/14-switch/article.md +++ b/1-js/02-first-steps/14-switch/article.md @@ -139,7 +139,11 @@ switch (a) { Sekarang baik `3` maupun `5` menampilkan pesan yang sama. +<<<<<<< HEAD Kemampuan "mengelompokkan" case adalah efek samping dari bagaimana `switch/case` bekerja tanpa `break`. Di sini exekusi dari `case 3` mulai dari baris `(*)` dan tembus ke `case 5`, karena tidak ada `break`. +======= +The ability to "group" cases is a side effect of how `switch/case` works without `break`. Here the execution of `case 3` starts from the line `(*)` and goes through `case 5`, because there's no `break`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Tipe berpengaruh diff --git a/1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md b/1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md index ace44886a..8b93517ce 100644 --- a/1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md +++ b/1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md @@ -1 +1,7 @@ -Tidak ada perbedaan. \ No newline at end of file +<<<<<<< HEAD +Tidak ada perbedaan. +======= +No difference! + +In both cases, `return confirm('Did parents allow you?')` executes exactly when the `if` condition is falsy. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/1-js/02-first-steps/15-function-basics/article.md b/1-js/02-first-steps/15-function-basics/article.md index fe07d4fbb..f62dccd75 100644 --- a/1-js/02-first-steps/15-function-basics/article.md +++ b/1-js/02-first-steps/15-function-basics/article.md @@ -24,7 +24,7 @@ Katakunci `fungsi` ditulis duluan, lalu *nama fungsinya*, kemudian daftar semua ```js function name(parameter1, parameter2, ... parameterN) { - ...body... + // body } ``` @@ -178,12 +178,21 @@ Ketika sebuah nilai dilewatkan sebagai parameter fungsi, itu juga disebut *argum Dengan kata lain, untuk meluruskan istilah-istilah ini: +<<<<<<< HEAD - Parameter adalah variabel yang tercantum di dalam tanda kurung dalam deklarasi fungsi (ini adalah istilah waktu deklarasi) - Argumen adalah nilai yang diteruskan ke fungsi saat dipanggil (ini adalah istilah waktu panggilan). +======= +- A parameter is the variable listed inside the parentheses in the function declaration (it's a declaration time term). +- An argument is the value that is passed to the function when it is called (it's a call time term). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Kami mendeklarasikan fungsi yang mencantumkan parameternya, lalu memanggilnya lewat argumen. +<<<<<<< HEAD Dalam contoh di atas, seseorang mungkin mengatakan: "fungsi `sayMessage` dideklarasikan dengan dua parameter, kemudian dipanggil dengan dua argumen: `from` dan `"Hello"`". +======= +In the example above, one might say: "the function `showMessage` is declared with two parameters, then called with two arguments: `from` and `"Hello"`". +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Nilai default @@ -208,7 +217,17 @@ function showMessage(from, *!*text = "no text given"*/!*) { showMessage("Ann"); // Ann: tidak diberikan teks ``` +<<<<<<< HEAD Sekarang, jika parameter `text` tidak ditentukan, parameter tersebut akan mengambil nilai `"no text give"` +======= +Now if the `text` parameter is not passed, it will get the value `"no text given"`. + +The default value also jumps in if the parameter exists, but strictly equals `undefined`, like this: + +```js +showMessage("Ann", undefined); // Ann: no text given +``` +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Disini `"no text give"` adalah string, tapi ia bisa menjadi suatu expresi nilai lebih kompleks, yang hanya dievaluasi dan ditetapkan jika tak ada nilai pada parameter. Jadi, ini juga mungkin ditetapkan: @@ -228,9 +247,47 @@ Di sisi lain, itu dipanggil secara independen setiap kali `teks` hilang. ``` +<<<<<<< HEAD ### Alternatif nilai default parameter Terkadang akan dapat dimengerti untuk memberikan nilai default untuk variabel bukan didalam deklarasi fungsi, tapi di tahap selanjutnya, didalam proses eksekusinya. +======= +````smart header="Default parameters in old JavaScript code" +Several years ago, JavaScript didn't support the syntax for default parameters. So people used other ways to specify them. + +Nowadays, we can come across them in old scripts. + +For example, an explicit check for `undefined`: + +```js +function showMessage(from, text) { +*!* + if (text === undefined) { + text = 'no text given'; + } +*/!* + + alert( from + ": " + text ); +} +``` + +...Or using the `||` operator: + +```js +function showMessage(from, text) { + // If the value of text is falsy, assign the default value + // this assumes that text == "" is the same as no text at all + text = text || 'no text given'; + ... +} +``` +```` + + +### Alternative default parameters + +Sometimes it makes sense to assign default values for parameters at a later stage after the function declaration. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Untuk memeriksa parameter yang tidak ada, kita bisa membandingkannya dengan `undefined`: @@ -250,7 +307,11 @@ function showMessage(text) { showMessage(); // empty message ``` +<<<<<<< HEAD ...Atau kita bisa menggunakan operator `||`: +======= +...Or we could use the `||` operator: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js // jika teks parameter tidak ada atau "", set variabel ke 'empty' @@ -427,7 +488,11 @@ Pada contoh-contoh ini diasumsikan arti-arti umum pada kata awalan. Kamu dan tim ```smart header="Ultrashort function names" Fungsi yang *digunakan secara sering* kadang-kadang memiliki nama yang sangat pendek. +<<<<<<< HEAD Sebagai contoh, framework [jQuary](http://jquary.com) mendefinisikan fungsi dengan simbol `$`. Library [Lodash](https://lodash.com) memiliki fungsi inti yang dinamakan dengan `_`. +======= +For example, the [jQuery](https://jquery.com/) framework defines a function with `$`. The [Lodash](https://lodash.com/) library has its core function named `_`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Hal-hal tersebut adalah pengecualian. Secara umum, nama fungsi sebaiknya ringkas dan menjelaskan maksudnya. ``` @@ -495,7 +560,11 @@ function name(parameters, delimited, by, comma) { Untuk membuat kode yang bersih dan mudah untuk dipahami, sangat dianjurkan untuk menggunakan variabel lokal dan parameter pada fungsi, tidak mengguunakan variabel luar / variabel global. +<<<<<<< HEAD Akan menjadi hal yang mudah untuk dipahami pada fungsi yang mendapatkan parameter, yang bekerja dengan parameter tersebut dan mengembalikan nilainya daripada fuungsi yang tidak memilki parameter, tetapi melakukan modifikasi terhadap variabel luar akan memiliki efek samping. +======= +It is always easier to understand a function which gets parameters, works with them and returns a result than a function which gets no parameters, but modifies outer variables as a side effect. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Penamaan fungsi: diff --git a/1-js/02-first-steps/16-function-expressions/article.md b/1-js/02-first-steps/16-function-expressions/article.md index c8d104b84..4dbf02ba9 100644 --- a/1-js/02-first-steps/16-function-expressions/article.md +++ b/1-js/02-first-steps/16-function-expressions/article.md @@ -12,7 +12,13 @@ function sayHi() { Ada syntax lain untuk membuat fungsi yang disebut *Expresi Fungsi*. +<<<<<<< HEAD Rupanya seperti ini: +======= +It allows us to create a new function in the middle of any expression. + +For example: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js let sayHi = function() { @@ -20,9 +26,25 @@ let sayHi = function() { }; ``` +<<<<<<< HEAD Di sini, fungsi dibuat dan diisi variabel secara explisit, seperti nilai lain manapun. Tak peduli bagaimana fungsi didefinisi, ia hanya suatu nilai yang disimpan dalam variabel `sayHi`. Arti dari sampel kode ini sama: "buatlah fungs dan taruhlah di dalam variabel `sayHi`". +======= +Here we can see a variable `sayHi` getting a value, the new function, created as `function() { alert("Hello"); }`. + +As the function creation happens in the context of the assignment expression (to the right side of `=`), this is a *Function Expression*. + +Please note, there's no name after the `function` keyword. Omitting a name is allowed for Function Expressions. + +Here we immediately assign it to the variable, so the meaning of these code samples is the same: "create a function and put it into the variable `sayHi`". + +In more advanced situations, that we'll come across later, a function may be created and immediately called or scheduled for a later execution, not stored anywhere, thus remaining anonymous. + +## Function is a value + +Let's reiterate: no matter how the function is created, a function is a value. Both examples above store a function in the `sayHi` variable. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Kita bahkan bisa mencetak nilai itu menggunakan `alert`: @@ -63,22 +85,31 @@ Inilah yang terjadi di atas secara detil: 2. Baris `(2)` mengkopinya ke variabel `func`. Tolong ingat lagi: tak ada tanda kurung setelah `sayHi`. Jika ada, maka `func = sayHi()` akan menulis *hasil panggilan* `sayHi()` ke `func`, bukan *fungsi* `sayHi` itu sendiri. 3. Sekarang fungsi bisa dipanggil baik sebagai `sayHi()` maupun `func()`. +<<<<<<< HEAD Catat bahwa kita jusa bisa menggunakan Expresi Fungsi untuk mendeklarasi `sayHi`, di baris pertama: +======= +We could also have used a Function Expression to declare `sayHi`, in the first line: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js -let sayHi = function() { +let sayHi = function() { // (1) create alert( "Hello" ); }; -let func = sayHi; +let func = sayHi; //(2) // ... ``` Semua akan berjalan sama. +<<<<<<< HEAD ````smart header="Kenapa ada semicolon di akhir?" Kamu mungkin penasaran, kenapa Expresi Fungsi punya semicolon `;` di akhir, tapi Deklarasi Fungsi tidak: +======= +````smart header="Why is there a semicolon at the end?" +You might wonder, why do Function Expressions have a semicolon `;` at the end, but Function Declarations do not: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js function sayHi() { @@ -90,9 +121,15 @@ let sayHi = function() { }*!*;*/!* ``` +<<<<<<< HEAD Jawabannya simpel: - `;` tidak dibutuhkan di akhir blok kode dan struktur syntax yang memakai mereka seperti `if { ... }`, `for { }`, `function f { }` dll. - Expresi Fungsi digunakan di dalam pernyataan: `let sayHi = ...;`, sebagai nilai. Ia bukan blok kode, tapi lebih ke penetapan. Semicolon `;` disarankan di akhir pernyataan, tak peduli nilainya apa. Jadi semicolon di sini tak ada hubungannya dengan Expresi Fungsi itu sendiri, ia hanya menstop pernyataan. +======= +The answer is simple: a Function Expression is created here as `function(…) {…}` inside the assignment statement: `let sayHi = …;`. The semicolon `;` is recommended at the end of the statement, it's not a part of the function syntax. + +The semicolon would be there for a simpler assignment, such as `let sayHi = 5;`, and it's also there for a function assignment. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```` ## Fungsi callback @@ -132,13 +169,21 @@ function showCancel() { ask("Do you agree?", showOk, showCancel); ``` +<<<<<<< HEAD Pada praktiknya, fungsi macam ini agak berguna. Perbedaan besar antara `ask` kehidupan-nyata dan contoh di atas adalah fungsi kehidupan-nyata memakai cara komplex untuk berinteraksi dengan pengguna daripada sekedar `confirm`. Di peramban, fungsi macam ini biasanya menarik window pertanyaan menarik. Tapi itu cerita lain lagi. +======= +In practice, such functions are quite useful. The major difference between a real-life `ask` and the example above is that real-life functions use more complex ways to interact with the user than a simple `confirm`. In the browser, such functions usually draw a nice-looking question window. But that's another story. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 **Argumen `showOk` dan `showCancel` dari `ask` dipanggil *fungsi callback* atau hanya *callback*.** Idenya adalah kita mengoper fungsi dan berharap ia "dipanggil kembali" kemudian jika dibutuhkan. Pada kasus kita, `showOk` menjadi callback untuk jawaban "yes", dan `showCancel` untuk jawaban "no". +<<<<<<< HEAD Kita bisa memakai Expresi Fungsi untuk menulis fungsi yang sama lebih pendek: +======= +We can use Function Expressions to write an equivalent, shorter function: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run no-beautify function ask(question, yes, no) { @@ -174,7 +219,11 @@ Mari kita rumuskan kunci perbedaan antara Deklarasi dan Expresi Fungsi. Pertama, syntax: bagaimana membedakan antara mereka dalam kode. +<<<<<<< HEAD - *Deklarasi Fungsi:* fungsi, yang dideklarasi sebagai pernyataan terpisah, dalam aliran kode utama. +======= +- *Function Declaration:* a function, declared as a separate statement, in the main code flow: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js // Deklarasi Fungsi @@ -182,7 +231,11 @@ Pertama, syntax: bagaimana membedakan antara mereka dalam kode. return a + b; } ``` +<<<<<<< HEAD - *Expresi Fungsi:* fungsi, yang dibuat dalam expresi atau dalam konstruksi syntax lain. Di sini, fungsi dibuat pada sisi kanan dari "expresi penetapan" `=`: +======= +- *Function Expression:* a function, created inside an expression or inside another syntax construct. Here, the function is created on the right side of the "assignment expression" `=`: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js // Expresi Fungsi @@ -279,9 +332,15 @@ if (age < 18) { welcome(); // \ (berjalan) */!* // | +<<<<<<< HEAD function welcome() { // | alert("Hello!"); // | Deklarasi Fungsi tersedia } // | di manapun dalam blok kode tempat dia dideklarasi +======= + function welcome() { // | + alert("Hello!"); // | Function Declaration is available + } // | everywhere in the block where it's declared +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 // | *!* welcome(); // / (berjalan) @@ -289,7 +348,7 @@ if (age < 18) { } else { - function welcome() { + function welcome() { alert("Greetings!"); } } @@ -347,8 +406,13 @@ welcome(); // sekarang ok ``` +<<<<<<< HEAD ```smart header="Kapan harus memilih Deklarasi Fungsi versus Expresi Fungsi?" Sebagai aturan praktis, saat kita harus mendeklarasi fungsi, hal pertama yang kita pertimbangkan ialah syntax Deklarasi Fungsi. Ia memberi kebebasan lebih dalam bagaimana mengorganisir kode kita, karena kita bisa memanggil fungsi macam ini sebelum mereka dideklarasi. +======= +```smart header="When to choose Function Declaration versus Function Expression?" +As a rule of thumb, when we need to declare a function, the first thing to consider is Function Declaration syntax. It gives more freedom in how to organize our code, because we can call such functions before they are declared. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Itu juga untuk keterbacaan yang lebih baik, karena lebih mudah melihat `function f(…) {…}` dalam kode ketimbang `let f = function(…) {…}`. Deklarasi Fungsi lebih "eye-catching". diff --git a/1-js/02-first-steps/17-arrow-functions-basics/article.md b/1-js/02-first-steps/17-arrow-functions-basics/article.md index 4a50a1c29..2598972c1 100644 --- a/1-js/02-first-steps/17-arrow-functions-basics/article.md +++ b/1-js/02-first-steps/17-arrow-functions-basics/article.md @@ -5,10 +5,14 @@ Terdapat sintaks lain yang sangat sederhana dan ringkas untuk membuat fungsi-fun Disebut sebagai "fungsi *arrow* (panah)", karena sintaks fungsinya terlihat seperti ini: ```js -let func = (arg1, arg2, ..., argN) => expression +let func = (arg1, arg2, ..., argN) => expression; ``` +<<<<<<< HEAD ...Ini membuat sebuah fungsi `func` yang menerima argumen `arg1..argN`, kemudian mengevaluasi `expression` yang ada di sisi kanan serta kegunaannya dan mengembalikan hasilnya. +======= +This creates a function `func` that accepts arguments `arg1..argN`, then evaluates the `expression` on the right side with their use and returns its result. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Dalam kata lain, fungsi tersebut adalah versi yang lebih pendek dari: @@ -33,7 +37,11 @@ let sum = function(a, b) { alert( sum(1, 2) ); // 3 ``` +<<<<<<< HEAD Seperti yang bisa dilihat, perhatikan `(a, b) => a + b` berarti sebuah fungsi yang menerima dua argumen yang diberinama `a` dan `b`. Ketika eksekusi, fungsi tersebut mengevaluasi ekpresi `a + b` dan mengembalikan hasilnya. +======= +As you can see, `(a, b) => a + b` means a function that accepts two arguments named `a` and `b`. Upon the execution, it evaluates the expression `a + b` and returns the result. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 - Jika kita memiliki satu argumen saja, maka *parentheses* di sekitar parameter bisa diabaikan, membuat sintaksnya jadi semakin pendek. @@ -48,7 +56,11 @@ Seperti yang bisa dilihat, perhatikan `(a, b) => a + b` berarti sebuah fungsi ya alert( double(3) ); // 6 ``` +<<<<<<< HEAD - Jika tidak ada argumen, *parentheses* akan kosong(tapi harus ditunjukkan): +======= +- If there are no arguments, parentheses are empty, but they must be present: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let sayHi = () => alert("Hello!"); @@ -64,7 +76,7 @@ Untuk membuat sebuah fungsi secara dinamis contohnya: let age = prompt("What is your age?", 18); let welcome = (age < 18) ? - () => alert('Hello') : + () => alert('Hello!') : () => alert("Greetings!"); welcome(); @@ -76,9 +88,15 @@ Fungsi *arrow* sangat memudahkan untuk sintaks-sintaks sederhana, saat kita terl ## Fungsi *arrow* multi-baris +<<<<<<< HEAD Contoh-contoh di atas mengambil argumen dari sisi kiri dari `=>` dan mengevaluasi ekpresi di sisi kanan. Terkadang kita memerlukan sesuatu yang agak sedikit rumit, seperti ekspresi atau pernyataan (*statement*) multi-baris (berbaris-baris). Hal tidaklah tidak mungkin, tapi kita harus menutup ekspresi atau pernyataan tersebut dengan tanda kurung kurawal. Kemudian menggunakan sebuah `return` normal diantaranya. +======= +The arrow functions that we've seen so far were very simple. They took arguments from the left of `=>`, evaluated and returned the right-side expression with them. + +Sometimes we need a more complex function, with multiple expressions and statements. In that case, we can enclose them in curly braces. The major difference is that curly braces require a `return` within them to return a value (just like a regular function does). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Seperti ini: @@ -86,7 +104,11 @@ Seperti ini: let sum = (a, b) => { // tanda kurung kurawal membuka fungsi multi-baris let result = a + b; *!* +<<<<<<< HEAD return result; // jika kita menggunakan kurung kurawal, selajutnya kita perlu menuliskan "return" +======= + return result; // if we use curly braces, then we need an explicit "return" +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 */!* }; @@ -105,7 +127,14 @@ Untuk sekarang, kita sudah bisa menggunakan fungsi arrow untuk sintaks-sintaks s ## Ringkasan +<<<<<<< HEAD Fungsi-fungsi *arrow* itu memudahkan untuk sintaks-sintaks yang hanya sebaris. Fungsi *arrow* juga hadir dengan dua cara: 1. Tanpa tanda kurung kurawal: `(...args) => expression` -- sisi kanan adalah sebuah ekspresi: fungsi tersebut mengevaluasi ekspresi dan mengembalikan hasilnya. 2. Dengan tanda kurung kurawal: `(...args) => { body }` -- tanda kurung kurawal membuat kita bisa menuliskan pernyataan-pernyataan berbaris-baris/multi-baris dalam fungsi tersebut, tapi kita perlu untuk menulsikan `return` untuk mengembalikan (hasil) sesuatu. +======= +Arrow functions are handy for simple actions, especially for one-liners. They come in two flavors: + +1. Without curly braces: `(...args) => expression` -- the right side is an expression: the function evaluates it and returns the result. Parentheses can be omitted, if there's only a single argument, e.g. `n => n*2`. +2. With curly braces: `(...args) => { body }` -- brackets allow us to write multiple statements inside the function, but we need an explicit `return` to return something. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/1-js/02-first-steps/18-javascript-specials/article.md b/1-js/02-first-steps/18-javascript-specials/article.md index 27f4b963e..7ad8dc841 100644 --- a/1-js/02-first-steps/18-javascript-specials/article.md +++ b/1-js/02-first-steps/18-javascript-specials/article.md @@ -55,7 +55,11 @@ Untuk mengaktifkan penuh semua fitur modern JavaScript, kita sebaiknya mulai scr Directive ini harus ada di paling atas script atau di awal badan fungsi. +<<<<<<< HEAD Tanpa `"use strict"`, apapun akan bekerja, tapi beberapa fitur bersikap dengan cara kuno, "kompatibel". Secara umum kita akan pilih sikap modern. +======= +Without `"use strict"`, everything still works, but some features behave in the old-fashioned, "compatible" way. We'd generally prefer the modern behavior. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Beberapa fitur modern bahasa ini (seperti kelas yang akan kita pelajari di kemudian) mengaktifkan mode ketat secara implisit. @@ -103,6 +107,7 @@ Lebih lanjut di: and . Kita menggunakan peramban sebagai lingkungan kerja, jadi fungsi UI dasar akan menjadi: +<<<<<<< HEAD [`prompt(question, [default])`](mdn:api/Window/prompt) : Menanyakan `question`, dan mengembalikan apa yang pengunjung isikan atau `null` jika mereka mengklik "cancel". @@ -111,6 +116,16 @@ Kita menggunakan peramban sebagai lingkungan kerja, jadi fungsi UI dasar akan me [`alert(message)`](mdn:api/Window/alert) : Menampilkan a `message`. +======= +[`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)`](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)`](https://developer.mozilla.org/en-US/docs/Web/API/Window/alert) +: Output a `message`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Semua fungsi ini adalah *modal*, mereka menyela exekusi kode dan mencegah pengunjung dari berinteraksi dengan laman hingga mereka menjawab. @@ -144,7 +159,11 @@ Penetapan : Ada penetapan simpel: `a = b` dan penetapan kombinasi seperti `a *= 2`. Bitwise +<<<<<<< HEAD : Operator bitwise bekerja dengan integer 32-bit di bit-level paling kecil: lihat [docs](mdn:/JavaScript/Reference/Operators/Bitwise_Operators) ketika mereka dibutuhkan. +======= +: 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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Kondisional : Satu-satunya operator dengan tiga parameter: `cond ? resultA : resultB`. Jika `cond` truthy, mengembalikan `resultA`, jika tidak `resultB`. @@ -256,7 +275,11 @@ Kita meliput tiga cara membuat fungsi di JavaScript: 3. Fungsi panah: ```js +<<<<<<< HEAD // expresi di sisi kanan +======= + // expression on the right side +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 let sum = (a, b) => a + b; // atau syntax baris-ganda dengan { ... }, butuh kembalian di sini: diff --git a/1-js/03-code-quality/01-debugging-chrome/article.md b/1-js/03-code-quality/01-debugging-chrome/article.md index 46318c4fd..0c467d657 100644 --- a/1-js/03-code-quality/01-debugging-chrome/article.md +++ b/1-js/03-code-quality/01-debugging-chrome/article.md @@ -38,7 +38,11 @@ Jika kita menekan `key:Esc`, maka konsol terbuka di bawah. Kita bisa mengetik co Setelah pernyataan diexekusi, hasilnya ditampilkan di bawah. +<<<<<<< HEAD Misalnya, `1+2` menghasilkan `3`, dan `hello("debugger")` tak mengembalikan apa-apa, jadi hasilnya `undefined`: +======= +For example, here `1+2` results in `3`, while the function call `hello("debugger")` returns nothing, so the result is `undefined`: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ![](chrome-sources-console.svg) @@ -62,13 +66,22 @@ Kita selalu bisa menemukan daftar breakpoint di panel kanan. Ini berguna ketika - Buang breakpoint dengan mengklik-kanan dan memilik Remove. - ...Dan banyak lagi. +<<<<<<< HEAD ```smart header="Breakpoint kondisional" *Klik kanan* di nomor baris bisa membuat breakpoint *kondisional*. Ia hanya terpicu saat expresi yang diberikan truthy. +======= +```smart header="Conditional breakpoints" +*Right click* on the line number allows to create a *conditional* breakpoint. It only triggers when the given expression, that you should provide when you create it, is truthy. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Ini praktis saat kita harus berhenti cuma untuk nilai variabel tertentu atau untuk parameter fungsi tertentu. ``` +<<<<<<< HEAD ## Command debugger +======= +## The command "debugger" +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Kita juga bisa menjeda kode menggunakan command `debugger` di dalamnya, seperti ini: @@ -84,8 +97,12 @@ function hello(name) { } ``` +<<<<<<< HEAD Ini sangat nyaman saat kita di dalam editor kode dan tak ingin berubah ke peramban dan mencari script di developer tools untuk mengeset breakpoint. +======= +Such command works only when the development tools are open, otherwise the browser ignores it. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Jeda dan lihat sekitar @@ -99,7 +116,11 @@ Silakan buka dropdown informasional ke kanan (dilabeli panah). Mereka membolehka 1. **`Watch` -- menampilkan nilai sekarang untuk expresi apapun.** +<<<<<<< HEAD Kamu bisa mengklik `+` dan menginput expresi. Debugger akan menampilkan nilainya kapan saja, otomatis merekalkulasi itu di proses exekusi. +======= + You can click the plus `+` and input an expression. The debugger will show its value, automatically recalculating it in the process of execution. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 2. **`Call Stack` -- menampilkan rantai panggilan bersarang.** @@ -134,12 +155,21 @@ Ada tombol untuk itu di ujung atas panel kanan. Ayo kita ikuti mereka. Mengklik ini akan melangkahi semua aksi script satu-satu. +<<<<<<< HEAD -- "Langkahi atas": jalankan command berikutnya, tapi *jangan masuk ke fungsi*, hotkey `key:F10`. : Serupa dengan command "Step" sebelumnya, tapi berbeda jika pernyataan berikutnya berupa panggilan fungsi. Yaitu: bukan built-in, seperti `alert`, tapi fungsi kita sendiri. Command "Langkahi" masuk ke dalam dan menjeda exekusi di baris pertama, sedangkan "Kangkangi" mengexekusi panggilan fungsi bersarang secara tak terlihat, mengabaikan internal fungsi. Exekusi kemudian segera dijeda setelah fungsi itu. +======= + -- "Step over": run the next command, but *don't go into a function*, hotkey `key:F10`. +: Similar to the previous "Step" command, but behaves differently if the next statement is a function call (not a built-in, like `alert`, but a function of our own). + + If we compare them, the "Step" command goes into a nested function call and pauses the execution at its first line, while "Step over" executes the nested function call invisibly to us, skipping the function internals. + + The execution is then paused immediately after that function call. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Itu baik jika kita tak tertarik mencaritahu ada apa di dalam panggilan fungsi. @@ -154,8 +184,13 @@ Ada tombol untuk itu di ujung atas panel kanan. Ayo kita ikuti mereka. -- nyalakan/matikan semua breakpoint. : Tombol itu tidak menggerakkan exekusi. Cuma on/off massal untuk breakpoint. +<<<<<<< HEAD -- nyalakan/matikan jeda otomatis jika ada galat. : Ketika menyala, dan developer tools terbuka, galat script otomatis menjeda exekusi. Lalu kita bisa menganalisa variabel untuk melihat apa yang salah. Jadi jika script kita mati karena galat, kita bisa buka debugger, menyalakan opsi ini dan memuat-ulang laman untuk melihat di mana ia mati dan apa kontexnya saat itu. +======= + -- enable/disable automatic pause in case of an error. +: When enabled, if the developer tools is open, an error during the script execution automatically pauses it. Then we can analyze variables in the debugger to see what went wrong. So if our script dies with an error, we can open debugger, enable this option and reload the page to see where it dies and what's the context at that moment. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```smart header="Lanjut ke sini" Klilk kanan di satu baris kode membuka context menu dengan opsi hebat yang disebut "Lanjut ke sini". @@ -187,7 +222,11 @@ Seperti yang kita lihat, ada tiga cara utama untuk menjeda script: 2. Pernyataan `debugger`. 3. Galat (jika dev tools terbuka dan tombol "menyala"). +<<<<<<< HEAD Ketika terjeda, kita bisa mendebug - periksa variabel dan menjejak kode untuk melihat di mana terjadi kesalahan exekusi. +======= +When paused, we can debug: examine variables and trace the code to see where the execution goes wrong. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Ada banyak lebih opsi di developer tool dari yang diliput di sini. Manual lengkap ada di . diff --git a/1-js/03-code-quality/02-coding-style/article.md b/1-js/03-code-quality/02-coding-style/article.md index 1ba318295..067615a6d 100644 --- a/1-js/03-code-quality/02-coding-style/article.md +++ b/1-js/03-code-quality/02-coding-style/article.md @@ -301,11 +301,15 @@ Yang keren dari ini ialah pengecekan gaya sekaligus menemukan bug., like typos i Berikut beberapa linting tool terkenal: -- [JSLint](http://www.jslint.com/) -- one of the first linters. -- [JSHint](http://www.jshint.com/) -- more settings than JSLint. -- [ESLint](http://eslint.org/) -- probably the newest one. +- [JSLint](https://www.jslint.com/) -- one of the first linters. +- [JSHint](https://jshint.com/) -- more settings than JSLint. +- [ESLint](https://eslint.org/) -- probably the newest one. +<<<<<<< HEAD Semuanya bisa melakukan itu. Penulis ini menggunakan [ESLint](http://eslint.org/). +======= +All of them can do the job. The author uses [ESLint](https://eslint.org/). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Kebanyakan linter terintegrasi dengan banyak editor populer: cuma mengaktifkan plugin di editor dan mengkonfigurasi gayanya. @@ -335,7 +339,11 @@ Berikut contoh file `.eslintrc`: Di sini directive `"extends"` menunjukkan bahwa konfigurasinya berdasarkan set pengaturan "eslint:recommended". Setelah itu, kita spesifikasikan punya kita sendiri. +<<<<<<< HEAD Selain itu, dimungkinkan juga mengunduh set aturan gaya dari web dan mengextend mereka. Lihat untuk detil lebih tentang instalasi. +======= +It is also possible to download style rule sets from the web and extend them instead. See for more details about installation. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Juga IDE tertentu punya linting built-in, yang nyaman tapi tak bisa dikustomisasi seperti ESLint. diff --git a/1-js/03-code-quality/03-comments/article.md b/1-js/03-code-quality/03-comments/article.md index 11f0027c8..499dbc1d5 100644 --- a/1-js/03-code-quality/03-comments/article.md +++ b/1-js/03-code-quality/03-comments/article.md @@ -143,7 +143,11 @@ Parameter dan kegunaan fungsi dokumen Oya, banyak editor seperti [WebStorm](https://www.jetbrains.com/webstorm/) bisa memahami mereka juga dan memakai mereka untuk menyediakan autocomplete dan beberapa pengecekan-kode otomatis. +<<<<<<< HEAD Juga, Ada tool seperti [JSDoc 3](https://github.com/jsdoc3/jsdoc) yang bisa menggenerate dokumentasi-HTML dari komentar. Kamu bisa baca informasi lebih tentang JSDoc di . +======= +Also, there are tools like [JSDoc 3](https://github.com/jsdoc/jsdoc) that can generate HTML-documentation from the comments. You can read more information about JSDoc at . +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Kenapa tugas ini diselesaikan begini? : Apa yang tertulis itu penting. Tapi apa yang *tak* tertilis mungkin lebih penting lagi untuk memahami yang terjadi. Kenapa tugas ini diselesaikan tepat seperti ini? Kodenya tak memberikan jawaban. diff --git a/1-js/03-code-quality/05-testing-mocha/article.md b/1-js/03-code-quality/05-testing-mocha/article.md index ba58d4078..d0908e70e 100644 --- a/1-js/03-code-quality/05-testing-mocha/article.md +++ b/1-js/03-code-quality/05-testing-mocha/article.md @@ -48,7 +48,12 @@ describe("pow", function () { Spek punya tiga blok bangunan utama yang bisa kamu lihat di bawah: +<<<<<<< HEAD `describe("title", function() { ... })` : Fungsionalitas apa yang kita jelaskan. Di kasus ini kita akan menjelaskan fungsi `pow`. Dipakai untuk mengelompokkan "pekerja" -- blok `it`. +======= +`describe("title", function() { ... })` +: What functionality we're describing? In our case we're describing the function `pow`. Used to group "workers" -- the `it` blocks. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 `it("use case description", function() { ... })` : Di judul `it` kita _dalam bahasa manusia_ menjelaskan use case tertentu, dan argumen kedua ialah fungsi yang mengetes itu. @@ -62,6 +67,7 @@ Spesifikasi ini bisa diexekusi, dan ia akan menjalankan tes yang dispesifikasi d Alur pengembangan biasanya seperti ini: +<<<<<<< HEAD 1. Spek inisial ditulis, dengan tes untuk kebanyakan fungsionalitas dasar. 2. Implementatsi inisial dibuat. 3. Untuk mengecek apakah ia bekerja, kita jalankan framework pengetesan [Mocha](http://mochajs.org/) (detil lebih segera) yang menjalankan spek. Saat fungsionalitas tak lengkap, galat ditampilkan. Kita buat koreksi hingga semuanya bekerja. @@ -69,20 +75,39 @@ Alur pengembangan biasanya seperti ini: 5. Kita tambah use case lain ke spek, mungkin belum didukung implementasinya. Tes mulai gagal. 6. Pergi ke 3, perbaharui implementasinya hingga tes tak memberikan galat. 7. Ulangi langkah 3-6 hingga fungsionalitasnya siap. +======= +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](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. +7. Repeat steps 3-6 till the functionality is ready. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Jadi, pengembangannya _iteratif_. Kita tulis spek, implementasikan, memastikan tes lulus, lalu menulis tes lainnya, memastikan mereka bekerja dll. Akhirnya kita punya implementasi yang bekerja dan tes untuk itu. Ayo lihat alur pengembangan ini di kasus praktik kita. +<<<<<<< HEAD Langkap pertama sudah lengkap: kita punya spek inisial untuk `pow`. Sekarang, sebelum membuat implementasinya, ayo pakai beberapa librari JavaScript untuk menjalankan tes, hanya untuk melihat mereka bekerja (mereka semua akan gagal). +======= +The first step is already complete: we have an initial spec for `pow`. Now, before making the implementation, let's use a few JavaScript libraries to run the tests, just to see that they are working (they will all fail). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Spec dalam aksi Di sini di tutorial ini kita akan memakai librari JavaScript untuk tes: +<<<<<<< HEAD - [Mocha](http://mochajs.org/) -- inti framework: menyediakan fungsi testing umum `describe` dan `it` dan fungsi utama yang menjalankan test. - [Chai](http://chaijs.com) -- librari dengan banyak penambahan. Ini membuatmu bisa untuk menggunakan banyak penambahan yang berbeda, untuk sekarang kita hanya membutuhkan `assert.equal`. - [Sinon](http://sinonjs.org/) -- sebuah librari untuk memata-matai fungsi, meniru fungsi bawaan dan lainnya, kita akan butuh ini nanti. +======= +- [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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Librari ini cocok baik untuk pengetesan in-browser dan server-side. Di sini kita akan mempertimbangkan varian peramban. @@ -329,6 +354,7 @@ Tes yang baru ditambahkan gagal, karena implementasi kita tak mendukung mereka. ```smart header="Assersi lain" Tolong catat assersi `assert.isNaN`: ia melakukan ecek terhadap `NaN`. +<<<<<<< HEAD Ada assersi lain di [Chai](http://chaijs.com) juga, misalnya: - `assert.equal(value1, value2)` -- mengecek ekualitas `value1 == value2`. @@ -337,6 +363,16 @@ Ada assersi lain di [Chai](http://chaijs.com) juga, misalnya: - `assert.isTrue(value)` -- mengecek apa `value === true` - `assert.isFalse(value)` -- mengecek apa `value === false` - ...daftar lengkapnya ada di [docs](http://chaijs.com/api/assert/) +======= +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](https://www.chaijs.com/api/assert/) +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` Jadi kita harus tambah beberapa baris `pow`: diff --git a/1-js/03-code-quality/06-polyfills/article.md b/1-js/03-code-quality/06-polyfills/article.md index 88074673d..d57d1ce85 100644 --- a/1-js/03-code-quality/06-polyfills/article.md +++ b/1-js/03-code-quality/06-polyfills/article.md @@ -2,13 +2,23 @@ JavaScript secara konsisten terus berevolusi. Proposal-proposal untuk menambah fitur-fitur baru terus bermunculan. Proposal-proposal ini akan didaftarkan pada jika memang berpotensi dan layak untuk ditambahkan dalam standard dalam bahasa pemrograman JavaScript. Kemudian proposal-proposal yang telah diterima akan dimasukkan dalam [daftar spesifikasi](http://www.ecma-international.org/publications/standards/Ecma-262.htm) JavaScript. +<<<<<<< HEAD Tim yang mengurus JavaScript mengerti dan akan mengusulkan mana dari proposal-proposal ini yang akan diimplementasikan terlebih dahulu. Tim ini boleh saja nanti memasukkan proposal-proposal ini kedalam kategori 'draft / dalam perancangan' atau 'postpone / tunda' karena mungkin menurut mereka proposal-proposal ini menarik untuk didiskusikan lebih dalam atau sulit untuk direalisasikan. +======= +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 and then progress to the [specification](https://www.ecma-international.org/publications-and-standards/standards/ecma-262/). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Sangat wajar jika kebanyakan dari browser-browser yang ada hanya mengimplementasikan bagian-bagian yang tidak terlalu sulit. +<<<<<<< HEAD Sebuah halaman yang bagus untuk melihat kondisi terkini dari fitur yang didukung oleh bahasa ini ialah (isinya banyak, kita masih banyak yang belum dipelajari) Sebagai programmer, kita suka untuk menggunakan fitur yang terbaru. lebih banyak fitur bagus - lebih baik lagi! +======= +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 (it's big, we have a lot to study yet). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 di sisi lain, bagaimana membuat kodingan modern bekerja di mesin yang lama yang tidak mengetahui fitur-fitur terbaru ? @@ -21,7 +31,11 @@ di chapter ini, tujuan kita adalah untuk mendapatkan intisari cara kerjanya, dan ## Transpilers +<<<<<<< HEAD Sebuah [transpiler](https://en.wikipedia.org/wiki/Source-to-source_compiler) adalah perangkat lunak khusus yang dapat mengurai ("membaca dan memahami") kode modern, dan menulis ulang menggunakan konstruksi sintaks yang lebih lama, sehingga hasilnya akan sama. +======= +A [transpiler](https://en.wikipedia.org/wiki/Source-to-source_compiler) is a special piece of software that translates source code to another source code. It can parse ("read and understand") modern code and rewrite it using older syntax constructs, so that it'll also work in outdated engines. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Misalnya. JavaScript sebelum tahun 2020 tidak memiliki "nullish coalescing operator" `??`. Jadi, jika pengunjung menggunakan browser yang sudah ketinggalan zaman, ia mungkin gagal memahami kode seperti `height = height ?? 100` @@ -39,9 +53,15 @@ Sekarang kode yang ditulis ulang cocok untuk mesin JavaScript lama. Biasanya, pengembang menjalankan transpiler di komputer mereka sendiri, dan kemudian menyebarkan kode yang ditranspilasi ke server. +<<<<<<< HEAD Berbicara tentang nama, [Babel](https://babeljs.io) adalah salah satu transpiler paling terkenal di luar sana. Sistem pembangunan proyek modern, seperti [webpack](http://webpack.github.io/), menyediakan sarana untuk menjalankan transpiler secara otomatis pada setiap perubahan kode, sehingga sangat mudah untuk diintegrasikan ke dalam proses pengembangan. +======= +Speaking of names, [Babel](https://babeljs.io) is one of the most prominent transpilers out there. + +Modern project build systems, such as [webpack](https://webpack.js.org/), provide a means to run a transpiler automatically on every code change, so it's very easy to integrate into the development process. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Polyfills @@ -68,17 +88,23 @@ if (!Math.trunc) { // kalo ga ada fungsi seperti ini } ``` +<<<<<<< HEAD JavaScript adalah bahasa yang sangat dinamis, skrip dapat menambah / memodifikasi fungsi apa pun, bahkan termasuk yang sudah ada di dalamnya. Dua library polyfill yang menarik adalah: - [core js](https://github.com/zloirock/core-js) yang mendukung banyak hal, memungkinkan untuk kita memasukkan hanya fitur yang dibutuhkan. - [polyfill.io](http://polyfill.io) layanan yang menyediakan skrip dengan polyfills, bergantung pada fitur dan browser pengguna. +======= +JavaScript is a highly dynamic language. Scripts may add/modify any function, even built-in ones. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 +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. ## Kesimpulan Di bab ini, kami ingin memotivasi Anda untuk mempelajari fitur bahasa modern dan bahkan "yang paling mutakhir", meskipun fitur tersebut belum didukung dengan baik oleh mesin JavaScript. +<<<<<<< HEAD Jangan lupa untuk menggunakan transpiler (jika menggunakan sintaks atau operator modern) dan polyfill (untuk menambahkan fungsi yang mungkin hilang). Dan mereka akan memastikan bahwa kodenya berfungsi. Misalnya, nanti saat Anda sudah terbiasa dengan JavaScript, Anda dapat menyiapkan sistem pembuatan kode berdasarkan [webpack](http://webpack.github.io/) dengan [babel-loader](https://github.com/babel/babel-loader). @@ -86,5 +112,16 @@ Misalnya, nanti saat Anda sudah terbiasa dengan JavaScript, Anda dapat menyiapka Sumber daya bagus yang menunjukkan status dukungan saat ini untuk berbagai fitur: - - untuk JavaScript murni. - - untuk fungsi terkait dengan browser. +======= +Just don't forget to use a transpiler (if using modern syntax or operators) and polyfills (to add functions that may be missing). They'll ensure that the code works. + +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: +- - for pure JavaScript. +- - 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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 P.S. Google Chrome biasanya paling mutakhir dengan fitur bahasa, coba saja jika demo tutorial gagal. Sebagian besar demo tutorial berfungsi dengan browser modern apa pun. \ No newline at end of file diff --git a/1-js/04-object-basics/01-object/article.md b/1-js/04-object-basics/01-object/article.md index e570cf995..c0371a23b 100644 --- a/1-js/04-object-basics/01-object/article.md +++ b/1-js/04-object-basics/01-object/article.md @@ -44,7 +44,11 @@ Hasil objek `user` bisa dibayangkan sebagai kabinet dengan dua file bertanda den ![user object](object-user.svg) +<<<<<<< HEAD Kita bisa tambah, hapus dan baca file darinya kapanpun. +======= +We can add, remove and read files from it at any time. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Nilai properti bisa diakses memakai notasi dot: @@ -62,7 +66,11 @@ user.isAdmin = true; ![user object 2](object-user-isadmin.svg) +<<<<<<< HEAD Untuk menghapus properti, kita bisa pakai operator `delete`: +======= +To remove a property, we can use the `delete` operator: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js delete user.age; @@ -201,13 +209,21 @@ let bag = { }; ``` +<<<<<<< HEAD Bracket kotak jauh lebih kuat dari notasi dot. Mereka membolehkan variabel dan nama properti apapun. Tapi mereka juga lebih rumit untuk ditulis. +======= +Square brackets are much more powerful than dot notation. They allow any property names and variables. But they are also more cumbersome to write. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Jadi seringnya, saat nama properti diketahui dan simpel, dot dipakai. Dan jika kita butuh sesuatu yang rumit, maka kita ganti ke bracket kotak. ## Singkatan nilai properti +<<<<<<< HEAD Di kode riil kita sering memakai variabel sebagai nilai untuk nama properti. +======= +In real code, we often use existing variables as values for property names. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Misalnya: @@ -252,7 +268,11 @@ let user = { ## Batasan nama properti +<<<<<<< HEAD Seperti yang sudah kita tahu, sebuah variabel tidak bisa memiliki nama yang sama dengan salah satu "kata yang telah dimiliki bahasa pemrograman" seperti "for", "let", "return" dan lainnya. +======= +As we already know, a variable cannot have a name equal to one of the language-reserved words like "for", "let", "return" etc. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Tapi dari sebuah properti objek, tidak ada batasan seperti itu: @@ -325,7 +345,11 @@ alert( "blabla" in user ); // false, user.blabla tak ada Tolong ingat bahwa di sebelah kiri `in` harus ada *nama properti*. Itu biasanya string yang dikuotasi. +<<<<<<< HEAD Jika kita menghilangkan kutipnya, berarti sebuah variabel, itu haruslah mengandung nama yang akan dites. Contoh: +======= +If we omit quotes, that means a variable should contain the actual name to be tested. For instance: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let user = { age: 30 }; @@ -357,7 +381,11 @@ Di contoh kode di atas, properti `obj.test` ada secara teknis. Tapi operator `in Situasi seperti ini jarang terjadi, karena `undefined` biasanya tak ditetapkan. Kita sering memakai `null` untuk nilai "unknown" atau "empty". Jadi operator `in` merupakan tamu exotik dalam kode. ```` +<<<<<<< HEAD ## "for..in" +======= +## The "for..in" loop [#forin] +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Untuk mengitari semua kunci objek, ada bentuk spesial dari loop: `for..in`. Ini sangat berbeda dari konstruksi `for(;;)` yang kita pelajari sebelumnya. @@ -415,7 +443,11 @@ for (let code in codes) { */!* ``` +<<<<<<< HEAD Objek ini digunakan untuk mensugesti daftar opsi ke pengguna. Jika kita membuat situs khusus untuk audiensi Jerman maka kita kemungkinan mau `49` jadi yang pertama. +======= +The object may be used to suggest a list of options to the user. If we're making a site mainly for a German audience then we probably want `49` to be the first. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Tapi jika kita menjalankan kodenya, kita lihat potret yang berbeda: @@ -427,9 +459,14 @@ Kode telpon berurut secara ascending, karena mereka integer. Jadi kita lihat `1, ````smart header="Properti integer? Apa itu?" Istilah "properti integer" di sini artinya string yang bisa dikonversi ke-dan-dari integer tanpa perubahan. +<<<<<<< HEAD Jadi, "49" nama properti integer, karena mereka ditransform ke angka integer dan kebalikannya, ia masih sama saja. Tapi "+49" dan "1.2" tidak: +======= +So, `"49"` is an integer property name, because when it's transformed to an integer number and back, it's still the same. But `"+49"` and `"1.2"` are not: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run +// Number(...) explicitly converts to a number // Math.trunc is a built-in function that removes the decimal part alert( String(Math.trunc(Number("49"))) ); // "49", sama, properti integer alert( String(Math.trunc(Number("+49"))) ); // "49", tidak sama "+49" ⇒ bukan properti integer @@ -482,9 +519,15 @@ Objek menyimpan properti (pasangan key-value), dimana: - kunci/key properti haruslah sebuah string atau simbol (biasanya string). - Nilai bisa tipe apapun. +<<<<<<< HEAD Untuk mengakses properti, kita bisa gunakan: - Notasi dot: `obj.properti`. - Notasi kurung siku `obj["properti"]`. Kurung siku memperbolehkan mengambil key dari sebuah variabel, seperti `obj[varDenganKey]`. +======= +To access a property, we can use: +- The dot notation: `obj.property`. +- Square brackets notation `obj["property"]`. Square brackets allow taking the key from a variable, like `obj[varWithKey]`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Operator tambahan: - Untuk menghapus properti: `delete obj.prop`. diff --git a/1-js/04-object-basics/02-object-copy/article.md b/1-js/04-object-basics/02-object-copy/article.md index 13918ab93..ad1b520ca 100644 --- a/1-js/04-object-basics/02-object-copy/article.md +++ b/1-js/04-object-basics/02-object-copy/article.md @@ -37,7 +37,11 @@ Dan ini bagaimana kita menyimpannya di dalam memory: Objek disimpan di suatu tempat di memori (di sebelah kanan gambar), sedangkan variabel `user` (di sebelah kiri) memiliki" referensi "padanya. +<<<<<<< HEAD Kita mungkin menganggap variabel objek, seperti `pengguna`, seperti selembar kertas dengan alamat objek di atasnya. +======= +We may think of an object variable, such as `user`, like a sheet of paper with the address of the object on it. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Saat kita melakukan tindakan dengan objek, misalnya: mengambil properti `user.name`, mesin JavaScript melihat apa yang ada di alamat itu dan melakukan operasi pada objek sebenarnya. @@ -103,6 +107,7 @@ alert( a == b ); // false Untuk perbandingan seperti `obj1 > obj2` atau untuk perbandingan dengan sebuah nilai primitif `obj == 5`, objek akan diubah dahulu menjadi primitif. Kita akan belajar bagaimana perubahan objek sebentar lagi, akan tetapi sebenarnya, perbandingan seperti itu muncul sangat jarang, biasanya hanya sebuah hasil dari kesalahan koding. +<<<<<<< HEAD ## Penggandaan dan penggabungan, Object.assign [#cloning-and-merging-object-assign] Jadi, menyalin sebuah variabel objek akan menciptakan satu lagi referensi kepada objek yang sama. @@ -237,6 +242,8 @@ Untuk membenarkan hal itu, kita harus menggunakan perulangan kloning yang memeri We can use recursion to implement it. Or, to not reinvent the wheel, take an existing implementation, for instance [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) from the JavaScript library [lodash](https://lodash.com). +======= +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ````smart header="Const objects can be modified" An important side effect of storing objects as references is that an object declared as `const` *can* be modified. @@ -261,6 +268,202 @@ Dengan kata lain, `const user` memberikan kesalahan hanya jika kita mencoba meny yang berarti, jika kita benar-benar perlu membuat properti objek konstan, itu juga mungkin, tetapi menggunakan metode yang sama sekali berbeda. Kita akan membahasnya di bab . ```` +<<<<<<< HEAD +======= +## Cloning and merging, Object.assign [#cloning-and-merging-object-assign] + +So, copying an object variable creates one more reference to the same object. + +But what if we need to duplicate an object? + +We can create a new object and replicate the structure of the existing one, by iterating over its properties and copying them on the primitive level. + +Like this: + +```js run +let user = { + name: "John", + age: 30 +}; + +*!* +let clone = {}; // the new empty object + +// let's copy all user properties into it +for (let key in user) { + clone[key] = user[key]; +} +*/!* + +// now clone is a fully independent object with the same content +clone.name = "Pete"; // changed the data in it + +alert( user.name ); // still John in the original object +``` + +We can also use the method [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign). + +The syntax is: + +```js +Object.assign(dest, ...sources) +``` + +- The first argument `dest` is a target object. +- Further arguments is a list of source objects. + +It copies the properties of all source objects into the target `dest`, and then returns it as the result. + +For example, we have `user` object, let's add a couple of permissions to it: + +```js run +let user = { name: "John" }; + +let permissions1 = { canView: true }; +let permissions2 = { canEdit: true }; + +*!* +// copies all properties from permissions1 and permissions2 into user +Object.assign(user, permissions1, permissions2); +*/!* + +// now user = { name: "John", canView: true, canEdit: true } +alert(user.name); // John +alert(user.canView); // true +alert(user.canEdit); // true +``` + +If the copied property name already exists, it gets overwritten: + +```js run +let user = { name: "John" }; + +Object.assign(user, { name: "Pete" }); + +alert(user.name); // now user = { name: "Pete" } +``` + +We also can use `Object.assign` to perform a simple object cloning: + +```js run +let user = { + name: "John", + age: 30 +}; + +*!* +let clone = Object.assign({}, user); +*/!* + +alert(clone.name); // John +alert(clone.age); // 30 +``` + +Here it copies all properties of `user` into the empty object and returns it. + +There are also other methods of cloning an object, e.g. using the [spread syntax](info:rest-parameters-spread) `clone = {...user}`, covered later in the tutorial. + +## Nested cloning + +Until now we assumed that all properties of `user` are primitive. But properties can be references to other objects. + +Like this: +```js run +let user = { + name: "John", + sizes: { + height: 182, + width: 50 + } +}; + +alert( user.sizes.height ); // 182 +``` + +Now it's not enough to copy `clone.sizes = user.sizes`, because `user.sizes` is an object, and will be copied by reference, so `clone` and `user` will share the same sizes: + +```js run +let user = { + name: "John", + sizes: { + height: 182, + width: 50 + } +}; + +let clone = Object.assign({}, user); + +alert( user.sizes === clone.sizes ); // true, same object + +// user and clone share sizes +user.sizes.width = 60; // change a property from one place +alert(clone.sizes.width); // 60, get the result from the other one +``` + +To fix that and make `user` and `clone` truly separate objects, we should use a cloning loop that examines each value of `user[key]` and, if it's an object, then replicate its structure as well. That is called a "deep cloning" or "structured cloning". There's [structuredClone](https://developer.mozilla.org/en-US/docs/Web/API/structuredClone) method that implements deep cloning. + + +### structuredClone + +The call `structuredClone(object)` clones the `object` with all nested properties. + +Here's how we can use it in our example: + +```js run +let user = { + name: "John", + sizes: { + height: 182, + width: 50 + } +}; + +*!* +let clone = structuredClone(user); +*/!* + +alert( user.sizes === clone.sizes ); // false, different objects + +// user and clone are totally unrelated now +user.sizes.width = 60; // change a property from one place +alert(clone.sizes.width); // 50, not related +``` + +The `structuredClone` method can clone most data types, such as objects, arrays, primitive values. + +It also supports circular references, when an object property references the object itself (directly or via a chain or references). + +For instance: + +```js run +let user = {}; +// let's create a circular reference: +// user.me references the user itself +user.me = user; + +let clone = structuredClone(user); +alert(clone.me === clone); // true +``` + +As you can see, `clone.me` references the `clone`, not the `user`! So the circular reference was cloned correctly as well. + +Although, there are cases when `structuredClone` fails. + +For instance, when an object has a function property: + +```js run +// error +structuredClone({ + f: function() {} +}); +``` + +Function properties aren't supported. + +To handle such complex cases we may need to use a combination of cloning methods, write custom code or, to not reinvent the wheel, take an existing implementation, for instance [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) from the JavaScript library [lodash](https://lodash.com). + +## Summary +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Ringkasan @@ -273,3 +476,7 @@ Untuk membuat "salinan asli" (kloning) kita dapat menggunakan `Object.assign` un +<<<<<<< HEAD +======= +To make a "real copy" (a clone) we can use `Object.assign` for the so-called "shallow copy" (nested objects are copied by reference) or a "deep cloning" function `structuredClone` or use a custom cloning implementation, such as [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/1-js/04-object-basics/03-garbage-collection/article.md b/1-js/04-object-basics/03-garbage-collection/article.md index ab5a46e6f..47bc99f39 100644 --- a/1-js/04-object-basics/03-garbage-collection/article.md +++ b/1-js/04-object-basics/03-garbage-collection/article.md @@ -74,7 +74,11 @@ Sekarang jika kita melakukan hal yang sama: user = null; ``` +<<<<<<< HEAD ...Maka objek "John" tersebut masih bisa dijangkau lewat variabel global `admin`, jadi masih ada di memori. Jika kita menimpa `admin` juga, barulah dapat dihilangkan. +======= +...Then the object is still reachable via `admin` global variable, so it must stay in memory. If we overwrite `admin` too, then it can be removed. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Objek-objek yang saling terkait @@ -169,11 +173,19 @@ Langkah pertama menandai _roots_-nya: ![](garbage-collection-2.svg) +<<<<<<< HEAD Kemudian rujukkannya ditandai: ![](garbage-collection-3.svg) ...Dan kemudian rujukkan dalamnya juga, jika masih ada: +======= +Then we follow their references and mark referenced objects: + +![](garbage-collection-3.svg) + +...And continue to follow further references, while possible: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ![](garbage-collection-4.svg) @@ -183,13 +195,23 @@ Sekarang objek-objek yang tak dapat dikunjungi selama proses berlangsung diangga Kita juga bisa membayangkan proses tersebut sebagai menumpahkan ember cat dari _roots_, yang mengalir ke semua rujukkan dan menandai semua objek yang terjangkau. Yang tidak tertandai akan dihapus. +<<<<<<< HEAD Itu merupakan konsep dari bagaimana cara kerja _garbage collection_. _Engines_ JavaScript menerapkan banyak optimisasi untuk membuatnya berjalan lebih cepat dan tanpa mempengaruhi eksekusi. +======= +That's the concept of how garbage collection works. JavaScript engines apply many optimizations to make it run faster and not introduce any delays into the code execution. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Beberapa optimisasi: +<<<<<<< HEAD - **Generational collection** -- objek-objek dibagi kedalam dua set: "yang baru" dan "yang lama". Kebanyakan objek muncul, melakukan tugasnya dan mati dengan cepat, mereka dapat dibersihkan secara agresif. Mereka yang bertahan cukup lama, akan menjadi "yang lama" dan tak akan sering diperiksa. - **Incremental collection** -- Jika terdapat banyak objek-objek, dan kita mencoba menapaki sambil menandai keseluruhan set objek sekaligus, itu dapat memakan waktu dan menimbulkan keterlambatan yang terlihat dalam eksekusi. Jadi _engine_ akan mencoba untuk memecah proses _garbage collection_ menjadi bagian-bagian kecil. Kemudian bagian-bagian kecil tersebut akan dieksekusi satu-persatu, secara terpisah. Itu memerlukan pencatatan ekstra diantara mereka untuk melacak perubahan, tetapi jadinya kta hanya mengalami keterlambatan kecil yang banyak daripada satuan yang besar. - **Idle-time collection** -- _garbage collector_ akan mencoba untuk jalan hanya ketika _CPU_ sedang _idle_, untuk mengurangi kemungkinan efek pada eksekusi. +======= +- **Generational collection** -- objects are split into two sets: "new ones" and "old ones". In typical code, many objects have a short life span: they appear, do their job and die fast, so it makes sense to track new objects and clear the memory from them if that's the case. Those that survive for long enough, become "old" and are examined less often. +- **Incremental collection** -- if there are many objects, and we try to walk and mark the whole object set at once, it may take some time and introduce visible delays in the execution. So the engine splits the whole set of existing objects into multiple parts. And then clear these parts one after another. There are many small garbage collections instead of a total one. That requires some extra bookkeeping between them to track changes, but we get many tiny delays instead of a big one. +- **Idle-time collection** -- the garbage collector tries to run only while the CPU is idle, to reduce the possible effect on the execution. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Terdapat optimisasi-optimisasi dan tipe-tipe lain dari algoritma _garbage collection_. Sebesar apapun keinginan untuk menjelaskannya disini, harus kutahan, karena _engines_ yang berbeda mengimplementasikan teknik dan _tweaks_ yang berbeda pula. Dan, yang lebih penting, hal-hal tersebut akan berubah seiring dengan pengembangan _engine_, jadi mempelajarinya lebih dalam "di awal", tanpa kebutuhan yang berarti mungkin akan sia-sia. Kecuali, tentu saja, jika itu merupakan murni masalah ketertarikan, maka ada beberapa tautan untukmu dibawah. @@ -197,16 +219,30 @@ Terdapat optimisasi-optimisasi dan tipe-tipe lain dari algoritma _garbage collec Hal utama yang perlu diketahui: +<<<<<<< HEAD - Pengumpulan sampah (_Garbage collection_) dilakukan secara otomatis. Kita tidak bisa memaksa ataupun mencegahnya. - Objek-objek dipertahankan dalam memori selagi mereka terjangkau (_reachable_). - Menjadi yang dirujuk tidak sama dengan menjadi terjangkau (dari sebuah _root_): sekumpulan objek yang saling terkait dapat menjadi tak terjangkau sebagai keseluruhan. +======= +- Garbage collection is performed automatically. We cannot force or prevent it. +- Objects are retained in memory while they are reachable. +- Being referenced is not the same as being reachable (from a root): a pack of interlinked objects can become unreachable as a whole, as we've seen in the example above. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 _Engine_ modern mengimplementasikan algoritma _garbage collection_ canggih (_advance_). Buku "The Garbage Collection Handbook: The Art of Automatic Memory Management" (R. Jones et al) mencakup beberapanya. +<<<<<<< HEAD Jika kamu familiar dengan pemrograman _low-level_, informasi mendalam tentang _garbage collector_ V8 terdapat pada artikel [A tour of V8: Garbage Collection](http://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection). [V8 blog](https://v8.dev/) juga mempublikasikan artikel-artikel tentang ubahan-ubahan dalam manajemen memori dari waktu ke waktu. Tentu saja, untuk belajar proses _garbage collection_, kamu lebih baik mempersiapkan diri dengan belajar tentang _internals_ V8 secara umum dan membaca blog [Vyacheslav Egorov](http://mrale.ph) yang merupakan salah seorang _engineer_ V8. Saya bilang: "V8", karena merupakan yang paling komprehensif di _cover_ oleh artikel-artikel di internet. Untuk _engine_ lainnya, pendekatannya kebanyakan mirip-mirip, tetapi _garbage collection_ berbeda dalam banyak aspek. Pengetahuan mendalam mengenai _engines_ itu bagus ketika membutuhkan optimisasi _low-level_. Tapi akan lebih bijak untuk merencanakan itu sebagai langkah selanjutnya setelah kamu akrab dengan bahasanya (JavaScript). +======= +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](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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/1-js/04-object-basics/04-object-methods/7-calculator/task.md b/1-js/04-object-basics/04-object-methods/7-calculator/task.md index 9ac8ad785..e742e18c0 100644 --- a/1-js/04-object-basics/04-object-methods/7-calculator/task.md +++ b/1-js/04-object-basics/04-object-methods/7-calculator/task.md @@ -6,9 +6,15 @@ importance: 5 Buatlah sebuah objek `calculator` dengan tiga metode: +<<<<<<< HEAD - `read()` mendorong kedua nilai dan menyimpan nilai-nilai tersebut sebagai properti objek. - `sum()` mengembalikan jumlah dari nilai-nilai yang disimpan. - `mul()` mengalikan nilai-nilai yang disimpan dan mengembalikan hasilnya. +======= +- `read()` prompts for two values and saves them as object properties with names `a` and `b` respectively. +- `sum()` returns the sum of saved values. +- `mul()` multiplies saved values and returns the result. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js let calculator = { @@ -21,4 +27,3 @@ alert( calculator.mul() ); ``` [demo] - diff --git a/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/solution.js b/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/solution.js index e98fe6410..a35c009cc 100644 --- a/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/solution.js +++ b/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/solution.js @@ -11,5 +11,6 @@ let ladder = { }, showStep: function() { alert(this.step); + return this; } }; \ No newline at end of file diff --git a/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/test.js b/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/test.js index a2b17fcc4..b4f2459b7 100644 --- a/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/test.js +++ b/1-js/04-object-basics/04-object-methods/8-chain-calls/_js.view/test.js @@ -32,6 +32,14 @@ describe('Ladder', function() { it('down().up().up().up() ', function() { assert.equal(ladder.down().up().up().up().step, 2); }); + + it('showStep() should return this', function() { + assert.equal(ladder.showStep(), ladder); + }); + + it('up().up().down().showStep().down().showStep()', function () { + assert.equal(ladder.up().up().down().showStep().down().showStep().step, 0) + }); after(function() { ladder.step = 0; diff --git a/1-js/04-object-basics/04-object-methods/8-chain-calls/solution.md b/1-js/04-object-basics/04-object-methods/8-chain-calls/solution.md index 14a735840..364c0006e 100644 --- a/1-js/04-object-basics/04-object-methods/8-chain-calls/solution.md +++ b/1-js/04-object-basics/04-object-methods/8-chain-calls/solution.md @@ -23,7 +23,7 @@ let ladder = { } }; -ladder.up().up().down().up().down().showStep(); // 1 +ladder.up().up().down().showStep().down().showStep(); // shows 1 then 0 ``` Kita juga bisa menuliskan sebuah panggilan di setiap baris. Untuk rantai kode yang panjang jadi lebih mudah dibaca seperti ini: @@ -33,7 +33,7 @@ ladder .up() .up() .down() - .up() + .showStep() // 1 .down() - .showStep(); // 1 + .showStep(); // 0 ``` diff --git a/1-js/04-object-basics/04-object-methods/8-chain-calls/task.md b/1-js/04-object-basics/04-object-methods/8-chain-calls/task.md index 305b6daf6..359f1bd49 100644 --- a/1-js/04-object-basics/04-object-methods/8-chain-calls/task.md +++ b/1-js/04-object-basics/04-object-methods/8-chain-calls/task.md @@ -4,7 +4,11 @@ importance: 2 # *Chaining* (merantaikan) +<<<<<<< HEAD Ada sebuah objek layaknya tangga (`ladder`) yang dapat naik dan turun: +======= +There's a `ladder` object that allows you to go up and down: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js let ladder = { @@ -21,19 +25,33 @@ let ladder = { }; ``` +<<<<<<< HEAD Kini, jika kita perlu untuk membuat beberapa panggilan secara berurutan, bisa dilakukan dengan cara seperti ini: +======= +Now, if we need to make several calls in sequence, we can do it like this: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js ladder.up(); ladder.up(); ladder.down(); ladder.showStep(); // 1 +ladder.down(); +ladder.showStep(); // 0 ``` +<<<<<<< HEAD Modifikasi kode `up`, `down` dan `showStep` untuk membuat panggilan-panggilan tersebut dapat dirantaikan satu sama lain, seperti ini: +======= +Modify the code of `up`, `down`, and `showStep` to make the calls chainable, like this: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js -ladder.up().up().down().showStep(); // 1 +ladder.up().up().down().showStep().down().showStep(); // shows 1 then 0 ``` +<<<<<<< HEAD Pendekatan demikian digunakan secara luas di banyak *library* JavaScript. +======= +Such an approach is widely used across JavaScript libraries. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/1-js/04-object-basics/04-object-methods/article.md b/1-js/04-object-basics/04-object-methods/article.md index 7f0eef898..76ac22c4f 100644 --- a/1-js/04-object-basics/04-object-methods/article.md +++ b/1-js/04-object-basics/04-object-methods/article.md @@ -51,7 +51,7 @@ let user = { // pertama, deklarasi function sayHi() { alert("Hello!"); -}; +} // lalu tambbahkan sebagai sebuah metodes user.sayHi = sayHi; @@ -90,7 +90,11 @@ user = { Seperti yang didemonstrasikan, kita bisa mengabaikan `"function"` dan hanya menuliskan `sayHi()`. +<<<<<<< HEAD Sebenarnya, notasi-notasi tersebut tidak sepenuhnya sama. Ada beberapa perbedaan kecil yang berhubungan dengan *object inheritance* atau pewarisan objek (akan dibahas nanti), tetapi untuk sekarang hal-hal tersebut tidak terlalu penting. Dalam hampir kebanyakan kasus sintaks ringkas lebih disukai. +======= +To tell the truth, the notations are not fully identical. There are subtle differences related to object inheritance (to be covered later), but for now they do not matter. In almost all cases, the shorter syntax is preferred. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## "this" dalam metode diff --git a/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md b/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md index c6d8318fd..0c0df9577 100644 --- a/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md +++ b/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/task.md @@ -4,14 +4,18 @@ importance: 2 # Dua fungsi – satu objek +<<<<<<< HEAD Apakah mungkin untuk membuat fungsi `A` dan fungsi `B` seperti `new A()==new B()`? +======= +Is it possible to create functions `A` and `B` so that `new A() == new B()`? +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js no-beautify function A() { ... } function B() { ... } -let a = new A; -let b = new B; +let a = new A(); +let b = new B(); alert( a == b ); // true ``` diff --git a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md index 043bddc01..d86eaa2d6 100644 --- a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md +++ b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/task.md @@ -6,9 +6,15 @@ importance: 5 Buatlah sebuah fungsi konstruktor `Calculator` yang membuat objek dengan 3 method: +<<<<<<< HEAD - `read()` tanyakan dua nilai menggunakan `prompt dan masukan mereka kedalam properti objek. - `sum()` mengembalikan jumlah dari properti-properti. - `mul()` mengembalikan perkalian produk dari properti-properti. +======= +- `read()` prompts for two values and saves them as object properties with names `a` and `b` respectively. +- `sum()` returns the sum of these properties. +- `mul()` returns the multiplication product of these properties. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Contoh: diff --git a/1-js/04-object-basics/06-constructor-new/article.md b/1-js/04-object-basics/06-constructor-new/article.md index 8580997c6..74c05aa87 100644 --- a/1-js/04-object-basics/06-constructor-new/article.md +++ b/1-js/04-object-basics/06-constructor-new/article.md @@ -1,6 +1,10 @@ # Konstruktor, operator "new" +<<<<<<< HEAD Sintaks reguler `{...}` memungkinkan kita untuk membuat satu objek. Tapi seringkali kita perlu untuk membuat banyak objek-objek serupa, seperti pengguna atau *item* menu berganda dan sebagainya. +======= +The regular `{...}` syntax allows us to create one object. But often we need to create many similar objects, like multiple users or menu items and so on. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Hal tersebut dapat diselesaikan dengan menggunakan fungsi konstruktor dan operator `"new"`. @@ -170,8 +174,13 @@ alert( new SmallUser().name ); // John Biasanya konstruktor tidak memiliki sebuah pernyataan `return`. Di sini kita menyebutkan perilaku khusus dengan cara mengembalikan objek dengan tujuan utamanya yakni hanya untuk melengkapi saja. +<<<<<<< HEAD ````smart header="Mengabaikan parentheses" Omong-omong, kita bisa mengabaikan parentheses setelah `new`, jika tidak memiliki argumen: +======= +````smart header="Omitting parentheses" +By the way, we can omit parentheses after `new`: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js let user = new User; // <-- tanpa parentheses diff --git a/1-js/04-object-basics/07-optional-chaining/article.md b/1-js/04-object-basics/07-optional-chaining/article.md index 7a0a0ff23..14afa1f39 100644 --- a/1-js/04-object-basics/07-optional-chaining/article.md +++ b/1-js/04-object-basics/07-optional-chaining/article.md @@ -25,14 +25,14 @@ That's the expected result. JavaScript works like this. As `user.address` is `un In many practical cases we'd prefer to get `undefined` instead of an error here (meaning "no street"). -...And another example. In the web development, we can get an object that corresponds to a web page element using a special method call, such as `document.querySelector('.elem')`, and it returns `null` when there's no such element. +...and another example. In Web development, we can get an object that corresponds to a web page element using a special method call, such as `document.querySelector('.elem')`, and it returns `null` when there's no such element. ```js run // document.querySelector('.elem') is null if there's no element let html = document.querySelector('.elem').innerHTML; // error if it's null ``` -Once again, if the element doesn't exist, we'll get an error accessing `.innerHTML` of `null`. And in some cases, when the absence of the element is normal, we'd like to avoid the error and just accept `html = null` as the result. +Once again, if the element doesn't exist, we'll get an error accessing `.innerHTML` property of `null`. And in some cases, when the absence of the element is normal, we'd like to avoid the error and just accept `html = null` as the result. How can we do this? @@ -44,11 +44,19 @@ let user = {}; alert(user.address ? user.address.street : undefined); ``` -It works, there's no error... But it's quite inelegant. As you can see, the `"user.address"` appears twice in the code. For more deeply nested properties, that becomes a problem as more repetitions are required. +It works, there's no error... But it's quite inelegant. As you can see, the `"user.address"` appears twice in the code. -E.g. let's try getting `user.address.street.name`. +Here's how the same would look for `document.querySelector`: -We need to check both `user.address` and `user.address.street`: +```js run +let html = document.querySelector('.elem') ? document.querySelector('.elem').innerHTML : null; +``` + +We can see that the element search `document.querySelector('.elem')` is actually called twice here. Not good. + +For more deeply nested properties, it becomes even uglier, as more repetitions are required. + +E.g. let's get `user.address.street.name` in a similar fashion. ```js let user = {}; // user has no address @@ -58,7 +66,7 @@ alert(user.address ? user.address.street ? user.address.street.name : null : nul That's just awful, one may even have problems understanding such code. -Don't even care to, as there's a better way to write it, using the `&&` operator: +There's a little better way to write it, using the `&&` operator: ```js run let user = {}; // user has no address @@ -92,6 +100,12 @@ alert( user?.address?.street ); // undefined (no error) The code is short and clean, there's no duplication at all. +Here's an example with `document.querySelector`: + +```js run +let html = document.querySelector('.elem')?.innerHTML; // will be undefined, if there's no element +``` + Reading the address with `user?.address` works even if `user` object doesn't exist: ```js run @@ -108,9 +122,9 @@ E.g. in `user?.address.street.name` the `?.` allows `user` to safely be `null/un ```warn header="Don't overuse the optional chaining" We should use `?.` only where it's ok that something doesn't exist. -For example, if according to our coding logic `user` object must exist, but `address` is optional, then we should write `user.address?.street`, but not `user?.address?.street`. +For example, if according to our code logic `user` object must exist, but `address` is optional, then we should write `user.address?.street`, but not `user?.address?.street`. -So, if `user` happens to be undefined due to a mistake, we'll see a programming error about it and fix it. Otherwise, coding errors can be silenced where not appropriate, and become more difficult to debug. +Then, if `user` happens to be undefined, we'll see a programming error about it and fix it. Otherwise, if we overuse `?.`, coding errors can be silenced where not appropriate, and become more difficult to debug. ``` ````warn header="The variable before `?.` must be declared" @@ -127,7 +141,7 @@ The variable must be declared (e.g. `let/const/var user` or as a function parame As it was said before, the `?.` immediately stops ("short-circuits") the evaluation if the left part doesn't exist. -So, if there are any further function calls or side effects, they don't occur. +So, if there are any further function calls or operations to the right of `?.`, they won't be made. For instance: @@ -135,7 +149,7 @@ For instance: let user = null; let x = 0; -user?.sayHi(x++); // no "sayHi", so the execution doesn't reach x++ +user?.sayHi(x++); // no "user", so the execution doesn't reach sayHi call and x++ alert(x); // 0, value not incremented ``` @@ -162,13 +176,13 @@ userAdmin.admin?.(); // I am admin */!* *!* -userGuest.admin?.(); // nothing (no such method) +userGuest.admin?.(); // nothing happens (no such method) */!* ``` -Here, in both lines we first use the dot (`userAdmin.admin`) to get `admin` property, because we assume that the user object exists, so it's safe read from it. +Here, in both lines we first use the dot (`userAdmin.admin`) to get `admin` property, because we assume that the `user` object exists, so it's safe read from it. -Then `?.()` checks the left part: if the admin function exists, then it runs (that's so for `userAdmin`). Otherwise (for `userGuest`) the evaluation stops without errors. +Then `?.()` checks the left part: if the `admin` function exists, then it runs (that's so for `userAdmin`). Otherwise (for `userGuest`) the evaluation stops without errors. The `?.[]` syntax also works, if we'd like to use brackets `[]` to access properties instead of dot `.`. Similar to previous cases, it allows to safely read a property from an object that may not exist. @@ -179,7 +193,7 @@ let user1 = { firstName: "John" }; -let user2 = null; +let user2 = null; alert( user1?.[key] ); // John alert( user2?.[key] ); // undefined @@ -192,17 +206,16 @@ delete user?.name; // delete user.name if user exists ``` ````warn header="We can use `?.` for safe reading and deleting, but not writing" -The optional chaining `?.` has no use at the left side of an assignment. +The optional chaining `?.` has no use on the left side of an assignment. For example: ```js run let user = null; user?.name = "John"; // Error, doesn't work -// because it evaluates to undefined = "John" +// because it evaluates to: undefined = "John" ``` -It's just not that smart. ```` ## Summary @@ -217,4 +230,8 @@ As we can see, all of them are straightforward and simple to use. The `?.` check A chain of `?.` allows to safely access nested properties. -Still, we should apply `?.` carefully, only where it's acceptable that the left part doesn't exist. So that it won't hide programming errors from us, if they occur. \ No newline at end of file +<<<<<<< HEAD +Still, we should apply `?.` carefully, only where it's acceptable that the left part doesn't exist. So that it won't hide programming errors from us, if they occur. +======= +Still, we should apply `?.` carefully, only where it's acceptable, according to our code logic, that the left part doesn't exist. So that it won't hide programming errors from us, if they occur. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/1-js/04-object-basics/08-symbol/article.md b/1-js/04-object-basics/08-symbol/article.md index 1f42cb775..ac2bf7359 100644 --- a/1-js/04-object-basics/08-symbol/article.md +++ b/1-js/04-object-basics/08-symbol/article.md @@ -1,9 +1,22 @@ # Tipe simbol +<<<<<<< HEAD Menurut spesifikasi spesifikasi, properti-properti kunci objek bisa saja bertipe *string*, atau bertipe simbol. Bukan angka (*number*), bukan *boolean*, hanya *string* atau simbol-simbol, kedua tipe ini. Hingga kini kita telah menggunakan *string* saja. Mari kita lihat keuntungan-keuntungan apa saja dari simbol yang bisa diberikan ke kita. +======= +By specification, only two primitive types may serve as object property keys: + +- string type, or +- symbol type. + +Otherwise, if one uses another type, such as number, it's autoconverted to string. So that `obj[1]` is the same as `obj["1"]`, and `obj[true]` is the same as `obj["true"]`. + +Until now we've been using only strings. + +Now let's explore symbols, see what they can do for us. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Simbol-simbol @@ -12,18 +25,29 @@ Sebuah "simbol" merepresentasikan sebuah pengidentifikasi yang unik. Nilai dari tipe ini dapat dibuat menggunakan `Symbol()`: ```js +<<<<<<< HEAD // id adalah sebuah simbol baru let id = Symbol(); ``` Selama penyusunan, kita bisa memberikan simbol sebuah deskripsi (juga disebut sebagai nama simbol), kebanyakan berguna untuk tujuan-tujuan *debugging*: +======= +let id = Symbol(); +``` + +Upon creation, we can give symbols a description (also called a symbol name), mostly useful for debugging purposes: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js // id adalah simbol dengan deskripsi "id" let id = Symbol("id"); ``` +<<<<<<< HEAD Simbol-simbol sudah pasti unik. Bahkan jika kita membuat banyak simbol dengan deskripsi yang, mereka memiliki nilai-nilai yang berbeda. Deskripsi hanyalah sebuah label yang tidak mempengaruhi apapun. +======= +Symbols are guaranteed to be unique. Even if we create many symbols with exactly the same description, they are different values. The description is just a label that doesn't affect anything. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Sebagai contoh, berikut ini ada dua simbol dengan deskripsi yang sama -- keduanya tidak sama: @@ -38,8 +62,15 @@ alert(id1 == id2); // false Jika kamu tidak asing dengan Ruby atau bahasa pemrograman lain yang juga memiliki hal seperti "simbol" -- tolong jangan sampai keliru. Simbol-simbol (di) JavaScript itu berbeda. +<<<<<<< HEAD ````warn header="Simbol-simbol tidak dikonversi otomatis menjadi string" Kebanyakan nilai-nilai dalam JavaScript mendukung konversi implisit menjadi sebuah string. Contohnya, kita bisa memberi `alert` pada hampir nilai apapun, dan masih akan berfungsi. Simbol itu istimewa. Mereka tidak terkonversi otomatis. +======= +So, to summarize, a symbol is a "primitive unique value" with an optional description. Let's see where we can use them. + +````warn header="Symbols don't auto-convert to a string" +Most values in JavaScript support implicit conversion to a string. For instance, we can `alert` almost any value, and it will work. Symbols are special. They don't auto-convert. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Sebagai contoh, `alert` ini akan memunculkan sebuah error: @@ -52,7 +83,12 @@ alert(id); // TypeError: Cannot convert a Symbol value to a string Hal tersebut adalah sebuah "garda bahasa pemrograman" untuk menghadapi adanya kekacauan, karena string dan simbol itu berbeda secara fundamental dan sudah seharusnya tidak akan terkonversi dari satu ke lainnya secara tidak sengaja. +<<<<<<< HEAD Jika kita benar-benar ingin menunjukkan sebuah simbol, kita perlu secara eskplisit memanggil `.toString()` sintaks tersebut, seperti berikut ini: +======= +If we really want to show a symbol, we need to explicitly call `.toString()` on it, like here: + +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let id = Symbol("id"); *!* @@ -60,7 +96,12 @@ alert(id.toString()); // Symbol(id), sekarang berfungsi */!* ``` +<<<<<<< HEAD Atau mengambil properti `symbol.description` untuk menunjuukan deskripsinya saja: +======= +Or get `symbol.description` property to show the description only: + +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let id = Symbol("id"); *!* @@ -72,7 +113,12 @@ alert(id.description); // id ## Properti "tersembunyi" (*hidden*) +<<<<<<< HEAD Simbol memungkinkan kita untuk membuat properti-properti yang "tersembunyi" (*hidden*) dari sebuah objek, yang mana tidak akan ada bagian lain dari kode yang bisa mengakses atau meng-*overwrite* tanpa sengaja. +======= + +Symbols allow us to create "hidden" properties of an object, that no other part of code can accidentally access or overwrite. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Sebagai contoh, jika kita bekerja dengan objek-objek `user`, yang dimiliki oleh sebuah kode pihak ketiga. Kita akan menambahkan pengidentifikasi pada objek-objek tersebut. @@ -92,9 +138,15 @@ alert( user[id] ); // kita bisa mengakses data menggunakan simbol sebagai kunci Apa keuntungan dari menggunakan `Symbol("id")` daripada sebuah *string* `"id"`? +<<<<<<< HEAD Sebagaimana objek-objek `user` adalah milik kode lain, dan kode itu juga berfungsi dengan objek-objek tadi, kita seharusnya tidak hanya menambahkan ruang apapun di situ. Hal tersebut tidak aman. Tetapi sebuah simbol tidak bisa diakses tanpa sengaja, kode pihak ketiga bahkan tidak akan melihatnya, jadi mungkin tidak masalah jika demikian. Juga, bayangkan *script* lain ingin memiliki pengidentifikasi sendiri dalam objek `user`, untuk tujuannya masing-masing. Hal tersebut bisa saja *library* JavaScript lainnya, jadi *script-script* tersebut benar-benar tidak menyadari satu sama lainnya. +======= +As `user` objects belong to another codebase, it's unsafe to add fields to them, since we might affect pre-defined behavior in that other codebase. However, symbols cannot be accessed accidentally. The third-party code won't be aware of newly defined symbols, so it's safe to add symbols to the `user` objects. + +Also, imagine that another script wants to have its own identifier inside `user`, for its own purposes. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Kemudian *script* tersebut bisa membuat `Symbol("id")`-nya sendiri, seperti berikut ini: @@ -157,11 +209,19 @@ let user = { for (let key in user) alert(key); // name, age (bukan simbol) */!* +<<<<<<< HEAD // akses langsung dengan simbol, berfungsi alert( "Direct: " + user[id] ); ``` `Object.keys(user)` juga mengabaikannya. Itu adalah bagian dari prinsip umum "menyembunyikan properti simbolis" (*hiding symbolic properties*). Jika *script* lain atau sebuah *library* melakukan pengulanagn pada objek kita, hal tersebut tidak akan mengakses sebuah properti simbolis tanpa diduga. +======= +// the direct access by the symbol works +alert( "Direct: " + user[id] ); // Direct: 123 +``` + +[Object.keys(user)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys) also ignores them. That's a part of the general "hiding symbolic properties" principle. If another script or a library loops over our object, it won't unexpectedly access a symbolic property. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Sebaliknya, [Object.assign](mdn:js/Object/assign) menyalin baik *string* properti maupun simbol properti: @@ -206,12 +266,20 @@ Simbol-simbol di dalam catatan (*registry*) disebut sebagai *simbol-simbol globa ```smart header="Simbol global itu seperti dalam Ruby" Dalam beberapa bahasa pemrograman, seperti Ruby, hanya ada satu simbol per nama. +<<<<<<< HEAD Dalam JavaScript, seperti yang bisa kita lihat, yakni simbol-simbol global. +======= +In JavaScript, as we can see, that's true for global symbols. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ### Symbol.keyFor +<<<<<<< HEAD Untuk simbol-simbol global, tidak hanya `Symbol.for(key)` yang mengembalikan sebuah simbol berdasarkan nama, tetapi ada sebuah panggilan sebaliknya: `Symbol.keyFor(sym)`, sintaks tersebut melakukan hal sebaliknya tadi: mengembalikan sebuah nama berdasarkan sebuah simbol global. +======= +We have seen that for global symbols, `Symbol.for(key)` returns a symbol by name. To do the opposite -- return a name by global symbol -- we can use: `Symbol.keyFor(sym)`: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Contohnya: @@ -227,7 +295,11 @@ alert( Symbol.keyFor(sym2) ); // id `Simbol.keyFor` secara internal menggunakan simbol registry global untuk mencari key/kunci dari simbolnya. Jadi itu tidak akan bekerja dengan simbol non-global. Jika simbolnya bukan global, itu tidak akan bisa menemukannya dan akan mengembalikan `undefined`. +<<<<<<< HEAD Seperti yang dikatakan, simbol apapun memiliki properti `description`. +======= +That said, all symbols have the `description` property. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Contohnya: @@ -267,11 +339,21 @@ Simbols selalu berbeda nilainya, bahkan jika mereka memiliki nama yang sama. Jik Simbol memiliki dua alasan utama pada pemakaiannya: +<<<<<<< HEAD 1. Properti objek yang "tersembunyi". Jika kita ingin menambahkan sebuah properti ke dala sebuah objek yang "dimiliki" oleh *script* lain atau sebuah *library*, kita bisa membuat sebuah simbol dan menggunakannya sebagai sebuah kunci properti. Sebuah properti simbolis tidak muncul dalam `for..in`, jadi hal tersbeut tidak akan tanpa sengaja terproses bersama properti-properti lain. Juga, simbol tidak akan diakses secara langsung, karena *script* tidak memiliki simbol kita. Jadi properti akan terlindungi dari penggunaan yang tak disengaja maupun tertimpa (*overwrite*). +======= +1. "Hidden" object properties. + + If we want to add a property into an object that "belongs" to another script or a library, we can create a symbol and use it as a property key. A symbolic property does not appear in `for..in`, so it won't be accidentally processed together with other properties. Also it won't be accessed directly, because another script does not have our symbol. So the property will be protected from accidental use or overwrite. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Jadi kita bisa "secara terselubung" menyembunyikan sesuatu ke dalam objek yang kita inginkan, tetapi tidak bisa diliha oleh pihak lain, menggunakn properti simbolis. 2. Terdapat banyak simbol sistem yang digunakan oleh oleh JavaScript yang mana dapat diakses sebagai `Symbol.*`. Kita bisa menggunakan simbol-simbol tersebut untuk mengubah beberapa perilaku bawaan (*built-in*). Sebagai contohnya, di tutorial selanjutnya kita akan menggunakan `Symbol.iterator` untuk [*iterables*](info:iterable), `Symbol.toPrimitive` untuk mengatur [konversi objek-ke-primitif](info:object-toprimitive) dan sebagainya. +<<<<<<< HEAD Secara teknis, simbol-simbol tidak 100% tersembunyi. Ada sebuah metode bawaan [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) yang membuat kita dapat mendapatkan semua simbol. Juga terdapat sebuah metode yang dinamakan [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) yang mengembalikan *semua* kunci dari sebuah objek termasuk yang kunci yang simbolik. Jadi simbol-simbol tersebut tidak sepenuhnya tersembunyi. Namun untuk sebagian besar *library*, fungsi-fungsi bawaan dan kontruksi sintaks constructs tidak menggunakan metode-metode ini. +======= +Technically, symbols are not 100% hidden. There is a built-in method [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) that allows us to get all symbols. Also there is a method named [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) that returns *all* keys of an object including symbolic ones. But most libraries, built-in functions and syntax constructs don't use these methods. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md index d0de05b0e..ae59d9d92 100644 --- a/1-js/04-object-basics/09-object-toprimitive/article.md +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -4,15 +4,27 @@ Apa yang terjadi ketika objek ditambahkan `obj1 + obj2`, dikurangi `obj1 - obj2` JavaScript tidak benar-benar memungkinkan untuk menyesuaikan cara operator bekerja pada objek. Tidak seperti beberapa bahasa pemrograman lain, seperti Ruby atau C++, kami tidak dapat mengimplementasikan metode objek khusus untuk menangani penambahan (atau operator lain). +<<<<<<< HEAD Dalam kasus operasi seperti itu, objek secara otomatis dikonversi ke primitif, dan kemudian operasi dilakukan di atas primitif ini dan menghasilkan nilai primitif. +======= +JavaScript doesn't allow you to customize how operators work on objects. Unlike some other programming languages, such as Ruby or C++, we can't implement a special object method to handle addition (or other operators). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Itu batasan penting, karena hasil dari `obj1 + obj2` tidak bisa menjadi objek lain! +<<<<<<< HEAD Misalnya. kita tidak dapat membuat objek yang mewakili vektor atau matriks (atau pencapaian atau apa pun), menambahkannya dan mengharapkan objek "dijumlahkan" sebagai hasilnya. Prestasi arsitektur seperti itu secara otomatis "di luar papan". Jadi, karena kita tidak bisa berbuat banyak di sini, tidak ada matematika dengan objek dalam proyek nyata. Ketika itu terjadi, biasanya karena kesalahan pengkodean. Dalam bab ini kita akan membahas bagaimana sebuah objek dikonversi ke primitif dan bagaimana menyesuaikannya. +======= +That's an important limitation: the result of `obj1 + obj2` (or another math operation) can't be another object! + +E.g. we can't make objects representing vectors or matrices (or achievements or whatever), add them and expect a "summed" object as the result. Such architectural feats are automatically "off the board". + +So, because we can't technically do much here, there's no maths with objects in real projects. When it happens, with rare exceptions, it's because of a coding mistake. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Kami memiliki dua tujuan: @@ -27,6 +39,7 @@ Dalam bab kita telah melihat aturan untuk konversi numer 2. Konversi numerik terjadi ketika kita mengurangi objek atau menerapkan fungsi matematika. Misalnya, objek `Tanggal` (akan dibahas dalam bab ) dapat dikurangi, dan hasil dari `tanggal1 - tanggal2` adalah perbedaan waktu antara dua tanggal. 3. Untuk konversi string -- biasanya terjadi ketika kita mengeluarkan objek seperti `alert(obj)` dan dalam konteks yang serupa. +<<<<<<< HEAD Kita dapat menyempurnakan konversi string dan numerik, menggunakan metode objek khusus. Ada tiga varian konversi tipe, yang terjadi dalam berbagai situasi. @@ -35,6 +48,24 @@ Mereka disebut "petunjuk", seperti yang dijelaskan dalam [spesifikasi](https://t `"tali"` : Untuk konversi objek-ke-string, saat kita melakukan operasi pada objek yang mengharapkan string, seperti `alert`: +======= +1. There's no conversion to boolean. All objects are `true` in a boolean context, as simple as that. There exist only numeric and string conversions. +2. The numeric conversion happens when we subtract objects or apply mathematical functions. For instance, `Date` objects (to be covered in the chapter ) can be subtracted, and the result of `date1 - date2` is the time difference between two dates. +3. As for the string conversion -- it usually happens when we output an object with `alert(obj)` and in similar contexts. + +We can implement string and numeric conversion by ourselves, using special object methods. + +Now let's get into technical details, because it's the only way to cover the topic in-depth. + +## Hints + +How does JavaScript decide which conversion to apply? + +There are three variants of type conversion, that happen in various situations. They're called "hints", as described in the [specification](https://tc39.github.io/ecma262/#sec-toprimitive): + +`"string"` +: For an object-to-string conversion, when we're doing an operation on an object that expects a string, like `alert`: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js // keluaran @@ -59,10 +90,16 @@ Mereka disebut "petunjuk", seperti yang dijelaskan dalam [spesifikasi](https://t biarkan lebih besar = pengguna1 > pengguna2; ``` + Most built-in mathematical functions also include such conversion. + `"default"` : Terjadi dalam kasus yang jarang terjadi ketika operator "tidak yakin" jenis apa yang diharapkan. +<<<<<<< HEAD Misalnya, biner plus `+` dapat bekerja baik dengan string (menggabungkannya) dan angka (menambahkannya), jadi string dan angka bisa digunakan. Jadi jika biner plus mendapatkan objek sebagai argumen, ia menggunakan petunjuk `"default"` untuk mengonversinya. +======= + For instance, binary plus `+` can work both with strings (concatenates them) and numbers (adds them). So if a binary plus gets an object as an argument, it uses the `"default"` hint to convert it. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Selain itu, jika suatu objek dibandingkan menggunakan `==` dengan string, angka, atau simbol, konversi mana yang harus dilakukan juga tidak jelas, sehingga petunjuk `"default"` digunakan. @@ -76,6 +113,7 @@ Mereka disebut "petunjuk", seperti yang dijelaskan dalam [spesifikasi](https://t Operator perbandingan yang lebih besar dan lebih kecil, seperti `<` `>`, dapat bekerja dengan string dan angka juga. Namun, mereka menggunakan petunjuk `"number"`, bukan `"default"`. Itu karena alasan historis. +<<<<<<< HEAD Namun dalam praktiknya, kita tidak perlu mengingat detail aneh ini, karena semua objek bawaan kecuali satu kasus (objek `Tanggal`, kita akan mempelajarinya nanti) mengimplementasikan konversi `"default"` dengan cara yang sama seperti ` "nomor"`. Dan kita bisa melakukan hal yang sama. ```smart header="Tidak ada petunjuk `\"boolean\"`" @@ -83,19 +121,213 @@ Harap dicatat -- hanya ada tiga petunjuk. Sesederhana itu. Tidak ada petunjuk "boolean" (semua objek `benar` dalam konteks boolean) atau yang lainnya. Dan jika kita memperlakukan `"default"` dan `"number"` sama, seperti kebanyakan built-in, maka hanya ada dua konversi. ``` +======= +In practice though, things are a bit simpler. + +All built-in objects except for one case (`Date` object, we'll learn it later) implement `"default"` conversion the same way as `"number"`. And we probably should do the same. + +Still, it's important to know about all 3 hints, soon we'll see why. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 **Untuk melakukan konversi, JavaScript mencoba menemukan dan memanggil tiga metode objek:** +<<<<<<< HEAD 1. Panggil `obj[Symbol.toPrimitive](hint)` - metode dengan kunci simbolis `Symbol.toPrimitive` (simbol sistem), jika metode tersebut ada, 2. Sebaliknya jika petunjuknya adalah `"string"` - coba `obj.toString()` dan `obj.valueOf()`, apa pun yang ada. 3. Jika petunjuknya adalah `"number"` atau `"default"` - coba `obj.valueOf()` dan `obj.toString()`, apa pun yang ada. +======= +1. Call `obj[Symbol.toPrimitive](hint)` - the method with the symbolic key `Symbol.toPrimitive` (system symbol), if such method exists, +2. Otherwise if hint is `"string"` + - try calling `obj.toString()` or `obj.valueOf()`, whatever exists. +3. Otherwise if hint is `"number"` or `"default"` + - try calling `obj.valueOf()` or `obj.toString()`, whatever exists. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Symbol.toPrimitive Mari kita mulai dari cara pertama. Ada simbol bawaan bernama `Symbol.toPrimitive` yang harus digunakan untuk menamai metode konversi, seperti ini: ```js +<<<<<<< HEAD obj[Simbol.toPrimitif] = fungsi(petunjuk) { - // dia \ No newline at end of file + // dia +======= +obj[Symbol.toPrimitive] = function(hint) { + // here goes the code to convert this object to a primitive + // it must return a primitive value + // hint = one of "string", "number", "default" +}; +``` + +If the method `Symbol.toPrimitive` exists, it's used for all hints, and no more methods are needed. + +For instance, here `user` object implements it: + +```js run +let user = { + name: "John", + money: 1000, + + [Symbol.toPrimitive](hint) { + alert(`hint: ${hint}`); + return hint == "string" ? `{name: "${this.name}"}` : this.money; + } +}; + +// conversions demo: +alert(user); // hint: string -> {name: "John"} +alert(+user); // hint: number -> 1000 +alert(user + 500); // hint: default -> 1500 +``` + +As we can see from the code, `user` becomes a self-descriptive string or a money amount, depending on the conversion. The single method `user[Symbol.toPrimitive]` handles all conversion cases. + +## toString/valueOf + +If there's no `Symbol.toPrimitive` then JavaScript tries to find methods `toString` and `valueOf`: + +- For the `"string"` hint: call `toString` method, and if it doesn't exist or if it returns an object instead of a primitive value, then call `valueOf` (so `toString` has the priority for string conversions). +- For other hints: call `valueOf`, and if it doesn't exist or if it returns an object instead of a primitive value, then call `toString` (so `valueOf` has the priority for maths). + +Methods `toString` and `valueOf` come from ancient times. They are not symbols (symbols did not exist that long ago), but rather "regular" string-named methods. They provide an alternative "old-style" way to implement the conversion. + +These methods must return a primitive value. If `toString` or `valueOf` returns an object, then it's ignored (same as if there were no method). + +By default, a plain object has following `toString` and `valueOf` methods: + +- The `toString` method returns a string `"[object Object]"`. +- The `valueOf` method returns the object itself. + +Here's the demo: + +```js run +let user = {name: "John"}; + +alert(user); // [object Object] +alert(user.valueOf() === user); // true +``` + +So if we try to use an object as a string, like in an `alert` or so, then by default we see `[object Object]`. + +The default `valueOf` is mentioned here only for the sake of completeness, to avoid any confusion. As you can see, it returns the object itself, and so is ignored. Don't ask me why, that's for historical reasons. So we can assume it doesn't exist. + +Let's implement these methods to customize the conversion. + +For instance, here `user` does the same as above using a combination of `toString` and `valueOf` instead of `Symbol.toPrimitive`: + +```js run +let user = { + name: "John", + money: 1000, + + // for hint="string" + toString() { + return `{name: "${this.name}"}`; + }, + + // for hint="number" or "default" + valueOf() { + return this.money; + } + +}; + +alert(user); // toString -> {name: "John"} +alert(+user); // valueOf -> 1000 +alert(user + 500); // valueOf -> 1500 +``` + +As we can see, the behavior is the same as the previous example with `Symbol.toPrimitive`. + +Often we want a single "catch-all" place to handle all primitive conversions. In this case, we can implement `toString` only, like this: + +```js run +let user = { + name: "John", + + toString() { + return this.name; + } +}; + +alert(user); // toString -> John +alert(user + 500); // toString -> John500 +``` + +In the absence of `Symbol.toPrimitive` and `valueOf`, `toString` will handle all primitive conversions. + +### A conversion can return any primitive type + +The important thing to know about all primitive-conversion methods is that they do not necessarily return the "hinted" primitive. + +There is no control whether `toString` returns exactly a string, or whether `Symbol.toPrimitive` method returns a number for the hint `"number"`. + +The only mandatory thing: these methods must return a primitive, not an object. + +```smart header="Historical notes" +For historical reasons, if `toString` or `valueOf` returns an object, there's no error, but such value is ignored (like if the method didn't exist). That's because in ancient times there was no good "error" concept in JavaScript. + +In contrast, `Symbol.toPrimitive` is stricter, it *must* return a primitive, otherwise there will be an error. +``` + +## Further conversions + +As we know already, many operators and functions perform type conversions, e.g. multiplication `*` converts operands to numbers. + +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 necessary for further calculations, the resulting primitive is also converted. + +For instance: + +```js run +let obj = { + // toString handles all conversions in the absence of other methods + toString() { + return "2"; + } +}; + +alert(obj * 2); // 4, object converted to primitive "2", then multiplication made it a number +``` + +1. The multiplication `obj * 2` first converts the object to primitive (that's a string `"2"`). +2. Then `"2" * 2` becomes `2 * 2` (the string is converted to number). + +Binary plus will concatenate strings in the same situation, as it gladly accepts a string: + +```js run +let obj = { + toString() { + return "2"; + } +}; + +alert(obj + 2); // "22" ("2" + 2), conversion to primitive returned a string => concatenation +``` + +## Summary + +The object-to-primitive conversion is called automatically by many built-in functions and operators that expect a primitive as a value. + +There are 3 types (hints) of it: +- `"string"` (for `alert` and other operations that need a string) +- `"number"` (for maths) +- `"default"` (few operators, usually objects implement it the same way as `"number"`) + +The specification describes explicitly which operator uses which hint. + +The conversion algorithm is: + +1. Call `obj[Symbol.toPrimitive](hint)` if the method exists, +2. Otherwise if hint is `"string"` + - try calling `obj.toString()` or `obj.valueOf()`, whatever exists. +3. Otherwise if hint is `"number"` or `"default"` + - try calling `obj.valueOf()` or `obj.toString()`, whatever exists. + +All these methods must return a primitive to work (if defined). + +In practice, it's often enough to implement only `obj.toString()` as a "catch-all" method for string conversions that should return a "human-readable" representation of an object, for logging or debugging purposes. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md b/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md index 6292b0f55..00b6cdf91 100644 --- a/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md +++ b/1-js/05-data-types/01-primitives-methods/1-string-new-property/task.md @@ -15,4 +15,8 @@ str.test = 5; alert(str.test); ``` -Bagaimana menurutmu, akankah itu bekerja? apa yang akan muncul? \ No newline at end of file +<<<<<<< HEAD +Bagaimana menurutmu, akankah itu bekerja? apa yang akan muncul? +======= +What do you think, will it work? What will be shown? +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/1-js/05-data-types/01-primitives-methods/article.md b/1-js/05-data-types/01-primitives-methods/article.md index c20885756..57dd3c0fd 100644 --- a/1-js/05-data-types/01-primitives-methods/article.md +++ b/1-js/05-data-types/01-primitives-methods/article.md @@ -39,7 +39,11 @@ Objek lebih "berat" dari primitif. Dan mereka membutuhkan sumber daya tambahan u Ini adalah paradoks yang dihadapi dari pencipta Javascript: +<<<<<<< HEAD - Terdapat banyak hal yang harus dilakukan dengan primitif seperti string atau angka. Akan menjadi lebih baik jika mereka bisa diakses sebagai method. +======= +- There are many things one would want to do with a primitive, like a string or a number. It would be great to access them using methods. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 - Primitives must be as fast and lightweight as possible. - Sebisa mungkin primitif haruslah cepat dan ringan. @@ -49,7 +53,11 @@ Solusinya terlihat sedikit aneh, tapi inilah solusinya: 2. Bahasanya membolehkan untuk mengakses method dan properti dari string, number, boolean dan symbols. 3. Untuk membuat itu bekerja, "objek pembungkus" spesial yang menyediakan fungsionalitas tambahan dibuat, dan lalu dihancurkan. +<<<<<<< HEAD "Objek pembungkus" berbeda untuk setiap tipe primitif dan dipanggil: `String`, `Number`, `Boolean` dan `Symbol`. Lalu, mereka menyediakan metode-metode yang berbeda. +======= +The "object wrappers" are different for each primitive type and are called: `String`, `Number`, `Boolean`, `Symbol` and `BigInt`. Thus, they provide different sets of methods. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Contoh, ada methode string [str.toUpperCase()](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) yang mengembalikan string `str` yang telah diubah menjadi huruf kapital. @@ -105,9 +113,16 @@ if (zero) { // zero adalah true, karena itu adalah sebuah objek } ``` +<<<<<<< HEAD Disisi lain, menggunakan fungsi yang sama `String/Number/Boolean` tanpa `new` adalah hal yang masuk akal dan hal yang berguna. Mereka mengubah nilai kedalam tipe yang sesuai: kedalam sebuah string, sebuah number, atau sebuah boolean(primitif). Contoh, hal ini sepenuhnya valid: +======= +On the other hand, using the same functions `String/Number/Boolean` without `new` is totally fine and useful thing. They convert a value to the corresponding type: to a string, a number, or a boolean (primitive). + +For example, this is entirely valid: + +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js let num = Number("123"); // mengubah string menjadi angka ``` diff --git a/1-js/05-data-types/02-number/2-why-rounded-down/solution.md b/1-js/05-data-types/02-number/2-why-rounded-down/solution.md index 13e7cc2a7..425f5576b 100644 --- a/1-js/05-data-types/02-number/2-why-rounded-down/solution.md +++ b/1-js/05-data-types/02-number/2-why-rounded-down/solution.md @@ -28,6 +28,6 @@ Perhatikan bahwa `63.5` tidak memiliki kehilangan presisi sama sekali. Itu karen ```js run -alert( Math.round(6.35 * 10) / 10); // 6.35 -> 63.5 -> 64(rounded) -> 6.4 +alert( Math.round(6.35 * 10) / 10 ); // 6.35 -> 63.5 -> 64(rounded) -> 6.4 ``` diff --git a/1-js/05-data-types/02-number/article.md b/1-js/05-data-types/02-number/article.md index 5abc8df8f..9b89cc104 100644 --- a/1-js/05-data-types/02-number/article.md +++ b/1-js/05-data-types/02-number/article.md @@ -2,9 +2,15 @@ Dalam JavaScript modern, ada dua tipe angka: +<<<<<<< HEAD 1. Angka regular di JavaScript yang disimpan dalam format 64-bit [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754-2008_revision), juga dikenal sebagai "angka double precision floating point". Inilah angka yang kita paling sering kita pakai, dan kita akan bahas tentang mereka di bab ini. 2. Angka BigInt, untuk mewakili integer dengan panjang sembarang. Mereka kadang dibutuhkan, karena angka regular tak bisa lebih dari 253 atau kurang dari -253. Karena bigint dipakai di sedikit area spesial, kita khususkan mereka bab spesial . +======= +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 (253-1) or be less than -(253-1), as we mentioned earlier in the chapter . As bigints are used in a few special areas, we devote them to a special chapter . +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Jadi di sini kita akan bahas angka regular. Ayo perluas pengetahuan kita tentang mereka. @@ -22,7 +28,11 @@ Kita juga bisa menggunakan `_` sebagai pemisahnya: let billion = 1_000_000_000; ``` +<<<<<<< HEAD Di sini, garis bawah `_` memainkan peran sebagai "syntactic sugar", ini membuat angka lebih mudah dibaca. Mesin JavaScript mengabaikan `_` di antara digit, jadi nilainya sama persis dengan satu miliar di atas. +======= +Here the underscore `_` plays the role of the "[syntactic sugar](https://en.wikipedia.org/wiki/Syntactic_sugar)", it makes the number more readable. The JavaScript engine simply ignores `_` between digits, so it's exactly the same one billion as above. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Tapi di kehidupan nyata, kita biasanya menghindari menulis string nol yang panjang karena rentan terjadi kesalahan. Selain itu, kita malas. Kita biasanya akan menulis sesuatu seperti `"1bn"` untuk milyar atau `"7.3bn"` untuk 7 milyar 300 juta. Sama halnya dengan angka besar lainnya. @@ -37,16 +47,21 @@ alert( 7.3e9 ); // 7.3 milyar (7,300,000,000) Dengan kata lain, `"e"` kalikan angkanya dengan `1` dengan jumlah nol yang diberikan. ```js -1e3 = 1 * 1000 // e3 means *1000 -1.23e6 = 1.23 * 1000000 // e6 means *1000000 +1e3 === 1 * 1000; // e3 means *1000 +1.23e6 === 1.23 * 1000000; // e6 means *1000000 ``` +<<<<<<< HEAD Sekarang ayo tulis sesuatu lebih kecil. Katakan, 1 microsecond (sepersejuta second): +======= +Now let's write something very small. Say, 1 microsecond (one-millionth of a second): +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js -let ms = 0.000001; +let mсs = 0.000001; ``` +<<<<<<< HEAD Sama seperti sebelumnya, memakai `"e"` bisa membantu. Jika kita ingin menghindari menulis nol eksplisit, kita bisa katakan hal yang sama: ```js @@ -54,15 +69,35 @@ let ms = 1e-6; // enam nol di sebelah kiri dari 1 ``` Jika kita hitung nol di `0.000001`, ada 6 dari mereka. Jadi alaminya `1e-6`. +======= +Just like before, using `"e"` can help. If we'd like to avoid writing the zeroes explicitly, we could write the same as: + +```js +let mcs = 1e-6; // five zeroes to the left from 1 +``` + +If we count the zeroes in `0.000001`, there are 6 of them. So naturally it's `1e-6`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Dengan kata lain, angka negatif setelah `"e"` artinya pembagian 1 dengan jumlah nol yang diberikan: ```js +<<<<<<< HEAD // -3 membagi 1 dengan 3 nol 1e-3 = 1 / 1000 (=0.001) // -6 membagi 1 dengan 6 nol 1.23e-6 = 1.23 / 1000000 (=0.00000123) +======= +// -3 divides by 1 with 3 zeroes +1e-3 === 1 / 1000; // 0.001 + +// -6 divides by 1 with 6 zeroes +1.23e-6 === 1.23 / 1000000; // 0.00000123 + +// an example with a bigger number +1234e-2 === 1234 / 100; // 12.34, decimal point moves 2 times +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ### Hex, angka binary dan octal @@ -100,13 +135,23 @@ alert( num.toString(16) ); // ff alert( num.toString(2) ); // 11111111 ``` +<<<<<<< HEAD `base` bisa bervariasi dari `2` hingga `36`. Defaultnya `10`. +======= +The `base` can vary from `2` to `36`. By default, it's `10`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Penggunaan umumnya ialah: +<<<<<<< HEAD - **base=16** dipakai untuk warna hex, character encoding dll, digit bisa `0..9` atau `A..F`. - **base=2** paling banyak untuk mendebug operasi bitwise, digit bisa `0` atau `1`. - **base=36** ini maximum, digit bisa `0..9` atau `A..Z`. Seluruh alfabet latin dipakai untuk merepresentasi angka. Hal lucu, tapi berguna untuk `36` ialah saat kita harus mengubah identifier numerik panjang ke dalam sesuatu yang lebih pendek, misalnya untuk membuat url pendek. Bisa direpresentasikan dalam sistem `36`: +======= +- **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`: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run alert( 123456..toString(36) ); // 2n9c @@ -115,9 +160,16 @@ Penggunaan umumnya ialah: ```warn header="Dua dot untuk memanggil metode" Tolong ingat bahwa dua dot di `123456..toString(36)` bukan typo. Jika kita mau memanggil langsung metode pada angka, seperti `toString` di contoh di atas, maka kita harus menaruh dua dot `..` setelahnya. +<<<<<<< HEAD Jika kita menaruh dot tunggal: `123456.toString(36)`, maka akan ada galat, karena syntax JavaScript berimplikasi bahwa bagian desimal setelah dot pertama. Dan jika kita menaruh satu dot lagi, maka JavaScript tahu bahwa bagian desimal kosong dan sekarang pergi ke metode. Juga bisa menulis `(123456).toString(36)`. +======= +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)`. + +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ## Pembulatan @@ -133,7 +185,11 @@ Ada beberapa fungsi built-in untuk pembulatan: : Membulat ke atas: `3.1` menjadi `4`, dan `-1.1` menjadi `-1`. `Math.round` +<<<<<<< HEAD : Membulatkan ke bilangan bulat terdekat: `3.1` menjadi` 3`, `3.6` menjadi` 4`, huruf tengah: `3.5` juga dibulatkan ke atas menjadi` 4`. +======= +: 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`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 `Math.trunc` (tidak didukung oleh Internet Explorer) : Menghapus apa pun setelah koma desimal tanpa pembulatan: `3.1` menjadi` 3`, `-1.1` menjadi` -1`. @@ -143,8 +199,10 @@ Ini tabel untuk meringkas perbedaan di antara mereka: | | `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` | @@ -156,7 +214,11 @@ Ada dua cara melakukannya: 1. Kali-dan-bagi. +<<<<<<< HEAD Misalnya, untuk membulatkan angka ke digit kedua setelah desimal, kita bisa mengalikan angkanya dengan `100` (atau sebuah pangkat dari 10), panggil fungsi pembulatan lalu membagi itu kembali. +======= + For example, to round the number to the 2nd digit after the decimal, we can multiply the number by `100`, call the rounding function and then divide it back. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let num = 1.23456; @@ -177,20 +239,34 @@ Ada dua cara melakukannya: alert( num.toFixed(1) ); // "12.4" ``` +<<<<<<< HEAD Silakan catat hasil dari `toFixed` ialah string. Jika bagian desimal lebih pendek dari yang dibutuhkan, nol ditambahkan di akhir: +======= + Please note that the result of `toFixed` is a string. If the decimal part is shorter than required, zeroes are appended to the end: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let num = 12.34; alert( num.toFixed(5) ); // "12.34000", tambah nol supaya tepat 5 digit ``` +<<<<<<< HEAD Kita bisa mengkonversi itu ke angka menggunakan unary plus atau panggilan `Number()`: `+num.toFixed(5)`. +======= + We can convert it to a number using the unary plus or a `Number()` call, e.g. write `+num.toFixed(5)`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Kalkulasi yang tidak tepat +<<<<<<< HEAD Secara internal, angka direpresentasikan dalam format 64-bit [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754-2008_revision), jadi ada tepat 64 bit untuk menyimpan angka: 52 di antaranya digunakan untuk menyimpan angka, 11 di antaranya menyimpan posisi titik desimal (nol untuk angka bilangan bulat), dan 1 bit untuk tanda. Jika angka terlalu besar, itu akan meluapkan penyimpanan 64-bit, berpotensi memberikan infinity: +======= +Internally, a number is represented in 64-bit format [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754), so there are exactly 64 bits to store a number: 52 of them are used to store the digits, 11 of them store the position of the decimal point, and 1 bit is for the sign. + +If a number is really huge, it may overflow the 64-bit storage and become a special numeric value `Infinity`: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run alert( 1e500 ); // Infinity @@ -198,7 +274,11 @@ alert( 1e500 ); // Infinity Yang mungkin agak kurang jelas, tetapi sering terjadi adalah hilangnya ketepatan. +<<<<<<< HEAD Pertimbangkan (falsy!) tes ini: +======= +Consider this (falsy!) equality test: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run alert( 0.1 + 0.2 == 0.3 ); // *!*false*/!* @@ -212,13 +292,27 @@ Aneh! Kenapa hasilnya itu dan tidak `0.3`? alert( 0.1 + 0.2 ); // 0.30000000000000004 ``` +<<<<<<< HEAD Aduh! Ada lebih banyak konsekuensi daripada perbandingan yang salah di sini. Bayangkan Anda membuat situs e-shopping dan pengunjung memasukkan barang-barang `$ 0,10` dan` $ 0,20` ke troli mereka. Total pesanan akan `$ 0,30000000000000004`. Itu akan mengejutkan siapa pun. +======= +Ouch! Imagine you're making an e-shopping site and the visitor puts `$0.10` and `$0.20` goods into their cart. The order total will be `$0.30000000000000004`. That would surprise anyone. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Tetapi kenapa hal ini bisa terjadi? Sebuah angka disimpan di memori dalam bentuk binary, sebuah urutan dari bits - satu dan nol. Tetapi bilangan pecahan seperti `0.1`, `0.2` yang terlihat sederhana dalam sistem angka desimal sebenarnya adalah pecahan tak berujung dalam bentuk binernya. +<<<<<<< HEAD Dengan kata lain, apa itu `0,1`? Ini adalah satu dibagi dengan sepuluh `1 / 10`, sepersepuluh. Dalam sistem angka desimal, angka-angka seperti itu mudah diwakili. Bandingkan dengan sepertiga: `1 / 3`. Ini menjadi pecahan yang tak berujung `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)`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Jadi, pembagian dengan kekuatan `10` dijamin bekerja dengan baik dalam sistem desimal, tetapi pembagian dengan `3` tidak. Untuk alasan yang sama, dalam sistem angka biner, pembagian dengan kekuatan `2` dijamin bekerja, tetapi `1 / 10` menjadi fraksi biner tanpa akhir. @@ -238,14 +332,18 @@ Itu sebabnya `0,1 + 0,2` tidak sepenuhnya` 0,3`. ```smart header="Tidak hanya JavaScript" Masalah yang sama ada di banyak bahasa pemrograman lainnya. +<<<<<<< HEAD PHP, Java, C, Perl, Ruby memberikan hasil yang sama persis, karena mereka didasarkan pada format numerik yang sama. +======= +PHP, Java, C, Perl, and Ruby give exactly the same result, because they are based on the same numeric format. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` Bisakah kita mengatasi masalah ini? Tentu, metode yang paling dapat diandalkan adalah melengkapi hasilnya dengan bantuan metode [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed): ```js run let sum = 0.1 + 0.2; -alert( sum.toFixed(2) ); // 0.30 +alert( sum.toFixed(2) ); // "0.30" ``` Harap dicatat bahwa `toFixed` selalu mengembalikan string. Ini memastikan bahwa ia memiliki 2 digit setelah titik desimal. Itu sebenarnya nyaman jika kita memiliki e-shopping dan perlu menunjukkan `$ 0,30`. Untuk kasus lain, kita dapat menggunakan plus unary untuk memaksanya menjadi nomor: @@ -262,7 +360,11 @@ alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3 alert( (0.28 * 100 + 0.14 * 100) / 100); // 0.4200000000000001 ``` +<<<<<<< HEAD Jadi, pendekatan perkalian/pembagian mengurangi kesalahan, tetapi tidak menghapusnya sama sekali. +======= +So, the multiply/divide approach reduces the error, but doesn't remove it totally. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Terkadang kita bisa mencoba menghindari pecahan sama sekali. Seperti jika kita berurusan dengan toko, maka kita dapat menyimpan harga dalam sen, bukan dalam dolar. Tetapi bagaimana jika kita menerapkan diskon 30%? Dalam praktiknya, menghindari pecahan sama sekali jarang dimungkinkan. Hanya bulatkan mereka untuk memotong "ekor" bila diperlukan. @@ -284,7 +386,11 @@ Konsekuensi lucu yang lain dari representasi internal dari angka adalah adanya d Itu karena sebuah tanda diwakili oleh satu bit, sehingga dapat diatur atau tidak diatur untuk angka apa pun termasuk nol. +<<<<<<< HEAD Dalam kebanyakan kasus perbedaannya tidak terlalu mencolok, karena operator cocok untuk memperlakukan mereka sebagai sesuatu yang sama. +======= +In most cases, the distinction is unnoticeable, because operators are suited to treat them as the same. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ## Tests: isFinite dan isNaN @@ -304,7 +410,11 @@ Mereka termasuk dalam tipe `angka`, tetapi bukan angka "normal", jadi ada fungsi alert( isNaN("str") ); // true ``` +<<<<<<< HEAD Tetapi apakah kita membutuhkan fungsi ini? Tidak bisakah kita menggunakan perbandingan `=== NaN`? Maaf, tapi jawabannya adalah tidak. Nilai `NaN` unik karena tidak sama dengan apa pun, termasuk dirinya sendiri: +======= + But do we need this function? Can't we just use the comparison `=== NaN`? Unfortunately not. The value `NaN` is unique in that it does not equal anything, including itself: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run alert( NaN === NaN ); // false @@ -328,6 +438,7 @@ let num = +prompt("Enter a number", ''); alert( isFinite(num) ); ``` +<<<<<<< HEAD Harap dicatat bahwa string kosong atau spasi-saja diperlakukan sebagai `0` dalam semua fungsi numerik termasuk` isFinite`. ```smart header="Dibandingkan dengan `Object.is`" @@ -336,10 +447,52 @@ Ada metode bawaan khusus [Object.is](mdn:js/Object/is) yang membandingkan nilai 1. Ini bekerja dengan `NaN`: `Object.is(NaN, NaN) === true`, itu hal yang bagus. 2. Nilai `0` and `-0` adalah berbeda: `Object.is(0, -0) === false`, secara teknis adalah benar, karena secara internal nomor tersebut memiliki bit tanda yang mungkin berbeda bahkan jika semua bit lainnya nol. +======= +Please note that an empty or a space-only string is treated as `0` in all numeric functions including `isFinite`. + +````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`. + + ```js run + alert( Number.isNaN(NaN) ); // true + alert( Number.isNaN("str" / 2) ); // true + + // Note the difference: + alert( Number.isNaN("str") ); // false, because "str" belongs to the string type, not the number type + 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`. + + ```js run + alert( Number.isFinite(123) ); // true + alert( Number.isFinite(Infinity) ); // false + alert( Number.isFinite(2 / 0) ); // false + + // Note the difference: + alert( Number.isFinite("123") ); // false, because "123" belongs to the string type, not the number type + alert( isFinite("123") ); // true, because isFinite converts string "123" into a number 123 + ``` + +In a way, `Number.isNaN` and `Number.isFinite` are simpler and more straightforward than `isNaN` and `isFinite` functions. In practice though, `isNaN` and `isFinite` are mostly used, as they're shorter to write. +```` + +```smart header="Comparison with `Object.is`" +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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Pada kasus lain, `Object.is(a, b)` adalah sama dengan `a === b`. +<<<<<<< HEAD Cara perbandingan ini sering digunakan dalam spesifikasi JavaScript. Ketika suatu algoritma internal perlu membandingkan dua nilai untuk menjadi persis sama, ia menggunakan `Object.is` (secara internal disebut [SameValue](https://tc39.github.io/ecma262/#sec-samevalue)). +======= +We mention `Object.is` here, because it's often used in JavaScript specification. When an internal algorithm needs to compare two values for being exactly the same, it uses `Object.is` (internally called [SameValue](https://tc39.github.io/ecma262/#sec-samevalue)). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` @@ -353,7 +506,11 @@ alert( +"100px" ); // NaN Satu-satunya pengecualian adalah spasi di awal atau di akhir string, karena diabaikan. +<<<<<<< HEAD Tetapi dalam kehidupan nyata kita sering memiliki nilai dalam satuan, seperti `"100px"` atau `"12pt"` dalam CSS. Juga di banyak negara simbol mata uang mengikuti jumlah, jadi kita memiliki `"€19"` dan ingin mengekstraksi nilai numerik dari itu. +======= +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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Untuk itulah `parseInt` dan` parseFloat` ada. @@ -399,8 +556,13 @@ Beberapa contoh: alert( Math.random() ); // ... (angka aca apa saja) ``` +<<<<<<< HEAD `Math.max(a, b, c...)` / `Math.min(a, b, c...)` : Mengembalikan argumen terbesar / terkecil dari jumlah argumen yang arbitrer. +======= +`Math.max(a, b, c...)` and `Math.min(a, b, c...)` +: Returns the greatest and smallest from the arbitrary number of arguments. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run alert( Math.max(3, 5, -10, 0, 1) ); // 5 @@ -429,7 +591,18 @@ Untuk sistem angka yang berbeda: - `parseInt(str, base)` mem-parsing string `str` menjadi bilangan bulat dalam sistem angka dengan diberikan `base`, `2 ≤ base ≤ 36`. - `num.toString(base)` mengonversi angka menjadi string dalam sistem angka dengan diberikan `base`. +<<<<<<< HEAD Untuk mengkonversi nilai seperti `12pt` dan `100px` menjadi sebuah angka: +======= +For regular number tests: + +- `isNaN(value)` converts its argument to a number and then tests it for being `NaN` +- `Number.isNaN(value)` checks whether its argument belongs to the `number` type, and if so, tests it for being `NaN` +- `isFinite(value)` converts its argument to a number and then tests it for not being `NaN/Infinity/-Infinity` +- `Number.isFinite(value)` checks whether its argument belongs to the `number` type, and if so, tests it for not being `NaN/Infinity/-Infinity` + +For converting values like `12pt` and `100px` to a number: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 - Gunakan `parseInt/parseFloat` untuk konversi "lembut", dimana membaca sebuah angka dari string dan mengembalikan nilai yang bisa dibaca sebelum terjadi kesalahan. @@ -440,4 +613,8 @@ Untuk pecahan: Lebih banyak fungsi matematika: +<<<<<<< HEAD - Lihat objek [Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) ketika Anda membutuhkannya. Perpustakaannya sangat kecil, tetapi dapat memenuhi kebutuhan dasar. +======= +- 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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/1-js/05-data-types/03-string/1-ucfirst/solution.md b/1-js/05-data-types/03-string/1-ucfirst/solution.md index 15f7bb241..3a51a936d 100644 --- a/1-js/05-data-types/03-string/1-ucfirst/solution.md +++ b/1-js/05-data-types/03-string/1-ucfirst/solution.md @@ -8,12 +8,16 @@ let newStr = str[0].toUpperCase() + str.slice(1); Tetapi ada sedikit masalah. Jika `str` bernilai kosong, maka `str[0]` bernilai `undefined`, dan `undefined` tidak memiliki method `toUpperCase()`. Hal tersebut yang menyebabkan error. +<<<<<<< HEAD Ada dua cara di sini: 1. Gunakan `str.charAt(0)`, karena method ini selalu mengembalikan string (mungkin kosong). 2. Tambahkan pengecekan string kosong. Berikut adalah cara yang kedua: +======= +The easiest way out is to add a test for an empty string, like this: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run demo function ucFirst(str) { diff --git a/1-js/05-data-types/03-string/3-truncate/task.md b/1-js/05-data-types/03-string/3-truncate/task.md index ee6262ab3..56d2eeb17 100644 --- a/1-js/05-data-types/03-string/3-truncate/task.md +++ b/1-js/05-data-types/03-string/3-truncate/task.md @@ -11,7 +11,7 @@ Hasil kembalian dari fungsi seharusnya string yang dipotong (jika diperlukan). Sebagai contoh: ```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!" ``` diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md index a385c03ad..39a1acbc4 100644 --- a/1-js/05-data-types/03-string/article.md +++ b/1-js/05-data-types/03-string/article.md @@ -48,9 +48,15 @@ let guestList = "Guests: // Error: Unexpected token ILLEGAL * John"; ``` +<<<<<<< HEAD Petik satu dan petik dua berasal dari masa lalu saat bahasa pemrograman dibuat, dimana kebutuhan untuk string lebih dari satu baris belum dipikirkan. Backtick muncul di kemudian hari, dan lebih fleksibel. Backtick juga memperbolehkan kita untuk menspesifikasi "fungsi template" sebelum backtick pertama. Syntaxnya yaitu: func`string`. Fungsi `func` dipanggil secara otomatis, menerima string dan ekspresi yang berada di dalamnya dan bisa memproses mereka. Ini disebut "tagged templates". Fitur ini membuat implementasi kustom templating lebih mudah, tapi jaran dipakai dalam praktik. Kamu bisa membaca lebih tentang ini di [manual](mdn:/JavaScript/Reference/Template_literals#Tagged_templates). +======= +Single and double quotes come from ancient times of language creation, when the need for multiline strings was not taken into account. Backticks appeared much later and thus are more versatile. + +Backticks also allow us to specify a "template function" before the first backtick. The syntax is: func`string`. The function `func` is called automatically, receives the string and embedded expressions and can process them. This feature is called "tagged templates", it's rarely seen, but you can read about it in the MDN: [Template literals](mdn:/JavaScript/Reference/Template_literals#Tagged_templates). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Karakter spesial @@ -59,10 +65,17 @@ Masih mungkin untuk membuat string dengan banyak baris menggunakan petik satu at ```js run let guestList = "Guests:\n * John\n * Pete\n * Mary"; +<<<<<<< HEAD alert(guestList); // list tamu yang dipisahkan per baris ``` Sebagai contoh, kedua baris berikut sama saja, hanya ditulis dengan cara yang berbeda: +======= +alert(guestList); // a multiline list of guests, same as above +``` + +As a simpler example, these two lines are equal, just written differently: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let str1 = "Hello\nWorld"; // dua baris menggunakan "simbol baris baru" @@ -74,6 +87,7 @@ World`; alert(str1 == str2); // true ``` +<<<<<<< HEAD Ada karakter spesial lain, tetapi mereka jarang digunakan Berikut adalah daftar lengkapnya: @@ -101,6 +115,28 @@ alert( "\u{1F60D}" ); // 😍, sebuah simbol wajah tersenyum (unicode panjang la Karakter-karakter spesial yang diawali dengan karakter backslash `\` kadang dipanggil dengan sebutan "escape character". Kita kadang dapat menggunakannya apabila kita ingin menggunakan petik di dalam string. +======= +There are other, less common special characters: + +| Character | Description | +|-----------|-------------| +|`\n`|New line| +|`\r`|In Windows text files a combination of two characters `\r\n` represents a new break, while on non-Windows OS it's just `\n`. That's for historical reasons, most Windows software also understands `\n`. | +|`\'`, `\"`, \\`|Quotes| +|`\\`|Backslash| +|`\t`|Tab| +|`\b`, `\f`, `\v`| Backspace, Form Feed, Vertical Tab -- mentioned for completeness, coming from old times, not used nowadays (you can forget them right now). | + +As you can see, all special characters start with a backslash character `\`. It is also called an "escape character". + +Because it's so special, if we need to show an actual backslash `\` within the string, we need to double it: + +```js run +alert( `The backslash: \\` ); // The backslash: \ +``` + +So-called "escaped" quotes `\'`, `\"`, \\` are used to insert a quote into the same-quoted string. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Misalnya: @@ -113,9 +149,10 @@ Seperti yang kita lihat, kita harus menambahkan backslash di depan petik yang di Tentu saja, hanya jenis petik yang sama dengan penutup string yang perlu di "escape". Jadi, solusi yang lebih elegan yaitu mengganti petik satu menjadi petik dua atau backtick: ```js run -alert( `I'm the Walrus!` ); // I'm the Walrus! +alert( "I'm the Walrus!" ); // I'm the Walrus! ``` +<<<<<<< HEAD Ingat bahwa backslash `\` hanya dipakai untuk Javascript agar dapat membaca string dengan benar. Di dalam memori, string tidak memiliki `\`. Anda dapat melihatnya secara langsung pada contoh `alert` di atas. Tetapi bagaimana jika kita ingin menampilkan backslash `\` di dalam sebuah string? @@ -125,6 +162,9 @@ Hal tersebut bisa dilakukan, tetapi kita harus menulisnya dua kali seperti ini ` ```js run alert( `The backslash: \\` ); // The backslash: \ ``` +======= +Besides these special characters, there's also a special notation for Unicode codes `\u…`, it's rarely used and is covered in the optional chapter about [Unicode](info:unicode). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Panjang string @@ -139,33 +179,55 @@ Perlu diingat bahwa `\n` adalah sebuah karakter spesial, jadi panjang dari strin ```warn header="`length` adalah sebuah properti" Orang dengan latar belakang di bahasa pemrograman lain kadang salah mengetik `str.length()` alih-alih `str.length`. Hal tersebut tidak bekerja. +<<<<<<< HEAD Perlu diingat bahwa `str.length` adalah properti numerik, bukan sebuah fungsi. Tidak perlu menambahkan kurung di belakangnya. +======= +Please note that `str.length` is a numeric property, not a function. There is no need to add parenthesis after it. Not `.length()`, but `.length`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ## Mengakses karakter di dalam string +<<<<<<< HEAD Untuk mengakses karakter pada posisi `pos`, digunakan kurung kotak `[pos]` atau dengan method [str.charAt(pos)](mdn:js/String/charAt). Karakter pertama dimulai dari posisi ke-0: +======= +To get a character at position `pos`, use square brackets `[pos]` or call the method [str.at(pos)](mdn:js/String/at). The first character starts from the zero position: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let str = `Hello`; // karakter pertama alert( str[0] ); // H -alert( str.charAt(0) ); // H +alert( str.at(0) ); // H // karakter terakhir alert( str[str.length - 1] ); // o +alert( str.at(-1) ); ``` +<<<<<<< HEAD Kurung kotak adalah cara modern untuk mengakses sebuah karakter, sementara `charAt` ada karena alasan historis. Perbedaan satu-satunya di antara mereka adalah apabila tidak ada karakter yang ditemukan, `[]` mengembalikan `undefined`, dan `charAt` mengembalikan string kosong: +======= +As you can see, the `.at(pos)` method has a benefit of allowing negative position. If `pos` is negative, then it's counted from the end of the string. + +So `.at(-1)` means the last character, and `.at(-2)` is the one before it, etc. + +The square brackets always return `undefined` for negative indexes, for instance: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let str = `Hello`; +<<<<<<< HEAD alert( str[1000] ); // undefined alert( str.charAt(1000) ); // '' (string kosong) +======= +alert( str[-2] ); // undefined +alert( str.at(-2) ); // l +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` Kita juga bisa mengakses karakter per karakter menggunakan sintaks `for..of`: @@ -214,7 +276,7 @@ alert( 'Interface'.toLowerCase() ); // interface Atau, apabila kita hanya ingin sebuah karakter yang diubah menjadi huruf kecil: -```js +```js run alert( 'Interface'[0].toLowerCase() ); // 'i' ``` @@ -310,6 +372,7 @@ if (str.indexOf("Widget") != -1) { } ``` +<<<<<<< HEAD #### Trik bitwise NOT Salah satu trik lama yang digunakan disini adalah operator [bitwise NOT](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_NOT) `~`. Operator ini mengubah angka menjadi integer 32-bit (menghilangkan bagian desimal jika ada) lalu menegasikan semua bit pada representasi binernya. @@ -349,6 +412,8 @@ Untuk lebih detail, karena bilangan yang besar dipotong menjadi 32-bit oleh oper Kita dapat melihat bahwa trik ini hanya digunakan di kode yang kuno, karena Javascript modern menyediakan method `.includes` (lihat di bawah). +======= +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ### includes, startsWith, endsWith Method yang lebih modern [str.includes(substr, pos)](mdn:js/String/includes) mengembalikan `true/false` tergantung dengan apakah `str` mengandung `substr` di dalamnya. @@ -371,8 +436,13 @@ alert( "Widget".includes("id", 3) ); // false, dari posisi 3 tidak ditemukan "id Method [str.startsWith](mdn:js/String/startsWith) dan [str.endsWith](mdn:js/String/endsWith) melakukan fungsi seperti namanya: ```js run +<<<<<<< HEAD alert( "Widget".startsWith("Wid") ); // true, "Widget" diawali oleh "Wid" alert( "Widget".endsWith("get") ); // true, "Widget" diakhiri oleh "get" +======= +alert( "*!*Wid*/!*get".startsWith("Wid") ); // true, "Widget" starts with "Wid" +alert( "Wid*!*get*/!*".endsWith("get") ); // true, "Widget" ends with "get" +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ## Mengambil substring @@ -407,9 +477,15 @@ Ada 3 cara untuk mengambil sebuah substring di Javascript: `substring`, `substr` ``` `str.substring(start [, end])` +<<<<<<< HEAD : Mengembalikan bagian dari string *di antara* `start` dan `end`. Method ini hampir sama dengan `slice`, tetapi nilai `start` boleh lebih besar daripada `end`. +======= +: Returns the part of the string *between* `start` and `end` (not including `end`). + + This is almost the same as `slice`, but it allows `start` to be greater than `end` (in this case it simply swaps `start` and `end` values). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Sebagai contoh: @@ -445,18 +521,36 @@ Ada 3 cara untuk mengambil sebuah substring di Javascript: `substring`, `substr` alert( str.substr(-4, 2) ); // gi, dari posisi ke-4 ambil 2 karakter ``` +<<<<<<< HEAD Mari kita review cara-cara tersebut untuk menghindari kebingungan: +======= + This method resides in the [Annex B](https://tc39.es/ecma262/#sec-string.prototype.substr) of the language specification. It means that only browser-hosted Javascript engines should support it, and it's not recommended to use it. In practice, it's supported everywhere. + +Let's recap these methods to avoid any confusion: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 | method | mengambil... | negatives | |--------|-----------|-----------| +<<<<<<< HEAD | `slice(start, end)` | dari `start` sampai `end` (tidak termasuk `end`) | nilai negatif diperbolehkan | | `substring(start, end)` | antara `start` dan `end` | nilai negatif berarti mean `0` | | `substr(start, length)` | dari `start` ambil `length` karakter | `start` negatif diperbolehkan | +======= +| `slice(start, end)` | from `start` to `end` (not including `end`) | allows negatives | +| `substring(start, end)` | between `start` and `end` (not including `end`)| negative values mean `0` | +| `substr(start, length)` | from `start` get `length` characters | allows negative `start` | +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```smart header="Cara mana yang harus kita gunakan?" Semuanya dapat melakukan pekerjaannya. Secara formal, `substr` memiliki kekurangan: fungsi ini tidak tercantum di spesifikasi inti Javascript, tetapi di Annex B, yang mencakup hanya fitur browser yang ada karena alasan historis. Jadi, environment non-browser mungkin gagal untuk mendukungnya. Tetapi dalam praktik fungsi ini bekerja di mana saja. +<<<<<<< HEAD Dibandingkan dengan dua varian yang lain, `slice` lebih fleksibel, karena memperbolehkan parameter negatif dan lebih pendek untuk ditulis. Jadi, dari ketiga cara sudah cukup untuk mengingat `slice`. +======= +Of the other two variants, `slice` is a little bit more flexible, it allows negative arguments and shorter to write. + +So, for practical use it's enough to remember only `slice`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ## Membandingkan string @@ -479,6 +573,7 @@ Akan tetapi, ada beberapa pengecualian. Hal ini dapat menyebabkan hasil yang aneh apabila kita mengurutkan nama-nama negara. Biasanya orang mengharapkan `Zealand` muncul setelah `Österreich` di daftar. +<<<<<<< HEAD Untuk memahami apa yang terjadi, mari kita review representasi internal string di Javascript. Semua string menggunakan encoding [UTF-16](https://en.wikipedia.org/wiki/UTF-16). Yaitu: setiap karakter memiliki masing-masing kode numerik. Ada method spesial yang memperbolehkan kita untuk mengambil karakter dari kode dan sebaliknya. @@ -489,7 +584,20 @@ Semua string menggunakan encoding [UTF-16](https://en.wikipedia.org/wiki/UTF-16) ```js run // karakter dengan case yang berbeda memiliki kode berbeda alert( "z".codePointAt(0) ); // 122 +======= +To understand what happens, we should be aware that strings in Javascript are encoded using [UTF-16](https://en.wikipedia.org/wiki/UTF-16). That is: each character has a corresponding numeric code. + +There are special methods that allow to get the character for the code and back: + +`str.codePointAt(pos)` +: Returns a decimal number representing the code for the character at position `pos`: + + ```js run + // different case letters have different codes +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 alert( "Z".codePointAt(0) ); // 90 + alert( "z".codePointAt(0) ); // 122 + alert( "z".codePointAt(0).toString(16) ); // 7a (if we need a hexadecimal value) ``` `String.fromCodePoint(code)` @@ -497,6 +605,7 @@ Semua string menggunakan encoding [UTF-16](https://en.wikipedia.org/wiki/UTF-16) ```js run alert( String.fromCodePoint(90) ); // Z +<<<<<<< HEAD ``` Kita juga dapat membuat karakter unicode dengan kode mereka menggunakan `\u` yang diikuti oleh kode heksadesimal: @@ -504,6 +613,9 @@ Semua string menggunakan encoding [UTF-16](https://en.wikipedia.org/wiki/UTF-16) ```js run // 90 bernilai 5a di dalam sistem heksadesimal alert( '\u005a' ); // Z +======= + alert( String.fromCodePoint(0x5a) ); // Z (we can also use a hex value as an argument) +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` Sekarang mari kita lihat karakter dengan kode di antara `65..220` (alfabet latin dan sedikit tambahan) dengan membuat string yang terdiri dari mereka: @@ -515,6 +627,7 @@ for (let i = 65; i <= 220; i++) { str += String.fromCodePoint(i); } alert( str ); +// Output: // ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„ // ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜ ``` @@ -534,7 +647,11 @@ Algoritma yang "benar" untuk melakukan perbandingan string lebih kompleks dari k Jadi, browser harus tahu bahasa yang digunakan untuk perbandingan. +<<<<<<< HEAD Beruntungnya, semua browser modern (IE10- memerlukan library tambahan [Intl.JS](https://github.com/andyearnshaw/Intl.js/)) mendukung standar internasionalisasi [ECMA 402](http://www.ecma-international.org/ecma-402/1.0/ECMA-402.pdf). +======= +Luckily, modern browsers support the internationalization standard [ECMA-402](https://www.ecma-international.org/publications-and-standards/standards/ecma-402/). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Hal tersebut menyediakan cara spesial untuk membandingkan stringi di berbeda bahasa, mengikuti peraturan mereka. @@ -552,6 +669,7 @@ alert( 'Österreich'.localeCompare('Zealand') ); // -1 Method ini sebenarnya menerima 2 argumen tambahan yang disebutkan di [dokumentasi](mdn:js/String/localeCompare), yang memperbolehkan untuk menyebutkan bahasa (yang biasanya diambil dari environment, urutan huruf bergantung dari bahasa) dan menyebutkan peraturan-peraturan tambahan seperti case sensitivity atau apakah `"a"` and `"á"` dianggap sama dan seterusnya. +<<<<<<< HEAD ## Bagian internal dari unicode ```warn header="Pengetahuan lanjutan" @@ -669,6 +787,17 @@ Jika Anda ingin belajar lebih lanjut tentang aturan normalisasi dan variasinya - - Untuk mengubah case kecil/besar dari string, gunakan: `toLowerCase/toUpperCase`. - Untuk mencari substring, gunakan: `indexOf`, atau `includes/startsWith/endsWith` untuk pengecekan sederhana. - Untuk membandingkan string mengikuti bahasa, gunakan `localeCompare`, jika tidak mereka akan dibandingkan berdasarkan kode karakter. +======= +## Summary + +- 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: `[]` 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. +- To compare strings according to the language, use: `localeCompare`, otherwise they are compared by character codes. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Ada beberapa metode string lain yang berguna: @@ -676,4 +805,10 @@ Ada beberapa metode string lain yang berguna: - `str.repeat(n)` -- mengulang string sebanyak `n` kali. - ...dan masih banyak lagi yang dapat ditemukan di dalam [manual](mdn:js/String). +<<<<<<< HEAD String juga memiliki method-method untuk mencari/mengganti dengan ekspresi reguler (regular expression). Tetapi itu adalah topik yang luas, jadi topik ini dibahas di bagiannya sendiri . +======= +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 . + +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 . +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/1-js/05-data-types/04-array/10-maximal-subarray/solution.md b/1-js/05-data-types/04-array/10-maximal-subarray/solution.md index f9d2db39a..cc97bde23 100644 --- a/1-js/05-data-types/04-array/10-maximal-subarray/solution.md +++ b/1-js/05-data-types/04-array/10-maximal-subarray/solution.md @@ -59,7 +59,11 @@ alert( getMaxSubSum([100, -9, 2, -3, 5]) ); // 100 Solusi tersebut memiliki waktu penyelesaian [O(n2)](https://en.wikipedia.org/wiki/Big_O_notation). Dalam kata lain, jika kita menambah ukuran *array* 2 kali lipat, algoritma akan bekerja 4 kali lipat lebih lama. +<<<<<<< HEAD Untuk *array* yang besar (1000, 10000 *item* atau lebih) algoritma yang demikian akan mengarah pada kelambanan yang parah. +======= +For big arrays (1000, 10000 or more items) such algorithms can lead to serious sluggishness. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 # Solusi cepat @@ -91,4 +95,8 @@ alert( getMaxSubSum([-1, -2, -3]) ); // 0 Algoritma tersebut membutuhkan tepat 1 *array* yang lolos, jadi waktu penyelesaian adalah O(n). +<<<<<<< HEAD Kamu dapat menemukan informasi yang lebih rinci tentang algoritma di sini: [Masalah *subarray* maksimum](http://en.wikipedia.org/wiki/Maximum_subarray_problem). Jika masih kurang jelas bagaimana hal tersebut bekerja, maka mohon menelusuri algoritma pada contoh di atas, perhatikan bagaimana algoritmanya bekerja, itulah cara yang paling baik. +======= +You can find more detailed information about the algorithm here: [Maximum subarray problem](http://en.wikipedia.org/wiki/Maximum_subarray_problem). If it's still not obvious why that works, then please trace the algorithm on the examples above, see how it works, that's better than any words. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/1-js/05-data-types/04-array/2-create-array/task.md b/1-js/05-data-types/04-array/2-create-array/task.md index e74f23a47..5429e1165 100644 --- a/1-js/05-data-types/04-array/2-create-array/task.md +++ b/1-js/05-data-types/04-array/2-create-array/task.md @@ -6,11 +6,19 @@ importance: 5 Mari coba 5 operasi *array*. +<<<<<<< HEAD 1. Buat sebuah *array* `styles` dengan elemen "Jazz" dan "Blues" di dalamnya. 2. Tambahkan "Rock-n-Roll" pada akhir *array*. 3. Ganti nilai yang berada di tengah menjadi "Classics". Kodemu untuk menemukan nilai di tengah harus berhasil untuk *array* sepanjang apapun. 4. Hilangkan nilai pertama dari *array* lalu tampilkan *array*. 5. Dahulan *array* dengan `Rap` and `Reggae` di depannya. +======= +1. Create an array `styles` with items "Jazz" and "Blues". +2. Append "Rock-n-Roll" to the end. +3. Replace the value in the middle with "Classics". Your code for finding the middle value should work for any arrays with odd length. +4. Strip off the first value of the array and show it. +5. Prepend `Rap` and `Reggae` to the array. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 *Array* selama proses: diff --git a/1-js/05-data-types/04-array/3-call-array-this/task.md b/1-js/05-data-types/04-array/3-call-array-this/task.md index dfe8704aa..eb1586af1 100644 --- a/1-js/05-data-types/04-array/3-call-array-this/task.md +++ b/1-js/05-data-types/04-array/3-call-array-this/task.md @@ -11,7 +11,7 @@ let arr = ["a", "b"]; arr.push(function() { alert( this ); -}) +}); arr[2](); // ? ``` diff --git a/1-js/05-data-types/04-array/article.md b/1-js/05-data-types/04-array/article.md index 813c1bf88..ab32bf5e0 100644 --- a/1-js/05-data-types/04-array/article.md +++ b/1-js/05-data-types/04-array/article.md @@ -92,6 +92,38 @@ let fruits = [ Gaya "tanda koma yang membuntuti" membuat lebih mudah untuk memasukkan/menghilangkan item dari sebuah array, karena semua baris serupa. ```` +## Get last elements with "at" + +[recent browser="new"] + +Let's say we want the last element of the array. + +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. + +We can explicitly calculate the last element index and then access it: `fruits[fruits.length - 1]`. + +```js run +let fruits = ["Apple", "Orange", "Plum"]; + +alert( fruits[fruits.length-1] ); // Plum +``` + +A bit cumbersome, isn't it? We need to write the variable name twice. + +Luckily, there's a shorter syntax: `fruits.at(-1)`: + +```js run +let fruits = ["Apple", "Orange", "Plum"]; + +// same as fruits[fruits.length-1] +alert( fruits.at(-1) ); // Plum +``` + +In other words, `arr.at(i)`: +- is exactly the same as `arr[i]`, if `i >= 0`. +- for negative values of `i`, it steps back from the end of the array. ## Metode *pop*/*push*, *shift*/*unshift* @@ -121,9 +153,15 @@ Sebuah *stack* biasanya diilustrasikan sebagai sebuah *pack* kartu: kartu-kartu Untuk *stack*, elemen terakhir yang di-*push* diterima lebih dulu, hal itu juga disebut sebagai prinsip LIFO (*Last-In-First-Out*) atau "terakhir masuk, pertama keluar". Sedangkan untuk *queue*, kita memiliki prinsip (*First-In-First-Out*) atau "pertama masuk, pertama keluar". +<<<<<<< HEAD *Array* dalam JavaScript dapat bekerja baik sebagai sebuah *queue* maupun *stack*. Keduanya membuat kamu bisa menambahkan/menghilangkan elemen baik dari/ke awal ataupun akhir. Dalam *computer science* struktur data yang memungkinkan kita bisa melakukan hal-hal demikian disebut sebagai [*deque* (*double-ended queue*)](https://en.wikipedia.org/wiki/Double-ended_queue). +======= +Arrays in JavaScript can work both as a queue and as a stack. They allow you to add/remove elements, both to/from the beginning or the end. + +In computer science, the data structure that allows this, is called [deque](https://en.wikipedia.org/wiki/Double-ended_queue). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 **Metode yang berfungsi dengan bagian akhir dari _array_:** @@ -138,6 +176,8 @@ Dalam *computer science* struktur data yang memungkinkan kita bisa melakukan hal alert( fruits ); // Apple, Orange ``` + Both `fruits.pop()` and `fruits.at(-1)` return the last element of the array, but `fruits.pop()` also modifies the array by removing it. + `push` : Mendorong elemen ke bagian akhir *array*: @@ -248,7 +288,11 @@ Mengapa bekerja dengan bagian akhir sebuah *array* ketimbang bagian depannya? Ma fruits.shift(); // mengambil 1 elemen dari bagian awal ``` +<<<<<<< HEAD Tidaklah cukup mengambil dan menghapus elemen dengan angka `0`. Elemen lainnya juga perlu diberi angka pula. +======= +It's not enough to take and remove the element with the index `0`. Other elements need to be renumbered as well. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Operasi `shift` harus menjalankan 3 hal: @@ -366,11 +410,19 @@ Ada satu sintaks lagi untuk membuat sebuah *array*: let arr = *!*new Array*/!*("Apple", "Pear", "etc"); ``` +<<<<<<< HEAD Sintaks tersebut jarang digunakan, karena tanda kurung siku `[]` lebih pendek. Juga terdapat sebuah fitur yang sukar di dalamnya. +======= +It's rarely used, because square brackets `[]` are shorter. Also, there's a tricky feature with it. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Jika `new Array` dipanggil dengan sebuah argumen tunggal yang mana adalah sebuah angka, maka sintaks tersebut akan membuat sebuah *array* yang *tanpa elemen, namun dengan panjang sesuai yang diberikan*. +<<<<<<< HEAD Mari lihat bagaimana orang-orang bisa terjebak dengan hal ini: +======= +Let's see how one can shoot themselves in the foot: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let arr = new Array(2); // akankah membuat sebuah array berisi [2] ? @@ -395,7 +447,11 @@ let matrix = [ [7, 8, 9] ]; +<<<<<<< HEAD alert( matrix[1][1] ); // 5, elemen pusat +======= +alert( matrix[0][1] ); // 2, the second value of the first inner array +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ## toString @@ -442,7 +498,11 @@ Mari kita ingat aturannya: - Jika salah satu argumen `==` adalah objek, dan argumen lainnya primitif, objek tersebut akan diubah menjadi primitif, seperti yang dijelaskan pada bab . - ... Dengan pengecualian `null` dan` undefined` yang sama `==` satu sama lain dan tidak ada yang lain. +<<<<<<< HEAD Perbandingan ketat `===` bahkan lebih sederhana, karena tidak mengonversi jenis. +======= +The strict comparison `===` is even simpler, as it doesn't convert types. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Jadi, jika kita membandingkan array dengan `==`, keduanya tidak akan pernah sama, kecuali jika kita membandingkan dua variabel yang mereferensikan array yang sama persis. @@ -462,7 +522,11 @@ alert( 0 == [] ); // true alert('0' == [] ); // false ``` +<<<<<<< HEAD Di sini, dalam kedua kasus, kami membandingkan primitif dengan objek array. Jadi, array `[]` diubah menjadi primitif untuk tujuan perbandingan dan menjadi string kosong `` '' `. +======= +Here, in both cases, we compare a primitive with an array object. So the array `[]` gets converted to primitive for the purpose of comparison and becomes an empty string `''`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Kemudian proses perbandingan berlanjut dengan primitif, seperti yang dijelaskan dalam bab : @@ -481,6 +545,7 @@ Sederhana saja: jangan gunakan operator `==`. Sebaliknya, bandingkan item-by-ite *Array* adalah sebuah objek berjenis khusus, cocok untuk menyimpan dan mengelola data yang tersusun. +<<<<<<< HEAD - Deklarasinya: ```js @@ -492,11 +557,33 @@ Sederhana saja: jangan gunakan operator `==`. Sebaliknya, bandingkan item-by-ite ``` Panggilan `new Array(number)` membuat sebuah *array* dengan panjang indeks (*length*) yang diberikan, tetapi tanpa elemen. +======= +The declaration: + +```js +// square brackets (usual) +let arr = [item1, item2...]; + +// new Array (exceptionally rare) +let arr = new Array(item1, item2...); +``` + +The call to `new Array(number)` creates an array with the given length, but without elements. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 - Properti `length` adalah panjang *array* atau, lebih tepatnya, angka indeks terakhir plus satu. Hal tersebut secara otomatis diatur dengan metode *array*. - Jika kita memendekkan `length` secara manuak, *array* tersebut akan terpotong. +<<<<<<< HEAD Kita bisa menggunakan sebuah *array* sebagai sebuah *deque* dengan operasi sebagai berikut: +======= +Getting the elements: + +- we can get element by its index, like `arr[0]` +- also we can use `at(i)` method that allows negative indexes. For negative values of `i`, it steps back from the end of the array. If `i >= 0`, it works same as `arr[i]`. + +We can use an array as a deque with the following operations: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 - `push(...items)` menambahkan `items` ke bagian akhir *array*. - `pop()` menghilangkan elemen dari bagian akhir *array* dan mengembalikannya. diff --git a/1-js/05-data-types/05-array-methods/12-reduce-object/task.md b/1-js/05-data-types/05-array-methods/12-reduce-object/task.md index d939723d4..7257b05f4 100644 --- a/1-js/05-data-types/05-array-methods/12-reduce-object/task.md +++ b/1-js/05-data-types/05-array-methods/12-reduce-object/task.md @@ -4,7 +4,11 @@ nilai penting: 4 # Buatlah objek dengan kunci dari array +<<<<<<< HEAD Anggaplah kita menerima sebuah array dari user didalam form `{id:..., name:..., age... }`. +======= +Let's say we received an array of users in the form `{id:..., name:..., age:... }`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Buatlah sebuah fungsi `groupById(arr)` yang membuat sebuah objek, dengan `id` sebagai key/kunci, dan item array sebagai nilai diff --git a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/test.js b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/test.js index db32d9a11..241b74c6e 100644 --- a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/test.js +++ b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/test.js @@ -4,13 +4,13 @@ describe("filterRangeInPlace", function() { let arr = [5, 3, 8, 1]; - filterRangeInPlace(arr, 1, 4); + filterRangeInPlace(arr, 2, 5); - assert.deepEqual(arr, [3, 1]); + assert.deepEqual(arr, [5, 3]); }); it("doesn't return anything", function() { assert.isUndefined(filterRangeInPlace([1,2,3], 1, 4)); }); -}); \ No newline at end of file +}); diff --git a/1-js/05-data-types/05-array-methods/article.md b/1-js/05-data-types/05-array-methods/article.md index bb1b59be7..e19f24663 100644 --- a/1-js/05-data-types/05-array-methods/article.md +++ b/1-js/05-data-types/05-array-methods/article.md @@ -1,6 +1,10 @@ # Metode *array* +<<<<<<< HEAD *Array* menyediakan begitu banyak metode. Untuk mempermudah, dalam bab ini metode-metode tersebut dibagi menjadi beberapa kelompok. +======= +Arrays provide a lot of methods. To make things easier, in this chapter, they are split into groups. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Menambahkan/menghapus *item* @@ -32,11 +36,19 @@ alert( arr.length ); // 3 Elemen tersebut telah dihapus, tetapi *array* itu masih memiliki 3 elemen, kita bisa melihat bahwa `arr.length == 3`. +<<<<<<< HEAD Hal itu alami, karena `delete obj.key` menghilangkan sebuah nilai berdasarkan `key`. Itulah yang dilakukannya. Tidak masalah bagi objek. Tapi untuk *array* kita biasanya ingin elemen yang tersisa untuk bergeser dan mengisi ruang yang dikosongkan tadi. Kita ingin memiliki sebuah *array* yang lebih pendek sekarang. +======= +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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Jadi, metode khusus harus digunakan. +<<<<<<< HEAD Metode [arr.splice(start)](mdn:js/Array/splice) adalahs sebuah fungsi serbaguna untuk *array*. *Splice* bisa melakukan banyak hal: memasukkan, menghilangkan serta mengganti elemen. +======= +The [arr.splice](mdn:js/Array/splice) method is a Swiss army knife for arrays. It can do everything: insert, remove and replace elements. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Sintaksnya yakni: @@ -64,7 +76,11 @@ alert( arr ); // ["I", "JavaScript"] Mudah, kan? Mulai dari indeks `1` metode ini menghilangkan elemen di indeks `1`. +<<<<<<< HEAD Dalam contoh selanjutnya kita menghilangkan 3 element dan menggantinya dengan 2 elemen lain: +======= +In the next example, we remove 3 elements and replace them with the other two: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let arr = [*!*"I", "study", "JavaScript",*/!* "right", "now"]; @@ -86,7 +102,11 @@ let removed = arr.splice(0, 2); alert( removed ); // "I", "study" <-- array yang berisi elemen-elemen yang dihapus ``` +<<<<<<< HEAD Metode `splice` juga mampu memasukkan elemen tanpa menghilangkan elemen apapun yang ada sebelumnya. Untuk itu kita perlu mengatur `deleteCount` menjadi `0`: +======= +The `splice` method is also able to insert the elements without any removals. For that, we need to set `deleteCount` to `0`: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let arr = ["I", "study", "JavaScript"]; @@ -116,7 +136,11 @@ alert( arr ); // 1,2,3,4,5 ### *slice* +<<<<<<< HEAD Metode [arr.slice](mdn:js/Array/slice) lebih sederhana daripada metode serupa sebelumnya yakni `arr.splice`. +======= +The method [arr.slice](mdn:js/Array/slice) is much simpler than the similar-looking `arr.splice`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Sintaksnya adalah: @@ -126,7 +150,11 @@ arr.slice([start], [end]) Metode ini mengembalikan sebuah sebuah *array* baru hasil salinan semua *item* yang ada dari indeks `start` hingga `end` (indeks `end` tidak termasuk). Baik `start` maupun `end` bisa saja negatif, dalam kasus tersebut posisi dari bagian akhir *array* sudah diasumsikan/diperkirakan. +<<<<<<< HEAD Mirip dengan metode *string* `str.slice`, namun membuat *subarray* bukan *substring*. +======= +It's similar to a string method `str.slice`, but instead of substrings, it makes subarrays. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Contohnya: @@ -208,7 +236,7 @@ Metode [arr.forEach](mdn:js/Array/forEach) membuat kita dapat menjalankan sebuah Sintaksnya: ```js arr.forEach(function(item, index, array) { - // ... do something with item + // ... do something with an item }); ``` @@ -236,6 +264,7 @@ Kini mari membahas metode-metode yang bertugas mencari dalam *array*. ### *indexOf/lastIndexOf* dan *includes* +<<<<<<< HEAD Metode [arr.indexOf](mdn:js/Array/indexOf), [arr.lastIndexOf](mdn:js/Array/lastIndexOf) dan [arr.includes](mdn:js/Array/includes) memiliki sintaks yang sama dan pada dasarnya keduanya melakukan fungsi yang samahave the same syntax, namun untuk mengoperasikannya perlu ditujukan *item* bukan karakter: - `arr.indexOf(item, from)` -- mencari `item` dimulai dari indeks `from`, dan mengembalikan indeks dimana *item* yang dicari itu ditemukan, jika tidak akan mengembalikan `-1`. @@ -243,6 +272,16 @@ Metode [arr.indexOf](mdn:js/Array/indexOf), [arr.lastIndexOf](mdn:js/Array/lastI - `arr.includes(item, from)` -- mencari `item` dimulai dari indeks `from`, mengembalkikan `true` jika yang dicari itu ditemukan. Contohnya: +======= +The methods [arr.indexOf](mdn:js/Array/indexOf) and [arr.includes](mdn:js/Array/includes) have the similar syntax and do essentially the same as their string counterparts, but operate on items instead of characters: + +- `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. + +For instance: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let arr = [1, 0, false]; @@ -254,6 +293,7 @@ alert( arr.indexOf(null) ); // -1 alert( arr.includes(1) ); // true ``` +<<<<<<< HEAD Perlu diperhatikan bahwa metode tersebut menggunakan perbandingan `===`. Jadi, jika kita mencari `false`, metode ini akan tepat mencari `false` dan bukan nol. Jika kita ingin memeriksa pencantuman, dan tidak ingin tahu indeks yang persis, maka direkomendasikan menggunakan `arr.includes`. @@ -264,11 +304,41 @@ Juga, perbedaan kecil dari `includes` yakni metode ini menangani `NaN` dengan te const arr = [NaN]; alert( arr.indexOf(NaN) ); // -1 (seharusnya 0, tetapi tanda persamaan === tidak berfungsi pada NaN) alert( arr.includes(NaN) );// true (benar) +======= +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 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. + +```js run +let fruits = ['Apple', 'Orange', 'Apple'] + +alert( fruits.indexOf('Apple') ); // 0 (first Apple) +alert( fruits.lastIndexOf('Apple') ); // 2 (last Apple) ``` +````smart header="The `includes` method handles `NaN` correctly" +A minor, but noteworthy feature of `includes` is that it correctly handles `NaN`, unlike `indexOf`: + +```js run +const arr = [NaN]; +alert( arr.indexOf(NaN) ); // -1 (wrong, should be 0) +alert( arr.includes(NaN) );// true (correct) +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 +``` +That's because `includes` was added to JavaScript much later and uses the more up-to-date comparison algorithm internally. +```` + +<<<<<<< HEAD ### *find* dan *findIndex* Bayangkan kita memiliki sebuah *array* berisi objek. Bagaimana cata kita menemukan sebuah objek dengan kondisi tertentu? +======= +### find and findIndex/findLastIndex + +Imagine we have an array of objects. How do we find an object with a specific condition? +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Berikut ini ada metode [arr.find(fn)](mdn:js/Array/find) yang dapat mudah digunakan. @@ -286,7 +356,11 @@ Fungsi tersebut dipanggil untuk elemen-elemen dalam *array*, satu sama lainnya: - `index` adalah indeks elemen tersebut. - `array` adalah *array* itu sendiri. +<<<<<<< HEAD Jika fungsi tersebut mengembalikan `true`, pencarian dihentikan, lalu `item` akan dikembalikan. Jika tidak ditemukan apa-apa, `undefined` yang dikembalikan. +======= +If it returns `true`, the search is stopped, the `item` is returned. If nothing is found, `undefined` is returned. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Sebagai contoh, kita memiliki sebuah *array* berisi elemen pengguna, tiap pengguna memiliki *field* `id` dan `name`. Mari cari pengguna dengan `id == 1`: @@ -302,11 +376,38 @@ let user = users.find(item => item.id == 1); alert(user.name); // John ``` +<<<<<<< HEAD Pada kehidupan nayata *array* berisi objek adalah hal yang umum, jadi metode `find` sangatlah berguna. +======= +In real life, arrays of objects are a common thing, so the `find` method is very useful. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Ingat bahwa contoh yang kami berikan untuk mencari (`find`) fungsi `item => item.id == 1` hanya dengan satu argumen. Ini adalah hal umum, argumen lainnya pada fungsi lainnya jarang digunakan. +<<<<<<< HEAD Metode [arr.findIndex](mdn:js/Array/findIndex) pada dasarnya sama, namun mengembalikan indeks dimana elemen tersebut ditemukan bukan elemen itu sendiri serta mengembalikan `-1` ketika tidak ditemukan apapun. +======= +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`. + +Here's an example: + +```js run +let users = [ + {id: 1, name: "John"}, + {id: 2, name: "Pete"}, + {id: 3, name: "Mary"}, + {id: 4, name: "John"} +]; + +// Find the index of the first John +alert(users.findIndex(user => user.name == 'John')); // 0 + +// Find the index of the last John +alert(users.findLastIndex(user => user.name == 'John')); // 3 +``` +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ### *filter* @@ -390,7 +491,12 @@ Secara harfiah, semua elemen dikonversi menjadi *string* untuk dibandingkan. Sed Untuk menggunakan urutan penataan kita sendiri, kita perlu memberikan sebuah fungsi sebagai argumen pada `arr.sort()`. +<<<<<<< HEAD Fungsi tersebut harus membandingkan dua nilai yang berubah-ubah dan mengembalikan (hasilnya): +======= +The function should compare two arbitrary values and return: + +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js function compare(a, b) { if (a > b) return 1; // if the first value is greater than the second @@ -419,11 +525,19 @@ alert(arr); // *!*1, 2, 15*/!* Kini metode tersebu berfungsi seperti yang diinginkan. +<<<<<<< HEAD Mari berhenti sejenak dan pikirkan apa yang terjadi. `arr` bisa jadi *array* berisi apapun, benar? *Array* itu bisa saja berisi angka atau *string* atau objek atau apapun. Kita memiliki sekumpulan *beberapa item*. Untuk mengurutkannya, kita perlu sebuah *fungsi pengurutan* yang tahu bagaimana cara untuk membandingkan elemen-elemen. Setelan awalnya adalah sebuah urutan *string*. +======= +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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Metode `arr.sort(fn)` mengimplementasikan sebuah algoritma pengurutan yang umum. Kita tidak perlu benar-benar tahu bagaimana algoritma itu bekerja (sebuah [cara cepat/*quicksort*](https://en.wikipedia.org/wiki/Quicksort) yang sudah teroptimasi sepanjang waktu). Algoritma itu akan menyusuri *array*, membandungkan elemen-elemennya menggunakan fungsi yang diberikan dan mengurutkan ulang elemen-elemen tersebut, yang perlu kita lakukan yakni memberikan `fn` yang mana akan melakukan operasi perbandingan. +<<<<<<< HEAD *Ngomong-omong*, jika kita pernah ingin tahu elemen mana saja yang dibandingkan -- cukup dengan cara memberi *alert*: +======= +By the way, if we ever want to know which elements are compared -- nothing prevents us from alerting them: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run [1, -2, 15, 2, 0, 8].sort(function(a, b) { @@ -480,7 +594,11 @@ Ini adalah situasi dari dunia nyata. Kita menulis sebuah aplikasi olahpesan, dan Metode [str.split(delim)](mdn:js/String/split) melakukan tepat hal yang dijelaskan di atas. Metode ini memisahkan *string* ke dalam *array* dengan *delimiter* (pemisah) `delim`. +<<<<<<< HEAD Dalam contoh berikut ini, kita memisahkan elemen dengan tanda koma yang diikuti oleh spasi: +======= +In the example below, we split by a comma followed by a space: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let names = 'Bilbo, Gandalf, Nazgul'; @@ -547,9 +665,15 @@ Argument-argumennya yakni: - `index` -- adalah posisi *item* tersebut. - `array` -- adalah *array*-nya. +<<<<<<< HEAD Jika fungsi sudah diterapkan, masil dari panggilan fungsi sebelumnya dioper ke panggilan selanjutnya sebagai argumen pertama. Memang terdengar rumit, tapi tidak seperti yang kamu pikirkan tentang argumen pertama sebagai "akumulator" yang menyimpan dan menggabungkan jasil dari semua eksekusi sebelumnya. Serta pada akhirnya, itu menjadi hasil dari `reduce`. +======= +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`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Cara termudah untuk memahami metode ini adalah dengan melihat contohnya. @@ -615,10 +739,14 @@ arr.reduce((sum, current) => sum + current); ``` +<<<<<<< HEAD Jadi sangat disarankan untuk selalu menspesifikasikan nilai awal. Metode [arr.reduceRight](mdn:js/Array/reduceRight) melaksanakan hal yang sama, tapi beroperasi dari kanan ke kiri. +======= +The method [arr.reduceRight](mdn:js/Array/reduceRight) does the same but goes from right to left. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Array.isArray @@ -627,8 +755,13 @@ Metode [arr.reduceRight](mdn:js/Array/reduceRight) melaksanakan hal yang sama, t Jadi `typeof` tidak membantu membedakan sebuah objek polos dari sebuah *array*: ```js run +<<<<<<< HEAD alert(typeof {}); // objek alert(typeof []); // sama +======= +alert(typeof {}); // object +alert(typeof []); // object (same) +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ...Tetapi *array* serung diguakan hingga ada metode khusus untuk hal ini: [Array.isArray(value)](mdn:js/Array/isArray). Metode ini mengembalikan `true` jika `value` adalah sebuah *array*, dan `false` jika sebaliknya. @@ -643,7 +776,11 @@ alert(Array.isArray([])); // true Hamppir semua metode *array* yang memanggil fungsi -- seperti `find`, `filter`, `map`, dengan pengecualian `sort`, menerima paramater tambahan yakni `thisArg`. +<<<<<<< HEAD Parameter itu tidak dijelaskan pada bab sebelumnya, karena jarang digunakan. Tetapi demi kelengkapan kita harus menutupi metodenya. +======= +That parameter is not explained in the sections above, because it's rarely used. But for completeness, we have to cover it. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Berikut ini adalah sintkas lengkap dari metode-metode tersebut: @@ -702,11 +839,19 @@ Sebuah panggilan ke `users.filter(army.canJoin, army)` bisa diganti dengan `user - `slice(start, end)` -- membuat *array* baru, menyalin elemen dari posisi `start` hingga `end` (tidak inklusif) ke dalam *array* baru tersebut. - `concat(...items)` --mengembalikan sebuah *array* baru: menyalin semua anggota *array* yang sekarang dan menambahkan `items` ke dalamnya. Jika `items` adalah sebuah *array*, maka elemennya yang akan diambil. +<<<<<<< HEAD - Untuk mencari di antara elemen-elemen: - `indexOf/lastIndexOf(item, pos)` -- mencari `item` mulai dari posisi `pos`, mengembalikan indeksnya atau `-1` jika tidak ditemukan. - `includes(value)` -- mengembalikan `true` jika *array* memiliki `value`, jika tidak akan mengembalikan `false`. - `find/filter(func)` -- menyaring elemen dengan menggunakan fungsi, mengembalikan nilai awal/semua nilai yang membuat hasil *return*-nya menjadi `true`. - `findIndex` seperti `find`, namun mengembalikan indeks bukan nilai. +======= +- To search among elements: + - `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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 - Untuk mengulang elemen: - `forEach(func)` -- memanggil `func` untuk setiap elemen, tidak mengembalikan apapun. @@ -718,8 +863,13 @@ Sebuah panggilan ke `users.filter(army.canJoin, army)` bisa diganti dengan `user - `split/join` -- mengonversi sebuah *string* menjadi *array* dan sebaliknya. - `reduce(func, initial)` -- menghitung sebuah nilai tunggal pada *array* dengan cara memanggil `func` untuk setiap elemen dan mengoper hasil tersebut di antara panggilan. +<<<<<<< HEAD - Sebagai tambahan: - `Array.isArray(arr)` memeriksa apakah `arr` merupakan *array* atau bukan. +======= +- Additionally: + - `Array.isArray(value)` checks `value` for being an array, if so returns `true`, otherwise `false`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Tolong diingat bahwa metode `sort`, `reverse` dan `splice` memodifikasi *array* itu sendiri. @@ -731,7 +881,12 @@ Metode-metode ini adalah yang paling sering digunakan, mencakupi 99% kasus pengg Metode ini berperilaku seperti operator `||` dan `&&`: jika `fn` mengembalikan nilai yang sebenarnya,` arr.some () `segera mengembalikan` true` dan berhenti melakukan iterasi pada item lainnya; jika `fn` mengembalikan nilai yang salah,` arr.every () `segera mengembalikan` false` dan juga menghentikan iterasi pada item lainnya. +<<<<<<< HEAD Kita bisa menggunakan `every` untuk membandingkan array: +======= + We can use `every` to compare arrays: + +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run function arraysEqual(arr1, arr2) { return arr1.length === arr2.length && arr1.every((value, index) => value === arr2[index]); @@ -748,7 +903,11 @@ Metode-metode ini adalah yang paling sering digunakan, mencakupi 99% kasus pengg Untuk daftar lengkapnya, lihat [manual](mdn:js/Array). +<<<<<<< HEAD Sejak pandangan pertama mungkin terlihat ada begitu banyak metode, cukup sulit untuk diingat. Namun sebenarnya hal itu jauh lebih mudah. +======= +At first sight, it may seem that there are so many methods, quite difficult to remember. But actually, that's much easier. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Lihat *cheat sheet* hanya untuk sekedar tahu semua metode tersebut. Lalu selesaikan *task* bab ini sebagai latihan, jadi kamu memiliki pengalaman mengenai metode *array*. diff --git a/1-js/05-data-types/06-iterable/article.md b/1-js/05-data-types/06-iterable/article.md index c394ead3f..dab3d5615 100644 --- a/1-js/05-data-types/06-iterable/article.md +++ b/1-js/05-data-types/06-iterable/article.md @@ -28,10 +28,17 @@ let range = { Untuk bisa membuat `range` bisa diiterasi (dan membuat `for..of` bekerja) kita harus menambahkan sebuah metode kedalam objeknya bernama `Symbol.iterator` (Simbol built-in spesian yang hanya digunakan untuk hal itu). +<<<<<<< HEAD 1. Ketika `for.of` dimulai, itu akan memanggil metodenya sekali (atau error jika tidak ditemukan). Metodenya haruslah mengembalikan sebuah *iterator* -- sebuah objek dengan metode `next`. 2. Selanjutnya, `for..of` bekerja *hanya bila itu mengembalikan objek*. 3. Ketika `for..of` menginginkan nilai selanjutnya, itu akan memanggil `next()` didalam objeknya. 4. Hasil dari `next()` harus mempunyai form `{done: Boolean, value: any}`, dimana `done=true` berarti iterasinya telah selesai, sebaliknya `value` adalah nilai selanjutnya. +======= +1. When `for..of` starts, it calls that method once (or errors if not found). The method must return an *iterator* -- an object with the method `next`. +2. Onward, `for..of` works *only with that returned object*. +3. When `for..of` wants the next value, it calls `next()` on that object. +4. The result of `next()` must have the form `{done: Boolean, value: any}`, where `done=true` means that the loop is finished, otherwise `value` is the next value. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Ini adalah implementasi penuh untuk `range` dengan catatan: @@ -44,11 +51,16 @@ let range = { // 1. panggil for..of pertama kali untuk memanggil ini range[Symbol.iterator] = function() { +<<<<<<< HEAD // ini akan mengembalikan objek iterator: // 2. Selanjutnya, for..of hanya bekerja dengan iterator ini, menanyakan nilai selanjutnya +======= + // ...it returns the iterator object: + // 2. Onward, for..of works only with the iterator object below, asking it for next values +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 return { current: this.from, - last: this.to, + last: this.to, // 3. next() dipanggil untuk setiap iterasi oleh perulangan for..of next() { @@ -174,7 +186,11 @@ ketika kita menggunakan javascript untuk melakukan prakter didalam browser atau Contoh, string adalah keduanya, bisa diiterasi (`for..of` dapat bekerja) dan seperti array(mempunyai indeks angka dan `length`(panjang)). +<<<<<<< HEAD Akan tetapi bisa diiterasi mungkin bukanlah array. Dan sebaliknya sebuah array mungkin tidak bisa diiterasi. +======= +But an iterable may not be array-like. And vice versa an array-like may not be iterable. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Contoh, `range` di contoh diatas bisa diiterasi, tapi tidak seperti array, karena itu tidak memiliki properti indeks dan `length`. @@ -218,8 +234,13 @@ alert(arr.pop()); // World (metode bekerja) Hal yang serupa terjadi untuk sesuatu yang bisa diiterasi: +<<<<<<< HEAD ```js // asumsikan bahwa range diambil dari contoh diatas +======= +```js run +// assuming that range is taken from the example above +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 let arr = Array.from(range); alert(arr); // 1,2,3,4,5 (konversi array toString bekerja) ``` @@ -233,8 +254,13 @@ Argumen kedua yang opsional `mapFn` bisa saja sebuah fungsi yang akan digunakan Contoh: +<<<<<<< HEAD ```js // asumsikan bahwa range diambil dari contoh diatas +======= +```js run +// assuming that range is taken from the example above +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 // kuadratkan setiap angka let arr = Array.from(range, num => num * num); @@ -271,7 +297,11 @@ for (let char of str) { alert(chars); ``` +<<<<<<< HEAD ...Tapi ini lebih pendek. +======= +...But it is shorter. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Kita bahkan bisa membangun `slice` pengganti didalamnya: diff --git a/1-js/05-data-types/07-map-set/article.md b/1-js/05-data-types/07-map-set/article.md index 9ec9951cf..0275e1b8b 100644 --- a/1-js/05-data-types/07-map-set/article.md +++ b/1-js/05-data-types/07-map-set/article.md @@ -10,10 +10,15 @@ Tapi itu tidak cukup dalam kehidupan nyata. Itu sebabnya `Map` dan` Set` juga ad ## Map +<<<<<<< HEAD [Map](mdn:js/Map) adalah kumpulan item data yang berkunci, seperti `Object`. Tetapi perbedaan utama adalah `Map` membolehkan kunci jenis apa pun. +======= +[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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Metode dan properti: +<<<<<<< HEAD - `new Map()` -- menciptakan map. - `map.set(key, value)` -- menyimpan nilai dengan kunci. - `map.get(key)` -- mengembalikan nilai dengan kunci, `undefined` jika` key` tidak ada di map. @@ -21,6 +26,15 @@ Metode dan properti: - `map.delete(key)` -- menghapus nilai dengan kunci. - `map.clear()` -- menghapus semua isi dari map. - `map.size` -- mengembalikan jumlah elemen saat ini. +======= +- [`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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Misalnya: @@ -100,14 +114,24 @@ map.set('1', 'str1') ``` ```` +<<<<<<< HEAD ## Iterasi Atas Map +======= +## Iteration over Map +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Untuk looping atas `map`, ada 3 method: +<<<<<<< HEAD - `map.keys()` -- mengembalikan iterable untuk kunci, - `map.values()` -- mengembalikan iterable untuk nilai, - `map.entries()` -- mengembalikan iterable untuk entri `[key, value]`, ini digunakan dengan standar di `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`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Misalnya: @@ -162,7 +186,11 @@ let map = new Map([ alert( map.get('1') ); // str1 ``` +<<<<<<< HEAD Jika kita memiliki objek biasa, dan kita mau menciptakan sebuah `Map` darinya, kita bisa menggunakan method built-in [Object.entries(obj)](mdn:js/Object/entries) yang mengembalikan array daripada pasangan-pasangan kunci/nilai untuk satu objek yang berformat persis sama. +======= +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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Jadi kita bisa menciptakan map dari objek seperti ini: @@ -233,16 +261,29 @@ Itu sama, karena `Object.fromEntries` mengharapkan objek iterabel sebagai argume ## Set +<<<<<<< HEAD `Set` adalah tipe koleksi spesial - "set nilai-nilai" (tanpa kunci), dimana setiap nilai hanya dapat terjadi sekali. +======= +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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Method utamanya adalah: +<<<<<<< HEAD - `new Set(iterable)` -- menciptakan set, dan jika objek `iterable` disediakan (biasanya array), menyalin nilai darinya ke set. - `set.add(value)` -- menambahkan nilai, mengembalikan set itu sendiri. - `set.delete(value)` -- menghapus nilai, mengembalikan `true` jika `value` ada pada saat panggilan berlangsung, jika tidak `false`. - `set.has(value)` -- mengembalikan `true` jika nilai ada di set, jika tidak `false`. - `set.clear()` -- menghapus semuanya dari set. - `set.size` -- adalah hitungan elemen. +======= +- [`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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Fitur utamanya adalah panggilan berulang `set.add(value)` dengan nilai yang sama tidak melakukan apa-apa. Itulah alasan mengapa setiap nilai hanya muncul dalam `Set` sekali. @@ -272,7 +313,11 @@ for (let user of set) { } ``` +<<<<<<< HEAD Alternatif untuk `Set` dapat berupa array pengguna, dan kode untuk memeriksa duplikat pada setiap insersi menggunakan [arr.find](mdn:js/Array/find). Tetapi kinerjanya akan jauh lebih buruk, karena metode ini menjalani seluruh array memeriksa setiap elemen. `Set` jauh lebih baik dioptimalkan secara internal untuk pemeriksaan keunikan. +======= +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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Iteration atas Set @@ -291,20 +336,35 @@ set.forEach((value, valueAgain, set) => { Ingat keanehannya. Fungsi callback yang dilewatkan dalam `forEach` memiliki 3 argumen: satu `value`, kemudian *nilai yang sama* `valueAgain`, dan kemudian objek target. Memang, nilai yang sama muncul dalam argumen dua kali. +<<<<<<< HEAD Itu untuk kompatibilitas dengan `Map` di mana callback yang dilewati `forEach` memiliki tiga argumen. Terlihat agak aneh, memang. Tetapi dapat membantu mengganti `Map` dengan` Set` dalam kasus-kasus tertentu dengan mudah, dan sebaliknya. +======= +That's for compatibility with `Map` where the callback passed `forEach` has three arguments. Looks a bit strange, for sure. But this may help to replace `Map` with `Set` in certain cases with ease, and vice versa. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Metode yang sama yang dimiliki `Map` untuk iterator juga didukung: +<<<<<<< HEAD - `set.keys()` -- mengembalikan objek iterable untuk nilai, - `set.values()` -- sama dengan `set.keys()`, untuk kompatibilitas dengan `Map`, - `set.entries()` -- mengembalikan objek iterable untuk entri `[nilai, nilai]`, ada untuk kompatibilitas dengan `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`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Ringkasan +<<<<<<< HEAD `Map` -- adalah kumpulan nilai-nilai berkunci. +======= +[`Map`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) -- is a collection of keyed values. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Metode dan properti: +<<<<<<< HEAD - `new Map([iterable])` -- membuat map, dengan `iterable` opsional (mis. array) dari pasangan `[key, value]` untuk inisialisasi. - `map.set(key, value)` -- menyimpan nilai dengan kunci. - `map.get(key)` -- mengembalikan nilai dengan kunci, `undefined` jika `key` tidak ada di map. @@ -312,21 +372,43 @@ Metode dan properti: - `map.delete(key)` -- menghapus nilai dengan kunci. - `map.clear()` -- menghapus semuanya dari peta. - `map.size` -- mengembalikan jumlah elemen saat ini. +======= +- [`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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Perbedaan dari `Object` biasa: - Kunci apa saja, objek bisa dijadikan kunci. - Metode-metode tambahan untuk kenyamanan, properti `size`. +<<<<<<< HEAD `Set` -- adalah kumpulan nilai-nilai unik. +======= +[`Set`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) -- is a collection of unique values. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Metode dan properti: +<<<<<<< HEAD - `new Set([iterable])` -- membuat set, dengan nilai opsional `iterable` (mis. array) untuk inisialisasi. - `set.add(value)` -- menambahkan nilai (tidak melakukan apa-apa jika `value` ada), mengembalikan set itu sendiri. - `set.delete(value)` -- menghapus nilai, mengembalikan `true` jika `value` ada pada saat panggilan berlangsung, jika tidak `false`. - `set.has(value)` -- mengembalikan `true` jika nilai ada di set, jika tidak `false`. - `set.clear()` -- menghapus semuanya dari set. - `set.size` -- adalah hitungan elemen. +======= +- [`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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Iterasi atas `Map` dan` Set` selalu dalam urutan insersi, jadi kami tidak dapat mengatakan bahwa koleksi ini tidak berurut, tetapi kami tidak dapat menyusun ulang elemen atau secara langsung mendapatkan elemen dengan nomornya. diff --git a/1-js/05-data-types/08-weakmap-weakset/article.md b/1-js/05-data-types/08-weakmap-weakset/article.md index 7b5d963de..3374ab95a 100644 --- a/1-js/05-data-types/08-weakmap-weakset/article.md +++ b/1-js/05-data-types/08-weakmap-weakset/article.md @@ -1,8 +1,18 @@ +<<<<<<< HEAD # WeakMap dan WeakSet +======= + +# WeakMap and WeakSet +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Seperti yang kita tahu dari bab , Mesin Javascript menyimpan sebuah nilai didalam memori selama itu bisa terjangkau (dan secara potensial bisa digunakan). +<<<<<<< HEAD Contoh: +======= +For instance: + +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js let john = { name: "John" }; @@ -55,13 +65,21 @@ john = null; // tulis ulang referensinya */!* ``` +<<<<<<< HEAD `WeakMap` secara dasar berbeda didalam aspek ini. Itu tidak akan mencegah pembuangan dari objek kunci. +======= +[`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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Ayo kita lihat didalam contoh. ## WeakMap +<<<<<<< HEAD Perbedaan pertama dari `Map` adalah kunci `WeakMap` haruslah objek, bukan nilai primitif: +======= +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: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let weakMap = new WeakMap(); @@ -95,10 +113,10 @@ Bandingkan itu dengan `Map` biasa dicontoh diatas. Sekarang jika `john` hanya ad `WeakMap` hanya mempunyai metode berikut: -- `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) Kenapa terdapat batasan seperti itu? Itu hanyalah untuk alasan teknis. Jika sebuah objek kehilangan semua referensi lainnya (seperti `john` didalam kode diatas), lalu itu akan dibuang secara otomatis. Tapi secara teknis itu tidak benar-benar di spesifikasikan *ketika pembersihan terjadi*. @@ -183,6 +201,7 @@ function process(obj) { let result = /* kalkulasi hasil */ obj; cache.set(obj, result); + return result; } return cache.get(obj); @@ -222,6 +241,7 @@ function process(obj) { let result = /* perhitungan hasil */ obj; cache.set(obj, result); + return result; } return cache.get(obj); @@ -243,11 +263,19 @@ obj = null; ## WeakSet +<<<<<<< HEAD `WeakSet` memiliki perilaku yang sama: - Analoginya adalah untuk meng-`Set`, tapi mungkin kita hanya butuh menambahkan objek kedalam `WeakSet` (bukan primitif). - Sebuah objek ada didalam set selama itu bisa dijangkau dari tempat lain. - Seperti `Set`, itu mendukung `add`, `has` dan `delete`, tapi tidak `size`, `keys()` dan tidak ada iterasi +======= +[`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`](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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 menjadi "weak", itu juga menyediakan penyimpanan tambahan. Tapi tidak untuk data yang asal-asalan, tapi untuk "yes/no". Keanggotaan dari `WeakSet` mungkin berarti sesuatu tentang objeknya. @@ -281,9 +309,15 @@ Hal yang paling bisa diingat adalah batasan dari `WeakMap` dan `WeakSet` adalah ## Ringkasan +<<<<<<< HEAD `WeakMap` adalah koleksi seperti-`Map` yang mengijinkan hanya objek sebagai kunci dan menghapus mereka bersama dengan nilai yang terkait sekalinya mereka menjadi tidak terjangkau. `WeakSet` adalah koleksi seperti-`Set` yang hanya menyimpan objek dan menghapus mereka sekalinya mereka menjadi tidak bisa diakses. +======= +[`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`](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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Keduanya tidak mendukung metode dan properti yang mengacu pada seluruh kunci atau jumlah mereka. Hanya operasi individual yang diperbolehkan. diff --git a/1-js/05-data-types/09-keys-values-entries/article.md b/1-js/05-data-types/09-keys-values-entries/article.md index 2ff3562ba..6fb782b3f 100644 --- a/1-js/05-data-types/09-keys-values-entries/article.md +++ b/1-js/05-data-types/09-keys-values-entries/article.md @@ -76,9 +76,15 @@ Objek kekurangan banyak method yang ada untuk arrays, contoh `map`, `filter` dan Jika kita ingin mengapplikasikan method-method tersebut, kita bisa menggunakan `Object.entries` diikuti oleh `Object.fromEntries`: +<<<<<<< HEAD 1. Gunakan `Object.entries(obj)` untuk mendapatkan array pasangan kunci/nilai dari `obj`. 2. Gunakan method array di array tersebut, contoh `map`. 3. Gunakan `Object.fromEntries(array)` di array hasil untuk mengubahnya kembali menjadi objek. +======= +1. Use `Object.entries(obj)` to get an array of key/value pairs from `obj`. +2. Use array methods on that array, e.g. `map`, to transform these key/value pairs. +3. Use `Object.fromEntries(array)` on the resulting array to turn it back into an object. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Sebagai contoh, kita mempunyai objek dengan harga-harga, dan mau melipat duakan harga-harganya: @@ -91,12 +97,22 @@ let prices = { *!* let doublePrices = Object.fromEntries( +<<<<<<< HEAD // ubah menjadi array, map, lalu fromEntries mengembalikan objeknya Object.entries(prices).map(([key, value]) => [key, value * 2]) +======= + // convert prices to array, map each key/value pair into another pair + // and then fromEntries gives back the object + Object.entries(prices).map(entry => [entry[0], entry[1] * 2]) +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ); */!* alert(doublePrices.meat); // 8 -``` +``` +<<<<<<< HEAD Mungkin ini terlihat susah pertama kalinya, tetapi ini akan menjadi mudah untuk di mengerti setelah kamu menggunakannya beberapa kali. Kita bisa membuat perantaian hebat dengan cara ini. +======= +It may look difficult at first sight, but becomes easy to understand after you use it once or twice. We can make powerful chains of transforms this way. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/1-js/05-data-types/10-destructuring-assignment/article.md b/1-js/05-data-types/10-destructuring-assignment/article.md index 370831864..ac56dec6a 100644 --- a/1-js/05-data-types/10-destructuring-assignment/article.md +++ b/1-js/05-data-types/10-destructuring-assignment/article.md @@ -2,6 +2,7 @@ Dua stuktur data yang paling banyak digunakan di Javascript adalah `Object` dan `Array` +<<<<<<< HEAD Objek memungkinkan kita untuk membuat entitas tunggal yang menyimpan data item berdasarkan kunci, dan array memungkinkan kita untuk mengumpulkan data item menjadi koleksi yang terurut. Tetapi ketika kita meneruskannya ke suatu fungsi, itu mungkin tidak perlu objek / array secara keseluruhan, melainkan potongan individual. @@ -9,11 +10,25 @@ Tetapi ketika kita meneruskannya ke suatu fungsi, itu mungkin tidak perlu objek *Destructuring assignment* adalah sebuah sintaks spesial yang memungkinkan kita untuk "membongkar" array atau objek menjadi variabel yang banyak, kadang-kadang itu memang lebih nyaman. Destrukturisasi juga berfungsi baik dengan fungsi-fungsi kompleks yang mempunyai banyak parameter, nilai default, dan sebagainya. ## Destrukturisasi 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. + +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 well with complex functions that have a lot of parameters, default values, and so on. Soon we'll see that. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Contoh bagaimana array di-destrukturisasi menjadi variabel: ```js +<<<<<<< HEAD // kita mempunyai array dengan nama, dan nama keluarga +======= +// we have an array with a name and surname +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 let arr = ["John", "Smith"] *!* @@ -37,10 +52,19 @@ alert(firstName); // John alert(surname); // Smith ``` +<<<<<<< HEAD ````smart header="\"Destructuring\" bukan berarti \"destructive\"." Ini disebut "destructuring assignment," karena "destructurizes" dengan menyalin item kedalam variabel. Tetapi array itu sendiri tidak dimodifikasi. Ini hanya cara singkat untuk menulis: +======= +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. However, the array itself is not modified. + +It's just a shorter way to write: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js // let [firstName, surname] = arr; let firstName = arr[0]; @@ -60,7 +84,11 @@ let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic alert( title ); // Consul ``` +<<<<<<< HEAD Pada kode diatas, elemen kedua dari array dilewati, yang ketiga ditetapkan untuk `title`, dan sisa item array juga dilewati (karena tidak ada variabel untuknya). +======= +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). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```` ````smart header="Bekerja dengan iterabel apapun di sisi kanan" @@ -71,11 +99,16 @@ Pada kode diatas, elemen kedua dari array dilewati, yang ketiga ditetapkan untuk let [a, b, c] = "abc"; // ["a", "b", "c"] let [one, two, three] = new Set([1, 2, 3]); ``` -That works, because internally a destructuring assignment works by iterating over the right value. It's kind of syntax sugar for calling `for..of` over the value to the right of `=` and assigning the values. +That works, because internally a destructuring assignment works by iterating over the right value. It's a kind of syntax sugar for calling `for..of` over the value to the right of `=` and assigning the values. ```` +<<<<<<< HEAD ````smart header="Menetapkan ke apa saja pada sisi kiri" +======= +````smart header="Assign to anything at the left-side" +We can use any "assignables" on the left side. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Kita bisa menggunakan "penetapan" apa saja pada sisi kiri. @@ -90,11 +123,18 @@ alert(user.surname); // Smith ```` +<<<<<<< HEAD ````smart header="Pengulangan dengan .entries()" Di bagian sebelumnya kita melihat metode [Object.entries(obj)](mdn:js/Object/entries). Kita bisa menggunakan itu untuk destrukturisasi untuk melompati kunci-dan-nilai sebuah objek: +======= +````smart header="Looping with .entries()" +In the previous chapter, we saw the [Object.entries(obj)](mdn:js/Object/entries) method. + +We can use it with destructuring to loop over the keys-and-values of an object: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let user = { @@ -102,7 +142,7 @@ let user = { age: 30 }; -// loop over keys-and-values +// loop over the keys-and-values *!* for (let [key, value] of Object.entries(user)) { */!* @@ -163,14 +203,24 @@ 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"*/!*]; *!* +<<<<<<< HEAD // Catatan bahwa tipe dari `rest` adalah Array. +======= +// rest is an array of items, starting from the 3rd one +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 alert(rest[0]); // Consul alert(rest[1]); // of the Roman Republic alert(rest.length); // 2 */!* ``` +<<<<<<< HEAD Nilai dari `rest` adalah array dari elemen array yang tersisa. Kita bisa menggunakan variabel lain apapun pada `rest`, hanya pastikan memiliki tiga titik sebelum itu dan pergi terakhir di penetapan destrukturisasi. +======= +The value of `rest` is the array of the remaining array elements. + +We can use any other variable name in place of `rest`, just make sure it has three dots before it and goes last in the destructuring assignment. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let [name1, name2, *!*...titles*/!*] = ["Julius", "Caesar", "Consul", "of the Roman Republic"]; @@ -179,7 +229,11 @@ let [name1, name2, *!*...titles*/!*] = ["Julius", "Caesar", "Consul", "of the Ro ### Nilai default +<<<<<<< HEAD Jika ada lebih sedikit nilai dalam array daripada variabel dalam penugasan, tidak akan ada kesalahan. Nilai absen dianggap undefined: +======= +If the array is shorter than the list of variables on the left, there will be no errors. Absent values are considered undefined: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run *!* @@ -227,7 +281,11 @@ Sintaks dasarnya adalah: let {var1, var2} = {var1:…, var2:…} ``` +<<<<<<< HEAD Kita memiliki objek yang ada di sisi kanan, yang ingin kita pisah menjadi beberapa variabel. Sisi kiri berisi "pola" untuk properti yang sesuai. Dalam kasus sederhana, itu adalah daftar nama variabel di `{...}`. +======= +We should have an existing object on the right side, that we want to split into variables. The left side contains an object-like "pattern" for corresponding properties. In the simplest case, that's a list of variable names in `{...}`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Contohnya: @@ -247,7 +305,13 @@ alert(width); // 100 alert(height); // 200 ``` +<<<<<<< HEAD Properti `options.title`, `options.width` dan `options.height` ditugaskan ke variabel yang sesuai. Urutannya tidak masalah. Ini juga berfungsi: +======= +Properties `options.title`, `options.width` and `options.height` are assigned to the corresponding variables. + +The order does not matter. This works too: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js // mengganti urutan di let {...} @@ -409,9 +473,15 @@ alert( title ); // Menu ## Destrukturisasi bersarang +<<<<<<< HEAD Jika suatu objek atau array berisi objek dan array bersarang lainnya, kita dapat menggunakan pola sisi kiri yang lebih kompleks untuk mengekstraksi bagian yang lebih dalam. Dalam kode di bawah ini `options` memiliki objek lain di properti` size` dan sebuah array di properti `items`. Pola di sisi kiri penugasan memiliki struktur yang sama untuk mengekstrak nilai dari mereka: +======= +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: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let options = { @@ -420,7 +490,7 @@ let options = { height: 200 }, items: ["Cake", "Donut"], - extra: true + extra: true }; // tugas dekstukturisasi dibagi dalam beberapa baris untuk kejelasan @@ -440,8 +510,12 @@ alert(item1); // Cake alert(item2); // Donut ``` +<<<<<<< HEAD Semua properti objek `options` kecuali` extra` yang tidak ada di bagian kiri, ditetapkan ke variabel yang sesuai: +======= +All properties of `options` object except `extra` which is absent in the left part, are assigned to corresponding variables: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ![](destructuring-complex.svg) @@ -451,9 +525,15 @@ Perhatikan bahwa tidak ada variabel untuk `size` dan` item`, karena kita mengamb ## Parameter fungsi cerdas +<<<<<<< HEAD Ada kalanya suatu fungsi memiliki banyak parameter, yang sebagian besar bersifat opsional. Itu terutama berlaku untuk antarmuka pengguna. Bayangkan sebuah fungsi yang menciptakan menu. Mungkin memiliki lebar, tinggi, judul, daftar item dan sebagainya. Berikut cara yang buruk untuk menulis fungsi tersebut: +======= +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 a function: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js function showMenu(title = "Untitled", width = 200, height = 100, items = []) { @@ -461,7 +541,11 @@ function showMenu(title = "Untitled", width = 200, height = 100, items = []) { } ``` +<<<<<<< HEAD Dalam kehidupan nyata, masalahnya adalah bagaimana cara mengingat urutan argumen. Biasanya IDE mencoba membantu kita, terutama jika kodenya didokumentasikan dengan baik, tetapi masih ... Masalah lain adalah bagaimana memanggil fungsi ketika sebagian besar parameter ok secara 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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Soperti ini? @@ -526,7 +610,11 @@ function({ }) ``` +<<<<<<< HEAD Kemudian, untuk objek parameter, akan ada variabel `varName` untuk properti` incomingProperty`, dengan `defaultValue` secara default. +======= +Then, for an object of parameters, there will be a variable `varName` for the property `incomingProperty`, with `defaultValue` by default. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Harap perhatikan bahwa destrukturisasi seperti itu mengasumsikan bahwa `showMenu ()` memang memiliki argumen. Jika kita menginginkan semua nilai secara default, maka kita harus menentukan objek kosong: @@ -553,7 +641,7 @@ Dalam kode di atas, objek argumen keseluruhan adalah `{}` secara default, jadi s - Penugasan destrukturisasi memungkinkan untuk memetakan objek atau array secara instan ke banyak variabel. - Sintaks lengkap objek: ```js - let {prop : varName = default, ...rest} = object + let {prop : varName = defaultValue, ...rest} = object ``` Ini berarti properti `prop` harus masuk ke variabel` varName` dan, jika tidak ada properti seperti itu, maka nilai `default` harus digunakan. @@ -563,9 +651,13 @@ Dalam kode di atas, objek argumen keseluruhan adalah `{}` secara default, jadi s - Sintaks lengkap array: ```js - let [item1 = default, item2, ...rest] = array + let [item1 = defaultValue, item2, ...rest] = array ``` +<<<<<<< HEAD Item pertama masuk ke `item1`; yang kedua masuk ke `item2`, sisanya membuat array `rest`. +======= + The first item goes to `item1`; the second goes into `item2`, and all the rest makes the array `rest`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 - Dimungkinkan untuk mengekstraksi data dari array / objek bersarang, untuk itu sisi kiri harus memiliki struktur yang sama dengan yang benar. diff --git a/1-js/05-data-types/11-date/1-new-date/solution.md b/1-js/05-data-types/11-date/1-new-date/solution.md index 41ea33cf4..e9700da0a 100644 --- a/1-js/05-data-types/11-date/1-new-date/solution.md +++ b/1-js/05-data-types/11-date/1-new-date/solution.md @@ -13,6 +13,6 @@ We could also create a date from a string, like this: ```js run //new Date(datastring) -let d2 = new Date("February 20, 2012 03:12:00"); +let d2 = new Date("2012-02-20T03:12"); alert( d2 ); ``` diff --git a/1-js/05-data-types/11-date/article.md b/1-js/05-data-types/11-date/article.md index b779b314a..f754bc630 100644 --- a/1-js/05-data-types/11-date/article.md +++ b/1-js/05-data-types/11-date/article.md @@ -57,10 +57,17 @@ Untuk membuat objek `Date` baru panggil `new Date()` dengan salah satu dari argu `new Date(year, month, date, hours, minutes, seconds, ms)` : Membuat waktu dengan komponen yang diberikan dari zona waktu lokal. Hanya dua argument pertama yang wajib. +<<<<<<< HEAD - `Tahun`nya harus mempunyai 4 angka: `2013` boleh, `98` tidak boleh. - Perhitungan `Bulan`nya dimulai dari `0` (Jan), sampai `11` (Des). - Parameter `date` sebenarnya adalah hari dari bulan, jika tidak ada maka akan diasumsikan `1`. - Jika `jam/menit/detik/milidetik` tidak ada, mereka akan diasumsikan sama dengan `0`. +======= + - The `year` should have 4 digits. For compatibility, 2 digits are also accepted and considered `19xx`, e.g. `98` is the same as `1998` here, but always using 4 digits is strongly encouraged. + - The `month` count starts with `0` (Jan), up to `11` (Dec). + - The `date` parameter is actually the day of month, if absent then `1` is assumed. + - If `hours/minutes/seconds/ms` is absent, they are assumed to be equal `0`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Contoh: @@ -378,7 +385,11 @@ for (let i = 0; i < 10; i++) { ```warn header="Berhati-hati saat melakukan microbenchmarking/pengujian kemampuan micro" Mesin Javascript modern melakukan banyak optimasi. mereka mungkin merekayasa hasil dari "test buatan" dibandingkan dengan "pemakaian normal", terutama ketika kita mengukur kemampuan sesuatu yang sangat kecil, seperti bagaimana operator bekerja, atau fungsi bawaan. Jadi jika kamu sangat serius ingin mengerti tentang performansi, maka pelajarilah bagaiman mesin Javascript bekerja. dan maka kamu mungkin tidak butuh microbenchmarking sama sekali +<<<<<<< HEAD Kumpulan artikel yang bagus tentang V8 bisa ditemukan di . +======= +The great pack of articles about V8 can be found at . +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ## Date.parse dari sebuah string @@ -409,7 +420,7 @@ Kita bisa secara instan membuat sebuah objek `new Date` dari timestamp: ```js run let date = new Date( Date.parse('2012-01-26T13:51:50.417-07:00') ); -alert(date); +alert(date); ``` ## Ringkasan diff --git a/1-js/05-data-types/12-json/article.md b/1-js/05-data-types/12-json/article.md index 19bf86d3e..ebc287030 100644 --- a/1-js/05-data-types/12-json/article.md +++ b/1-js/05-data-types/12-json/article.md @@ -27,7 +27,11 @@ Untungnya, (kita) tak perlu untuk menulis kode untuk menangani semua hal ini. Tu ## JSON.stringify +<<<<<<< HEAD [JSON](http://en.wikipedia.org/wiki/JSON) (*JavaScript Object Notation*) adalah sebuah format umum yang merepresentasikan nilai-nilai dan objek. JSON dideskripsikan sebagaimana dalam standar [RFC 4627](http://tools.ietf.org/html/rfc4627). Awalnya JSON dibuat untuk JavaScript, tapi banyak bahasa pemrograman lain memiliki *library* untuk menangani JSON juga. Oleh karena itu, kini jadi mudah untuk menggunakan JSON untuk tujuan pertukaran data ketika klien menggunakan JavaScript dan server ditulis menggunakan bahasa pemrograman Ruby/PHP/Java/apapun itu. +======= +The [JSON](https://en.wikipedia.org/wiki/JSON) (JavaScript Object Notation) is a general format to represent values and objects. It is described as in [RFC 4627](https://tools.ietf.org/html/rfc4627) standard. Initially it was made for JavaScript, but many other languages have libraries to handle it as well. So it's easy to use JSON for data exchange when the client uses JavaScript and the server is written on Ruby/PHP/Java/Whatever. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 JavaScript menyediakan metode-metode seperti: @@ -41,7 +45,7 @@ let student = { age: 30, isAdmin: false, courses: ['html', 'css', 'js'], - wife: null + spouse: null }; *!* @@ -58,7 +62,7 @@ alert(json); "age": 30, "isAdmin": false, "courses": ["html", "css", "js"], - "wife": null + "spouse": null } */ */!* @@ -402,7 +406,7 @@ Untuk men-*decode* sebuah *string* JSON, kita memerlukan sebuah metode lain bern Sintaksnya: ```js -let value = JSON.parse(str, [reviver]); +let value = JSON.parse(str[, reviver]); ``` *str* @@ -448,7 +452,11 @@ let json = `{ Selaain itu semua, JSON tidak mendukung komentar. Menambahkan sebuah komentar ke JSON akan membuat JSON tersebut tidak valid. +<<<<<<< HEAD Terdapat format lain yang dinamakan [JSON5](http://json5.org/), yang mengizinkan *key* tanpa tanda kutip, adanya komentar dan lain-lain. Tapi ini adalah *library* yang berdiri sendiri, tidak terdapat dalam spesifikasi bahasa pemrograman. +======= +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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 JSON biasa memang seketat itu bukan karena para pengembangnya malas, tetapi agar implementasinya mudah, dapat diandalkan dan cepat saat proses *parsing* algoritma. diff --git a/1-js/06-advanced-functions/01-recursion/01-sum-to/solution.md b/1-js/06-advanced-functions/01-recursion/01-sum-to/solution.md index a5390dc0e..e9e4967cb 100644 --- a/1-js/06-advanced-functions/01-recursion/01-sum-to/solution.md +++ b/1-js/06-advanced-functions/01-recursion/01-sum-to/solution.md @@ -37,4 +37,8 @@ Catatan. Biasanya, rumus adalah solusi tercepat. Itu hanya menggunakan 3 operasi varian perulangan adalah yang kedua dalam hal waktu. Di varian rekusif dan perulangan kita menambahkan angka yang sama. Tapi rekursi melibatkan pemanggilan bercabang dan manajemen tumpukan eksekusi. Itu juga memakan sumberdaya, jadi itu lebih lambat. +<<<<<<< HEAD Catatan+. Beberapa mesin mendukung optimasi "tail call": jika sebuah pemanggilan rekursi adalah yang paling terakhir didalam fungsi (seperti dalam `sumTo` diatas), maka fungsi terluar tidak butuh untuk melanjutkan eksekusi, jadi mesinnya tidak akan mengingat konteks dari eksekusi. Itu akan menghilangkan beban didalam memori, jadi menghitung `sumTo(100000)` menjadi mungkin. Tapi jika mesin Javascript tidak mendukung optimasi tail call (kebanyakan tidak), disana akan terdapat error: "maximum stack size exceeded", karena disana biasanya terdapat batasan dalam total ukuran stack/penumpukan. +======= +P.P.S. Some engines support the "tail call" optimization: if a recursive call is the very last one in the function, with no other calculations performed, then the outer function will not need to resume the execution, so the engine doesn't need to remember its execution context. That removes the burden on memory. But if the JavaScript engine does not support tail call optimization (most of them don't), there will be an error: maximum stack size exceeded, because there's usually a limitation on the total stack size. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/1-js/06-advanced-functions/01-recursion/05-output-single-linked-list-reverse/solution.md b/1-js/06-advanced-functions/01-recursion/05-output-single-linked-list-reverse/solution.md index 2ec804d5f..0f4f94113 100644 --- a/1-js/06-advanced-functions/01-recursion/05-output-single-linked-list-reverse/solution.md +++ b/1-js/06-advanced-functions/01-recursion/05-output-single-linked-list-reverse/solution.md @@ -33,7 +33,11 @@ printReverseList(list); # Menggunakan perulangan +<<<<<<< HEAD Varian perulangan juga sedikit lebih rumit daripada mengeluarkannya secara langsung. +======= +The loop variant is also a little bit more complicated than the direct output. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Tidak ada cara untuk mendapatkan nilai terakhir didalam `list` kita. Kita juga tidak bisa "berjalan mundur". diff --git a/1-js/06-advanced-functions/01-recursion/article.md b/1-js/06-advanced-functions/01-recursion/article.md index 05b912bf1..e0f597834 100644 --- a/1-js/06-advanced-functions/01-recursion/article.md +++ b/1-js/06-advanced-functions/01-recursion/article.md @@ -61,7 +61,7 @@ Ketika `pow(x, n)` dipanggil, eksekusinya dibagi menjadi dua cabang: if n==1 = x / pow(x, n) = - \ + \ else = x * pow(x, n - 1) ``` @@ -287,7 +287,11 @@ Interatif `pow` menggunakan konteks tunggal mengganti `i` dan `result` didalam p **Rekursi apapun bisa ditulis ulang sebagai perulangan. Varian perulangan biasanya bisa dibuat lebih efektif.** +<<<<<<< HEAD ...Tapi terkadang menulis ulang bukanlah hal yang sepele, terutama ketika fungsi menggunakan pemanggilan rekursif yang berbeda tergantung dari kondisi dan menyatukan hasil mereka atau cabangnya lebih rumit. Dan optimasinya mungkin tidak dibutuhkan dan benar-benar menghabiskan tenaga. +======= +...But sometimes the rewrite is non-trivial, especially when a function uses different recursive subcalls depending on conditions and merges their results or when the branching is more intricate. And the optimization may be unneeded and totally not worth the efforts. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Rekursi bisa memberikan kode yang lebih pendek, lebih mudah dimengerti dan didukung. Optimasi tidak dibutuhkan di setiap tempat, kebanyakan kita butuh kode yang bagus, itulah kenapa itu digunakan. @@ -538,7 +542,11 @@ Istilah: list = { value, next -> list } ``` +<<<<<<< HEAD Pohon seperti pohon elemen HTML atau pohon departemen dari bab ini juga secara natural rekursif: cabang mereka dan setuap cabang mempunyai cabang lainnya. +======= + Trees like HTML elements tree or the department tree from this chapter are also naturally recursive: they have branches and every branch can have other branches. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Fungsi rekursif bisa digunakan untuk menyusurinya seperti yang telah kita lihat didalam contoh `sumSalary`. diff --git a/1-js/06-advanced-functions/02-rest-parameters-spread/article.md b/1-js/06-advanced-functions/02-rest-parameters-spread/article.md index 09c8a7611..9b539946a 100644 --- a/1-js/06-advanced-functions/02-rest-parameters-spread/article.md +++ b/1-js/06-advanced-functions/02-rest-parameters-spread/article.md @@ -23,7 +23,11 @@ function sum(a, b) { alert( sum(1, 2, 3, 4, 5) ); ``` +<<<<<<< HEAD Disana tidak akan terdapat error karena argumen "berlebihan". Tapi tentu saja hasilnya hanya dua angka pertama yang dihitung. +======= +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`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Sisa parameternya bisa digunakan didalam fungsi dengan menggunakan tiga titik `...` diikuti nama dari array yang akan berisi mereka. Titik secara harfiah berarti "kumpulkan sisa parameter didalam array". diff --git a/1-js/06-advanced-functions/03-closure/5-function-in-if/task.md b/1-js/06-advanced-functions/03-closure/5-function-in-if/task.md index c180224b4..52950977b 100644 --- a/1-js/06-advanced-functions/03-closure/5-function-in-if/task.md +++ b/1-js/06-advanced-functions/03-closure/5-function-in-if/task.md @@ -1,5 +1,11 @@ +importance: 5 +<<<<<<< HEAD # Fungsi di dalam if +======= +--- +# Function in if +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Lihatlah kode di bawah ini. Apa hasil dari panggilan fungsi di baris terakhir? diff --git a/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/test.js b/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/test.js index e3c335e03..802f28c4d 100644 --- a/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/test.js +++ b/1-js/06-advanced-functions/03-closure/9-sort-by-field/_js.view/test.js @@ -23,7 +23,7 @@ describe("byField", function(){ { name: "John", age: 20, surname: "Johnson"}, ]; let ageSortedAnswer = users.sort(byField("age")); - assert.deepEqual(ageSortedKey, ageSortedKey); + assert.deepEqual(ageSortedKey, ageSortedAnswer); }); it("sorts users by surname", function(){ diff --git a/1-js/06-advanced-functions/03-closure/article.md b/1-js/06-advanced-functions/03-closure/article.md index c406df77e..4b61db81e 100644 --- a/1-js/06-advanced-functions/03-closure/article.md +++ b/1-js/06-advanced-functions/03-closure/article.md @@ -8,7 +8,11 @@ Tapi apa yang terjadi jika variabel luar berubah saat fungsinya dibuat? Akankan Dan bagaimana jika sebuah fungsi diberikan sebagai paramter dan dipanggil dibagian kode lain, akankah itu mendapatkan akses ke variabel luar ditempat itu? +<<<<<<< HEAD Ayo kita peruas pengetahuan kita untuk mengerti skenario ini dan skenario yang lebih kompleks. +======= +And what if a function is passed along as an argument and called from another place of code, will it get access to outer variables at the new place? +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```smart header="Kita akan bahas tentang variabel `let/const` di sini" Di JavaScript, ada 3 cara mendeklarasi variabel: `let`, `const` (cara-cara modern), dan `var` (sisa masa lalu). diff --git a/1-js/06-advanced-functions/04-var/article.md b/1-js/06-advanced-functions/04-var/article.md index 61a8bad58..204328fd8 100644 --- a/1-js/06-advanced-functions/04-var/article.md +++ b/1-js/06-advanced-functions/04-var/article.md @@ -1,9 +1,16 @@ # Si Tua "var" +<<<<<<< HEAD ```smart header="Artikel ini untuk memahami script lama" Informasi yang terdapat di artikel ini berguna untuk memahami script lama. Hal itu bukanlah cara kita menulis kode baru. +======= +```smart header="This article is for understanding old scripts" +The information in this article is useful for understanding old scripts. + +That's not how we write new code. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` Di bab paling awal tentang [variabel](info:variables), kami menyebutkan tiga cara untuk deklarasi variabel: @@ -55,7 +62,7 @@ alert(test); // Error: test tidak didefinisikan Hal yang sama juga untuk loop: `var` tidak dapat berupa blok atau loop-lokal: -```js +```js run for (var i = 0; i < 10; i++) { var one = 1; // ... @@ -166,7 +173,7 @@ Lebih baik didemonstrasikan dengan sebuah contoh: ```js run function sayHi() { - alert(phrase); + alert(phrase); *!* var phrase = "Hello"; @@ -246,12 +253,21 @@ Ada beberapa cara lain selain tanda kurung untuk memberi tahu Javascript bahwa y ```js run // Cara membuat IIFE +<<<<<<< HEAD (function() { alert("kurung disekitar fungsi"); }*!*)*/!*(); (function() { alert("kurung disekitar semuanya"); +======= +*!*(*/!*function() { + alert("Parentheses around the function"); +}*!*)*/!*(); + +*!*(*/!*function() { + alert("Parentheses around the whole thing"); +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 }()*!*)*/!*; *!*!*/!*function() { diff --git a/1-js/06-advanced-functions/05-global-object/article.md b/1-js/06-advanced-functions/05-global-object/article.md index a6c8afcce..026df1b2e 100644 --- a/1-js/06-advanced-functions/05-global-object/article.md +++ b/1-js/06-advanced-functions/05-global-object/article.md @@ -25,7 +25,11 @@ var gVar = 5; alert(window.gVar); // 5 (menjadi properti objek global) ``` +<<<<<<< HEAD Mohon jangan bergantung dengan itu! Perilaku ini ada untuk alasan kompatibilitas. Script modern menggunakan [JavaScript modules](info:modules) dimana hal-hal tersebut tidak terjadi. +======= +Function declarations have the same effect (statements with `function` keyword in the main code flow, not function expressions). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Jika kita menggunakan `let`, hal tersebut tidak akan terjadi: diff --git a/1-js/06-advanced-functions/06-function-object/article.md b/1-js/06-advanced-functions/06-function-object/article.md index d41f83c4d..4956433e7 100644 --- a/1-js/06-advanced-functions/06-function-object/article.md +++ b/1-js/06-advanced-functions/06-function-object/article.md @@ -326,7 +326,11 @@ welcome(); // Hello, Guest (pemanggilan bercabang bekerja) Sekarang hal itu bekerja karena nama `"func"` adalah fungsi-lokal. Fungsi itu tidak diambil dari luar (dan tidak terlihat dari luar). Spesifikasinya menjamin itu akan selalu mereferensi fungsi saat ini. +<<<<<<< HEAD Fungsi dari luar kode mempunyai variabel `sayHi` atau `welcome`nya sendiri. Dan `func` adalah sebuah "nama fungsi internal", bagaimana fungsi bisa memanggil dirinya sendiri secara internal. +======= +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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```smart header="Tidak ada hal semacam itu untuk deklarasi fungsi" Fitur "nama internal" dideskripsikan disini hanya tersedia untuk ekspresi fungsi, bukan deklarasi fungsi. Untuk deklarasi fungsi, tidak terdapat sintaks untuk menambahkan sebuah nama "internal". diff --git a/1-js/06-advanced-functions/08-settimeout-setinterval/article.md b/1-js/06-advanced-functions/08-settimeout-setinterval/article.md index cc0650309..adc774da9 100644 --- a/1-js/06-advanced-functions/08-settimeout-setinterval/article.md +++ b/1-js/06-advanced-functions/08-settimeout-setinterval/article.md @@ -27,7 +27,11 @@ Biasanya, adalah sebuah fungsi. Untuk beberapa alasan, sebuah string dari kode b : Penundaannya sebelum berjalan, didalam milidetik (1000 milidetik = 1 detik), secara default 0. `arg1`, `arg2`... +<<<<<<< HEAD : Argumen-argumen untuk fungsinya (tidak didukung didalam IE9-). +======= +: Arguments for the function +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Contoh, kode ini memanggil `sayHi()` setelah satu detik: @@ -102,7 +106,11 @@ Seperti yang bisa kita lihat dari keluaran `alert`, didalam peramban identifier Lainnya, tidak terdapat spesifikasi universal untuk metode-metode ini, jadi tidak ada masalah. +<<<<<<< HEAD Untuk peramban, timer dideskripsikan didalam [bagian timer](https://www.w3.org/TR/html5/webappapis.html#timers) dari standar HTML5. +======= +For browsers, timers are described in the [timers section](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers) of HTML Living Standard. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## setInterval @@ -232,7 +240,11 @@ setTimeout(function() {...}, 100); Untuk `setInterval` fungsinya akan tetap didalam memori sampai `clearInterval` dipanggil. +<<<<<<< HEAD Tidak terdapat efek-samping pada hal itu. Sebuah fungsi mereferensi lingkungan leksikal luar, jadi, selama itu masih ada, variabel luar pun akan tetap ada. Hal itu mungkin akan memakan memori daripada fungsinya sendiri. Jadi ketika kita tidak butuh fungsi yang sudah dijadwalkan lagi, akan lebih baik untuk dibatalkan/diberhentikan, bahkan jika itu sebuah kode yang sangat pendek/kecil. +======= +There's a side effect. A function references the outer lexical environment, so, while it lives, outer variables live too. They may take much more memory than the function itself. So when we don't need the scheduled function anymore, it's better to cancel it, even if it's very small. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```` ## setTimeout dengan penundaan nol @@ -255,8 +267,13 @@ Pada baris pertama "akan memasukan pemanggilan kedalam urutan pemanggilan setela Juga terdapat kasus yang berhubungan dengan peramban, kita akan membahasnya didalam bab . +<<<<<<< HEAD ````smart header="Penundaan dengan nol faktanya tidaklah nol (didalam peramban)" Didalam peramban, terdapat sebuah batasan seberapa seringnya timer bercabang bisa berjalan. [standar HTML5](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers) mengatakan: "setelah lima timer bercabang, intervalnya dipaksa untuk berjalan setidaknya 4 milidetik.". +======= +````smart header="Zero delay is in fact not zero (in a browser)" +In the browser, there's a limitation of how often nested timers can run. The [HTML Living Standard](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers) says: "after five nested timers, the interval is forced to be at least 4 milliseconds.". +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Let's demonstrate what it means with the example below. The `setTimeout` call in it re-schedules itself with zero delay. Each call remembers the real time from the previous one in the `times` array. What do the real delays look like? Let's see: Ayo kita prakterkan apa artinya itu dengan contoh dibawah. Pemanggilan `setTimeout` menjadwalkan ulang dengan penundaan 0. Setiap pemanggilan mengingat waktu yang asli dari pemanggilan sebelumnya didalam array `times`. Seperti apa penundaan sesungguhnya terlihat? Lihat dibawah: @@ -295,9 +312,16 @@ Untuk Javascript dibagian server, batasan itu tidaklah ada, dan disana terdapat Perhatikan bahwa seluruh metode penjadwalan tidak *menjamin* delay yang tepat. +<<<<<<< HEAD Contoh, didalam peramban timer mungkin lebih lambat untuk beberapa alasan: - CPU-nya sedang melakukan banyak pekerjaan. - Ada tab peramban yang sedang berjalan dalam mode background. - Laptopnya sedang menggunakan mode batre. +======= +For example, the in-browser timer may slow down for a lot of reasons: +- The CPU is overloaded. +- The browser tab is in the background mode. +- The laptop is on battery saving mode. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Semua itu mungkin menaikan resolusi timernya (delay minimalnya) menjadi 300ms atau bahkan 1000ms tergantung perambannya dan performasi pada OS-nya. diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md index 6035fe6e3..d292a927d 100644 --- a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md +++ b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md @@ -8,9 +8,15 @@ Buatlah sebuah dekorator "penutup" `throttle(f, ms)` -- yang mengembalikan sebua Ketika fungsinya dipanggil beberapa kali, fungsinya akan melakukan pemanggilan kepada `f` maksimal sekali per `ms` milidetik. +<<<<<<< HEAD Perbedaannya dengan dekorator debounce adalah keduanya benar-benar dekorator berbeda: - `debounce` menjalankan fungsinya sekali setelah masa "tidak aktif". Bagus untuk memproses hasil akhir. - `throttle` menjalankan fungsinya tidak lebih banyak dari waktu `ms` yang diberikan. Bagus untuk update tersusun yang tidak terlalu sering dipanggil. +======= +Compared to the debounce decorator, the behavior is completely different: +- `debounce` runs the function once after the "cooldown" period. Good for processing the final result. +- `throttle` runs it not more often than given `ms` time. Good for regular updates that shouldn't be very often. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Dengan kata lain, `throttle` seperti seorang sekertaris yang menerima panggilan telefon, tapi menggangu bos nya (memanggil fungsi `f` asli) tidak lebih sering dari sekali per `ms` milidetik. diff --git a/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md b/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md index 08962f264..33f5b8330 100644 --- a/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md +++ b/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md @@ -1,5 +1,9 @@ +<<<<<<< HEAD Errornya muncul karena `ask` mendapatkan fungsi `loginOk/loginFail` tanpa objeknya. +======= +The error occurs because `askPassword` gets functions `loginOk/loginFail` without the object. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ketika `ask` memanggil, `loginOk/loginFail` mengasumsikan bahwa `this=undefined`. diff --git a/1-js/06-advanced-functions/10-bind/article.md b/1-js/06-advanced-functions/10-bind/article.md index 43bfe08d9..39dba7ec6 100644 --- a/1-js/06-advanced-functions/10-bind/article.md +++ b/1-js/06-advanced-functions/10-bind/article.md @@ -187,8 +187,13 @@ let user = { let say = user.say.bind(user); +<<<<<<< HEAD say("Hello"); // Hello, John (argumen "Hello" dikirim untuk digunakan) say("Bye"); // Bye, John ("Bye" dikirim untuk digunakan) +======= +say("Hello"); // Hello, John! ("Hello" argument is passed to say) +say("Bye"); // Bye, John! ("Bye" is passed to say) +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ````smart header="Metode yang bermanfaat: `bindAll`" @@ -202,7 +207,12 @@ for (let key in user) { } ``` +<<<<<<< HEAD Librari Javascript juga menyediakan fungsi untuk memudahkan pengikatan/binding masal, contoh [_.bindAll(object, methodNames)](http://lodash.com/docs#bindAll) didalam lodash. +======= +JavaScript libraries also provide functions for convenient mass binding , e.g. [_.bindAll(object, methodNames)](https://lodash.com/docs#bindAll) in lodash. +```` +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Partial functions/Fungsi sebagian diff --git a/1-js/07-object-properties/01-property-descriptors/article.md b/1-js/07-object-properties/01-property-descriptors/article.md index 7b2f842fa..82669bfb7 100644 --- a/1-js/07-object-properties/01-property-descriptors/article.md +++ b/1-js/07-object-properties/01-property-descriptors/article.md @@ -19,7 +19,11 @@ Properti Objek, selain sebuah **`Nilai`**, memiliki tiga atribut spesial (yang d Kita belum melihat mereka, karena biasanya mereka tidak muncul. Ketika kita membuat sebuah properti "dengan cara biasa", Semua dari tiga attribut diatas biasanya bernilai `benar`.namun, kita juga bisa mengubahnya kapan pun kita mau. +<<<<<<< HEAD Pertama, mari kita lihat bagaimana cara mendapatkan properti flag tersebut. +======= +The method [Object.getOwnPropertyDescriptor](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptor) allows to query the *full* information about a property. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Pada Method [Object.getOwnPropertyDescriptor](mdn:js/Object/getOwnPropertyDescriptor) memperbolehkan kita untuk melakukan query terhadap informasi *komplit* dari sebuah properti. @@ -56,7 +60,11 @@ alert( JSON.stringify(descriptor, null, 2 ) ); */ ``` +<<<<<<< HEAD Untuk mengganti flag tersebut, kita dapat menggunakan [Object.defineProperty](mdn:js/Object/defineProperty). +======= +To change the flags, we can use [Object.defineProperty](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Sintaksnya adalah: @@ -125,7 +133,11 @@ Sekarang tidak ada yang dapat mengubah nama dari user kita, kecuali mereka menet ```smart header="Errors appear only in strict mode" +<<<<<<< HEAD Pada mode non-strict, tidak ada eror yang terjadi ketika menulis pada properti non-writable dan sejenisnya. tapi operasi itu tetap tidak akan berhasil. Aksi pelanggaran flag hanya saja diabaikan pada mode 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. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` Berikut contoh kasus yang sama, tapi properti itu dibuat dari awal: @@ -196,7 +208,11 @@ alert(Object.keys(user)); // name Flag non-configurable (`configurable:false`) terkadang sudah diatur sebelumnya untuk objek dan properti bawaan. +<<<<<<< HEAD Sebuah properti non-configurable tidak bisa di hapus. +======= +A non-configurable property can't be deleted, its attributes can't be modified. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Sebagai contoh, `Math.PI` adalah non-writable, non-enumerable and non-configurable: @@ -216,12 +232,13 @@ alert( JSON.stringify(descriptor, null, 2 ) ); Jadi, seorang programer tidak akan bisa mengganti nilai dari sebuah `Math.PI` atau juga menimpanya. ```js run -Math.PI = 3; // Error +Math.PI = 3; // Error, because it has writable: false // menghapus Math.PI juga tidak akan bekerja ``` Membuat sebuah properti non-configurable adalah jalan satu arah. kita tidak bisa mengubahnya kembali dengan `defineProperty`. +<<<<<<< HEAD Tepatnya, non-configurable memberlakukan beberapa pembatasan pada `defineProperty`: 1. tidak bisa mengubah flag `configurable` . 2. tidak bisa mengubah flag `enumerable` . @@ -229,6 +246,22 @@ Tepatnya, non-configurable memberlakukan beberapa pembatasan pada `definePropert 4. tidak bisa mengubah `get/set` untuk sebuah properti aksesor (tapi bisa menetapkannya jika kosong). Disini kita membuat `user.name` menjadi sebuah konstant "yang selamanya tersegel": +======= +We also can't change `Math.PI` to be `writable` again: + +```js run +// Error, because of configurable: false +Object.defineProperty(Math, "PI", { writable: true }); +``` + +There's absolutely nothing we can do with `Math.PI`. + +Making a property non-configurable is a one-way road. We cannot change it back with `defineProperty`. + +**Please note: `configurable: false` prevents changes of property flags and its deletion, while allowing to change its value.** + +Here `user.name` is non-configurable, but we can still change it (as it's writable): +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run let user = { @@ -243,7 +276,7 @@ user.name = "Pete"; // works fine delete user.name; // Error ``` -And here we make `user.name` a "forever sealed" constant: +And here we make `user.name` a "forever sealed" constant, just like the built-in `Math.PI`: ```js run let user = { @@ -265,15 +298,26 @@ Object.defineProperty(user, "name", {writable: true}); // Error */!* ``` +<<<<<<< HEAD ```smart header="\"Non-configurable\" doesn't mean \"non-writable\"" Catatan pengecualian: sebuah nilai dari non-configurable, tapi writable properti masih bisa diubah. Ide dari `configurable: false` adalah untuk mencegah perubahan properti flag dan penghapusannya, bukan perubahan dalam nilainya. +======= +```smart header="The only attribute change possible: writable true -> false" +There's a minor exception about changing flags. + +We can change `writable: true` to `false` for a non-configurable property, thus preventing its value modification (to add another layer of protection). Not the other way around though. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ## Object.defineProperties +<<<<<<< HEAD Ada sebuah method [Object.defineProperties(obj, descriptors)](mdn:js/Object/defineProperties) yang memperbolehkan untuk mendefinisikan banyak properti pada satu waktu. +======= +There's a method [Object.defineProperties(obj, descriptors)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperties) that allows to define many properties at once. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Sintaksnya adalah: @@ -299,7 +343,11 @@ Jadi, kita bisa mengatur banyak properti dalam satu waktu. ## Object.getOwnPropertyDescriptors +<<<<<<< HEAD Untuk mendapat semua properti deskriptor pada satu waktu, kita dapat menggunakan sebuah method [Object.getOwnPropertyDescriptors(obj)](mdn:js/Object/getOwnPropertyDescriptors). +======= +To get all property descriptors at once, we can use the method [Object.getOwnPropertyDescriptors(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyDescriptors). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Bersamaan dengan `Object.defineProperties` itu dapat digunakan menjadi cara "flags-aware" untuk mengkloning sebuah objek: @@ -318,12 +366,17 @@ for (let key in user) { Perbedaan lainnya adalah jika `for..in` mengabaikan properti simbolik, tapi `Object.getOwnPropertyDescriptors` mengembalikan *semua* properti deskriptor termasuk properti simboliknya. +<<<<<<< HEAD ## menyegel sebuah objek secara global +======= +Another difference is that `for..in` ignores symbolic and non-enumerable properties, but `Object.getOwnPropertyDescriptors` returns *all* property descriptors including symbolic and non-enumerable ones. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Properti deskriptor bekerja pada level invidual propertinya. Dan ada juga method yang memberi batasan akses terkait *keselurhan* objek: +<<<<<<< HEAD [Object.preventExtensions(obj)](mdn:js/Object/preventExtensions) : Melarang penambahan pada properti baru dalam objek. @@ -332,9 +385,20 @@ Dan ada juga method yang memberi batasan akses terkait *keselurhan* objek: [Object.freeze(obj)](mdn:js/Object/freeze) : Melarang penambahan/pengurangan/pengubahan pada properti. Menetapkan `configurable: false, writable: false` untuk semua properti yang ada. +======= +[Object.preventExtensions(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/preventExtensions) +: Forbids the addition of new properties to the object. + +[Object.seal(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal) +: Forbids adding/removing of properties. Sets `configurable: false` for all existing properties. + +[Object.freeze(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze) +: Forbids adding/removing/changing of properties. Sets `configurable: false, writable: false` for all existing properties. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Dan ada juga test untuk mereka: +<<<<<<< HEAD [Object.isExtensible(obj)](mdn:js/Object/isExtensible) : Mengembalikan `false` jika menambahkan properti itu dilarang, selain itu `true`. @@ -343,5 +407,15 @@ Dan ada juga test untuk mereka: [Object.isFrozen(obj)](mdn:js/Object/isFrozen) : Mengembalikan `true` jika menambahkan/mengurangi/mengubah properti itu dilarang, dan semua properti yang sekarang memiliki `configurable: false, writable: false`. +======= +[Object.isExtensible(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isExtensible) +: Returns `false` if adding properties is forbidden, otherwise `true`. + +[Object.isSealed(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isSealed) +: Returns `true` if adding/removing properties is forbidden, and all existing properties have `configurable: false`. + +[Object.isFrozen(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isFrozen) +: Returns `true` if adding/removing/changing properties is forbidden, and all current properties are `configurable: false, writable: false`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Method diatas biasanya jarang digunakan pada prakteknya. diff --git a/1-js/07-object-properties/02-property-accessors/article.md b/1-js/07-object-properties/02-property-accessors/article.md index d9adfa6e1..1ad9fbe45 100644 --- a/1-js/07-object-properties/02-property-accessors/article.md +++ b/1-js/07-object-properties/02-property-accessors/article.md @@ -5,7 +5,11 @@ Terdapat dua jenis properti objek. Yang pertama adalah *properti data*. Kita telah mengetahui bagaimana cara kerja mereka. Semua properti yang kita gunakan sampai sekarang adalah properti data. +<<<<<<< HEAD Yang kedua adalah properti yang bisa dibilang cukup baru. Properti itu adalah *properti aksesor*. Mereka sebenarnya adalah fungsi untuk mendapatkan dan mengatur sebuah nilai, tapi mereka mirip seperti properti biasa pada kode eksternal. +======= +The second type of property is something new. It's an *accessor property*. They are essentially functions that execute on getting and setting a value, but look like regular properties to an external code. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Getter dan setter diff --git a/1-js/08-prototypes/01-prototype-inheritance/article.md b/1-js/08-prototypes/01-prototype-inheritance/article.md index 894b47cb2..967a74dfb 100644 --- a/1-js/08-prototypes/01-prototype-inheritance/article.md +++ b/1-js/08-prototypes/01-prototype-inheritance/article.md @@ -54,7 +54,11 @@ alert( rabbit.eats ); // true (**) alert( rabbit.jumps ); // true ``` +<<<<<<< HEAD Pada baris `(*)` menyetel `animal` untuk menjadi prototype dari `rabbit`. +======= +Here the line `(*)` sets `animal` to be the prototype of `rabbit`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Lalu, ketika `alert` mencoba untuk membaca properti `rabbit.eats` `(**)`, ternyata `rabbit` tidak memiliki propertinya, maka Javascript mengikuti referensi `[[Prototype]]`nya dan menemukan `animal` (mencari dari bawah ke atas): @@ -131,9 +135,14 @@ Akan tetapi terdapat dua batasan: Dan juga tentu saja: hanya terdapat satu `[[Prototype]]`. Sebuah objek tidak bisa mewarisi dari dua objek. +<<<<<<< HEAD ```smart header="`__proto__` adalah asal usul getter/setter untuk `[[Prototype]]`" Biasanya kesalan *developer* pemula adalah tidak mengetahui perbedaan antara keduanya. +======= +```smart header="`__proto__` is a historical getter/setter for `[[Prototype]]`" +It's a common mistake of novice developers not to know the difference between these two. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Perlu diingat bahwa `__proto__` *tidak sama* dengan properti internal `[[Prototype]]`. Itu hanyalah *getter/setter* untuk `[[Prototype]]`. Nanti kita akan melihat situasi dimana hal itu akan digunakan, untuk sekarang kita hanya perlu tahu, kita akan terus bangun pemahaman kita tentang Javascript. @@ -287,7 +296,11 @@ for(let prop in rabbit) alert(prop); // jumps, lalu eats */!* ``` +<<<<<<< HEAD Jika itu bukanlah hal yang kita inginkanm dan kita ingin untuk mengecualikan properti warisan, terdapat metode bawaan [obj.hasOwnProperty(key)](mdn:js/Object/hasOwnProperty): yang mengembalikan `true` jika `obj` memiliki properti bernama `key` (bukan properti warisan). +======= +If that's not what we want, and we'd like to exclude inherited properties, there's a built-in method [obj.hasOwnProperty(key)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/hasOwnProperty): it returns `true` if `obj` has its own (not inherited) property named `key`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Jadi kita bisa memisahkan properti warisan (atau melakukan sesuatu dengan properti warisan itu): diff --git a/1-js/08-prototypes/03-native-prototypes/article.md b/1-js/08-prototypes/03-native-prototypes/article.md index c1f70ae89..0f7db592a 100644 --- a/1-js/08-prototypes/03-native-prototypes/article.md +++ b/1-js/08-prototypes/03-native-prototypes/article.md @@ -2,7 +2,11 @@ Properti `"prototype"` adalah properti yang banyak digunakan oleh Javascript itu sendiri. Semua konstruktor fungsi menggunakannya. +<<<<<<< HEAD Pertama kita akan melihat lebih lengkapnya dan bagaimana cara menggunakannya untuk menambah kemampuan dari objek-objek bawaan. +======= +First we'll look at the details, and then how to use it for adding new capabilities to built-in objects. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Object.prototype diff --git a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md index 837d34e8e..4735b9ac7 100644 --- a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md +++ b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md @@ -28,4 +28,8 @@ alert(dictionary); // "apple,__proto__" Ketika kita membuat sebuah properti menggunakan deskriptor, tandanya akan menjadi `false` secara bawaan. Jadi kode diatas, `dictionary.toString` tidak bisa dihitung. +<<<<<<< HEAD Lihat bab [](info:property-descriptors) untuk review. +======= +See the chapter [](info:property-descriptors) for review. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/1-js/08-prototypes/04-prototype-methods/article.md b/1-js/08-prototypes/04-prototype-methods/article.md index a4ce2646c..9c5f1eb3d 100644 --- a/1-js/08-prototypes/04-prototype-methods/article.md +++ b/1-js/08-prototypes/04-prototype-methods/article.md @@ -3,15 +3,18 @@ In the first chapter of this section, we mentioned that there are modern methods to setup a prototype. -The `__proto__` is considered outdated and somewhat deprecated (in browser-only part of the JavaScript standard). +Setting or reading the prototype with `obj.__proto__` is considered outdated and somewhat deprecated (moved to the so-called "Annex B" of the JavaScript standard, meant for browsers only). -The modern methods are: +The modern methods to get/set a prototype are: -- [Object.create(proto, [descriptors])](mdn:js/Object/create) -- creates an empty object with given `proto` as `[[Prototype]]` and optional property descriptors. - [Object.getPrototypeOf(obj)](mdn:js/Object/getPrototypeOf) -- returns the `[[Prototype]]` of `obj`. - [Object.setPrototypeOf(obj, proto)](mdn:js/Object/setPrototypeOf) -- sets the `[[Prototype]]` of `obj` to `proto`. -These should be used instead of `__proto__`. +The only usage of `__proto__`, that's not frowned upon, is as a property when creating a new object: `{ __proto__: ... }`. + +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. For instance: @@ -22,7 +25,7 @@ let animal = { // create a new object with animal as a prototype *!* -let rabbit = Object.create(animal); +let rabbit = Object.create(animal); // same as {__proto__: animal} */!* alert(rabbit.eats); // true @@ -36,7 +39,9 @@ Object.setPrototypeOf(rabbit, {}); // change the prototype of rabbit to {} */!* ``` -`Object.create` has an optional second argument: property descriptors. We can provide additional properties to the new object there, like this: +The `Object.create` method is a bit more powerful, as it has an optional second argument: property descriptors. + +We can provide additional properties to the new object there, like this: ```js run let animal = { @@ -57,26 +62,34 @@ The descriptors are in the same format as described in the chapter >>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run // menjalankan Class User hanya dengan fungsi diff --git a/1-js/09-classes/02-class-inheritance/article.md b/1-js/09-classes/02-class-inheritance/article.md index 742a61356..cca448000 100644 --- a/1-js/09-classes/02-class-inheritance/article.md +++ b/1-js/09-classes/02-class-inheritance/article.md @@ -107,7 +107,11 @@ class Rabbit extends Animal { } ``` +<<<<<<< HEAD Biasanya kita tidak ingin sepenuhnya mengganti metode induk, melainkan untuk membangun di atasnya untuk mengubah atau memperluas fungsinya. Kita melakukan sesuatu dalam metode kita, tetapi memanggil metode induk sebelum/sesudahnya atau dalam proses. +======= +Usually, however, we don't want to totally replace a parent method, but rather to build on top of it to tweak or extend its functionality. We do something in our method, but call the parent method before/after it or in the process. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Kelas menyediakan kata kunci `"super"` untuk itu. @@ -160,7 +164,12 @@ Sekarang `Rabbit` mempunyai metode `stop` yang memanggil induk `super.stop()` di ````smart header="_Arrow functions_ tidak mempunyai `super`" Seperti yang disebutkan di bab , _arrow functions_ tidak memiliki `super`. +<<<<<<< HEAD Jika diakses, itu diambil dari fungsi luar. Misalnya: +======= +If accessed, it's taken from the outer function. For instance: + +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js class Rabbit extends Animal { stop() { @@ -177,9 +186,13 @@ setTimeout(function() { super.stop() }, 1000); ``` ````` +<<<<<<< HEAD ## Mengganti konstruktor Dengan konstruktor, ini menjadi sedikit rumit. +======= +## Overriding constructor +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Sampai sekarang, `Rabbit` tidak mempunyai `constructor` sendiri. @@ -280,7 +293,11 @@ alert(rabbit.earLength); // 10 */!* ``` +<<<<<<< HEAD ### Mengganti bidang kelas: catatan rumit +======= +### Overriding class fields: a tricky note +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```warn header="Advanced note" Catatan ini mengasumsikan kamu memiliki pengalaman tertentu dengan kelas, mungkin dalam bahasa pemrograman lain. @@ -315,13 +332,21 @@ new Rabbit(); // animal */!* ``` +<<<<<<< HEAD Di sini, kelas `Rabbit` memperluas `Animal` dan mengganti bidang `nama` dengan nilainya sendiri. +======= +Here, class `Rabbit` extends `Animal` and overrides the `name` field with its own value. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Tidak ada konstruktor sendiri dalam `Rabbit`, jadi konstruktor `Animal` dipanggil. Yang menarik adalah dalam kedua kasus: `new Animal()` dan `new Rabbit()`, `alert` di baris `(*)` menampilkan `animal`. +<<<<<<< HEAD **Dengan kata lain, konstruktor induk selalu menggunakan nilai bidangnya sendiri, bukan yang diganti.** +======= +**In other words, the parent constructor always uses its own field value, not the overridden one.** +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Apa yang aneh tentang itu? @@ -358,24 +383,40 @@ Dan itulah yang secara natural kita harapkan. Ketika konstruktor induk dipanggil ...Tetapi untuk bidang kelas tidak demikian. Seperti yang dikatakan, konstruktor induk selalu menggunakan bidang induk. +<<<<<<< HEAD Mengapa ada bedanya? Nah, alasannya ada di urutan bidang inisialisasi. Bidang kelas diinisialisasi: +======= +Why is there a difference? + +Well, the reason is the field initialization order. The class field is initialized: +- Before constructor for the base class (that doesn't extend anything), +- Immediately after `super()` for the derived class. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 - Sebelum konstruktor untuk kelas dasar (yang tidak memperluas apa pun), - Langsung setelah `super()` untuk kelas turunan. Dalam kasus kita, `Rabbit` adalah kelas turunannya. Tidak ada `constructor()` di dalamnya. Seperti yang dikatakan sebelumnya, itu sama seperti jika ada konstruktor kosong hanya dengan `super(...args)`. +<<<<<<< HEAD Jadi, `new Rabbit()` memanggil `super()`, sehingga mengeksekusi konstruktor induk, dan (sesuai aturan untuk kelas turunan) hanya setelah bidang kelasnya diinisialisasi. Pada saat eksekusi induk konstruktor, belum ada bidang kelas `Rabbit`, itulah mengapa bidang `Animal` digunakan. +======= +This subtle difference between fields and methods is specific to JavaScript. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Perbedaan halus antara bidang dan metode ini khusus untuk JavaScript Untungnya, perilaku ini hanya muncul dengan sendirinya jika bidang yang diganti digunakan di konstruktor induk. Maka mungkin sulit untuk memahami apa yang sedang terjadi, jadi kita menjelaskannya di sini. +<<<<<<< HEAD Jika ini menjadi masalah, seseorang dapat memperbaikinya dengan menggunakan metode atau _getter_/_setter_ sebagai ganti bidang. ## _Super: internals, [[HomeObject]]_ +======= +## Super: internals, [[HomeObject]] +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```warn header="Advanced information" Jika Anda membaca tutorial untuk pertama kali - bagian ini mungkin dilewati. diff --git a/1-js/09-classes/03-static-properties-methods/3-class-extend-object/solution.md b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/solution.md index 3a1179b20..6435be8c2 100644 --- a/1-js/09-classes/03-static-properties-methods/3-class-extend-object/solution.md +++ b/1-js/09-classes/03-static-properties-methods/3-class-extend-object/solution.md @@ -21,14 +21,22 @@ alert( rabbit.hasOwnProperty('name') ); // true Tapi itu belum semuanya. +<<<<<<< HEAD Bahkan setelah perbaikan, masih ada perbedaan penting dalam `"class Rabbit extends Object"` versus `class Rabbit`. +======= +Even after the fix, there's still an important difference between `"class Rabbit extends Object"` and `class Rabbit`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Seperti yang kita tahu, sintaks "extends" menyiapkan dua prototipe: 1. Antara `"prototype"` dari fungsi konstruktor (untuk metode). 2. Antara konstruktor berfungsi sendiri (untuk metode statis). +<<<<<<< HEAD Dalam kasus kita, untuk `class Rabbit extends Object` itu berarti: +======= +In the case of `class Rabbit extends Object` it means: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run class Rabbit extends Object {} @@ -37,7 +45,11 @@ alert(Rabbit.prototype.__proto__ === Object.prototype); // (1) true alert(Rabbit.__proto__ === Object); // (2) true ``` +<<<<<<< HEAD Jadi `Rabbit` sekarang menyediakan akses ke metode statis `Object` melalui `Rabbit`, seperti ini: +======= +So `Rabbit` now provides access to the static methods of `Object` via `Rabbit`, like this: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run class Rabbit extends Object {} @@ -67,7 +79,11 @@ alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error Jadi `Rabbit` tidak menyediakan akses ke metode statis `Object` dalam hal itu. +<<<<<<< HEAD Ngomong-ngomong, `Function.prototype` mempunyai fungsi metode "generic", seperti `call`, `bind` dll. Mereka terakhir tersedia dalam kedua kasus, karena untuk konstruktor `Object` bawaan, `Object.__proto__ === Function.prototype`. +======= +By the way, `Function.prototype` also has "generic" function methods, like `call`, `bind` etc. They are ultimately available in both cases, because for the built-in `Object` constructor, `Object.__proto__ === Function.prototype`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Berikut gambarnya: diff --git a/1-js/09-classes/03-static-properties-methods/article.md b/1-js/09-classes/03-static-properties-methods/article.md index a0a6b50db..f3f019c41 100644 --- a/1-js/09-classes/03-static-properties-methods/article.md +++ b/1-js/09-classes/03-static-properties-methods/article.md @@ -2,7 +2,13 @@ Kita juga dapat menetapkan metode ke fungsi kelas itu sendiri, bukan ke `" prototipe "`-nya. Metode seperti itu disebut _static_. +<<<<<<< HEAD Di dalam kelas, mereka ditambahkan oleh kata kunci `static`, seperti ini: +======= +We can also assign a method to the class as a whole. Such methods are called *static*. + +In a class declaration, they are prepended by `static` keyword, like this: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run class User { @@ -30,9 +36,17 @@ User.staticMethod(); // true Nilai `this` dalam panggilan `User.staticMethod()` adalah konstruktor kelas `User` itu sendiri (aturan "object before dot"). +<<<<<<< HEAD Biasanya, metode statis digunakan untuk mengimplementasikan fungsi yang dimiliki kelas, tetapi tidak untuk objek tertentu darinya. Misalnya, kita punya objek `Article` dan membutuhkan sebuah fungsi untuk membandingkan mereka. Solusi natural adalah menambahkan metode `Article.compare`, seperti ini: +======= +Usually, static methods are used to implement functions that belong to the class as a whole, but not to any particular object of it. + +For instance, we have `Article` objects and need a function to compare them. + +A natural solution would be to add `Article.compare` static method: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run class Article { @@ -62,9 +76,17 @@ articles.sort(Article.compare); alert( articles[0].title ); // CSS ``` +<<<<<<< HEAD Di sini `Article.compare` berdiri "di atas" _articles_, sebagai alat untuk membandingkannya. Ini bukan metode _article_, melainkan seluruh kelas. Contoh lain adalah apa yang disebut metode "factory". Bayangkan, kita butuh beberapa cara untuk membuat _article_: +======= +Here `Article.compare` method stands "above" articles, as a means to compare them. It's not a method of an article, but rather of the whole class. + +Another example would be a so-called "factory" method. + +Let's say, we need multiple ways to create an article: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 1. Buat dengan parameter yang diberikan (`title`, `date` dsb). 2. Buat _article_ kosong dengan tanggal hari ini. @@ -72,7 +94,11 @@ Contoh lain adalah apa yang disebut metode "factory". Bayangkan, kita butuh bebe Cara pertama dapat diterapkan oleh konstruktor. Dan untuk yang kedua kita bisa membuat metode statis kelas. +<<<<<<< HEAD Seperti `Article.createTodays()` di sini: +======= +Such as `Article.createTodays()` here: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run class Article { @@ -99,12 +125,32 @@ Sekarang setiap kali kita perlu membuat _today's digest_, kita dapat memanggil ` Metode statis juga digunakan dalam kelas terkait basis data untuk mencari/menyimpan/menghapus entri dari basis data, seperti ini: ```js +<<<<<<< HEAD // dengan asumsi Article adalah kelas khusus untuk mengelola articles // metode statis untuk menghapus article: Article.remove({ id: 12345 }); ``` ## Properti Statis +======= +// assuming Article is a special class for managing articles +// static method to remove the article by id: +Article.remove({id: 12345}); +``` + +````warn header="Static methods aren't available for individual objects" +Static methods are callable on classes, not on individual objects. + +E.g. such code won't work: + +```js +// ... +article.createTodays(); /// Error: article.createTodays is not a function +``` +```` + +## Static properties +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 [recent browser=Chrome] diff --git a/1-js/09-classes/04-private-protected-properties-methods/article.md b/1-js/09-classes/04-private-protected-properties-methods/article.md index 00c5748c8..b15f21ed0 100644 --- a/1-js/09-classes/04-private-protected-properties-methods/article.md +++ b/1-js/09-classes/04-private-protected-properties-methods/article.md @@ -112,8 +112,13 @@ class CoffeeMachine { // membuat mesin kopi let coffeeMachine = new CoffeeMachine(100); +<<<<<<< HEAD // tambahkan air coffeeMachine.waterAmount = -10; // Error: Negative water +======= +// add water +coffeeMachine.waterAmount = -10; // _waterAmount will become 0, not -10 +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` Sekarang aksesnya terkendali, jadi pengaturan air di bawah nol gagal. diff --git a/1-js/09-classes/06-instanceof/article.md b/1-js/09-classes/06-instanceof/article.md index 8bbd94b09..57af23879 100644 --- a/1-js/09-classes/06-instanceof/article.md +++ b/1-js/09-classes/06-instanceof/article.md @@ -93,7 +93,7 @@ Algoritma `obj instanceof Class` bekerja kurang lebih sebgai berikut: alert(rabbit instanceof Animal); // true */!* - // rabbit.__proto__ === Rabbit.prototype + // rabbit.__proto__ === Animal.prototype (no match) *!* // rabbit.__proto__.__proto__ === Animal.prototype (match!) */!* diff --git a/1-js/09-classes/07-mixins/article.md b/1-js/09-classes/07-mixins/article.md index 081141339..f47e41f0b 100644 --- a/1-js/09-classes/07-mixins/article.md +++ b/1-js/09-classes/07-mixins/article.md @@ -103,7 +103,11 @@ Berikut diagramnya (lihat bagian kanan): Itu karena metode `sayHi` dan `sayBye` awalnya dibuat di `sayHiMixin`. Jadi, meskipun disalin, properti internal `[[HomeObject]]` mereferensikan `sayHiMixin`, seperti yang ditunjukkan pada gambar di atas. +<<<<<<< HEAD Karena `super` mencari metode induk di `[[HomeObject]].[[Prototype]]`, itu berarti mencari `sayHiMixin.[[Prototype]]`, bukan `User.[[Prototype]]`. +======= +As `super` looks for parent methods in `[[HomeObject]].[[Prototype]]`, that means it searches `sayHiMixin.[[Prototype]]`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Peristiwa _Mixin_ diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md index a90f95819..1dd9240ce 100644 --- a/1-js/10-error-handling/1-try-catch/article.md +++ b/1-js/10-error-handling/1-try-catch/article.md @@ -633,7 +633,11 @@ Sebagai contoh: Peran dari global handler `window.onerror` biasanya bukan untuk memulihkan eksekusi dari kodingannya - itu biasanya tidak mungkin jika terjadi kesalahan pemrograman, namun tugasnya adalah untuk mengirim pesan eror ke pengembang. +<<<<<<< HEAD Ada juga layanan web yang menyediakan pencatatan eror untuk kasus seperti itu, seperti or . +======= +There are also web-services that provide error-logging for such cases, like or . +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Mereka bekerja seperti ini: diff --git a/1-js/10-error-handling/2-custom-errors/article.md b/1-js/10-error-handling/2-custom-errors/article.md index e598cd666..8b61fbc39 100644 --- a/1-js/10-error-handling/2-custom-errors/article.md +++ b/1-js/10-error-handling/2-custom-errors/article.md @@ -22,9 +22,15 @@ Secara internal, kita akan menggunakan `JSON.parse`. Jika menerima `json` yang s Fungsi kita `readUser(json)` tidak hanya akan membaca JSON, tetapi juga memeriksa ("memvalidasi") data. Jika tidak ada bidang yang wajib diisi, atau formatnya salah, itu adalah kesalahan. Dan itu bukan `SyntaxError`, karena datanya benar secara sintaksis, tetapi jenis kesalahan lain. Kita akan menyebutnya `ValidationError` dan membuat kelas untuk itu. Kesalahan semacam itu juga harus membawa informasi tentang bidang yang melanggar. +<<<<<<< HEAD Kelas `ValidationError` kita harus mewarisi dari kelas `Error` bawaan. Kelas itu sudah ada di dalamnya, tetapi berikut ini kode perkiraannya sehingga kita dapat memahami apa yang kita perluas: +======= +Our `ValidationError` class should inherit from the `Error` class. + +The `Error` class is built-in, but here's its approximate code so we can understand what we're extending: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js // "Kode semu" untuk kelas Kesalahan bawaan yang ditentukan oleh JavaScript itu sendiri @@ -39,7 +45,7 @@ class Error { Sekarang mari kita mewarisi `ValidationError` darinya dan mencobanya dalam tindakan: -```js run untrusted +```js run *!* class ValidationError extends Error { */!* @@ -122,11 +128,19 @@ Kita juga bisa melihat `err.name`, seperti ini: Versi `instanceof` jauh lebih baik, karena di masa mendatang kita akan memperluas `ValidationError`, membuat subtipe darinya, seperti `PropertyRequiredError`. Dan pemeriksaan `instanceof` akan terus berfungsi untuk kelas pewaris baru. Jadi itu bukti masa depan. +<<<<<<< HEAD Juga penting bahwa jika `catch` menemui kesalahan yang tidak diketahui, maka itu akan ditarik kembali di baris `(**)`. Blok `catch` hanya mengetahui cara menangani validasi dan kesalahan sintaksis, jenis lain (karena kesalahan ketik pada kode atau kesalahan lain yang tidak diketahui) akan gagal. +======= +Also it's important that if `catch` meets an unknown error, then it rethrows it in the line `(**)`. The `catch` block only knows how to handle validation and syntax errors, other kinds (caused by a typo in the code or other unknown reasons) should fall through. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Warisan lebih lanjut +<<<<<<< HEAD Kelas `ValidationError` sangat umum. Banyak hal mungkin salah. Properti mungkin tidak ada atau mungkin dalam format yang salah (seperti nilai string untuk `age`). Mari kita buat kelas yang lebih konkret `PropertyRequiredError`, tepatnya untuk properti yang tidak ada. Ini akan membawa informasi tambahan tentang properti yang hilang. +======= +The `ValidationError` class is very generic. Many things may go wrong. The property may be absent or it may be in a wrong format (like a string value for `age` instead of a number). Let's make a more concrete class `PropertyRequiredError`, exactly for absent properties. It will carry additional information about the property that's missing. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js run class ValidationError extends Error { diff --git a/1-js/11-async/01-callbacks/article.md b/1-js/11-async/01-callbacks/article.md index 8daa4f08d..12b843dd8 100644 --- a/1-js/11-async/01-callbacks/article.md +++ b/1-js/11-async/01-callbacks/article.md @@ -28,7 +28,11 @@ function loadScript(src) { } ``` +<<<<<<< HEAD Fungsi tersebut menambahkan ke dokumen baru, dibuat secara dinamis, tag ` + + diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.js b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.js new file mode 100644 index 000000000..ea55b4478 --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-dom.view/index.js @@ -0,0 +1,24 @@ +const startMessagesBtn = document.querySelector('.start-messages'); // (1) +const closeWindowBtn = document.querySelector('.window__button'); // (2) +const windowElementRef = new WeakRef(document.querySelector(".window__body")); // (3) + +startMessagesBtn.addEventListener('click', () => { // (4) + startMessages(windowElementRef); + startMessagesBtn.disabled = true; +}); + +closeWindowBtn.addEventListener('click', () => document.querySelector(".window__body").remove()); // (5) + + +const startMessages = (element) => { + const timerId = setInterval(() => { // (6) + if (element.deref()) { // (7) + const payload = document.createElement("p"); + payload.textContent = `Message: System status OK: ${new Date().toLocaleTimeString()}`; + element.deref().append(payload); + } else { // (8) + alert("The element has been deleted."); // (9) + clearInterval(timerId); + } + }, 1000); +}; \ No newline at end of file diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-01.svg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-01.svg new file mode 100644 index 000000000..2a507dbcd --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-01.svg @@ -0,0 +1,32 @@ + + + + + + + + user + + name: "John" + Object + + <global> + + + + + + + + + + + + + + + + admin + + + \ No newline at end of file diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-02.svg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-02.svg new file mode 100644 index 000000000..6cc199a12 --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-02.svg @@ -0,0 +1,33 @@ + + + + + + + + + + <global> + + + name: "John" + Object + + + + + + + + + + + + admin + + + + + + + \ No newline at end of file diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-03.svg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-03.svg new file mode 100644 index 000000000..949a14f9f --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-03.svg @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + key + value + image-01.jpg + image-02.jpg + image-03.jpg + + + + + + + + + + + + + + WeakRef object + + + + + + + + + + + + + + + + WeakRef object + + + + + + + + + + + + + + + + + + + WeakRef object + + + + + + + \ No newline at end of file diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-04.svg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-04.svg new file mode 100644 index 000000000..1177d6580 --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-04.svg @@ -0,0 +1,77 @@ + + + + + + + name: "John" + Object + + admin + + + + + + + + + key + value + image-01.jpg + image-02.jpg + image-03.jpg + + + + + + + + + + + + + + WeakRef object + + + + + + + + + + + + + + + + WeakRef object + + + + + undefined + undefined + + + + + + + + + + + + + + + WeakRef object + + + \ No newline at end of file diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-05.svg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-05.svg new file mode 100644 index 000000000..e738f8e7e --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-05.svg @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + image-02.jpg + image-03.jpg + + key + value + image-01.jpg + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + WeakRef object + + + + + + + + + + + + + + + + WeakRef object + + + + + undefined + undefined + Deleted by FinalizationRegistry cleanup callback + + + + + + + + + + + + + + + WeakRef object + + + + \ No newline at end of file diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-01.png b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-01.png new file mode 100644 index 000000000..fc33a023a Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-01.png differ diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-02.png b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-02.png new file mode 100644 index 000000000..7d8bb01e8 Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-02.png differ diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-03.gif b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-03.gif new file mode 100644 index 000000000..b81966dda Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-03.gif differ diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-04.jpg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-04.jpg new file mode 100644 index 000000000..ba60f1e86 Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-04.jpg differ diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-05.gif b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-05.gif new file mode 100644 index 000000000..d34bda4d7 Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-05.gif differ diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-06.jpg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-06.jpg new file mode 100644 index 000000000..b2655540f Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-06.jpg differ diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-07.gif b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-07.gif new file mode 100644 index 000000000..51f874518 Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-07.gif differ diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-08.jpg b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-08.jpg new file mode 100644 index 000000000..5f98aec14 Binary files /dev/null and b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry-demo-08.jpg differ diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.css b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.css new file mode 100644 index 000000000..e6c9e3960 --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.css @@ -0,0 +1,285 @@ +:root { + --mineralGreen: 60, 98, 85; + --viridianGreen: 97, 135, 110; + --swampGreen: 166, 187, 141; + --fallGreen: 234, 231, 177; + --brinkPink: #FA7070; + --silverChalice: 178, 178, 178; + --white: 255, 255, 255; + --black: 0, 0, 0; + + --topBarHeight: 64px; + --itemPadding: 32px; + --containerGap: 8px; +} + +@keyframes zoom-in { + 0% { + transform: scale(1, 1); + } + + 100% { + transform: scale(1.30, 1.30); + } +} + +body, html { + margin: 0; + padding: 0; +} + +.app { + min-height: 100vh; + background-color: rgba(var(--viridianGreen), 0.5); +} + +.header { + height: var(--topBarHeight); + padding: 0 24px; + display: flex; + justify-content: space-between; + align-items: center; + background-color: rgba(var(--mineralGreen), 1); +} + +.header-text { + color: white; +} + +.container { + display: flex; + gap: 24px; + padding: var(--itemPadding); +} + +.item { + width: 50%; +} + +.item--scrollable { + overflow-y: scroll; + height: calc(100vh - var(--topBarHeight) - (var(--itemPadding) * 2)); +} + +.thumbnails-container { + display: flex; + flex-wrap: wrap; + gap: 8px; + justify-content: center; + align-items: center; +} + +.thumbnail-item { + width: calc(25% - var(--containerGap)); + cursor: pointer; + position: relative; +} + +.thumbnail-item:hover { + z-index: 1; + animation: zoom-in 0.1s forwards; +} + +.thumbnail-item--selected { + outline: 3px solid rgba(var(--fallGreen), 1); + outline-offset: -3px; +} + +.badge { + width: 16px; + height: 16px; + display: flex; + justify-content: center; + align-items: center; + padding: 4px; + position: absolute; + right: 8px; + bottom: 8px; + border-radius: 50%; + border: 2px solid rgba(var(--fallGreen), 1); + background-color: rgba(var(--swampGreen), 1); +} + +.check { + display: inline-block; + transform: rotate(45deg); + border-bottom: 2px solid white; + border-right: 2px solid white; + width: 6px; + height: 12px; +} + +.img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.actions { + display: flex; + flex-wrap: wrap; + justify-content: center; + align-content: center; + padding: 0 0 16px 0; + gap: 8px; +} + +.select { + padding: 16px; + cursor: pointer; + font-weight: 700; + color: rgba(var(--black), 1); + border: 2px solid rgba(var(--swampGreen), 0.5); + background-color: rgba(var(--swampGreen), 1); +} + +.select:disabled { + cursor: not-allowed; + background-color: rgba(var(--silverChalice), 1); + color: rgba(var(--black), 0.5); + border: 2px solid rgba(var(--black), 0.25); +} + +.btn { + outline: none; + padding: 16px; + cursor: pointer; + font-weight: 700; + color: rgba(var(--black), 1); + border: 2px solid rgba(var(--black), 0.5); +} + +.btn--primary { + background-color: rgba(var(--mineralGreen), 1); +} + +.btn--primary:hover:not([disabled]) { + background-color: rgba(var(--mineralGreen), 0.85); +} + +.btn--secondary { + background-color: rgba(var(--viridianGreen), 0.5); +} + +.btn--secondary:hover:not([disabled]) { + background-color: rgba(var(--swampGreen), 0.25); +} + +.btn--success { + background-color: rgba(var(--fallGreen), 1); +} + +.btn--success:hover:not([disabled]) { + background-color: rgba(var(--fallGreen), 0.85); +} + +.btn:disabled { + cursor: not-allowed; + background-color: rgba(var(--silverChalice), 1); + color: rgba(var(--black), 0.5); + border: 2px solid rgba(var(--black), 0.25); +} + +.previewContainer { + margin-bottom: 16px; + display: flex; + width: 100%; + height: 40vh; + overflow: scroll; + border: 3px solid rgba(var(--black), 1); +} + +.previewContainer--disabled { + background-color: rgba(var(--black), 0.1); + cursor: not-allowed; +} + +.canvas { + margin: auto; + display: none; +} + +.canvas--ready { + display: block; +} + +.spinnerContainer { + display: flex; + gap: 8px; + flex-direction: column; + align-content: center; + align-items: center; + margin: auto; +} + +.spinnerContainer--hidden { + display: none; +} + +.spinnerText { + margin: 0; + color: rgba(var(--mineralGreen), 1); +} + +.spinner { + display: inline-block; + width: 50px; + height: 50px; + margin: auto; + border: 3px solid rgba(var(--mineralGreen), 0.3); + border-radius: 50%; + border-top-color: rgba(var(--mineralGreen), 0.9); + animation: spin 1s ease-in-out infinite; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + +.loggerContainer { + display: flex; + flex-direction: column; + gap: 8px; + padding: 0 8px 8px 8px; + width: 100%; + min-height: 30vh; + max-height: 30vh; + overflow: scroll; + border-left: 3px solid rgba(var(--black), 0.25); +} + +.logger-title { + display: flex; + align-items: center; + padding: 8px; + position: sticky; + height: 40px; + min-height: 40px; + top: 0; + left: 0; + background-color: rgba(var(--viridianGreen), 1); + font-size: 24px; + font-weight: 700; + margin: 0; +} + +.logger-item { + font-size: 14px; + padding: 8px; + border: 2px solid #5a5a5a; + color: white; +} + +.logger--primary { + background-color: #13315a; +} + +.logger--success { + background-color: #385a4e; +} + +.logger--error { + background-color: #5a1a24; +} \ No newline at end of file diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.html b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.html new file mode 100644 index 000000000..7ce52f927 --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.html @@ -0,0 +1,49 @@ + + + + + + + Photo Library Collage + + + + +
+
+

+ Photo Library Collage +

+
+
+
+ +
+
+
+
+
+ + + + +
+
+
+
+

+
+ +
+
+

Logger:

+
+
+
+
+
+ + + + + diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.js b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.js new file mode 100644 index 000000000..983b34d9a --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/index.js @@ -0,0 +1,228 @@ +import { + createImageFile, + loadImage, + weakRefCache, + LAYOUTS, + images, + THUMBNAIL_PARAMS, + stateObj, +} from "./utils.js"; + +export const state = new Proxy(stateObj, { + set(target, property, value) { + const previousValue = target[property]; + + target[property] = value; + + if (previousValue !== value) { + handleStateChange(target); + } + + return true; + }, +}); + +// Elements. +const thumbnailsContainerEl = document.querySelector(".thumbnails-container"); +const selectEl = document.querySelector(".select"); +const previewContainerEl = document.querySelector(".previewContainer"); +const canvasEl = document.querySelector(".canvas"); +const createCollageBtn = document.querySelector(".btn-create-collage"); +const startOverBtn = document.querySelector(".btn-start-over"); +const downloadBtn = document.querySelector(".btn-download"); +const spinnerContainerEl = document.querySelector(".spinnerContainer"); +const spinnerTextEl = document.querySelector(".spinnerText"); +const loggerContainerEl = document.querySelector(".loggerContainer"); + +// Renders. +// Render thumbnails previews. +images.forEach((img) => { + const thumbnail = document.createElement("div"); + thumbnail.classList.add("thumbnail-item"); + + thumbnail.innerHTML = ` + + `; + + thumbnail.addEventListener("click", (e) => handleSelection(e, img)); + + thumbnailsContainerEl.appendChild(thumbnail); +}); +// Render layouts select. +LAYOUTS.forEach((layout) => { + const option = document.createElement("option"); + option.value = JSON.stringify(layout); + option.innerHTML = layout.name; + selectEl.appendChild(option); +}); + +const handleStateChange = (state) => { + if (state.loading) { + selectEl.disabled = true; + createCollageBtn.disabled = true; + startOverBtn.disabled = true; + downloadBtn.disabled = true; + previewContainerEl.classList.add("previewContainer--disabled"); + spinnerContainerEl.classList.remove("spinnerContainer--hidden"); + spinnerTextEl.innerText = "Loading..."; + canvasEl.classList.remove("canvas--ready"); + } else if (!state.loading) { + selectEl.disabled = false; + createCollageBtn.disabled = false; + startOverBtn.disabled = false; + downloadBtn.disabled = false; + previewContainerEl.classList.remove("previewContainer--disabled"); + spinnerContainerEl.classList.add("spinnerContainer--hidden"); + canvasEl.classList.add("canvas--ready"); + } + + if (!state.selectedImages.size) { + createCollageBtn.disabled = true; + document.querySelectorAll(".badge").forEach((item) => item.remove()); + } else if (state.selectedImages.size && !state.loading) { + createCollageBtn.disabled = false; + } + + if (!state.collageRendered) { + downloadBtn.disabled = true; + } else if (state.collageRendered) { + downloadBtn.disabled = false; + } +}; +handleStateChange(state); + +const handleSelection = (e, imgName) => { + const imgEl = e.currentTarget; + + imgEl.classList.toggle("thumbnail-item--selected"); + + if (state.selectedImages.has(imgName)) { + state.selectedImages.delete(imgName); + state.selectedImages = new Set(state.selectedImages); + imgEl.querySelector(".badge")?.remove(); + } else { + state.selectedImages = new Set(state.selectedImages.add(imgName)); + + const badge = document.createElement("div"); + badge.classList.add("badge"); + badge.innerHTML = ` +
+ `; + imgEl.prepend(badge); + } +}; + +// Make a wrapper function. +let getCachedImage; +(async () => { + getCachedImage = await weakRefCache(loadImage); +})(); + +const calculateGridRows = (blobsLength) => + Math.ceil(blobsLength / state.currentLayout.columns); + +const drawCollage = (images) => { + state.drawing = true; + + let context = canvasEl.getContext("2d"); + + /** + * Calculate canvas dimensions based on the current layout. + * */ + context.canvas.width = + state.currentLayout.itemWidth * state.currentLayout.columns; + context.canvas.height = + calculateGridRows(images.length) * state.currentLayout.itemHeight; + + let currentRow = 0; + let currentCanvasDx = 0; + let currentCanvasDy = 0; + + for (let i = 0; i < images.length; i++) { + /** + * Get current row of the collage. + * */ + if (i % state.currentLayout.columns === 0) { + currentRow += 1; + currentCanvasDx = 0; + + if (currentRow > 1) { + currentCanvasDy += state.currentLayout.itemHeight; + } + } + + context.drawImage( + images[i], + 0, + 0, + images[i].width, + images[i].height, + currentCanvasDx, + currentCanvasDy, + state.currentLayout.itemWidth, + state.currentLayout.itemHeight, + ); + + currentCanvasDx += state.currentLayout.itemWidth; + } + + state.drawing = false; + state.collageRendered = true; +}; + +const createCollage = async () => { + state.loading = true; + + const images = []; + + for (const image of state.selectedImages.values()) { + const blobImage = await getCachedImage(image.img); + + const url = URL.createObjectURL(blobImage); + const img = await createImageFile(url); + + images.push(img); + URL.revokeObjectURL(url); + } + + state.loading = false; + + drawCollage(images); +}; + +/** + * Clear all settled data to start over. + * */ +const startOver = () => { + state.selectedImages = new Set(); + state.collageRendered = false; + const context = canvasEl.getContext("2d"); + context.clearRect(0, 0, canvasEl.width, canvasEl.height); + + document + .querySelectorAll(".thumbnail-item--selected") + .forEach((item) => item.classList.remove("thumbnail-item--selected")); + + loggerContainerEl.innerHTML = '

Logger:

'; +}; + +const downloadCollage = () => { + const date = new Date(); + const fileName = `Collage-${date.getDay()}-${date.getMonth()}-${date.getFullYear()}.png`; + const img = canvasEl.toDataURL("image/png"); + const link = document.createElement("a"); + link.download = fileName; + link.href = img; + link.click(); + link.remove(); +}; + +const changeLayout = ({ target }) => { + state.currentLayout = JSON.parse(target.value); +}; + +// Listeners. +selectEl.addEventListener("change", changeLayout); +createCollageBtn.addEventListener("click", createCollage); +startOverBtn.addEventListener("click", startOver); +downloadBtn.addEventListener("click", downloadCollage); diff --git a/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/utils.js b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/utils.js new file mode 100644 index 000000000..f0140c116 --- /dev/null +++ b/1-js/99-js-misc/07-weakref-finalizationregistry/weakref-finalizationregistry.view/utils.js @@ -0,0 +1,321 @@ +const loggerContainerEl = document.querySelector(".loggerContainer"); + +export const images = [ + { + img: "https://images.unsplash.com/photo-1471357674240-e1a485acb3e1", + }, + { + img: "https://images.unsplash.com/photo-1589118949245-7d38baf380d6", + }, + { + img: "https://images.unsplash.com/photo-1527631746610-bca00a040d60", + }, + { + img: "https://images.unsplash.com/photo-1500835556837-99ac94a94552", + }, + { + img: "https://images.unsplash.com/photo-1503220317375-aaad61436b1b", + }, + { + img: "https://images.unsplash.com/photo-1501785888041-af3ef285b470", + }, + { + img: "https://images.unsplash.com/photo-1528543606781-2f6e6857f318", + }, + { + img: "https://images.unsplash.com/photo-1523906834658-6e24ef2386f9", + }, + { + img: "https://images.unsplash.com/photo-1539635278303-d4002c07eae3", + }, + { + img: "https://images.unsplash.com/photo-1533105079780-92b9be482077", + }, + { + img: "https://images.unsplash.com/photo-1516483638261-f4dbaf036963", + }, + { + img: "https://images.unsplash.com/photo-1502791451862-7bd8c1df43a7", + }, + { + img: "https://plus.unsplash.com/premium_photo-1663047367140-91adf819d007", + }, + { + img: "https://images.unsplash.com/photo-1506197603052-3cc9c3a201bd", + }, + { + img: "https://images.unsplash.com/photo-1517760444937-f6397edcbbcd", + }, + { + img: "https://images.unsplash.com/photo-1518684079-3c830dcef090", + }, + { + img: "https://images.unsplash.com/photo-1505832018823-50331d70d237", + }, + { + img: "https://images.unsplash.com/photo-1524850011238-e3d235c7d4c9", + }, + { + img: "https://plus.unsplash.com/premium_photo-1661277758451-b5053309eea1", + }, + { + img: "https://images.unsplash.com/photo-1541410965313-d53b3c16ef17", + }, + { + img: "https://images.unsplash.com/photo-1528702748617-c64d49f918af", + }, + { + img: "https://images.unsplash.com/photo-1502003148287-a82ef80a6abc", + }, + { + img: "https://plus.unsplash.com/premium_photo-1661281272544-5204ea3a481a", + }, + { + img: "https://images.unsplash.com/photo-1503457574462-bd27054394c1", + }, + { + img: "https://images.unsplash.com/photo-1499363536502-87642509e31b", + }, + { + img: "https://images.unsplash.com/photo-1551918120-9739cb430c6d", + }, + { + img: "https://plus.unsplash.com/premium_photo-1661382219642-43e54f7e81d7", + }, + { + img: "https://images.unsplash.com/photo-1497262693247-aa258f96c4f5", + }, + { + img: "https://images.unsplash.com/photo-1525254134158-4fd5fdd45793", + }, + { + img: "https://plus.unsplash.com/premium_photo-1661274025419-4c54107d5c48", + }, + { + img: "https://images.unsplash.com/photo-1553697388-94e804e2f0f6", + }, + { + img: "https://images.unsplash.com/photo-1574260031597-bcd9eb192b4f", + }, + { + img: "https://images.unsplash.com/photo-1536323760109-ca8c07450053", + }, + { + img: "https://images.unsplash.com/photo-1527824404775-dce343118ebc", + }, + { + img: "https://images.unsplash.com/photo-1612278675615-7b093b07772d", + }, + { + img: "https://images.unsplash.com/photo-1522010675502-c7b3888985f6", + }, + { + img: "https://images.unsplash.com/photo-1501555088652-021faa106b9b", + }, + { + img: "https://plus.unsplash.com/premium_photo-1669223469435-27e091439169", + }, + { + img: "https://images.unsplash.com/photo-1506012787146-f92b2d7d6d96", + }, + { + img: "https://images.unsplash.com/photo-1511739001486-6bfe10ce785f", + }, + { + img: "https://images.unsplash.com/photo-1553342385-111fd6bc6ab3", + }, + { + img: "https://images.unsplash.com/photo-1516546453174-5e1098a4b4af", + }, + { + img: "https://images.unsplash.com/photo-1527142879-95b61a0b8226", + }, + { + img: "https://images.unsplash.com/photo-1520466809213-7b9a56adcd45", + }, + { + img: "https://images.unsplash.com/photo-1516939884455-1445c8652f83", + }, + { + img: "https://images.unsplash.com/photo-1545389336-cf090694435e", + }, + { + img: "https://plus.unsplash.com/premium_photo-1669223469455-b7b734c838f4", + }, + { + img: "https://images.unsplash.com/photo-1454391304352-2bf4678b1a7a", + }, + { + img: "https://images.unsplash.com/photo-1433838552652-f9a46b332c40", + }, + { + img: "https://images.unsplash.com/photo-1506125840744-167167210587", + }, + { + img: "https://images.unsplash.com/photo-1522199873717-bc67b1a5e32b", + }, + { + img: "https://images.unsplash.com/photo-1495904786722-d2b5a19a8535", + }, + { + img: "https://images.unsplash.com/photo-1614094082869-cd4e4b2905c7", + }, + { + img: "https://images.unsplash.com/photo-1474755032398-4b0ed3b2ae5c", + }, + { + img: "https://images.unsplash.com/photo-1501554728187-ce583db33af7", + }, + { + img: "https://images.unsplash.com/photo-1515859005217-8a1f08870f59", + }, + { + img: "https://images.unsplash.com/photo-1531141445733-14c2eb7d4c1f", + }, + { + img: "https://images.unsplash.com/photo-1500259783852-0ca9ce8a64dc", + }, + { + img: "https://images.unsplash.com/photo-1510662145379-13537db782dc", + }, + { + img: "https://images.unsplash.com/photo-1573790387438-4da905039392", + }, + { + img: "https://images.unsplash.com/photo-1512757776214-26d36777b513", + }, + { + img: "https://images.unsplash.com/photo-1518855706573-84de4022b69b", + }, + { + img: "https://images.unsplash.com/photo-1500049242364-5f500807cdd7", + }, + { + img: "https://images.unsplash.com/photo-1528759335187-3b683174c86a", + }, +]; +export const THUMBNAIL_PARAMS = "w=240&h=240&fit=crop&auto=format"; + +// Console styles. +export const CONSOLE_BASE_STYLES = [ + "font-size: 12px", + "padding: 4px", + "border: 2px solid #5a5a5a", + "color: white", +].join(";"); +export const CONSOLE_PRIMARY = [ + CONSOLE_BASE_STYLES, + "background-color: #13315a", +].join(";"); +export const CONSOLE_SUCCESS = [ + CONSOLE_BASE_STYLES, + "background-color: #385a4e", +].join(";"); +export const CONSOLE_ERROR = [ + CONSOLE_BASE_STYLES, + "background-color: #5a1a24", +].join(";"); + +// Layouts. +export const LAYOUT_4_COLUMNS = { + name: "Layout 4 columns", + columns: 4, + itemWidth: 240, + itemHeight: 240, +}; +export const LAYOUT_8_COLUMNS = { + name: "Layout 8 columns", + columns: 8, + itemWidth: 240, + itemHeight: 240, +}; +export const LAYOUTS = [LAYOUT_4_COLUMNS, LAYOUT_8_COLUMNS]; + +export const createImageFile = async (src) => + new Promise((resolve, reject) => { + const img = new Image(); + img.src = src; + img.onload = () => resolve(img); + img.onerror = () => reject(new Error("Failed to construct image.")); + }); + +export const loadImage = async (url) => { + try { + const response = await fetch(url); + if (!response.ok) { + throw new Error(String(response.status)); + } + + return await response.blob(); + } catch (e) { + console.log(`%cFETCHED_FAILED: ${e}`, CONSOLE_ERROR); + } +}; + +export const weakRefCache = (fetchImg) => { + const imgCache = new Map(); + const registry = new FinalizationRegistry(({ imgName, size, type }) => { + const cachedImg = imgCache.get(imgName); + if (cachedImg && !cachedImg.deref()) { + imgCache.delete(imgName); + console.log( + `%cCLEANED_IMAGE: Url: ${imgName}, Size: ${size}, Type: ${type}`, + CONSOLE_ERROR, + ); + + const logEl = document.createElement("div"); + logEl.classList.add("logger-item", "logger--error"); + logEl.innerHTML = `CLEANED_IMAGE: Url: ${imgName}, Size: ${size}, Type: ${type}`; + loggerContainerEl.appendChild(logEl); + loggerContainerEl.scrollTop = loggerContainerEl.scrollHeight; + } + }); + + return async (imgName) => { + const cachedImg = imgCache.get(imgName); + + if (cachedImg?.deref() !== undefined) { + console.log( + `%cCACHED_IMAGE: Url: ${imgName}, Size: ${cachedImg.size}, Type: ${cachedImg.type}`, + CONSOLE_SUCCESS, + ); + + const logEl = document.createElement("div"); + logEl.classList.add("logger-item", "logger--success"); + logEl.innerHTML = `CACHED_IMAGE: Url: ${imgName}, Size: ${cachedImg.size}, Type: ${cachedImg.type}`; + loggerContainerEl.appendChild(logEl); + loggerContainerEl.scrollTop = loggerContainerEl.scrollHeight; + + return cachedImg?.deref(); + } + + const newImg = await fetchImg(imgName); + console.log( + `%cFETCHED_IMAGE: Url: ${imgName}, Size: ${newImg.size}, Type: ${newImg.type}`, + CONSOLE_PRIMARY, + ); + + const logEl = document.createElement("div"); + logEl.classList.add("logger-item", "logger--primary"); + logEl.innerHTML = `FETCHED_IMAGE: Url: ${imgName}, Size: ${newImg.size}, Type: ${newImg.type}`; + loggerContainerEl.appendChild(logEl); + loggerContainerEl.scrollTop = loggerContainerEl.scrollHeight; + + imgCache.set(imgName, new WeakRef(newImg)); + registry.register(newImg, { + imgName, + size: newImg.size, + type: newImg.type, + }); + + return newImg; + }; +}; + +export const stateObj = { + loading: false, + drawing: true, + collageRendered: false, + currentLayout: LAYOUTS[0], + selectedImages: new Set(), +}; diff --git a/2-ui/1-document/01-browser-environment/article.md b/2-ui/1-document/01-browser-environment/article.md index f6aa6a09d..9406b5b92 100644 --- a/2-ui/1-document/01-browser-environment/article.md +++ b/2-ui/1-document/01-browser-environment/article.md @@ -2,11 +2,21 @@ # Browser environment, specs Bahasa JavaScript awal mulanya dibuat untuk web browser. Sejak saat itu terus berevolusi dan menjadi sebuah bahasa dengan banyak pengguna dan platform. +<<<<<<< HEAD Sebuah platform bisa menjadi browser, atau sebuah web-server ataupun *host* yang lain, sampai sebuah mesin kopi yang "cerdas", jika itu bisa menjalankan JavaScript. Masing-masing darinya menyediakan fungsionalitas platform yang spesifik. Spesifik JavaScript menyebut itu sebagai sebuah *host environment*. Sebuah host environment menyediakan objek-objek tersendiri dan fungsi-fungsi tambahan ke pusat bahasa. Web browser memberikan sebuah sarana untuk mengontrol halaman-halaman web. Berikut adalah sebuah pandangan luas tentang apa yang kita punya ketika JavaScript berjalan di sebuah web browser: +======= +The JavaScript language was initially created for web browsers. Since then, it has evolved into a language with many uses and platforms. + +A platform may be a browser, or a web-server or another *host*, or even a "smart" coffee machine if it can run JavaScript. Each of these provides platform-specific functionality. The JavaScript specification calls that a *host environment*. + +A host environment provides its own objects and functions in addition to the language core. Web browsers give a means to control web pages. Node.js provides server-side features, and so on. + +Here's a bird's-eye view of what we have when JavaScript runs in a web browser: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ![](windowObjects.svg) @@ -15,9 +25,15 @@ Ada sebuah "root" objek yang dinamakan `window`. Mempunyai 2 peranan: 1. Pertama, ini adalah sebuah global objek untuk kode JavaScript, dideskripsikan di bab . 2. Kedua, ini mempresentasikan dari "browser window" dan menyediakan metode-metode untuk mengontrolnya. +<<<<<<< HEAD Misalnya, disini kita akan menggunakannya sebagai sebuah global objek: ```js berjalan +======= +For instance, we can use it as a global object: + +```js run global +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 function sayHi() { alert("Hello"); } @@ -27,18 +43,30 @@ function sayHi() { window.sayHi(); ``` +<<<<<<< HEAD Dan sekarang kita menggunakannya sebagai jendela browser, untuk melihat tinggi jendela: +======= +And we can use it as a browser window, to show the window height: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```js berjalan alert(window.innerHeight); // tinggi jendela bagian dalam ``` +<<<<<<< HEAD Berikut lebih banyak metode dan properti window-specific, kita akan membahasnya nanti. +======= +There are more window-specific methods and properties, which we'll cover later. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## DOM (Document Object Model) Document Object Model, atau disingkat DOM, mempresentasikan semua konten halaman sebagai objek yang bisa dimodifikasi. +<<<<<<< HEAD Objek `document` adalah "pintu masuk" utama dari halaman. Kita bisa mengubahnya atau membuat apapun untuk dipakai halaman tersebut. +======= +The Document Object Model, or DOM for short, represents all page content as objects that can be modified. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Sebagai contoh: ```js run @@ -49,18 +77,30 @@ document.body.style.background = "red"; setTimeout(() => document.body.style.background = "", 1000); ``` +<<<<<<< HEAD Disini kita menggunakan `document.body.style`, tapi ada lebih banyak, banyak lagi. Properti dan metode-metode dideskripsikan di spesifikasi: [DOM Living Standard](https://dom.spec.whatwg.org). +======= +Here, we used `document.body.style`, but there's much, much more. Properties and methods are described in the specification: [DOM Living Standard](https://dom.spec.whatwg.org). +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```smart header="DOM is not only for browsers" Spesifikasi DOM menjelaskan struktur dari sebuah dokumen dan penyedia objek untuk memanipulasinya. Ada instrumen dari non-browser yang menggunakan DOM juga. +<<<<<<< HEAD Sebagai contoh, skrip server-side yang mengunduh halaman-halaman HTML dan memprosesnya juga menggunakan DOM. Mereka mungkin hanya mendukung sebagian dari spesifikasi tersebut. +======= +For instance, server-side scripts that download HTML pages and process them can also use the DOM. They may support only a part of the specification though. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ```smart header="CSSOM for styling" Ada juga spesifikasi terpisah, [CSS Object Model (CSSOM)](https://www.w3.org/TR/cssom-1/) untuk aturan dan stylesheets CSS, yang menjelaskan bagaimana mereka di representasilan sebagai objek, dan bagaimana mereka membaca dan menulisnya. +<<<<<<< HEAD CSSOM digunakan bersamaan dengan DOM ketika kita memodifikasi style aturan untuk dokumen. Di prakteknya sekalipun, CSSOM jarang dibutuhkan, karena kita jarang untuk memodifikasi aturan CSS dari JavaScript (biasanya kita hanya menambah/menghapus class dari CSS, tidak memodifikasi aturan dari CSS-nya), tapi itu juga memungkinkan. +======= +The CSSOM is used together with the DOM when we modify style rules for the document. In practice though, the CSSOM is rarely required, because we rarely need to modify CSS rules from JavaScript (usually we just add/remove CSS classes, not modify their CSS rules), but that's also possible. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ## BOM (Browser Object Model) @@ -69,8 +109,13 @@ Browser Object Model (BOM) mempresentasikan tambahan dari objek-objek yang dised Sebagai contoh: +<<<<<<< HEAD - Objek [navigator](mdn:api/Window/navigator) menyediakan informasi di latar belakang tentang browser dan operasi sistem. Disitu banyak sekali properti, tapi ada 2 yang sudah banyak diketahui yaitu: `navigator.userAgent` -- tentang browser sekarang, dan `navigator.platform` -- tentang platform (yang bisa membantu untuk membedakan antara Windows/Linux/Mac dan sebagainya). - Objek [location](mdn:api/Window/location) memungkinkan kita untuk membaca URL sekarang yang akan mengarahkan browser ke satu yang baru. +======= +- The [navigator](mdn:api/Window/navigator) object provides background information about the browser and the operating system. There are many properties, but the two most widely known are: `navigator.userAgent` -- about the current browser, and `navigator.platform` -- about the platform (can help to differentiate between Windows/Linux/Mac etc). +- The [location](mdn:api/Window/location) object allows us to read the current URL and can redirect the browser to a new one. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Berikut adalah bagaimana kita bisa menggunakan objek `location`: @@ -81,33 +126,60 @@ if (confirm("Pergi ke Wikipedia?")) { } ``` +<<<<<<< HEAD Fungsi `alert/confirm/prompt` juga bagian dari BOM: mereka tidak berhubungan secara langsung dengan dokumen, tapi mempresentasikan metode komunikasi dengan pengguna pada browser asli. ```smart header="Specifications" BOM adalah bagian dari [spesifikasi HTML](https://html.spec.whatwg.org) pada umumnya. Ya, yang kamu dengar benar. Spesifikasi HTML pada bukanlah satu-satunya tentang "bahasa HTML" (tags, attributes), tapi juga mencakup banyak objek, metode-metode dan spesifikasi-browser ekstensi DOM. Itu adalah "HTML dalam istilah yang luas". Juga, beberapa bagian-bagian punya tambahan spesifikasi yang terdaftar di . +======= +The functions `alert/confirm/prompt` are also a part of the BOM: they are not directly related to the document, but represent pure browser methods for communicating with the user. + +```smart header="Specifications" +The BOM is a part of the general [HTML specification](https://html.spec.whatwg.org). + +Yes, you heard that right. The HTML spec at is not only about the "HTML language" (tags, attributes), but also covers a bunch of objects, methods, and browser-specific DOM extensions. That's "HTML in broad terms". Also, some parts have additional specs listed at . +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ``` ## Ringkasan Berbicara tentang standard, kita mempunyai: +<<<<<<< HEAD Spesifikasi DOM : Mendeskripsikan struktur dokumen, manipulasi dan events, lihat . Spesifikasi CSSOM : Mendeskripsikan stylesheets dan aturan gaya, manipulasi dengannya dan perbandingannya dengan dokumen, lihat . +======= +DOM specification +: Describes the document structure, manipulations, and events, see . + +CSSOM specification +: Describes stylesheets and style rules, manipulations with them, and their binding to documents, see . +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Spesifikasi HTML : Menjelaskan bahasa HTML (contoh. tags) dan juga BOM (browser object model) -- macam-macam fungsi browser: `setTimeout`, `alert`, `location` dan banyak lagi, lihat . Dengan itu bisa mengambil spesifikasi DOM dan meluaskannya dengan banyak properti dan metode. Selain itu, beberapa class telah dideskripsikan terpisah di . +<<<<<<< HEAD Mohon catat tautan ini, karena ada begitu banyak hal untuk dipelajari dan mustahil untuk mencakup dan mengingat semuanya. Ketika anda ingin untuk membaca tentang sebua properti atau sebuah metode, Mozilla manual di juga sebuah bahan yang bagus, tapi kesesuaian spesifikasi mungkin lebih baik: ada yang lebih kompleks dan bacaan yang panjang, tapi akan membuat dasar pengetahuan anda bersuara dan lengkap. +======= +Please note these links, as there's so much to learn that it's impossible to cover everything and remember it all. + +When you'd like to read about a property or a method, the Mozilla manual at is also a nice resource, but the corresponding spec may be better: it's more complex and longer to read, but will make your fundamental knowledge sound and complete. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Untuk menemukan sesuatu, akan semakin nyaman memakai pencarian internet "WHATWG [term]" atau "MDN [term]", contoh , . +<<<<<<< HEAD Sekarang kita akan turun untuk mempelajari DOM, karena dokumen memiliki peranan pusat dalam UI. +======= +Now, we'll get down to learning the DOM, because the document plays the central role in the UI. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/2-ui/1-document/02-dom-nodes/article.md b/2-ui/1-document/02-dom-nodes/article.md index e08acd681..b0f76af37 100644 --- a/2-ui/1-document/02-dom-nodes/article.md +++ b/2-ui/1-document/02-dom-nodes/article.md @@ -51,7 +51,7 @@ DOM menggambarkan HTML seperti struktur pohon pada tag. Begini tampilannya:
@@ -211,7 +211,11 @@ Ada [12 jenis-jenis node](https://dom.spec.whatwg.org/#node). Dalam praktiknya k ## Melihatnya untuk kita sendiri +<<<<<<< HEAD Untuk melihat struktur DOM secara real-time, coba [Live DOM Viewer](http://software.hixie.ch/utilities/js/live-dom-viewer/). Cukup ketikkan dokumen, dan itu akan muncul sebagai DOM dalam sekejap. +======= +To see the DOM structure in real-time, try [Live DOM Viewer](https://software.hixie.ch/utilities/js/live-dom-viewer/). Just type in the document, and it will show up as a DOM at an instant. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Cara lain untuk menjelajahi DOM gunakan alat pengembang browser. Sebenarnya itulah yang kita gunakan saat mengembangkan. diff --git a/2-ui/1-document/04-searching-elements-dom/article.md b/2-ui/1-document/04-searching-elements-dom/article.md index 214145e56..a039d85b2 100644 --- a/2-ui/1-document/04-searching-elements-dom/article.md +++ b/2-ui/1-document/04-searching-elements-dom/article.md @@ -54,7 +54,12 @@ Dan juga, terdapat variabel global yang dinamakan `id` untuk mereferensikan elem ``` +<<<<<<< HEAD ```warn header= "Tolong jangan gunakan variabel global dengan nama id untuk mengakses elemen" +======= +```warn header="Please don't use id-named global variables to access elements" +This behavior is described [in the specification](https://html.spec.whatwg.org/multipage/window-object.html#named-access-on-the-window-object), but it is supported mainly for compatibility. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Perilaku ini dideskripsikan pada [di spesifikasi](http://www.whatwg.org/specs/web-apps/current-work/#dom-window-nameditem), Jadi ini sudah standar. Tetapi ini didukung terutama untuk kompabilitas. @@ -118,7 +123,11 @@ Metode sebelumnya digunakan untuk mencari DOM. metode [elem.matches(css)](http://dom.spec.whatwg.org/#dom-element-matches) tidak mencari apapun, metode ini hanya memeriksa apakan `elem` sama dengan *selector* CSS yang diberikan. Metode ini mengembalikan `true` atau `false`. +<<<<<<< HEAD Metode ini akan berguna saat kita mengulang elemen yang banyak (seperti *array* atau yang lain) dan mencoba untuk menyaring apa yang kita inginkan. +======= +The [elem.matches(css)](https://dom.spec.whatwg.org/#dom-element-matches) does not look for anything, it merely checks if `elem` matches the given CSS-selector. It returns `true` or `false`. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Contoh: @@ -154,7 +163,7 @@ Contoh:
  • Chapter 1
  • -
  • Chapter 1
  • +
  • Chapter 2
diff --git a/2-ui/1-document/05-basic-dom-node-properties/article.md b/2-ui/1-document/05-basic-dom-node-properties/article.md index fc3bf6525..99dde5bcd 100644 --- a/2-ui/1-document/05-basic-dom-node-properties/article.md +++ b/2-ui/1-document/05-basic-dom-node-properties/article.md @@ -10,7 +10,7 @@ Different DOM nodes may have different properties. For instance, an element node Each DOM node belongs to the corresponding built-in class. -The root of the hierarchy is [EventTarget](https://dom.spec.whatwg.org/#eventtarget), that is inherited by [Node](http://dom.spec.whatwg.org/#interface-node), and other DOM nodes inherit from it. +The root of the hierarchy is [EventTarget](https://dom.spec.whatwg.org/#eventtarget), that is inherited by [Node](https://dom.spec.whatwg.org/#interface-node), and other DOM nodes inherit from it. Here's the picture, explanations to follow: @@ -18,16 +18,39 @@ Here's the picture, explanations to follow: The classes are: -- [EventTarget](https://dom.spec.whatwg.org/#eventtarget) -- is the root "abstract" class. Objects of that class are never created. It serves as a base, so that all DOM nodes support so-called "events", we'll study them later. -- [Node](http://dom.spec.whatwg.org/#interface-node) -- is also an "abstract" class, serving as a base for DOM nodes. It provides the core tree functionality: `parentNode`, `nextSibling`, `childNodes` and so on (they are getters). Objects of `Node` class are never created. But there are concrete node classes that inherit from it, namely: `Text` for text nodes, `Element` for element nodes and more exotic ones like `Comment` for comment nodes. -- [Element](http://dom.spec.whatwg.org/#interface-element) -- is a base class for DOM elements. It provides element-level navigation like `nextElementSibling`, `children` and searching methods like `getElementsByTagName`, `querySelector`. A browser supports not only HTML, but also XML and SVG. The `Element` class serves as a base for more specific classes: `SVGElement`, `XMLElement` and `HTMLElement`. -- [HTMLElement](https://html.spec.whatwg.org/multipage/dom.html#htmlelement) -- is finally the basic class for all HTML elements. It is inherited by concrete HTML elements: +- [EventTarget](https://dom.spec.whatwg.org/#eventtarget) -- is the root "abstract" class for everything. + + Objects of that class are never created. It serves as a base, so that all DOM nodes support so-called "events", we'll study them later. + +- [Node](https://dom.spec.whatwg.org/#interface-node) -- is also an "abstract" class, serving as a base for DOM nodes. + + It provides the core tree functionality: `parentNode`, `nextSibling`, `childNodes` and so on (they are getters). Objects of `Node` class are never created. But there are other classes that inherit from it (and so inherit the `Node` functionality). + +- [Document](https://dom.spec.whatwg.org/#interface-document), for historical reasons often inherited by `HTMLDocument` (though the latest spec doesn't dictate it) -- is a document as a whole. + + The `document` global object belongs exactly to this class. It serves as an entry point to the DOM. + +- [CharacterData](https://dom.spec.whatwg.org/#interface-characterdata) -- an "abstract" class, inherited by: + - [Text](https://dom.spec.whatwg.org/#interface-text) -- the class corresponding to a text inside elements, e.g. `Hello` in `

Hello

`. + - [Comment](https://dom.spec.whatwg.org/#interface-comment) -- the class for comments. They are not shown, but each comment becomes a member of DOM. + +- [Element](https://dom.spec.whatwg.org/#interface-element) -- is the base class for DOM elements. + + It provides element-level navigation like `nextElementSibling`, `children` and searching methods like `getElementsByTagName`, `querySelector`. + + A browser supports not only HTML, but also XML and SVG. So the `Element` class serves as a base for more specific classes: `SVGElement`, `XMLElement` (we don't need them here) and `HTMLElement`. + +- Finally, [HTMLElement](https://html.spec.whatwg.org/multipage/dom.html#htmlelement) is the basic class for all HTML elements. We'll work with it most of the time. + + It is inherited by concrete HTML elements: - [HTMLInputElement](https://html.spec.whatwg.org/multipage/forms.html#htmlinputelement) -- the class for `` elements, - [HTMLBodyElement](https://html.spec.whatwg.org/multipage/semantics.html#htmlbodyelement) -- the class for `` elements, - [HTMLAnchorElement](https://html.spec.whatwg.org/multipage/semantics.html#htmlanchorelement) -- the class for `` elements, - - ...and so on, each tag has its own class that may provide specific properties and methods. + - ...and so on. + +There are many other tags with their own classes that may have specific properties and methods, while some elements, such as ``, `
`, `
` do not have any specific properties, so they are instances of `HTMLElement` class. -So, the full set of properties and methods of a given node comes as the result of the inheritance. +So, the full set of properties and methods of a given node comes as the result of the chain of inheritance. For example, let's consider the DOM object for an `` element. It belongs to [HTMLInputElement](https://html.spec.whatwg.org/multipage/forms.html#htmlinputelement) class. @@ -128,13 +151,13 @@ For instance: ```html run - ``` +<<<<<<< HEAD Tetapi ada pengecualian, misalnya `input.value` disinkronkan hanya dari atribut -> ke properti, tapi tidak sebaliknya: +======= +But there are exclusions, for instance `input.value` synchronizes only from attribute -> property, but not back: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```html run diff --git a/2-ui/1-document/07-modifying-document/10-clock-setinterval/solution.view/index.html b/2-ui/1-document/07-modifying-document/10-clock-setinterval/solution.view/index.html index de8ec9aee..84ee26f19 100644 --- a/2-ui/1-document/07-modifying-document/10-clock-setinterval/solution.view/index.html +++ b/2-ui/1-document/07-modifying-document/10-clock-setinterval/solution.view/index.html @@ -45,7 +45,7 @@ function clockStart() { // set a new interval only if the clock is stopped // otherwise we would rewrite the timerID reference to the running interval and wouldn't be able to stop the clock ever again - if (!timerId) { + if (!timerId) { timerId = setInterval(update, 1000); } update(); // <-- start right now, don't wait 1 second till the first setInterval works @@ -56,7 +56,6 @@ timerId = null; // <-- clear timerID to indicate that the clock has been stopped, so that it is possible to start it again in clockStart() } - clockStart(); diff --git a/2-ui/1-document/07-modifying-document/5-why-aaa/task.md b/2-ui/1-document/07-modifying-document/5-why-aaa/task.md index f87074dba..861f70503 100644 --- a/2-ui/1-document/07-modifying-document/5-why-aaa/task.md +++ b/2-ui/1-document/07-modifying-document/5-why-aaa/task.md @@ -22,6 +22,6 @@ Why does that happen? alert(table); // the table, as it should be table.remove(); - // why there's still aaa in the document? + // why there's still "aaa" in the document? ``` diff --git a/2-ui/1-document/08-styles-and-classes/article.md b/2-ui/1-document/08-styles-and-classes/article.md index 9154d43d6..46aaa3b00 100644 --- a/2-ui/1-document/08-styles-and-classes/article.md +++ b/2-ui/1-document/08-styles-and-classes/article.md @@ -128,6 +128,14 @@ setTimeout(() => document.body.style.display = "", 1000); // back to normal If we set `style.display` to an empty string, then the browser applies CSS classes and its built-in styles normally, as if there were no such `style.display` property at all. +Also there is a special method for that, `elem.style.removeProperty('style property')`. So, We can remove a property like this: + +```js run +document.body.style.background = 'red'; //set background to red + +setTimeout(() => document.body.style.removeProperty('background'), 1000); // remove background after 1 second +``` + ````smart header="Full rewrite with `style.cssText`" Normally, we use `style.*` to assign individual style properties. We can't set the full style like `div.style="color: red; width: 100px"`, because `div.style` is an object, and it's read-only. @@ -261,20 +269,6 @@ So nowadays `getComputedStyle` actually returns the resolved value of the proper We should always ask for the exact property that we want, like `paddingLeft` or `marginTop` or `borderTopWidth`. Otherwise the correct result is not guaranteed. For instance, if there are properties `paddingLeft/paddingTop`, then what should we get for `getComputedStyle(elem).padding`? Nothing, or maybe a "generated" value from known paddings? There's no standard rule here. - -There are other inconsistencies. As an example, some browsers (Chrome) show `10px` in the document below, and some of them (Firefox) -- do not: - -```html run - - -``` ```` ```smart header="Styles applied to `:visited` links are hidden!" diff --git a/2-ui/1-document/09-size-and-scroll/article.md b/2-ui/1-document/09-size-and-scroll/article.md index 13e245ebb..66f28115f 100644 --- a/2-ui/1-document/09-size-and-scroll/article.md +++ b/2-ui/1-document/09-size-and-scroll/article.md @@ -17,8 +17,8 @@ As a sample element to demonstrate properties we'll use the one given below: width: 300px; height: 200px; border: 25px solid #E8C48F; - padding: 20px; - overflow: auto; + padding: 20px; + overflow: auto; } ``` @@ -106,7 +106,7 @@ Geometry properties are calculated only for displayed elements. If an element (or any of its ancestors) has `display:none` or is not in the document, then all geometry properties are zero (or `null` for `offsetParent`). -For example, `offsetParent` is `null`, and `offsetWidth`, `offsetHeight` are `0` when we created an element, but haven't inserted it into the document yet, or it (or it's ancestor) has `display:none`. +For example, `offsetParent` is `null`, and `offsetWidth`, `offsetHeight` are `0` when we created an element, but haven't inserted it into the document yet, or it (or its ancestor) has `display:none`. We can use this to check if an element is hidden, like this: @@ -116,7 +116,7 @@ function isHidden(elem) { } ``` -Please note that such `isHidden` returns `true` for elements that are on-screen, but have zero sizes (like an empty `
`). +Please note that such `isHidden` returns `true` for elements that are on-screen, but have zero sizes. ```` ## clientTop/Left diff --git a/2-ui/1-document/11-coordinates/article.md b/2-ui/1-document/11-coordinates/article.md index 4775ff0eb..fc605c414 100644 --- a/2-ui/1-document/11-coordinates/article.md +++ b/2-ui/1-document/11-coordinates/article.md @@ -36,7 +36,7 @@ Additionally, there are derived properties: ```online For instance click this button to see its window coordinates: -

+

diff --git a/2-ui/3-event-details/6-pointer-events/slider.view/style.css b/2-ui/3-event-details/6-pointer-events/slider.view/style.css index 9b3d3b82d..a84cd5e7e 100644 --- a/2-ui/3-event-details/6-pointer-events/slider.view/style.css +++ b/2-ui/3-event-details/6-pointer-events/slider.view/style.css @@ -8,6 +8,7 @@ } .thumb { + touch-action: none; width: 10px; height: 25px; border-radius: 3px; diff --git a/2-ui/3-event-details/7-keyboard-events/article.md b/2-ui/3-event-details/7-keyboard-events/article.md index 54bde42b4..12fe63201 100644 --- a/2-ui/3-event-details/7-keyboard-events/article.md +++ b/2-ui/3-event-details/7-keyboard-events/article.md @@ -107,7 +107,7 @@ So, `event.code` may match a wrong character for unexpected layout. Same letters To reliably track layout-dependent characters, `event.key` may be a better way. -On the other hand, `event.code` has the benefit of staying always the same, bound to the physical key location, even if the visitor changes languages. So hotkeys that rely on it work well even in case of a language switch. +On the other hand, `event.code` has the benefit of staying always the same, bound to the physical key location. So hotkeys that rely on it work well even in case of a language switch. Do we want to handle layout-dependant keys? Then `event.key` is the way to go. @@ -139,22 +139,25 @@ For instance, the `` below expects a phone number, so it does not accept ```html autorun height=60 run ``` -Please note that special keys, such as `key:Backspace`, `key:Left`, `key:Right`, `key:Ctrl+V`, do not work in the input. That's a side-effect of the strict filter `checkPhoneKey`. +The `onkeydown` handler here uses `checkPhoneKey` to check for the key pressed. If it's valid (from `0..9` or one of `+-()`), then it returns `true`, otherwise `false`. -Let's relax it a little bit: +As we know, the `false` value returned from the event handler, assigned using a DOM property or an attribute, such as above, prevents the default action, so nothing appears in the `` for keys that don't pass the test. (The `true` value returned doesn't affect anything, only returning `false` matters) +Please note that special keys, such as `key:Backspace`, `key:Left`, `key:Right`, do not work in the input. That's a side effect of the strict filter `checkPhoneKey`. These keys make it return `false`. + +Let's relax the filter a little bit by allowing arrow keys `key:Left`, `key:Right` and `key:Delete`, `key:Backspace`: ```html autorun height=60 run @@ -162,7 +165,9 @@ function checkPhoneKey(key) { Now arrows and deletion works well. -...But we still can enter anything by using a mouse and right-click + Paste. So the filter is not 100% reliable. We can just let it be like that, because most of time it works. Or an alternative approach would be to track the `input` event -- it triggers after any modification. There we can check the new value and highlight/modify it when it's invalid. +Even though we have the key filter, one still can enter anything using a mouse and right-click + Paste. Mobile devices provide other means to enter values. So the filter is not 100% reliable. + +The alternative approach would be to track the `oninput` event -- it triggers *after* any modification. There we can check the new `input.value` and modify it/highlight the `` when it's invalid. Or we can use both event handlers together. ## Legacy diff --git a/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/index.html b/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/index.html index 401062830..a0d5a4f40 100644 --- a/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/index.html +++ b/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/index.html @@ -28,7 +28,7 @@ - + diff --git a/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/script.js b/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/script.js index 5eba24c7a..d97f7a7b5 100644 --- a/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/script.js +++ b/2-ui/3-event-details/7-keyboard-events/keyboard-dump.view/script.js @@ -5,6 +5,8 @@ let lastTime = Date.now(); function handle(e) { if (form.elements[e.type + 'Ignore'].checked) return; + area.scrollTop = 1e6; + let text = e.type + ' key=' + e.key + ' code=' + e.code + diff --git a/2-ui/4-forms-controls/1-form-elements/article.md b/2-ui/4-forms-controls/1-form-elements/article.md index b67a8c185..4ef57d60e 100644 --- a/2-ui/4-forms-controls/1-form-elements/article.md +++ b/2-ui/4-forms-controls/1-form-elements/article.md @@ -154,7 +154,11 @@ Mari bicara tentang kontrol form. ### input dan textarea +<<<<<<< HEAD Kita bisa akses nilai mereka dengan `input.value` (string) atau `input.checked` (boolean) untuk checkboxes. +======= +We can access their value as `input.value` (string) or `input.checked` (boolean) for checkboxes and radio buttons. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Seperti ini: @@ -247,7 +251,11 @@ This syntax is optional. We can use `document.createElement('option')` and set a - `defaultSelected` -- jika `true`, maka `selected` HTML-attribute dibuat, - `selected` -- jika `true`, maka option nya *selected*. +<<<<<<< HEAD Disana mungkin sedikit bingung tentang `defaultSelected` dan `selected`. That's simple: `defaultSelected` *set* HTML-attribute, dengan itu kita bisa dapat menggunakan `option.getAttribute('selected')`. Dan `selected` - baik opsi *selected* atau tidak, itu yang lebih penting. Biasanya kedua nilai baik di *set* ke `true` atau tidak di *set* (sama dengan `false`). +======= +The difference between `defaultSelected` and `selected` is that `defaultSelected` sets the HTML-attribute (that we can get using `option.getAttribute('selected')`), while `selected` sets whether the option is selected or not. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Misalnya: diff --git a/2-ui/4-forms-controls/2-focus-blur/article.md b/2-ui/4-forms-controls/2-focus-blur/article.md index c460543e7..540ef5e03 100644 --- a/2-ui/4-forms-controls/2-focus-blur/article.md +++ b/2-ui/4-forms-controls/2-focus-blur/article.md @@ -97,6 +97,8 @@ Jika kita sedang mengetik/memasukkan sesuatu ke input dan coba menggunakan`key:T Perlu diingat bahwa kita tidak bisa "mencegah hilangnya fokus" dengan memanggil `event.preventDefault()` pada `onblur`, karena `onblur` bekerja saat element hilang fokus. +In practice though, one should think well, before implementing something like this, because we generally *should show errors* to the user, but *should not prevent their progress* in filling our form. They may want to fill other fields first. + ```warn header="JavaScript-initiated focus loss" Focus loss bisa terjadi untuk alasan tertentu. diff --git a/2-ui/4-forms-controls/3-events-change-input/1-deposit-calculator/solution.view/index.html b/2-ui/4-forms-controls/3-events-change-input/1-deposit-calculator/solution.view/index.html index 4850b2ca9..0515c839e 100644 --- a/2-ui/4-forms-controls/3-events-change-input/1-deposit-calculator/solution.view/index.html +++ b/2-ui/4-forms-controls/3-events-change-input/1-deposit-calculator/solution.view/index.html @@ -96,7 +96,7 @@ let years = form.months.value / 12; if (!years) return; - let result = Math.round(initial * (1 + interest * years)); + let result = Math.round(initial * (1 + interest) ** years); let height = result / form.money.value * 100 + 'px'; document.getElementById('height-after').style.height = height; diff --git a/2-ui/4-forms-controls/3-events-change-input/1-deposit-calculator/task.md b/2-ui/4-forms-controls/3-events-change-input/1-deposit-calculator/task.md index e324577a9..73f0477ff 100644 --- a/2-ui/4-forms-controls/3-events-change-input/1-deposit-calculator/task.md +++ b/2-ui/4-forms-controls/3-events-change-input/1-deposit-calculator/task.md @@ -17,5 +17,5 @@ The formula is: // initial: the initial money sum // interest: e.g. 0.05 means 5% per year // years: how many years to wait -let result = Math.round(initial * (1 + interest * years)); +let result = Math.round(initial * (1 + interest) ** years); ``` diff --git a/2-ui/4-forms-controls/3-events-change-input/article.md b/2-ui/4-forms-controls/3-events-change-input/article.md index 28286ef27..b4efa3501 100644 --- a/2-ui/4-forms-controls/3-events-change-input/article.md +++ b/2-ui/4-forms-controls/3-events-change-input/article.md @@ -58,22 +58,36 @@ Jadi kita tidak bisa menggunakan `event.preventDefault()` disana -- terlalu terl *Event* ini terjadi saat memotong/menyalin/menempelkan nilai. +<<<<<<< HEAD Mereka termasuk dalam kelas [ClipboardEvent](https://www.w3.org/TR/clipboard-apis/#clipboard-event-interfaces) dan menyediakan akses ke data yang disalin/ditempel. +======= +They belong to [ClipboardEvent](https://www.w3.org/TR/clipboard-apis/#clipboard-event-interfaces) class and provide access to the data that is cut/copied/pasted. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 Kita juga bisa menggunakan `event.preventDefault()` untuk membatalkan aksi, maka tidak akan ada yang disalin/ditempel. +<<<<<<< HEAD Contohnya, kode di bawah ini mencegah semua *event* tersebut dan menunjukkan apa yang kita coba potong/salin/tempel: +======= +For instance, the code below prevents all `cut/copy/paste` events and shows the text we're trying to cut/copy/paste: +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ```html autorun height=40 run ``` +<<<<<<< HEAD Harap dicatat, bahwa memungkinkan untuk salin/tempel tidak hanya teks, tetapi semuanya. Misalnya, kita dapat menyalin file di manajer file OS, dan menempelkannya. Itu karena `clipboardData` mengimplementasikan *interface* `DataTransfer`, yang biasa digunakan untuk drag'n'drop dan salin/tempel. Ini sedikit di luar jangkauan kita sekarang, tetapi Anda dapat menemukan metodenya [dalam spesifikasi ini](https://html.spec.whatwg.org/multipage/dnd.html#the-datatransfer-interface). @@ -83,6 +97,31 @@ Itu karena `clipboardData` mengimplementasikan *interface* `DataTransfer`, yang Juga dilarang untuk membuat *event* *clipboard* "custom" dengan `dispatchEvent` di semua peramban kecuali Firefox. ``` +======= +Please note: inside `cut` and `copy` event handlers a call to `event.clipboardData.getData(...)` returns an empty string. That's because technically the data isn't in the clipboard yet. If we use `event.preventDefault()` it won't be copied at all. + +So the example above uses `document.getSelection()` to get the selected text. You can find more details about document selection in the article . + +It's possible to copy/paste not just text, but everything. For instance, we can copy a file in the OS file manager, and paste it. + +That's because `clipboardData` implements `DataTransfer` interface, commonly used for drag'n'drop and copy/pasting. It's a bit beyond our scope now, but you can find its methods in the [DataTransfer specification](https://html.spec.whatwg.org/multipage/dnd.html#the-datatransfer-interface). + +Also, there's an additional asynchronous API of accessing the clipboard: `navigator.clipboard`. More about it in the specification [Clipboard API and events](https://www.w3.org/TR/clipboard-apis/), [not supported by Firefox](https://caniuse.com/async-clipboard). + +### Safety restrictions + +The clipboard is a "global" OS-level thing. A user may switch between various applications, copy/paste different things, and a browser page shouldn't see all that. + +So most browsers allow seamless read/write access to the clipboard only in the scope of certain user actions, such as copying/pasting etc. + +It's forbidden to generate "custom" clipboard events with `dispatchEvent` in all browsers except Firefox. And even if we manage to dispatch such event, the specification clearly states that such "synthetic" events must not provide access to the clipboard. + +Even if someone decides to save `event.clipboardData` in an event handler, and then access it later -- it won't work. + +To reiterate, [event.clipboardData](https://www.w3.org/TR/clipboard-apis/#clipboardevent-clipboarddata) works solely in the context of user-initiated event handlers. + +On the other hand, [navigator.clipboard](https://www.w3.org/TR/clipboard-apis/#h-navigator-clipboard) is the more recent API, meant for use in any context. It asks for user permission, if needed. +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Ringkasan @@ -90,6 +129,12 @@ Juga dilarang untuk membuat *event* *clipboard* "custom" dengan `dispatchEvent` | *Event* | Deskripsi | Specials | |---------|----------|-------------| +<<<<<<< HEAD | `change`| Sebuah *value* diubah. | Untuk pemicu input teks pada saat kehilangan fokus. | | `input` | Untuk input teks pada setiap perubahan. | Pemicu langsung tidak seperti `change`. | | `cut/copy/paste` | Tindakan potong/salin/tempel. | Tindakan tersebut dapat dicegah. Properti `event.clipboardData` memberikan akses baca/tulis ke *clipboard*. | +======= +| `change`| A value was changed. | For text inputs triggers on focus loss. | +| `input` | For text inputs on every change. | Triggers immediately unlike `change`. | +| `cut/copy/paste` | Cut/copy/paste actions. | The action can be prevented. The `event.clipboardData` property gives access to the clipboard. All browsers except Firefox also support `navigator.clipboard`. | +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 diff --git a/2-ui/5-loading/01-onload-ondomcontentloaded/article.md b/2-ui/5-loading/01-onload-ondomcontentloaded/article.md index 9cc9fc7c5..07624a658 100644 --- a/2-ui/5-loading/01-onload-ondomcontentloaded/article.md +++ b/2-ui/5-loading/01-onload-ondomcontentloaded/article.md @@ -2,7 +2,7 @@ The lifecycle of an HTML page has three important events: -- `DOMContentLoaded` -- the browser fully loaded HTML, and the DOM tree is built, but external resources like pictures `` and stylesheets may not yet have loaded. +- `DOMContentLoaded` -- the browser fully loaded HTML, and the DOM tree is built, but external resources like pictures `` and stylesheets may not yet have loaded. - `load` -- not only HTML is loaded, but also all the external resources: images, styles etc. - `beforeunload/unload` -- the user is leaving the page. @@ -88,7 +88,7 @@ But there's a pitfall. If we have a script after the style, then that script mus ```html run ``` @@ -114,7 +114,7 @@ The example below correctly shows image sizes, because `window.onload` waits for ```html run height=200 refresh diff --git a/2-ui/5-loading/01-onload-ondomcontentloaded/readystate.view/index.html b/2-ui/5-loading/01-onload-ondomcontentloaded/readystate.view/index.html index a4685a716..27df70939 100644 --- a/2-ui/5-loading/01-onload-ondomcontentloaded/readystate.view/index.html +++ b/2-ui/5-loading/01-onload-ondomcontentloaded/readystate.view/index.html @@ -9,8 +9,8 @@ [20] readyState:interactive [21] DOMContentLoaded [30] iframe onload - [40] readyState:complete [40] img onload + [40] readyState:complete [40] window onload --> diff --git a/2-ui/5-loading/02-script-async-defer/article.md b/2-ui/5-loading/02-script-async-defer/article.md index 93c32a7f5..f97c000d6 100644 --- a/2-ui/5-loading/02-script-async-defer/article.md +++ b/2-ui/5-loading/02-script-async-defer/article.md @@ -133,8 +133,12 @@ Async scripts are great when we integrate an independent third-party script into ``` +```smart header="The `async` attribute is only for external scripts" +Just like `defer`, the `async` attribute is ignored if the ` +``` + +Here's a more complex example, with `@keyframes`: + +```html run height=80 autorun no-beautify +

click me to start / stop

+ +``` + ## Summary -CSS animations allow smoothly (or not) animated changes of one or multiple CSS properties. +CSS animations allow smoothly (or step-by-step) animated changes of one or multiple CSS properties. They are good for most animation tasks. We're also able to use JavaScript for animations, the next chapter is devoted to that. @@ -422,6 +525,8 @@ Limitations of CSS animations compared to JavaScript animations: - Not just property changes. We can create new elements in JavaScript as part of the animation. ``` +In early examples in this chapter, we animate `font-size`, `left`, `width`, `height`, etc. In real life projects, we should use `transform: scale()` and `transform: translate()` for better performance. + The majority of animations can be implemented using CSS as described in this chapter. And the `transitionend` event allows JavaScript to be run after the animation, so it integrates fine with the code. But in the next chapter we'll do some JavaScript animations to cover more complex cases. diff --git a/7-animation/3-js-animation/1-animate-ball/solution.view/index.html b/7-animation/3-js-animation/1-animate-ball/solution.view/index.html index 7e031e8d1..146033cf7 100644 --- a/7-animation/3-js-animation/1-animate-ball/solution.view/index.html +++ b/7-animation/3-js-animation/1-animate-ball/solution.view/index.html @@ -21,7 +21,7 @@ } function bounce(timeFraction) { - for (let a = 0, b = 1, result; 1; a += b, b /= 2) { + for (let a = 0, b = 1; 1; a += b, b /= 2) { if (timeFraction >= (7 - 4 * a) / 11) { return -Math.pow((11 - 6 * a - 11 * timeFraction) / 4, 2) + Math.pow(b, 2) } diff --git a/7-animation/3-js-animation/2-animate-ball-hops/solution.view/index.html b/7-animation/3-js-animation/2-animate-ball-hops/solution.view/index.html index b246f422f..f587ff607 100644 --- a/7-animation/3-js-animation/2-animate-ball-hops/solution.view/index.html +++ b/7-animation/3-js-animation/2-animate-ball-hops/solution.view/index.html @@ -21,7 +21,7 @@ } function bounce(timeFraction) { - for (let a = 0, b = 1, result; 1; a += b, b /= 2) { + for (let a = 0, b = 1; 1; a += b, b /= 2) { if (timeFraction >= (7 - 4 * a) / 11) { return -Math.pow((11 - 6 * a - 11 * timeFraction) / 4, 2) + Math.pow(b, 2) } diff --git a/7-animation/3-js-animation/article.md b/7-animation/3-js-animation/article.md index 517b2481b..b85e91e21 100644 --- a/7-animation/3-js-animation/article.md +++ b/7-animation/3-js-animation/article.md @@ -79,7 +79,7 @@ These several independent redraws should be grouped together, to make the redraw There's one more thing to keep in mind. Sometimes CPU is overloaded, or there are other reasons to redraw less often (like when the browser tab is hidden), so we really shouldn't run it every `20ms`. -But how do we know about that in JavaScript? There's a specification [Animation timing](http://www.w3.org/TR/animation-timing/) that provides the function `requestAnimationFrame`. It addresses all these issues and even more. +But how do we know about that in JavaScript? There's a specification [Animation timing](https://www.w3.org/TR/animation-timing/) that provides the function `requestAnimationFrame`. It addresses all these issues and even more. The syntax: ```js @@ -96,7 +96,7 @@ The returned value `requestId` can be used to cancel the call: cancelAnimationFrame(requestId); ``` -The `callback` gets one argument -- the time passed from the beginning of the page load in microseconds. This time can also be obtained by calling [performance.now()](mdn:api/Performance/now). +The `callback` gets one argument -- the time passed from the beginning of the page load in milliseconds. This time can also be obtained by calling [performance.now()](mdn:api/Performance/now). Usually `callback` runs very soon, unless the CPU is overloaded or the laptop battery is almost discharged, or there's another reason. @@ -159,7 +159,7 @@ Function `animate` accepts 3 parameters that essentially describes the animation } ``` - It's graph: + Its graph: ![](linear.svg) That's just like `transition-timing-function: linear`. There are more interesting variants shown below. @@ -283,7 +283,7 @@ The `bounce` function does the same, but in the reverse order: "bouncing" starts ```js function bounce(timeFraction) { - for (let a = 0, b = 1, result; 1; a += b, b /= 2) { + for (let a = 0, b = 1; 1; a += b, b /= 2) { if (timeFraction >= (7 - 4 * a) / 11) { return -Math.pow((11 - 6 * a - 11 * timeFraction) / 4, 2) + Math.pow(b, 2) } @@ -452,4 +452,4 @@ Surely we could improve it, add more bells and whistles, but JavaScript animatio JavaScript animations can use any timing function. We covered a lot of examples and transformations to make them even more versatile. Unlike CSS, we are not limited to Bezier curves here. -The same is about `draw`: we can animate anything, not just CSS properties. +The same is true about `draw`: we can animate anything, not just CSS properties. diff --git a/7-animation/3-js-animation/bounce-easeinout.view/index.html b/7-animation/3-js-animation/bounce-easeinout.view/index.html index 837c50db1..aed3d9d08 100644 --- a/7-animation/3-js-animation/bounce-easeinout.view/index.html +++ b/7-animation/3-js-animation/bounce-easeinout.view/index.html @@ -26,7 +26,7 @@ function bounce(timeFraction) { - for (let a = 0, b = 1, result; 1; a += b, b /= 2) { + for (let a = 0, b = 1; 1; a += b, b /= 2) { if (timeFraction >= (7 - 4 * a) / 11) { return -Math.pow((11 - 6 * a - 11 * timeFraction) / 4, 2) + Math.pow(b, 2) } diff --git a/7-animation/3-js-animation/bounce-easeout.view/index.html b/7-animation/3-js-animation/bounce-easeout.view/index.html index e52eae8de..69dbb7ce0 100644 --- a/7-animation/3-js-animation/bounce-easeout.view/index.html +++ b/7-animation/3-js-animation/bounce-easeout.view/index.html @@ -22,7 +22,7 @@ } function bounce(timeFraction) { - for (let a = 0, b = 1, result; 1; a += b, b /= 2) { + for (let a = 0, b = 1; 1; a += b, b /= 2) { if (timeFraction >= (7 - 4 * a) / 11) { return -Math.pow((11 - 6 * a - 11 * timeFraction) / 4, 2) + Math.pow(b, 2) } diff --git a/7-animation/3-js-animation/bounce.view/index.html b/7-animation/3-js-animation/bounce.view/index.html index 1be2580d9..3575ed820 100644 --- a/7-animation/3-js-animation/bounce.view/index.html +++ b/7-animation/3-js-animation/bounce.view/index.html @@ -19,7 +19,7 @@ animate({ duration: 3000, timing: function bounce(timeFraction) { - for (let a = 0, b = 1, result; 1; a += b, b /= 2) { + for (let a = 0, b = 1; 1; a += b, b /= 2) { if (timeFraction >= (7 - 4 * a) / 11) { return -Math.pow((11 - 6 * a - 11 * timeFraction) / 4, 2) + Math.pow(b, 2) } diff --git a/7-animation/3-js-animation/text.view/index.html b/7-animation/3-js-animation/text.view/index.html index e404fe5c4..4947e4cd4 100644 --- a/7-animation/3-js-animation/text.view/index.html +++ b/7-animation/3-js-animation/text.view/index.html @@ -29,14 +29,14 @@ timing: bounce, draw: function(progress) { let result = (to - from) * progress + from; - textArea.value = text.substr(0, Math.ceil(result)) + textArea.value = text.slice(0, Math.ceil(result)) } }); } function bounce(timeFraction) { - for (let a = 0, b = 1, result; 1; a += b, b /= 2) { + for (let a = 0, b = 1; 1; a += b, b /= 2) { if (timeFraction >= (7 - 4 * a) / 11) { return -Math.pow((11 - 6 * a - 11 * timeFraction) / 4, 2) + Math.pow(b, 2) } diff --git a/8-web-components/1-webcomponents-intro/article.md b/8-web-components/1-webcomponents-intro/article.md index 8945edcd1..a0a410727 100644 --- a/8-web-components/1-webcomponents-intro/article.md +++ b/8-web-components/1-webcomponents-intro/article.md @@ -29,9 +29,15 @@ Stasiun Luar Angkasa Internasional: ...Dan benda ini terbang, membuat manusia tetap hidup di luar angkasa! +<<<<<<< HEAD Bagaimana perangkat rumit seperti itu dibuat? Prinsip mana yang bisa kita pinjam agar membuat pengembangan kita pada tingkat yang sama handal dan terukur? Atau, setidaknya, mendekati. +======= +How are such complex devices created? + +Which principles could we borrow to make our development same-level reliable and scalable? Or, at least, close to it? +>>>>>>> 3d7abb9cc8fa553963025547717f06f126c449b6 ## Arsitektur Komponen diff --git a/8-web-components/4-template-element/article.md b/8-web-components/4-template-element/article.md index 46111465a..8eab470a6 100644 --- a/8-web-components/4-template-element/article.md +++ b/8-web-components/4-template-element/article.md @@ -1,7 +1,11 @@ # Elemen template +<<<<<<< HEAD Elemen `