diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..d3877a5382 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +* text=auto eol=lf +*.svg binary diff --git a/1-js/01-getting-started/1-intro/article.md b/1-js/01-getting-started/1-intro/article.md index 8105893b61..f98fdd73eb 100644 --- a/1-js/01-getting-started/1-intro/article.md +++ b/1-js/01-getting-started/1-intro/article.md @@ -1,9 +1,14 @@ # JavaScript 入門 +<<<<<<< HEAD JavaScript について、何が特別なのか、それを使ってできることや他のどの技術と上手くやるのか見てみましょう。 +======= +Let's see what's so special about JavaScript, what we can achieve with it, and which other technologies play well with it. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## JavaScript とは? +<<<<<<< HEAD *JavaScript* は当初 *"Webページを活かすため"* に作られました。 この言語のプログラムは *スクリプト* と呼ばれます。それらはHTMLの中に書かれ、ページが読み込まれると自動的に実行されます。 @@ -31,6 +36,35 @@ JavaScript が作られたとき, 当初は別の名前を持っていました: これらの用語は、インターネット上の開発者の記事で使用されているため、覚えておくと良いでしょう。 たとえば、"ある機能 X がV8でサポートされている" と言った場合、おそらくChromeとOperaで動作します。 ```smart header="エンジンはどのように動く?" +======= +*JavaScript* was initially created to "make web pages alive". + +The programs in this language are called *scripts*. They can be written right in a web page's HTML and run automatically as the page loads. + +Scripts are provided and executed as plain text. They don't need special preparation or compilation to run. + +In this aspect, JavaScript is very different from another language called [Java](https://en.wikipedia.org/wiki/Java_(programming_language)). + +```smart header="Why is it called JavaScript?" +When JavaScript was created, it initially had another name: "LiveScript". But Java was very popular at that time, so it was decided that positioning a new language as a "younger brother" of Java would help. + +But as it evolved, JavaScript became a fully independent language with its own specification called [ECMAScript](http://en.wikipedia.org/wiki/ECMAScript), and now it has no relation to Java at all. +``` + +Today, JavaScript can execute not only in the browser, but also on the server, or actually on any device that has a special program called [the JavaScript engine](https://en.wikipedia.org/wiki/JavaScript_engine). + +The browser has an embedded engine sometimes called a "JavaScript virtual machine". + +Different engines have different "codenames". For example: + +- [V8](https://en.wikipedia.org/wiki/V8_(JavaScript_engine)) -- in Chrome and Opera. +- [SpiderMonkey](https://en.wikipedia.org/wiki/SpiderMonkey) -- in Firefox. +- ...There are other codenames like "Trident" and "Chakra" for different versions of IE, "ChakraCore" for Microsoft Edge, "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 and Opera. + +```smart header="How do engines work?" +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 エンジンは複雑ですが、基本は単純です。 @@ -38,16 +72,28 @@ JavaScript が作られたとき, 当初は別の名前を持っていました: 2. その後、スクリプトを機械語に変換("コンパイル")します。 3. 機械語が実行されます。非常に早く動作します。 +<<<<<<< HEAD エンジンは処理の各ステップで最適化を行います。実行時にコンパイルされたスクリプトも見ており、そこを流れるデータを分析し、それ基づいて機械語を最適化します。 最終的に、スクリプトはとても速く実行されます。 +======= +The engine applies optimizations at each step of the process. It even watches the compiled script as it runs, analyzes the data that flows through it, and further optimizes the machine code based on that knowledge. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` ## ブラウザ内のJavaScriptができることは? +<<<<<<< HEAD モダンなJavaScriptは "安全な" プログラミング言語です。それは、メモリやCPUのような低レベルのアクセスは提供しません。なぜなら、当初はそれらを必要としないブラウザ用に作成されたものだからです。 JavaScript の機能は、実行される環境に大きく依存します。 例えば、[Node.JS](https://wikipedia.org/wiki/Node.js) では、JavaScriptが任意のファイルを読み書きしたりできる機能をサポートしています。 ブラウザ内のJavaScriptは、Webページの操作、ユーザやWebサーバとのやり取りに関する様々ことを実行することができます。 +======= +Modern JavaScript is a "safe" programming language. It does not provide low-level access to memory or CPU, because it was initially created for browsers which do not require it. + +JavaScript's capabilities greatly depend on the environment it's running in. For instance, [Node.js](https://wikipedia.org/wiki/Node.js) supports functions that allow JavaScript to read/write arbitrary files, perform network requests, etc. + +In-browser JavaScript can do everything related to webpage manipulation, interaction with the user, and the webserver. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 たとえば、ブラウザ内のJavaScriptは次のようなことが可能です: @@ -60,15 +106,22 @@ JavaScript の機能は、実行される環境に大きく依存します。 ## ブラウザ内のJavaScriptで出来ないことは? +<<<<<<< HEAD ブラウザでは、JavaScriptの機能はユーザの安全のために制限されています。 その目的は、悪意のあるWebページがプライベートな情報へアクセスしたり、ユーザデータへ危害を加えることを防ぐことです。 制限の例として、次のようなものがあります: +======= +Examples of such restrictions include: + +- JavaScript on a webpage may not read/write arbitrary files on the hard disk, copy them or execute programs. It has no direct access to OS functions. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 - Webページ上のJavaScriptは、ハードディスク上の任意のファイルの読み書きや、それらのコピー、プログラムの実行をすることができません。OSのシステム機能に直接アクセスすることはできません。 現代のブラウザは、ファイルを扱うことはできますがアクセスは制限されており、ブラウザウィンドウへのファイルの "ドロップ" や、`` タグを経由したファイル選択と言ったユーザの特定の操作のみを提供しています。 +<<<<<<< HEAD カメラ/マイクやその他デバイスとやり取りする方法はありますが、ユーザの明示的な許可が求められます。したがって、JavaScriptが有効なページがWebカメラを密かに有効にしたり、それを利用して利用者の周囲を観察したり、[NSA](https://en.wikipedia.org/wiki/National_Security_Agency) に情報を送信すると言ったことはできません。 - 異なるタブやウィンドウは一般的にお互いについて知りません。時々、例えばあるウィンドウがJavaScriptを利用して別のウィンドウを開くケースはあります。しかし、この場合においても、あるページからのJavaScriptは、別のサイト(異なるドメイン、プロトコル、ポート)からのものである場合は、アクセスすることはできません。 @@ -78,6 +131,16 @@ JavaScript の機能は、実行される環境に大きく依存します。 - JavaScriptはネットワークを介して、現在のページがきたサーバと簡単にやり取りすることができます。しかし、他のサイト/ドメインからデータを受信することは制限されています。可能ですが、リモート側からの明示的な同意(HTTPヘッダで表現)が必要になります。繰り返しますが、これらは安全上の制限です。 ![](limitations.svg) +======= + This is called the "Same Origin Policy". To work around that, *both pages* must agree for data exchange and contain a 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` 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 limits do not exist if JavaScript is used outside of the browser, for example on a server. Modern browsers also allow plugin/extensions which may ask for extended permissions. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 JavaScriptがブラウザ外で使われる場合はこのような制限は存在しません。たとえば、サーバ上です。また、現代のブラウザは、より拡張されたアクセス権限を必要とするプラグイン/拡張機能を利用することもできます。 @@ -86,17 +149,30 @@ JavaScriptがブラウザ外で使われる場合はこのような制限は存 JavaScriptには少なくとも *3つ* の素晴らしいことがあります: ```compare +<<<<<<< HEAD + HTML/CSSとの完全な統合 + シンプルなことはシンプルに + すべてのメジャーブラウザでサポートされており、デフォルトで有効 +======= ++ Full integration with HTML/CSS. ++ Simple things are done simply. ++ Support by all major browsers and enabled by default. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` +JavaScript is the only browser technology that combines these three things. +<<<<<<< HEAD これら3つの事柄はJavaScript特有のことであり、他のブラウザ技術にはありません。 これがJavaScriptをユニークなものにしています。だからこそ、ブラウザインタフェースを作成するための最も普及したツールとなっています。 ## JavaScriptを "覆う" 言語 +======= +That's what makes JavaScript unique. That's why it's the most widespread tool for creating browser interfaces. + +That said, JavaScript also allows to create servers, mobile applications, etc. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 JavaScriptの構文は、すべての人のニーズにマッチしている訳ではありません。人によって求める機能は異なります。 @@ -105,18 +181,37 @@ JavaScriptの構文は、すべての人のニーズにマッチしている訳 そのため、最近では新しい言語が数多く登場しています。これらはブラウザで実行する前にJavaScriptに *トランスパイル* (変換)されます。 +<<<<<<< HEAD 最新のツールは非常に高速にトランスパイルでき、透過的です。開発者が別の言語でコードを作成し、それを自動変換することができます。 +======= +Modern tools make the transpilation very fast and transparent, actually allowing developers to code in another language and auto-converting it "under the hood". +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 これは、そのような言語の例です: +<<<<<<< HEAD - [CoffeeScript](http://coffeescript.org/) はJavaScriptの "シンタックスシュガー"です。より短い構文を導入し、より簡潔でクリアなコードを書くことができます。たいてい、Ruby 開発者は好きです。 - [TypeScript](http://www.typescriptlang.org/) は "厳密なデータ型指定" の追加に焦点をあてています。それは複雑なシステムの開発とサポートを簡素化するためです。これは Microsoftにより開発されています。 - [Dart](https://www.dartlang.org/) はブラウザ以外の環境(モバイルアプリのような)で動作する独自のエンジンを持ったスタンドアローンな言語です。最初はGoogleによってJavaScriptの代わりとなる位置づけで提供されましたが、現時点では、上述のようにJavaScriptへトランスパイルする必要があります。 他にもあります。もちろん、上記のような言語を利用する予定だとしても、実際に行われていることを本当に理解するためにJavaScriptは知っておくのがよいです。 +======= +- [CoffeeScript](http://coffeescript.org/) is a "syntactic sugar" for JavaScript. It introduces shorter syntax, allowing us to write clearer and more precise code. Usually, Ruby devs like it. +- [TypeScript](http://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](http://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. + +There are more. Of course, even if we use one of transpiled languages, we should also know JavaScript to really understand what we're doing. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## サマリ +<<<<<<< HEAD - JavaScriptは当初ブラウザ用の言語として作られました。しかし今はその他の多くの環境で利用されています。 - 現時点では、JavaScriptはHTML/CSSと完全に統合し、最も広く採用されたブラウザ言語として、独立した地位にいます。 - JavaScriptに "トランスパイル" し、特定の機能を提供する多くの言語があります。 JavaScriptをマスターした後、少なくとも簡単にでも目を通しておくことをお勧めします。 +======= +- JavaScript was initially created as a browser-only language, but is now used in many other environments as well. +- Today, JavaScript has a unique position as the most widely-adopted browser language with full integration 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. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 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 dda1ce56b3..e254a606b7 100644 --- a/1-js/01-getting-started/2-manuals-specifications/article.md +++ b/1-js/01-getting-started/2-manuals-specifications/article.md @@ -1,4 +1,5 @@ +<<<<<<< HEAD # マニュアルと仕様 この本は *チュートリアル* であり、あなたが徐々に言語を学ぶのを助けることを目的としています。そのため、基本が理解できたら別の情報源が必要になってきます。 @@ -40,3 +41,46 @@ JavaScript は開発中の言語であり、定期的に新機能が追加され これらのリソースは、言語の詳細やサポートなどに関する貴重な情報が含まれているため、実際の開発に役立ちます。 特定の機能に関する詳細な情報が必要な場合は、それら(またはこのページ)を覚えておいてください。 +======= +# Manuals and specifications + +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 sources. + +## Specification + +[The ECMA-262 specification](https://www.ecma-international.org/publications/standards/Ecma-262.htm) contains the most in-depth, detailed and formalized information about JavaScript. It defines the language. + +But being that formalized, it's difficult to understand at first. So if you need the most trustworthy source of information about the language details, the specification is the right place. But it's not for everyday use. + +A new specification version is released every year. In-between these releases, the latest specification draft is at . + +To read about new bleeding-edge features, including those that are "almost standard" (so-called "stage 3"), see proposals at . + +Also, if you're in developing for the browser, then there are other specs covered in the [second part](info:browser-environment) of the tutorial. + +## Manuals + +- **MDN (Mozilla) JavaScript Reference** is a manual with examples and other information. It's great to get in-depth information about individual language functions, methods etc. + + One 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 `parseInt` function. + + +- **MSDN** – Microsoft manual with a lot of information, including JavaScript (often referred to as JScript). If one needs something specific to Internet Explorer, better go there: . + + Also, we can use an internet search with phrases such as "RegExp MSDN" or "RegExp MSDN jscript". + +## Compatibility tables + +JavaScript is a developing language, new features get added regularly. + +To see their support among browser-based and other engines, see: + +- - 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. + +Please remember them (or this page) for the cases when you need in-depth information about a particular feature. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 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 b061ca35cd..b4d2597a7b 100644 --- a/1-js/01-getting-started/3-code-editors/article.md +++ b/1-js/01-getting-started/3-code-editors/article.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD # コードエディタ コードエディタはプログラマが最も時間を費やす場所です。 @@ -45,3 +46,51 @@ Windows には、"Visual Studio"もあります。"Visual Studio Code" と混同 この広い世界には他にも素晴らしいエディタがあります。ぜひあなたが最も好きなものを選んでください。 エディタの選択は、他のツールのようにプロジェクト、習慣や個人の趣向によります。 +======= +# Code editors + +A code editor is the place where programmers spend most of their time. + +There are two main types of code editors: IDEs and lightweight editors. Many people use one tool of each type. + +## IDE + +The term [IDE](https://en.wikipedia.org/wiki/Integrated_development_environment) (Integrated Development Environment) refers to a powerful editor with many features that usually operates on a "whole project." As the name suggests, it's not just an editor, but a full-scale "development environment." + +An IDE loads the project (which can be many files), allows navigation between files, provides autocompletion based on the whole project (not just the open file), and integrates with a version management system (like [git](https://git-scm.com/)), a testing environment, and other "project-level" stuff. + +If you haven't selected an IDE yet, consider the following options: + +- [Visual Studio Code](https://code.visualstudio.com/) (cross-platform, free). +- [WebStorm](http://www.jetbrains.com/webstorm/) (cross-platform, paid). + +For Windows, there's also "Visual Studio", not to be confused with "Visual Studio Code". "Visual Studio" is a paid and mighty Windows-only editor, well-suited for the .NET platform. It's also good at JavaScript. There's also a free version [Visual Studio Community](https://www.visualstudio.com/vs/community/). + +Many IDEs are paid, but have a trial period. Their cost is usually negligible compared to a qualified developer's salary, so just choose the best one for you. + +## Lightweight editors + +"Lightweight editors" are not as powerful as IDEs, but they're fast, elegant and simple. + +They are mainly used to open and edit a file instantly. + +The main difference between a "lightweight editor" and an "IDE" is that an IDE works on a project-level, so it loads much more data on start, analyzes the project structure if needed and so on. A lightweight editor is much faster if we need only one file. + +In practice, lightweight editors may have a lot of plugins including directory-level syntax analyzers and autocompleters, so there's no strict border between a lightweight editor and an IDE. + +The following options deserve your attention: + +- [Atom](https://atom.io/) (cross-platform, free). +- [Visual Studio Code](https://code.visualstudio.com/) (cross-platform, free). +- [Sublime Text](http://www.sublimetext.com) (cross-platform, shareware). +- [Notepad++](https://notepad-plus-plus.org/) (Windows, free). +- [Vim](http://www.vim.org/) and [Emacs](https://www.gnu.org/software/emacs/) are also cool if you know how to use them. + +## Let's not argue + +The editors in the lists above are those that either I or my friends whom I consider good developers have been using for a long time and are happy with. + +There are other great editors in our big world. Please choose the one you like the most. + +The choice of an editor, like any other tool, is individual and depends on your projects, habits, and personal preferences. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/01-getting-started/4-devtools/article.md b/1-js/01-getting-started/4-devtools/article.md index 9895e32855..7c4c453fce 100644 --- a/1-js/01-getting-started/4-devtools/article.md +++ b/1-js/01-getting-started/4-devtools/article.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD # 開発者コンソール コードにエラーはつきものです。少なくともあなたが [ロボット](https://en.wikipedia.org/wiki/Bender_(Futurama)) ではなく人間であるなら、あなたは *絶対に* 間違いをする、ということです。 @@ -58,3 +59,68 @@ Preferencesを開き、"Advanced" ペインに行きます。一番下にチェ - Windows下では、ほとんどのブラウザは `key:F12` で開くことができます。Mac用のChromeは `key:Cmd+Opt+J` が必要で、Safariは`key:Cmd+Opt+C`です(最初に有効化が必要)。 これで環境が整いました。次のセクションでは、JavaScriptの説明に入ります。 +======= +# Developer console + +Code is prone to errors. You will quite likely make errors... Oh, what am I talking about? You are *absolutely* going to make errors, at least if you're a human, not a [robot](https://en.wikipedia.org/wiki/Bender_(Futurama)). + +But in the browser, users don't see errors by default. So, if something goes wrong in the script, we won't see what's broken and can't fix it. + +To see errors and get a lot of other useful information about scripts, "developer tools" have been embedded in browsers. + +Most developers lean towards Chrome or Firefox for development because those browsers have the best developer tools. Other browsers also provide developer tools, sometimes with special features, but are usually playing "catch-up" to Chrome or Firefox. So most developers have a "favorite" browser and switch to others if a problem is browser-specific. + +Developer tools are potent; they have many features. To start, we'll learn how to open them, look at errors, and run JavaScript commands. + +## Google Chrome + +Open the page [bug.html](bug.html). + +There's an error in the JavaScript code on it. It's hidden from a regular visitor's eyes, so let's open developer tools to see it. + +Press `key:F12` or, if you're on Mac, then `key:Cmd+Opt+J`. + +The developer tools will open on the Console tab by default. + +It looks somewhat like this: + +![chrome](chrome.png) + +The exact look of developer tools depends on your version of Chrome. It changes from time to time but should be similar. + +- Here we can see the red-colored error message. In this case, the script contains an unknown "lalala" command. +- On the right, there is a clickable link to the source `bug.html:12` with the line number where the error has occurred. + +Below the error message, there is a blue `>` symbol. It marks a "command line" where we can type JavaScript commands. Press `key:Enter` to run them. + +Now we can see errors, and that's enough for a start. We'll come back to developer tools later and cover debugging more in-depth in the chapter . + +```smart header="Multi-line input" +Usually, when we put a line of code into the console, and then press `key:Enter`, it executes. + +To insert multiple lines, press `key:Shift+Enter`. This way one can enter long fragments of JavaScript code. +``` + +## Firefox, Edge, and others + +Most other browsers use `key:F12` to open developer tools. + +The look & feel of them is quite similar. Once you know how to use one of these tools (you can start with Chrome), you can easily switch to another. + +## Safari + +Safari (Mac browser, not supported by Windows/Linux) is a little bit special here. We need to enable the "Develop menu" first. + +Open Preferences and go to the "Advanced" pane. There's a checkbox at the bottom: + +![safari](safari.png) + +Now `key:Cmd+Opt+C` can toggle the console. Also, note that the new top menu item named "Develop" has appeared. It has many commands and options. + +## Summary + +- Developer tools allow us to see errors, run commands, examine variables, and much more. +- They can be opened with `key:F12` for most browsers on Windows. Chrome for Mac needs `key:Cmd+Opt+J`, Safari: `key:Cmd+Opt+C` (need to enable first). + +Now we have the environment ready. In the next section, we'll get down to JavaScript. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/02-first-steps/01-hello-world/1-hello-alert/index.html b/1-js/02-first-steps/01-hello-world/1-hello-alert/index.html new file mode 100644 index 0000000000..ff1d871b08 --- /dev/null +++ b/1-js/02-first-steps/01-hello-world/1-hello-alert/index.html @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/1-js/02-first-steps/01-hello-world/1-hello-alert/solution.md b/1-js/02-first-steps/01-hello-world/1-hello-alert/solution.md index e69de29bb2..81552913b9 100644 --- a/1-js/02-first-steps/01-hello-world/1-hello-alert/solution.md +++ b/1-js/02-first-steps/01-hello-world/1-hello-alert/solution.md @@ -0,0 +1,2 @@ + +[html src="index.html"] 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 0183232f98..5d19e44479 100644 --- a/1-js/02-first-steps/01-hello-world/article.md +++ b/1-js/02-first-steps/01-hello-world/article.md @@ -1,5 +1,6 @@ # Hello, world! +<<<<<<< HEAD このチュートリアルは、プラットフォームに依存しないJavaScriptのコアについてです。もっと先に、Node.JSや他のプラットフォームについて学びます。 しかし、私たちは今スクリプトを動かすための動作環境が必要です。ちょうどこのチュートリアルはオンラインなので、ブラウザが良い選択肢です。ここでは、ブラウザ固有のコマンド(`alert`のような)が最小限になるようにします。 @@ -13,6 +14,18 @@ ## "script" タグ JavaScriptプログラムは、` ``` +<<<<<<< HEAD それらのコメントは` ``` +<<<<<<< HEAD `/path/to/script.js` はスクリプトファイルの絶対パスです(サイトルートからの)。 また、現在のページからの相対パスで指定することもできます。例えば、`src="script.js"` は現在のフォルダにある `"script.js"` を意味するでしょう。 完全なURLも同様に可能です。たとえば: +======= +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"` would mean a file `"script.js"` in the current folder. + +We can give a full URL as well. For instance: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```html - + ``` 複数のスクリプトを使う場合は、複数のタグを使います: @@ -96,6 +145,7 @@ JavaScriptプログラムは、` ``` +<<<<<<< HEAD どちらか一方にしなければなりません: 外部の `` で挿入できます。 ブラウザスクリプトやそれらとWebページとのやり取りについては、学ぶことがまだまだあります。しかし、このチュートリアルのこのパートは JavaScript 言語に専念していることに留意してください。JavaScriptを実行するための方法としてここではブラウザを使っており、オンラインでの読み込みではとても便利ですが、数ある実行方法の1つでしかありません。 +======= +- We can use a ``. + + +There is much more to learn about browser scripts and their interaction with the webpage. But let's keep in mind that this part of the tutorial is devoted to the JavaScript language, so we shouldn't distract ourselves with browser-specific implementations of it. We'll be using the browser as a way to run JavaScript, which is very convenient for online reading, but only one of many. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/02-first-steps/02-structure/article.md b/1-js/02-first-steps/02-structure/article.md index 23ae90eab4..25b7918845 100644 --- a/1-js/02-first-steps/02-structure/article.md +++ b/1-js/02-first-steps/02-structure/article.md @@ -1,24 +1,40 @@ # コード構造 +<<<<<<< HEAD 最初の勉強は、コードの基本的な要素に関してです。 [cut] +======= +The first thing we'll study is the building blocks of code. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## 文(命令文) 文は、構文構造でアクションを実行するコマンドです。 +<<<<<<< HEAD 私たちは既に `alert('Hello, world!')` という文を見ました。それはメッセージを表示します。 私たちは必要なだけ文をコードに含めることができます。文はセミコロンで区切ることができます。 たとえば、これはメッセージを2つに分けます: +======= +We've already seen a statement, `alert('Hello, world!')`, which shows the message "Hello, world!". + +We can have as many statements in our code as we want. Statements can be separated with a semicolon. + +For example, here we split "Hello World" into two alerts: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run no-beautify alert('Hello'); alert('World'); ``` +<<<<<<< HEAD 通常、それぞれの文は別の行に書かれます -- これによりコードの可読性が向上します。 +======= +Usually, statements are written on separate lines to make the code more readable: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run no-beautify alert('Hello'); @@ -36,12 +52,20 @@ alert('Hello') alert('World') ``` +<<<<<<< HEAD ここでJavaScriptは、改行を "暗黙" のセミコロンと解釈します。 これは[自動セミコロン挿入](https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion)と呼ばれます。 **ほとんどのケースで改行はセミコロンを意味します。しかし "ほとんどのケース" は "いつも" ではありません!** これは改行はセミコロンを意味しないケースです、例えば: +======= +Here, JavaScript interprets the line break as an "implicit" semicolon. This is called an [automatic semicolon insertion](https://tc39.github.io/ecma262/#sec-automatic-semicolon-insertion). + +**In most cases, a newline implies a semicolon. But "in most cases" does not mean "always"!** + +There are cases when a newline does not mean a semicolon. For example: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run no-beautify alert(3 + @@ -49,7 +73,11 @@ alert(3 + + 2); ``` +<<<<<<< HEAD このコードは `6` を出力します、なぜなら JavaScript はセミコロンを挿入しないからです。もし行の終わりがプラス `"+"` で終わっている場合、直感的には "不完全な表現" であり、セミコロンが必要ないのは明らかです。このケースでは、それは意図した通りに動作します。 +======= +The code outputs `6` because JavaScript does not insert semicolons here. It is intuitively obvious that if the line ends with a plus `"+"`, then it is an "incomplete expression", so the semicolon is not required. And in this case that works as intended. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 **しかしJavaScriptが、本当に必要なときにセミコロンを想定 "し損なう" ケースがあります。** @@ -62,9 +90,15 @@ alert(3 + [1, 2].forEach(alert) ``` +<<<<<<< HEAD 角括弧 `[]` や `forEach` の意味についてはまだ考える必要はありません。それらについては後ほど勉強するので今のところ問題ではありません。ただ結果を覚えておきましょう: "1", そして "2" が表示されます。 今、コードの前に `alert` を追加し、セミコロンで終わら "ない" ようにしましょう: +======= +No need to think about the meaning of the brackets `[]` and `forEach` yet. We'll study them later. For now, just remember the result of the code: it shows `1` then `2`. + +Now, let's add an `alert` before the code and *not* finish it with a semicolon: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run no-beautify alert("There will be an error") @@ -72,7 +106,11 @@ alert("There will be an error") [1, 2].forEach(alert) ``` +<<<<<<< HEAD 実行すると、最初の `alert` だけが表示され、エラーが発生するでしょう! +======= +Now if we run the code, only the first `alert` is shown and then we have an error! +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 しかし、`alert` の後にセミコロンをつけた場合はすべてうまく行きます: ```js run @@ -81,15 +119,25 @@ alert("All fine now"); [1, 2].forEach(alert) ``` +<<<<<<< HEAD これで "All fine now" メッセージ、そして `1`, `2` が表示されます。 JavaScriptでは角括弧 `[...]` の前にはセミコロンを想定しません。そのため、セミコロンは自動挿入されないので最初の例のコードは1つの文として扱われます。 エンジンは次のように解釈しています: +======= +Now we have the "All fine now" message followed by `1` and `2`. + + +The error in the no-semicolon variant occurs because JavaScript does not assume a semicolon before square brackets `[...]`. + +So, because the semicolon is not auto-inserted, the code in the first example is treated as a single statement. Here's how the engine sees it: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run no-beautify alert("There will be an error")[1, 2].forEach(alert) ``` +<<<<<<< HEAD しかし、本来は1つではなく2つの文であるべきです。今回のケースのようなマージは間違っているのでエラーです。このようなことが起こるシチュエーションは他にもあります。 ```` @@ -102,6 +150,20 @@ alert("There will be an error")[1, 2].forEach(alert) コメントはスクリプトのどの場所にも書くことができます。エンジンはそれらを無視するので、実行には影響しません。 **1行のコメントは、2つのスラッシュ文字 `//` から始まります。** +======= +But it should be two separate statements, not one. Such a merging in this case is just wrong, hence the error. This can happen in other situations. +```` + +We recommend putting semicolons between statements even if they are separated by newlines. This rule is widely adopted by the community. Let's note once again -- *it is possible* to leave out semicolons most of the time. But it's safer -- especially for a beginner -- to use them. + +## Comments [#code-comments] + +As time goes on, programs become more and more complex. It becomes necessary to add *comments* which describe what the code does and why. + +Comments can be put into any place of a script. They don't affect its execution because the engine simply ignores them. + +**One-line comments start with two forward slash characters `//`.** +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 残りの行はコメントです。それは行全体または文に従います。 @@ -125,10 +187,16 @@ alert('Hello'); alert('World'); ``` +<<<<<<< HEAD コメントの内容は無視されます、そのため、/* ... */ の中にコードをおいても実行されません。 これはコードの一部を一時的に無効にしたいときに便利です: +======= +The content of comments is ignored, so if we put code inside /* ... */, it won't execute. + +Sometimes it can be handy to temporarily disable a part of code: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run /* コードのコメントアウト @@ -137,9 +205,14 @@ alert('Hello'); alert('World'); ``` +<<<<<<< HEAD ```smart header="ホットキーを使いましょう!" ほとんどのエディタでは、コードの行は1行コメントとして `key:Ctrl+/` ホットキーによりコメントアウトすることができます。そして `key:Ctrl+Shift+/` で複数行コメントです(コードの一部を選択し、ホットキーを押します)。 Macでは、 `key:Ctrl` の代わりに `key:Cmd` を試してください。 +======= +```smart header="Use hotkeys!" +In most editors, a line of code can be commented out by pressing the `key:Ctrl+/` hotkey for a single-line comment and something like `key:Ctrl+Shift+/` -- for multiline comments (select a piece of code and press the hotkey). For Mac, try `key:Cmd` instead of `key:Ctrl` and `key:Option` instead of `key:Shift`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` ````warn header="入れ子のコメントはサポートされていません!" @@ -157,6 +230,12 @@ alert( 'World' ); コードにコメントするのを躊躇わないでください。 +<<<<<<< HEAD コメントはコード規模を増加させますが、それは全く問題ではありません。プロダクションサーバへリリースする前にコードを minify する多くのツールがあります。それらはコメントを除去するので、実行されるスクリプトには現れません。そのため、コメント書くことによるネガティブな影響は全くありません。 さらにこのチュートリアルでは、より良いコメントの書き方を説明するチャプター もあります。 +======= +Comments increase the overall code footprint, but that's not a problem at all. There are many tools which minify code before publishing to a production server. They remove comments, so they don't appear in the working scripts. Therefore, comments do not have negative effects on production at all. + +Later in the tutorial there will be a chapter that also explains how to write better comments. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/02-first-steps/03-strict-mode/article.md b/1-js/02-first-steps/03-strict-mode/article.md index f0ff8fde69..24d42a4085 100644 --- a/1-js/02-first-steps/03-strict-mode/article.md +++ b/1-js/02-first-steps/03-strict-mode/article.md @@ -1,5 +1,6 @@ # モダンなモード, "use strict" +<<<<<<< HEAD 長い間、JavaScriptは互換性の問題なしに進化していました。新しい機能は言語に追加されましたが、古い機能は変更されませんでした。 それは既存のコードが決して壊れないというメリットがありました。しかし、欠点はJavaScript作成者による間違いや不十分な決定がこの言語から抜け出せなくなったことです。 @@ -7,12 +8,25 @@ ECMAScript 5(ES5) が登場したときは2009年でした。新しい機能が言語に追加され、既存の機能のいくつかが修正されました。古いコードが動作するのを保つために、ほとんどの修正はデフォルトではOFFです。特別なディレクティブ `"use strict"` を明示的に有効にする必要があります。 [cut] +======= +For a long time, JavaScript evolved without compatibility issues. New features were added to the language while old functionality didn't change. + +That had the benefit of never breaking existing code. But the downside was that any mistake or an imperfect decision made by JavaScript's creators got stuck in the language forever. + +This was the case until 2009 when ECMAScript 5 (ES5) appeared. It added new features to the language and modified some of the existing ones. To keep the old code working, most such modifications are off by default. You need to explicitly enable them with a special directive: `"use strict"`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## "use strict" +<<<<<<< HEAD そのディレクティブは文字列のように見えます: `"use strict"` もしくは `'use strict'`。 これがスクリプトの先頭に位置する場合、すべてのスクリプトは "最新の" 方法で動作します。 例えば +======= +The directive looks like a string: `"use strict"` or `'use strict'`. When it is located at the top of a script, the whole script works the "modern" way. + +For example: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js "use strict"; @@ -21,6 +35,7 @@ ECMAScript 5(ES5) が登場したときは2009年でした。新しい機能が ... ``` +<<<<<<< HEAD 私たちはこの後 関数(コマンドをグループ化する方法) をすぐに学ぶでしょう。 先読みの備考として、`"use strict"` はスクリプト全体の代わりに関数(ほとんどの種類の関数) の頭に置くことができます。 @@ -35,6 +50,18 @@ ECMAScript 5(ES5) が登場したときは2009年でした。新しい機能が ```js no-strict alert("some code"); // 下の "use strict" は無視されます, 先頭にある必要があります +======= +Quite soon we're going to learn functions (a way to group commands), so let's note in advance that `"use strict"` can be put at the beginning of a function. Doing that enables strict mode in that function only. But usually people use it for the whole script. + +````warn header="Ensure that \"use strict\" is at the top" +Please make sure that `"use strict"` is at the top of your scripts, otherwise strict mode may not be enabled. + +Strict mode isn't enabled here: + +```js no-strict +alert("some code"); +// "use strict" below is ignored--it must be at the top +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 "use strict"; @@ -44,6 +71,7 @@ alert("some code"); コメントだけは `"use strict"` の上に置けます。 ```` +<<<<<<< HEAD ```warn header="`use strict` をキャンセルする方法はありません" `"no use strict"` または同系の古い振る舞いを返すようなディレクティブはありません。 @@ -62,3 +90,54 @@ alert("some code"); 2. strict mode は先頭の `"use strict"` で有効になります。また、自動的に strict mode を有効にする "classes" や "modules" のようないくつかの機能もあります。 3. strict mode はすべてのモダンブラウザによってサポートされています。 4. 常に `"use strict"` で始まるスクリプトは推奨されます。このチュートリアルのすべての例は、そうでないと明示されていない限り(ほとんどないですが)それを想定しています。 +======= +```warn header="There's no way to cancel `use strict`" +There is no directive like `"no use strict"` that reverts the engine to old behavior. + +Once we enter strict mode, there's no going back. +``` + +## Browser console + +When you use a [developer console](info:devtools) to run code, please note that it doesn't `use strict` by default. + +Sometimes, when `use strict` makes a difference, you'll get incorrect results. + +So, how to actually `use strict` in the console? + +First, you can try to press `key:Shift+Enter` to input multiple lines, and put `use strict` on top, like this: + +```js +'use strict'; +// ...your code + +``` + +It works in most browsers, namely Firefox and Chrome. + +If it doesn't, e.g. in an old browser, there's an ugly, but reliable way to ensure `use strict`. Put it inside this kind of wrapper: + +```js +(function() { + 'use strict'; + + // ...your code here... +})() +``` + +## Should we "use strict"? + +The question may sound obvious, but it's not so. + +One could recommend to start scripts with `"use strict"`... But you know what's cool? + +Modern JavaScript supports "classes" and "modules" - advanced language structures (we'll surely get to them), that enable `use strict` automatically. So we don't need to add the `"use strict"` directive, if we use them. + +**So, for now `"use strict";` is a welcome guest at the top of your scripts. Later, when your code is all in classes and modules, you may omit it.** + +As of now, we've got to know about `use strict` in general. + +In the next chapters, as we learn language features, we'll see the differences between the strict and old modes. Luckily, there aren't many and they actually make our lives better. + +All examples in this tutorial assume strict mode unless (very rarely) specified otherwise. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/02-first-steps/04-variables/2-declare-variables/solution.md b/1-js/02-first-steps/04-variables/2-declare-variables/solution.md index ae6f10cc10..3689d8db23 100644 --- a/1-js/02-first-steps/04-variables/2-declare-variables/solution.md +++ b/1-js/02-first-steps/04-variables/2-declare-variables/solution.md @@ -1,4 +1,8 @@ +<<<<<<< HEAD 最初に、我々の惑星の名前に対する変数からです。 +======= +## The variable for our planet +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 シンプルです: @@ -8,7 +12,11 @@ let ourPlanetName = "Earth"; 注意してください。より短い名前 `planet` を使うことはできますが、どの惑星を指しているかが明白ではありません。より冗長な方がよいです。少なくとも変数が長すぎない程度まで。 +<<<<<<< HEAD 2つ目に、現在の訪問者の名前です。: +======= +## The name of the current visitor +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let currentUserName = "John"; @@ -18,4 +26,8 @@ let currentUserName = "John"; 現代のエディタや自動補完により、長い変数名を簡単に書くことができます。節約は不要です。3単語の名前は良いです。 +<<<<<<< HEAD また、もしあなたのエディタが適切な自動補完を持っていない場合には、[新しいエディタ](/code-editors) を入手してください。 +======= +And if your editor does not have proper autocompletion, get [a new one](/code-editors). +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/02-first-steps/04-variables/2-declare-variables/task.md b/1-js/02-first-steps/04-variables/2-declare-variables/task.md index 98e33463f7..57beef9cb3 100644 --- a/1-js/02-first-steps/04-variables/2-declare-variables/task.md +++ b/1-js/02-first-steps/04-variables/2-declare-variables/task.md @@ -4,5 +4,10 @@ importance: 3 # 正しい名前を与える +<<<<<<< HEAD 1. 我々の惑星の名前を持つ変数を作成してください。あなたはこのような変数の名前をどのように指定しますか? 2. 現在の訪問者の名前を格納する変数を作成してください。あなたはそのような変数の名前をどのように指定しますか? +======= +1. Create a variable with the name of our planet. How would you name such a variable? +2. Create a variable to store the name of a current visitor to a website. How would you name that variable? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/02-first-steps/04-variables/3-uppercast-constant/solution.md b/1-js/02-first-steps/04-variables/3-uppercast-constant/solution.md index a4785f0a55..3c4c3a54ad 100644 --- a/1-js/02-first-steps/04-variables/3-uppercast-constant/solution.md +++ b/1-js/02-first-steps/04-variables/3-uppercast-constant/solution.md @@ -2,4 +2,8 @@ このコードでは、`birthday` はまさにそうです。なので、大文字を使います。 +<<<<<<< HEAD 対照的に、`age` は実行時に評価されます。 今日はある年齢で、1年後に別の年齢になります。コード実行によって変化しないという意味で一定ですがそれは `birthday` より "定数ではありません"。それは計算されるので、小文字を維持する必要があります。 +======= +In contrast, `age` is evaluated in run-time. Today we have one age, a year after we'll have another one. It is constant in a sense that it does not change through the code execution. But it is a bit "less of a constant" than `birthday`: it is calculated, so we should keep the lower case for it. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/02-first-steps/04-variables/article.md b/1-js/02-first-steps/04-variables/article.md index fbe3c96655..b410ad57df 100644 --- a/1-js/02-first-steps/04-variables/article.md +++ b/1-js/02-first-steps/04-variables/article.md @@ -1,11 +1,18 @@ # 変数 +<<<<<<< HEAD ほとんどの場合、JavaScript アプリケーションは情報を処理する必要があります。ここに2つの例があります。 1. オンラインショップ -- 情報は "売られている商品" や "ショッピングカート" などが考えられます。 2. チャットアプリケーション -- 情報は "ユーザ"、"メッセージ" やその他より多くのものが考えられます。 +======= +Most of the time, a JavaScript application needs to work with information. Here are two examples: +1. An online shop -- the information might include goods being sold and a shopping cart. +2. A chat application -- the information might include users, messages, and much more. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 変数は情報を保持するために使われます。 +<<<<<<< HEAD [cut] ## 変数 @@ -15,12 +22,25 @@ JavaScriptで変数を作るには、`let` キーワードを使います。 下の文は "message" という名前の変数を作ります(別の言い方: *宣言* または *定義* ): +======= +## A variable + +A [variable](https://en.wikipedia.org/wiki/Variable_(computer_science)) is a "named storage" for data. We can use variables to store goodies, visitors, and other data. + +To create a variable in JavaScript, use the `let` keyword. + +The statement below creates (in other words: *declares*) a variable with the name "message": +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let message; ``` +<<<<<<< HEAD 代入演算子 `=` を使って、データを置く事ができます。 +======= +Now, we can put some data into it by using the assignment operator `=`: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let message; @@ -41,7 +61,11 @@ alert(message); // 変数の中身を表示します */!* ``` +<<<<<<< HEAD 簡潔にするために、変数宣言と代入を1行で書くことができます。 +======= +To be concise, we can combine the variable declaration and assignment into a single line: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let message = 'Hello!'; // 変数宣言と値の代入 @@ -55,7 +79,11 @@ alert(message); // Hello! let user = 'John', age = 25, message = 'Hello'; ``` +<<<<<<< HEAD より短いように見えるかもしれませんが、これは推奨しません。可読性のため、1変数1行にしてください。 +======= +That might seem shorter, but we don't recommend it. For the sake of better readability, please use a single line per variable. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 複数行のケースはちょっと長くなりますが、読みやすいです。 @@ -65,7 +93,11 @@ let age = 25; let message = 'Hello'; ``` +<<<<<<< HEAD 多くの変数がある場合、このように書く人もいます: +======= +Some people also define multiple variables in this multiline style: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js no-beautify let user = 'John', age = 25, @@ -80,25 +112,39 @@ let user = 'John' , message = 'Hello'; ``` +<<<<<<< HEAD 技術的にはこれらすべてのパターンは同じです。なので、これは個人の好みと美学の問題です。 ````smart header="`let` の代わりに `var`" 古いスクリプトには、別のキーワードがあるかもしれません: `let` の代わりに `var` です: +======= +Technically, all these variants do the same thing. So, it's a matter of personal taste and aesthetics. + +````smart header="`var` instead of `let`" +In older scripts, you may also find another keyword: `var` instead of `let`: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js *!*var*/!* message = 'Hello'; ``` +<<<<<<< HEAD キーワード `var` は `let` と *ほとんど* 一緒です。それも変数を宣言します。が、わずかに違います, 伝統的スタイルのやり方です。 `let` と `var` には微妙な違いがありますが、まだ気にする必要はありません。その詳細については、 のチャプターで説明します。 +======= +The `var` keyword is *almost* the same as `let`. It also declares a variable, but in a slightly different, "old-school" way. + +There are subtle differences between `let` and `var`, but they do not matter for us yet. We'll cover them in detail in the chapter . +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```` ## 現実での例え ユニークな名前のステッカーを付けたデータの "箱" として想像すれば、"変数" という概念を簡単に把握できます。 +<<<<<<< HEAD たとえば、変数 `message` は値 `"Hello!"` を持った `"message"` とラベル付けされた箱として想像することができます。: ![](variable.svg) @@ -106,7 +152,15 @@ let user = 'John' 箱の中にはどんな値でも入れることができます。 また、それを変えることもできます。値は必要なだけ何度でも変更することができます。 +======= +For instance, the variable `message` can be imagined as a box labeled `"message"` with the value `"Hello!"` in it: +![](variable.svg) + +We can put any value in the box. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 + +We can also change it as many times as we want: ```js run let message; @@ -138,29 +192,65 @@ alert(hello); // Hello world! alert(message); // Hello world! ``` +<<<<<<< HEAD ```smart header="関数型言語" 変数の値の変更を禁止する[関数型プログラミング言語](https://ja.wikipedia.org/wiki/関数型言語)と呼ばれる言語も存在することを知っておくと良いかもしれません。関数型言語の例として[Scala](http://www.scala-lang.org/) や[Erlang](http://www.erlang.org/)が挙げられます。 +======= +````warn header="Declaring twice triggers an error" +A variable should be declared only once. + +A repeated declaration of the same variable is an error: + +```js run +let message = "This"; + +// repeated 'let' leads to an error +let message = "That"; // SyntaxError: 'message' has already been declared +``` +So, we should declare a variable once and then refer to it without `let`. +```` + +```smart header="Functional languages" +It's interesting to note that there exist [functional](https://en.wikipedia.org/wiki/Functional_programming) programming languages, like [Scala](http://www.scala-lang.org/) or [Erlang](http://www.erlang.org/) that forbid changing variable values. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 このような言語では、一度"箱の中"に格納された値は、永遠に変化することがありません。もし他の値を"箱の中"に格納したい場合、新たな箱を作る、すなわち新たな変数を宣言する必要があります。一度使った変数を再利用することはできません。 +<<<<<<< HEAD 一見すると少し奇妙に見えるかもしれませんが、それらの言語は本格的な開発に適しています。それ以上に、並列計算のような分野ではこの制限が恩恵をもたらしさえします。このような言語を勉強することは視野を広げるために推奨されています(たとえすぐにそれを使う予定がなくても)。 +======= +Though it may seem a little odd at first sight, these languages are quite capable of serious development. More than that, there are areas like parallel computations where this limitation confers certain benefits. Studying such a language (even if you're not planning to use it soon) is recommended to broaden the mind. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` ## 変数のネーミング +<<<<<<< HEAD JavaScript変数名は2つの制限があります: 1. 名前は文字、数字、記号 `$` と `_` のみを含む必要があります。 2. 最初の文字は数字であってはいけません。 変数名の例: +======= +There are two limitations on variable names in JavaScript: + +1. The name must contain only letters, digits, or the symbols `$` and `_`. +2. The first character must not be a digit. + +Examples of valid names: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let userName; let test123; ``` +<<<<<<< HEAD 名前に複数の単語を含む場合、[camelCase](https://en.wikipedia.org/wiki/CamelCase) が一般的に使われます。 つまり: 単語が続々と続き, 各単語は大文字で始まります。: `myVeryLongName`. +======= +When the name contains multiple words, [camelCase](https://en.wikipedia.org/wiki/CamelCase) is commonly used. That is: words go one after another, each word except first starting with a capital letter: `myVeryLongName`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 興味深いことに -- ドル `'$'` や アンダースコア `'_'` も名前に使うことができます。それらは単に文字のように特別な意味をもたない普通の記号です。 @@ -178,6 +268,7 @@ alert($ + _); // 3 ```js no-beautify let 1a; // 数値から開始はできません +<<<<<<< HEAD let my-name; // ハイフン '-' は名前で許可されていません ``` @@ -187,12 +278,24 @@ let my-name; // ハイフン '-' は名前で許可されていません ````smart header="英語以外の文字も使用できますが、推奨されません。" キリル文字や象牙文字を含め、どの言語を使うことも可能です。: +======= +let my-name; // hyphens '-' aren't allowed in the name +``` + +```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 or even hieroglyphs, like this: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let имя = '...'; let 我 = '...'; ``` +<<<<<<< HEAD 技術的には、ここでエラーは起きず、このような名前も許可されます。しかし変数名では英語を使うのが国際的な伝統です。たとえ小さなスクリプトを書いているとしても、そのコードはこの先も残るかもしれません。他の国の人々がそれを見ることがあるかもしれません。 ```` @@ -200,6 +303,15 @@ let 我 = '...'; 予約語の一覧があります。これらは言語自身によって使用されるため、変数名として使用することはできません。 たとえば、単語 `let`, `class`, `return`, `function` は予約されています。 +======= +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 some time. +```` + +````warn header="Reserved names" +There is a [list of reserved words](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords), which cannot be used as variable names because they are used by the language itself. + +For example: `let`, `class`, `return`, and `function` are reserved. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 下のコードは構文エラーです: @@ -211,37 +323,56 @@ let return = 5; // 同様に "return" という名前もエラーです! ````warn header="`use strict` なしでの代入" +<<<<<<< HEAD 通常、変数を使う前に定義する必要があります。しかし、以前は `let` なしで、単に値を代入するだけで変数を作成することが技術的に可能でした。`use strict` でない場合には今でも動作します。この動作は古いスクリプトの互換性のために維持されています。 +======= +Normally, we need to define a variable before using it. But in the old times, it was technically possible to create a variable by a mere assignment of the value without using `let`. This still works now if we don't put `use strict` in our scripts to maintain compatibility with old scripts. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run no-strict // 注意: この例は "use strict" なしモードです +<<<<<<< HEAD num = 5; // 存在しなかった場合、変数 "num" が作られます +======= +num = 5; // the variable "num" is created if it didn't exist +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 alert(num); // 5 ``` +<<<<<<< HEAD これは悪い習慣です、strict モードではエラーになります: +======= +This is a bad practice and would cause an error in strict mode: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 -```js run untrusted +```js "use strict"; *!* num = 5; // エラー: num が未定義です */!* ``` - ```` ## 定数 +<<<<<<< HEAD 定数を宣言するためには、 `let` の代わりに `const` を使います。 +======= +To declare a constant (unchanging) variable, use `const` instead of `let`: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js const myBirthday = '18.04.1982'; ``` +<<<<<<< HEAD `const` を使って宣言された変数は "定数" と呼ばれます。それらは変更することが出来ません。変更しようとするとエラーになります: +======= +Variables declared using `const` are called "constants". They cannot be reassigned. An attempt to do so would cause an error: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run const myBirthday = '18.04.1982'; @@ -249,7 +380,11 @@ const myBirthday = '18.04.1982'; myBirthday = '01.01.2001'; // エラー, 定数の再代入はできません! ``` +<<<<<<< HEAD プログラマがその変数は決して変更されるべきでないと確信するとき、それを保証しつつみんなにその事実を明示的に示すために `const` を使います。 +======= +When a programmer is sure that a variable will never change, they can declare it with `const` to guarantee and clearly communicate that fact to everyone. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ### 大文字の定数 @@ -258,7 +393,11 @@ myBirthday = '01.01.2001'; // エラー, 定数の再代入はできません! このような定数は大文字とアンダースコアを使って名前がつけられます。 +<<<<<<< HEAD このように: +======= +For instance, let's make constants for colors in so-called "web" (hexadecimal) format: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run const COLOR_RED = "#F00"; @@ -273,6 +412,7 @@ alert(color); // #FF7F00 メリット: +<<<<<<< HEAD - `COLOR_ORANGE` は `"#FF7F00"` よりも覚えるのが遥かに簡単です。 - `COLOR_ORANGE` よりも `"#FF7F00"` のほうがタイプミスをし易いです。 - コードを読むとき、`#FF7F00` よりも `COLOR_ORANGE` のほうがより意味があります。 @@ -280,13 +420,26 @@ alert(color); // #FF7F00 いつ定数に大文字を使うべきなのか、いつ通常の名前をつけるべきなのかを明らかにしましょう。 "定数" であることは、その値は決して変わらないことを意味します。が、実行する前に知られている定数(赤の16進数のような)と、実行中にランタイムで *計算* されますが、代入後は変更されないものがあります。 +======= +- `COLOR_ORANGE` is much easier to remember than `"#FF7F00"`. +- It is much easier to mistype `"#FF7F00"` than `COLOR_ORANGE`. +- When reading the code, `COLOR_ORANGE` is much more meaningful than `#FF7F00`. + +When should we use capitals for a constant and when should we name it normally? Let's make that clear. + +Being a "constant" just means that a variable's value never changes. But there are constants that are known prior to execution (like a hexadecimal value for red) and there are constants that are *calculated* in run-time, during the execution, but do not change after their initial assignment. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 たとえば: ```js const pageLoadTime = /* webページの読み込み時間 */; ``` +<<<<<<< HEAD `pageLoadTime` の値はページロードする前にはわからないので、通常の名前がつけられます。しかし代入後は変更されないのでこれも定数です。 +======= +The value of `pageLoadTime` is not known prior to the page load, so it's named normally. But it's still a constant because it doesn't change after assignment. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 つまり、大文字の名前の定数は "ハードコードされた" 値のエイリアスとしてのみ使います。 @@ -294,6 +447,7 @@ const pageLoadTime = /* webページの読み込み時間 */; 変数について話すとき、もう1つ極めて重要な事があります。 +<<<<<<< HEAD 変数は分かりやすい名前にしてください。必要に応じて考えましょう。 変数のネーミングは、プログラミングにおいて、もっとも重要で複雑なスキルの1つです。変数名をちょっと見れば、どのコードが初心者で書かれ、どれが経験豊富な開発者によって書かれたものかがわかります。 @@ -301,9 +455,19 @@ const pageLoadTime = /* webページの読み込み時間 */; 実際のプロジェクトでは、スクラッチで完全に分離された何かを書くよりも、既存のコードベースの修正や拡張に最も時間を費やします。そして、何か他のことをした後にコードに戻ったとき、よくラベル付けされた情報を探すのははるかに簡単です。それは言い換えると、適切な名前がついている変数、です。 変数を宣言する前に正しい名前について考えるようにしてください。それは多くのことに報いるでしょう。 +======= +A variable name should have a clean, obvious meaning, describing the data that it stores. + +Variable naming is one of the most important and complex skills in programming. A quick 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-labeled. Or, in other words, when the variables have good names. + +Please spend time thinking about the right name for a variable before declaring it. Doing so will repay you handsomely. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 いくつかの良いルールです: +<<<<<<< HEAD - `userName` または `shoppingCart` のように人間が読みやすい名前を使ってください。 - 本当に何をしているか分かっている場合を除き、 `a`, `b`, `c` のような略語や短い名前は避けてください。 - 最大限説明的、かつ簡潔な名前を作ってください。悪い名前の例としては `data` や `value` です。このような名前からは何も分かりません。コンテキストからデータや値が意味することが例外的に明白な場合のみ使ってもOKです。 @@ -317,14 +481,34 @@ const pageLoadTime = /* webページの読み込み時間 */; その結果、変数はステッカーの変更なしに異なったものを投げ入れる箱になります。今何が入っているでしょうか?誰が知っているでしょうか...? より細かくチェックが必要になります。 このようなプログラマは変数定義では多少節約しますが、デバッグで10倍以上の時間を失います。 +======= +- Use human-readable names like `userName` or `shoppingCart`. +- Stay away from abbreviations or short names like `a`, `b`, `c`, unless you really 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 own mind. If a site visitor is called a "user" then we should name related variables `currentUser` or `newUser` instead of `currentVisitor` or `newManInTown`. + +Sounds simple? Indeed it is, but creating descriptive and concise variable names in practice is not. Go for it. + +```smart header="Reuse or create?" +And the last note. There are some lazy programmers who, instead of declaring new variables, tend to reuse existing ones. + +As a result, their variables are like boxes into which people throw different things without changing their stickers. What's inside the box now? Who knows? We need to come closer and check. + +Such programmers save a little bit on variable declaration but lose ten times more on debugging. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 余分な変数は良く、悪ではないです。 +<<<<<<< HEAD モダンなJavaScriptは minify したり、ブラウザは十分にコードを最適化します。なので、パフォーマンスの問題になることはありません。異なる値に対して異なる変数を使うことは、エンジンの最適化を助けることもあります。 +======= +Modern JavaScript minifiers and browsers optimize code well enough, so it won't create performance issues. Using different variables for different values can even help the engine optimize your code. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` ## サマリ +<<<<<<< HEAD データを格納するために変数を宣言することができます。それは `var`, `let`, または `const` を使うことでできます。 - `let` -- は現代の変数宣言です。Chrome(V8)では、`let` を使うには、そのコードは strict モードである必要があります。 @@ -332,3 +516,12 @@ const pageLoadTime = /* webページの読み込み時間 */; - `const` -- は `let` のようですが、変数の値は変更することができません。 変数は、内部のことを簡単に理解できるように命名するべきです。 +======= +We can declare variables to store data by using the `var`, `let`, or `const` keywords. + +- `let` -- is a modern variable declaration. +- `var` -- is an old-school variable declaration. Normally we don't use it at all, but we'll cover subtle differences from `let` in the chapter , just in case you need them. +- `const` -- is like `let`, but the value of the variable can't be changed. + +Variables should be named in a way that allows us to easily understand what's inside them. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/02-first-steps/05-types/article.md b/1-js/02-first-steps/05-types/article.md index 98f009fea0..d84baa7f05 100644 --- a/1-js/02-first-steps/05-types/article.md +++ b/1-js/02-first-steps/05-types/article.md @@ -1,6 +1,14 @@ # データ型 +<<<<<<< HEAD JavaScriptの変数はどんなデータでも入れることができます。変数はある時点では文字列で、その後数値を受け取ることができます。: +======= +A value in JavaScript is always of a certain type. For example, a string or a number. + +There are eight basic data types in JavaScript. Here, we'll cover them in general and in the next chapters we'll talk about each of them in detail. + +We can put any type in a variable. For example, a variable can at one moment be a string and then store a number: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js // エラーなし @@ -8,6 +16,7 @@ let message = "hello"; message = 123456; ``` +<<<<<<< HEAD このようなことができるプログラミング言語は "動的型付け" と呼ばれ、データ型はありますが、変数はそのどれにもバインドされないことを意味します。 JavaScriptでは7つの基本的なデータ型があります。ここでは基本を学び、次のチャプターでそれらの詳細について話しましょう。 @@ -15,17 +24,30 @@ JavaScriptでは7つの基本的なデータ型があります。ここでは基 [cut] ## 数値 +======= +Programming languages that allow such things, such as JavaScript, are called "dynamically typed", meaning that there exist data types, but variables are not bound to any of them. + +## Number +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let n = 123; n = 12.345; ``` +<<<<<<< HEAD *数値* 型は整数と浮動小数点両方に使われます。 数値に関する多くの操作があります、 e.g. 乗算 `*`, 除算 `/`, 加算 `+`, 減算 `-` など。 通常の数値に加えて、これらのタイプに属する "特別な数値型" もあります。: `Infinity`、 `-Infinity`、 `NaN`. +======= +The *number* type represents both integer and floating point numbers. + +There are many operations for numbers, e.g. multiplication `*`, division `/`, addition `+`, subtraction `-`, and so on. + +Besides regular numbers, there are so-called "special numeric values" which also belong to this data type: `Infinity`, `-Infinity` and `NaN`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 - `Infinity` は数学的な[無限大](https://en.wikipedia.org/wiki/Infinity) ∞ を表します。どの値よりも大きい特別な値です。 @@ -35,7 +57,11 @@ n = 12.345; alert( 1 / 0 ); // 無限大 ``` +<<<<<<< HEAD もしくは、単にコードに直接書くこともできます: +======= + Or just reference it directly: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run alert( Infinity ); // 無限大 @@ -46,12 +72,17 @@ n = 12.345; alert( "not a number" / 2 ); // NaN, このような除算は誤りです ``` +<<<<<<< HEAD `NaN` は粘着性です。`NaN` 以降はどのような操作をしても `NaN` になります: +======= + `NaN` is sticky. Any further operation on `NaN` returns `NaN`: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run alert( "not a number" / 2 + 5 ); // NaN ``` +<<<<<<< HEAD そのため、数学的な表現の中のどこかに `NaN` がある場合、結果全体に伝搬します。 ```smart header="算術演算子は安全です" @@ -61,17 +92,55 @@ JavaScriptでは数学をするのは安全です。ゼロによる除算、数 ``` 特別な数値は正式には "数値" 型に所属します。もちろん、常識では数値ではありませんが。 +======= + So, if there's a `NaN` somewhere in a mathematical expression, it propagates to the whole result. + +```smart header="Mathematical operations are safe" +Doing maths is "safe" in JavaScript. We can do anything: divide by zero, treat non-numeric strings as numbers, etc. + +The script will never stop with a fatal error ("die"). At worst, we'll get `NaN` as the result. +``` + +Special numeric values formally belong to the "number" type. Of course they are not numbers in the common sense of this word. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 チャプター でより数値の動作について見ていきます。 +<<<<<<< HEAD ## 文字列 JavaScriptの文字列は引用符で囲む必要があります。 +======= +## BigInt + +In JavaScript, the "number" type cannot represent integer values larger than (253-1) (that's `9007199254740991`), or less than -(-253-1) for negatives. It's a technical limitation caused by their internal representation. + +For most purposes that's quite enough, but sometimes we need really big numbers, e.g. for cryptography or microsecond-precision timestamps. + +`BigInt` type was recently added to the language to represent integers of arbitrary length. + +A `BigInt` value is created by appending `n` to the end of an integer: + +```js +// the "n" at the end means it's a BigInt +const bigInt = 1234567890123456789012345678901234567890n; +``` + +As `BigInt` numbers are rarely needed, we don't cover them here, but devoted them a separate chapter . Read it when you need such big numbers. + +```smart header="Compatability issues" +Right now `BigInt` is supported in Firefox/Chrome/Edge, but not in Safari/IE. +``` + +## String + +A string in JavaScript must be surrounded by quotes. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let str = "Hello"; let str2 = 'Single quotes are ok too'; -let phrase = `can embed ${str}`; +let phrase = `can embed another ${str}`; ``` JavScriptでは3種類の引用符があります。 @@ -80,7 +149,11 @@ JavScriptでは3種類の引用符があります。 2. シングルクォート: `'Hello'`. 3. バッククォート: `Hello`. +<<<<<<< HEAD ダブル/シングルクォートは "シンプルな" 引用符です。JavaScriptの中ではそれらに違いはありません。 +======= +Double and single quotes are "simple" quotes. There's practically no difference between them in JavaScript. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 バッククォートは "拡張機能" の引用符です。変数を `${…}` の中にラップすることで、変数を埋め込み文字列の中で表現することができます。たとえば: @@ -94,23 +167,38 @@ alert( `Hello, *!*${name}*/!*!` ); // Hello, John! alert( `the result is *!*${1 + 2}*/!*` ); // 結果は 3 ``` +<<<<<<< HEAD `${…}` の中の表現は評価され、結果は文字列の一部になります。そこには何でも置くことができます: `name` のような変数、`1 + 2` のような算術表現、またはより複雑なものを書くこともできます。 これはバッククォートでのみ可能なことに留意してください。他のクォートはこのような埋め込みは許容しません! +======= +The expression inside `${…}` is evaluated and the result becomes a part of the string. We can put anything in there: a variable like `name` or an arithmetical expression like `1 + 2` or something more complex. + +Please note that this can only be done in backticks. Other quotes don't have this embedding functionality! +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run alert( "the result is ${1 + 2}" ); // 結果は ${1 + 2} です(ダブルクォートは何もしません) ``` チャプター で、より深く文字列の説明をします。 +<<<<<<< HEAD ```smart header="*character* 型はありません" 言語によっては、1文字のための特別な "文字" 型があります。たとえば、C言語やJavaでは、それは `char` です。 +======= +```smart header="There is no *character* type." +In some languages, there is a special "character" type for a single character. For example, in the C language and in Java it is called "char". +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 JavaScriptではこのような型はありません。`string` 型の1つなだけです。文字列は単一の文字または複数の文字から構成されます。 ``` +<<<<<<< HEAD ## boolean (論理型) +======= +## Boolean (logical type) +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 boolean 型は2つの値だけを持ちます: `true` と `false` @@ -131,68 +219,125 @@ let isGreater = 4 > 1; alert( isGreater ); // true (比較結果は "yes" です) ``` +<<<<<<< HEAD 後ほどチャプターでbooleanのより詳細を説明します。 +======= +We'll cover booleans more deeply in the chapter . +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## "null" 値 +<<<<<<< HEAD 特殊な `null` 値は上で述べたどの型にも属しません。 それは自身の別の型を形成し、`null` 値だけを含みます。 +======= +The special `null` value does not belong to any of the types described above. + +It forms a separate type of its own which contains only the `null` value: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let age = null; ``` +<<<<<<< HEAD JavaScriptでは、 `null` は他の言語のような "存在しないオブジェクトへの参照" または "null へのポインタ" ではありません。 それは、 "無し"、"空" または "不明な値" と言った意味を持つ特別な値です。 上のコードは、 `age` は何らかの理由で不明な値もしくは空であることを述べています。 +======= +In JavaScript, `null` is not a "reference to a non-existing object" or a "null pointer" like in some other languages. + +It's just a special value which represents "nothing", "empty" or "value unknown". + +The code above states that `age` is unknown. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## "undefined" 値 +<<<<<<< HEAD 特殊な値 `undefined` も別に扱われます。`null` のように、それ自身の型を持ちます。 +======= +The special value `undefined` also stands apart. It makes a type of its own, just like `null`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 `undefined` の意味は "値は代入されていません" です。 +<<<<<<< HEAD もしも変数は宣言されているが代入されていない場合、その値は正確には `undefined` です: +======= +If a variable is declared, but not assigned, then its value is `undefined`: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run -let x; +let age; +<<<<<<< HEAD alert(x); // "undefined" を表示 ``` 技術的にはどの変数にも `undefined` を代入することができます。 +======= +alert(age); // shows "undefined" +``` + +Technically, it is possible to explicitly assign `undefined` to a variable: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run -let x = 123; +let age = 100; -x = undefined; +// change the value to undefined +age = undefined; -alert(x); // "undefined" +alert(age); // "undefined" ``` +<<<<<<< HEAD ...しかし、そのようにするのは推奨されません。一般的には、 "空" や "不明な値" と言った用途では `null` を使い、`undefined` は変数が割り当てられているか、もしくは似たような確認のために使います。 +======= +...But we don't recommend doing that. Normally, one uses `null` to assign an "empty" or "unknown" value to a variable, while `undefined` is reserved as a default initial value for unassigned things. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## オブジェクトとシンボル `object` 型は特殊です。 +<<<<<<< HEAD 他のすべての型は、値は1つのもの(文字列, 数値, または何でも)だけを含むので、"プリミティブ" と呼ばれます。対照的に、オブジェクトはデータのコレクションやより複雑なエンティティを格納するために使われます。ここでは、プリミティブについて十分に知った後、後ほどチャプターで扱います。 `symbol` 型はオブジェクトの一意な識別子を作るのに使われます。完全性のためにここで言及していますが、オブジェクトの後で勉強するのがよいでしょう。 +======= +All other types are called "primitive" because their values can contain only a single thing (be it a string or a number or whatever). In contrast, objects are used to store collections of data and more complex entities. + +Being that important, objects deserve a special treatment. We'll deal with them later in the chapter , after we learn more about primitives. + +The `symbol` type is used to create unique identifiers for objects. We have to mention it here for the sake of completeness, but also postpone the details till we know objects. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## typeof 操作 +<<<<<<< HEAD `typeof` 操作は、引数の型を返します。異なる型の値を別々に処理したい、または素早くチェックしたいときに役立ちます。 +======= +The `typeof` operator returns the type of the argument. It's useful when we want to process values of different types differently or just want to do a quick check. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 これは2つの形式の構文をサポートします: +<<<<<<< HEAD 1. 演算子として: `typeof x`. 2. 関数スタイル: `typeof(x)`. 言い換えると、それは括弧があってもなくても動作します。結果は同じです。 +======= +1. As an operator: `typeof x`. +2. As a function: `typeof(x)`. + +In other words, it works with parentheses or without them. The result is the same. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 `typeof x` の呼び出しは型名の文字列を返します。: @@ -201,6 +346,8 @@ typeof undefined // "undefined" typeof 0 // "number" +typeof 10n // "bigint" + typeof true // "boolean" typeof "foo" // "string" @@ -220,15 +367,23 @@ typeof alert // "function" (3) */!* ``` +<<<<<<< HEAD 最後の3行については追加の説明が必要かもしれません: 1. `Math` は数学的な操作を提供する組み込みオブジェクトです。チャプターで学ぶでしょう。ここでは、単にオブジェクトとしての例です。 2. `typeof null` の結果は `"object"` です。これは間違っています。これは `typeof` において、公式に認められているエラーで、互換性のために維持されています。もちろん、`null` はオブジェクトではありません。それは自身の別の型をもつ特殊な値です。なので、繰り返しますがそれは言語のエラーです。 3. `alert` は言語の機能なので、`typeof alert` の結果は `"function"` です。我々は次のチャプターで function を勉強します。そして、言語の中には特別な "function" 型がないことがわかるでしょう。function はオブジェクト型に属します。しかし `typeof` はそれらを別々に扱います。正式にはそれは正しくありませんが、実際にはとても便利です。 +======= +The last three lines may need additional explanation: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 +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` behavior, coming from the 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. +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. ## サマリ +<<<<<<< HEAD JavaScriptには7つの基本型があります。 - `number` あらゆる種類の数値: 整数または浮動小数点 @@ -246,3 +401,23 @@ JavaScriptには7つの基本型があります。 - `null` は `"object"` を返します -- それは言語のエラーで、実際はオブジェクトではありません。 次のチャプターではプリミティブ値について集中し、それらに精通した後オブジェクトに進みます。 +======= +There are 8 basic data types in JavaScript. + +- `number` for numbers of any kind: integer or floating-point, integers are limited by ±253. +- `bigint` is 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`. +- `object` for more complex data structures. +- `symbol` for unique identifiers. + +The `typeof` operator allows us to see which type is stored in a variable. + +- Two forms: `typeof x` or `typeof(x)`. +- 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. + +In the next chapters, we'll concentrate on primitive values and once we're familiar with them, we'll move on to objects. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/02-first-steps/09-alert-prompt-confirm/1-simple-page/solution.md b/1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/solution.md similarity index 100% rename from 1-js/02-first-steps/09-alert-prompt-confirm/1-simple-page/solution.md rename to 1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/solution.md diff --git a/1-js/02-first-steps/09-alert-prompt-confirm/1-simple-page/task.md b/1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/task.md similarity index 100% rename from 1-js/02-first-steps/09-alert-prompt-confirm/1-simple-page/task.md rename to 1-js/02-first-steps/06-alert-prompt-confirm/1-simple-page/task.md diff --git a/1-js/02-first-steps/06-alert-prompt-confirm/article.md b/1-js/02-first-steps/06-alert-prompt-confirm/article.md new file mode 100644 index 0000000000..25bf72482b --- /dev/null +++ b/1-js/02-first-steps/06-alert-prompt-confirm/article.md @@ -0,0 +1,105 @@ +# Interaction: alert, prompt, confirm + +As we'll be using the browser as our demo environment, let's see a couple of functions to interact with the user: `alert`, `prompt` and `confirm`. + +## alert + +This one we've seen already. It shows a message and waits for the user to presses "OK". + +For example: + +```js run +alert("Hello"); +``` + +The mini-window with the message is called a *modal window*. The word "modal" means that the visitor can't interact with the rest of the page, press other buttons, etc, until they have dealt with the window. In this case -- until they press "OK". + +## prompt + +The function `prompt` accepts two arguments: + +```js no-beautify +result = prompt(title, [default]); +``` + +It shows a modal window with a text message, an input field for the visitor, and the buttons OK/Cancel. + +`title` +: The text to show the visitor. + +`default` +: An optional second parameter, the initial value for the input field. + +```smart header="The square brackets in syntax `[...]`" +The square brackets around `default` in the syntax above denote that the parameter as optional, not required. +``` + +The visitor can type something in the prompt input field and press OK. Then we get that text in the `result`. Or they can cancel the input by pressing Cancel or hitting the `key:Esc` key, then we get `null` as the `result`. + +The call to `prompt` returns the text from the input field or `null` if the input was canceled. + +For instance: + +```js run +let age = prompt('How old are you?', 100); + +alert(`You are ${age} years old!`); // You are 100 years old! +``` + +````warn header="In IE: always supply a `default`" +The second parameter is optional, but if we don't supply it, Internet Explorer will insert the text `"undefined"` into the prompt. + +Run this code in Internet Explorer to see: + +```js run +let test = prompt("Test"); +``` + +So, for prompts to look good in IE, we recommend always providing the second argument: + +```js run +let test = prompt("Test", ''); // <-- for IE +``` +```` + +## confirm + +The syntax: + +```js +result = confirm(question); +``` + +The function `confirm` shows a modal window with a `question` and two buttons: OK and Cancel. + +The result is `true` if OK is pressed and `false` otherwise. + +For example: + +```js run +let isBoss = confirm("Are you the boss?"); + +alert( isBoss ); // true if OK is pressed +``` + +## Summary + +We covered 3 browser-specific functions to interact with visitors: + +`alert` +: shows a message. + +`prompt` +: shows a message asking the user to input text. It returns the text or, if Cancel button or `key:Esc` is clicked, `null`. + +`confirm` +: shows a message and waits for the user to press "OK" or "Cancel". It returns `true` for OK and `false` for Cancel/`key:Esc`. + +All these methods are modal: they pause script execution and don't allow the visitor to interact with the rest of the page until the window has been dismissed. + +There are two limitations shared by all the methods above: + +1. The exact location of the modal window is determined by the browser. Usually, it's in the center. +2. The exact look of the window also depends on the browser. We can't modify it. + +That is the price for simplicity. There are other ways to show nicer windows and richer interaction with the visitor, but if "bells and whistles" do not matter much, these methods work just fine. diff --git a/1-js/02-first-steps/06-type-conversions/article.md b/1-js/02-first-steps/07-type-conversions/article.md similarity index 55% rename from 1-js/02-first-steps/06-type-conversions/article.md rename to 1-js/02-first-steps/07-type-conversions/article.md index 51796a7f71..dcb9959457 100644 --- a/1-js/02-first-steps/06-type-conversions/article.md +++ b/1-js/02-first-steps/07-type-conversions/article.md @@ -1,9 +1,14 @@ # 型変換 +<<<<<<< HEAD:1-js/02-first-steps/06-type-conversions/article.md 多くの場合、演算子と関数は自動的に値を正しい型に変換します。それを "型変換" と呼びます。 +======= +Most of the time, operators and functions automatically convert the values given to them to the right type. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/07-type-conversions/article.md たとえば、 `alert` は表示するために、自動的にある値を文字列へ変換します。数学的な処理は値を数値に変換します。 +<<<<<<< HEAD:1-js/02-first-steps/06-type-conversions/article.md また、物事を正しくするために、ある値を明示的に変換する必要がある場合もあります。 [cut] @@ -13,12 +18,27 @@ ``` ## 文字列変換 +======= +There are also cases when we need to explicitly convert a value to the expected type. + +```smart header="Not talking about objects yet" +In this chapter, we won't cover objects. For now we'll just be talking about primitives. + +Later, after we learn about objects, in the chapter we'll see how objects fit in. +``` + +## String Conversion +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/07-type-conversions/article.md 文字列変換は、文字列形式の値が必要なときに発生します。 たとえば、`alert(value)` は値を表示するためにそれを行います。 +<<<<<<< HEAD:1-js/02-first-steps/06-type-conversions/article.md また、そのために、`String(value)` 関数を使うこともできます: +======= +We can also call the `String(value)` function to convert a value to a string: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/07-type-conversions/article.md ```js run let value = true; @@ -30,9 +50,15 @@ alert(typeof value); // string */!* ``` +<<<<<<< HEAD:1-js/02-first-steps/06-type-conversions/article.md 文字列変換はほとんどが明白です。`false` は `"false"` に、 `null` は `"null"` になります。 ## 数値変換 +======= +String conversion is mostly obvious. A `false` becomes `"false"`, `null` becomes `"null"`, etc. + +## Numeric Conversion +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/07-type-conversions/article.md 数値変換は数学的関数や表現の中で自動的に起こります。 @@ -42,7 +68,11 @@ alert(typeof value); // string alert( "6" / "2" ); // 3, 文字列は数値に変換されます ``` +<<<<<<< HEAD:1-js/02-first-steps/06-type-conversions/article.md また、明示的に `value` を変換するために `Number(value)` を使うことができます。 +======= +We can use the `Number(value)` function to explicitly convert a `value` to a number: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/07-type-conversions/article.md ```js run let str = "123"; @@ -53,9 +83,15 @@ let num = Number(str); // 数値の 123 になります alert(typeof num); // number ``` +<<<<<<< HEAD:1-js/02-first-steps/06-type-conversions/article.md テキストフォームのような文字列ベースのソースから値を読むが、数値が入力されることを想定するときには通常明示的な変換が必要になります。 文字列が有効な数値でない場合、このような変換の結果は `NaN` です。たとえば: +======= +Explicit conversion is usually required when we read a value from a string-based source like a text form but expect a number to be entered. + +If the string is not a valid number, the result of such a conversion is `NaN`. For instance: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/07-type-conversions/article.md ```js run let age = Number("an arbitrary string instead of a number"); @@ -69,8 +105,13 @@ alert(age); // NaN, 変換失敗 |-------|-------------| |`undefined`|`NaN`| |`null`|`0`| +<<<<<<< HEAD:1-js/02-first-steps/06-type-conversions/article.md |true と false | `1` and `0` | | `string` | 最初と最後のスペースは取り除かれます。そして、残った文字列が空の場合は結果は 0 になります。そうでなければ、文字列から "読んだ" 数値です。 エラーでは `NaN` が与えられます。| +======= +|true and false | `1` and `0` | +| `string` | Whitespaces 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`. | +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/07-type-conversions/article.md 例: @@ -81,6 +122,7 @@ alert( Number(true) ); // 1 alert( Number(false) ); // 0 ``` +<<<<<<< HEAD:1-js/02-first-steps/06-type-conversions/article.md `null` と `undefined` はここでは異なる振る舞いをすることに留意してください。: `undefined` が `NaN` になる一方、`null` は 0 になります。 ````smart header="'+'は文字列を連結します" @@ -97,15 +139,31 @@ alert( '1' + 2 ); // '12' (左側が文字列) ```` ## Boolean変換 +======= +Please note that `null` and `undefined` behave differently here: `null` becomes zero while `undefined` becomes `NaN`. + +Most mathematical operators also perform such conversion, we'll see that in the next chapter. + +## Boolean Conversion +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/07-type-conversions/article.md 真偽値(Boolean)変換はシンプルです。 +<<<<<<< HEAD:1-js/02-first-steps/06-type-conversions/article.md 論理演算(後ほど条件テストや他の種類を見ます)で起こりますが、`Boolean(value)` を呼ぶことで手動で実行することもできます。 +======= +It happens in logical operations (later we'll meet condition tests and other similar things) but can also be performed explicitly with a call to `Boolean(value)`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/07-type-conversions/article.md 変換ルール: +<<<<<<< HEAD:1-js/02-first-steps/06-type-conversions/article.md - `0`, 空文字, `null`, `undefined` や `NaN` のように直感的に "空" の値は `false` になります。 - 他の値は `true` になります。 +======= +- Values that are intuitively "empty", like `0`, an empty string, `null`, `undefined`, and `NaN`, become `false`. +- Other values become `true`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/07-type-conversions/article.md 例: @@ -117,8 +175,13 @@ alert( Boolean("hello") ); // true alert( Boolean("") ); // false ``` +<<<<<<< HEAD:1-js/02-first-steps/06-type-conversions/article.md ````warn header="注意してください: ゼロの文字列 `\"0\"` は `true` です" 幾つかの言語(すなわち PHP)は `”0”` を `false` として扱います。しかし、JavaScriptでは、非空文字は常に `true` です。 +======= +````warn header="Please note: the string with zero `\"0\"` is `true`" +Some languages (namely PHP) treat `"0"` as `false`. But in JavaScript, a non-empty string is always `true`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/07-type-conversions/article.md ```js run alert( Boolean("0") ); // true @@ -126,6 +189,7 @@ alert( Boolean(" ") ); // スペースもまた true です (任意の非空文 ``` ```` +<<<<<<< HEAD:1-js/02-first-steps/06-type-conversions/article.md ## サマリ @@ -134,6 +198,15 @@ alert( Boolean(" ") ); // スペースもまた true です (任意の非空文 **`文字列変換`** -- 何かを出力するときに起こり、`String(value)` で行うことができます。文字列への変換は、通常はプリミティブな値にとって明白です。 **`数値変換`** -- 算術演算で起こり、`Number(value)` で実行できます。 +======= +## Summary + +The three most widely used type conversions are to string, to number, and to boolean. + +**`String Conversion`** -- Occurs when we output something. Can be performed with `String(value)`. The conversion to string is usually obvious for primitive values. + +**`Numeric Conversion`** -- Occurs in math operations. Can be performed with `Number(value)`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/07-type-conversions/article.md 変換は次のルールに従います: @@ -144,7 +217,11 @@ alert( Boolean(" ") ); // スペースもまた true です (任意の非空文 |true と false | `1` and `0` | | `string` | 最初と最後のスペースは取り除かれます。そして、残った文字列が空の場合は結果は 0 になります。そうでなければ、文字列から "読んだ" 数値です。 エラーでは `NaN` が与えられます。| +<<<<<<< HEAD:1-js/02-first-steps/06-type-conversions/article.md **`真偽値変換`** -- 論理演算で発生するか、`Boolean(value)` で実行できます。 +======= +**`Boolean Conversion`** -- Occurs in logical operations. Can be performed with `Boolean(value)`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/07-type-conversions/article.md 次のルールに従います: @@ -159,4 +236,8 @@ alert( Boolean(" ") ); // スペースもまた true です (任意の非空文 - `undefined` は文字列としては `NaN` です, `0` ではりません。 - `"0"` と `" "` のようなスペースだけの文字列は真偽値としては true です。 +<<<<<<< HEAD:1-js/02-first-steps/06-type-conversions/article.md オブジェクトについてはここでは説明しませんが、JavaScriptについての基本的なことを学んだら、オブジェクトに専念する の章の後半に戻ります。 +======= +Objects aren't covered here. We'll return to them later in the chapter that is devoted exclusively to objects after we learn more basic things about JavaScript. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/07-type-conversions/article.md diff --git a/1-js/02-first-steps/08-comparison/1-comparison-questions/task.md b/1-js/02-first-steps/08-comparison/1-comparison-questions/task.md deleted file mode 100644 index c1153f6323..0000000000 --- a/1-js/02-first-steps/08-comparison/1-comparison-questions/task.md +++ /dev/null @@ -1,17 +0,0 @@ -importance: 5 - ---- - -# 比較 - -式の結果はどうなるでしょう? - -```js no-beautify -5 > 4 -"apple" > "pineapple" -"2" > "12" -undefined == null -undefined === null -null == "\n0\n" -null === +"\n0\n" -``` diff --git a/1-js/02-first-steps/07-operators/1-increment-order/solution.md b/1-js/02-first-steps/08-operators/1-increment-order/solution.md similarity index 100% rename from 1-js/02-first-steps/07-operators/1-increment-order/solution.md rename to 1-js/02-first-steps/08-operators/1-increment-order/solution.md diff --git a/1-js/02-first-steps/07-operators/1-increment-order/task.md b/1-js/02-first-steps/08-operators/1-increment-order/task.md similarity index 100% rename from 1-js/02-first-steps/07-operators/1-increment-order/task.md rename to 1-js/02-first-steps/08-operators/1-increment-order/task.md diff --git a/1-js/02-first-steps/07-operators/2-assignment-result/solution.md b/1-js/02-first-steps/08-operators/2-assignment-result/solution.md similarity index 100% rename from 1-js/02-first-steps/07-operators/2-assignment-result/solution.md rename to 1-js/02-first-steps/08-operators/2-assignment-result/solution.md diff --git a/1-js/02-first-steps/07-operators/2-assignment-result/task.md b/1-js/02-first-steps/08-operators/2-assignment-result/task.md similarity index 100% rename from 1-js/02-first-steps/07-operators/2-assignment-result/task.md rename to 1-js/02-first-steps/08-operators/2-assignment-result/task.md 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 new file mode 100644 index 0000000000..4964a623a4 --- /dev/null +++ b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/solution.md @@ -0,0 +1,26 @@ + +```js no-beautify +"" + 1 + 0 = "10" // (1) +"" - 1 + 0 = -1 // (2) +true + false = 1 +6 / "3" = 2 +"2" * "3" = 6 +4 + 5 + "px" = "9px" +"$" + 4 + 5 = "$45" +"4" - 2 = 2 +"4px" - 2 = NaN +7 / 0 = Infinity +" -9 " + 5 = " -9 5" // (3) +" -9 " - 5 = -14 // (4) +null + 1 = 1 // (5) +undefined + 1 = NaN // (6) +" \t \n" - 2 = -2 // (7) +``` + +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`. diff --git a/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/task.md b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/task.md new file mode 100644 index 0000000000..930c715140 --- /dev/null +++ b/1-js/02-first-steps/08-operators/3-primitive-conversions-questions/task.md @@ -0,0 +1,27 @@ +importance: 5 + +--- + +# Type conversions + +What are results of these expressions? + +```js no-beautify +"" + 1 + 0 +"" - 1 + 0 +true + false +6 / "3" +"2" * "3" +4 + 5 + "px" +"$" + 4 + 5 +"4" - 2 +"4px" - 2 +7 / 0 +" -9 " + 5 +" -9 " - 5 +null + 1 +undefined + 1 +" \t \n" - 2 +``` + +Think well, write down and then compare with the answer. diff --git a/1-js/02-first-steps/08-operators/4-fix-prompt/solution.md b/1-js/02-first-steps/08-operators/4-fix-prompt/solution.md new file mode 100644 index 0000000000..04f73fbd0b --- /dev/null +++ b/1-js/02-first-steps/08-operators/4-fix-prompt/solution.md @@ -0,0 +1,32 @@ +The reason is that prompt returns user input as a string. + +So variables have values `"1"` and `"2"` respectively. + +```js run +let a = "1"; // prompt("First number?", 1); +let b = "2"; // prompt("Second number?", 2); + +alert(a + b); // 12 +``` + +What we should to is to convert strings to numbers before `+`. For example, using `Number()` or prepending them with `+`. + +For example, right before `prompt`: + +```js run +let a = +prompt("First number?", 1); +let b = +prompt("Second number?", 2); + +alert(a + b); // 3 +``` + +Or in the `alert`: + +```js run +let a = prompt("First number?", 1); +let b = prompt("Second number?", 2); + +alert(+a + +b); // 3 +``` + +Using both unary and binary `+` in the latest code. Looks funny, doesn't it? diff --git a/1-js/02-first-steps/08-operators/4-fix-prompt/task.md b/1-js/02-first-steps/08-operators/4-fix-prompt/task.md new file mode 100644 index 0000000000..b3ea4a3a3c --- /dev/null +++ b/1-js/02-first-steps/08-operators/4-fix-prompt/task.md @@ -0,0 +1,18 @@ +importance: 5 + +--- + +# Fix the addition + +Here's a code that asks the user for two numbers and shows their sum. + +It works incorrectly. The output in the example below is `12` (for default prompt values). + +Why? Fix it. The result should be `3`. + +```js run +let a = prompt("First number?", 1); +let b = prompt("Second number?", 2); + +alert(a + b); // 12 +``` diff --git a/1-js/02-first-steps/08-operators/article.md b/1-js/02-first-steps/08-operators/article.md new file mode 100644 index 0000000000..48c453cec6 --- /dev/null +++ b/1-js/02-first-steps/08-operators/article.md @@ -0,0 +1,470 @@ +# Basic operators, maths + +We know many operators from school. They are things like addition `+`, multiplication `*`, subtraction `-`, and so on. + +In this chapter, we’ll start with simple operators, then concentrate on JavaScript-specific aspects, not covered by school arithmetic. + +## Terms: "unary", "binary", "operand" + +Before we move on, let's grasp some common terminology. + +- *An operand* -- is what operators are applied to. For instance, in the multiplication of `5 * 2` there are two operands: the left operand is `5` and the right operand is `2`. Sometimes, people call these "arguments" instead of "operands". +- An operator is *unary* if it has a single operand. For example, the unary negation `-` reverses the sign of a number: + + ```js run + let x = 1; + + *!* + x = -x; + */!* + alert( x ); // -1, unary negation was applied + ``` +- An operator is *binary* if it has two operands. The same minus exists in binary form as well: + + ```js run no-beautify + let x = 1, y = 3; + alert( y - x ); // 2, binary minus subtracts values + ``` + + Formally, in the examples above we have two different operators that share the same symbol: the negation operator, a unary operator that reverses the sign, and the subtraction operator, a binary operator that subtracts one number from another. + +## Maths + +The following math operations are supported: + +- Addition `+`, +- Subtraction `-`, +- Multiplication `*`, +- Division `/`, +- Remainder `%`, +- Exponentiation `**`. + +The first four are straightforward, while `%` and `**` need a few words about them. + +### Remainder % + +The remainder operator `%`, despite its appearance, is not related to percents. + +The result of `a % b` is the [remainder](https://en.wikipedia.org/wiki/Remainder) of the integer division of `a` by `b`. + +For instance: + +```js run +alert( 5 % 2 ); // 1, a remainder of 5 divided by 2 +alert( 8 % 3 ); // 2, a remainder of 8 divided by 3 +``` + +### Exponentiation ** + +The exponentiation operator `a ** b` multiplies `a` by itself `b` times. + +For instance: + +```js run +alert( 2 ** 2 ); // 4 (2 multiplied by itself 2 times) +alert( 2 ** 3 ); // 8 (2 * 2 * 2, 3 times) +alert( 2 ** 4 ); // 16 (2 * 2 * 2 * 2, 4 times) +``` + +Mathematically, the exponentiation is defined for non-integer numbers as well. For example, a square root is an exponentiation by `1/2`: + +```js run +alert( 4 ** (1/2) ); // 2 (power of 1/2 is the same as a square root) +alert( 8 ** (1/3) ); // 2 (power of 1/3 is the same as a cubic root) +``` + + +## String concatenation with binary + + +Let's meet features of JavaScript operators that are beyond school arithmetics. + +Usually, the plus operator `+` sums numbers. + +But, if the binary `+` is applied to strings, it merges (concatenates) them: + +```js +let s = "my" + "string"; +alert(s); // mystring +``` + +Note that if any of the operands is a string, then the other one is converted to a string too. + +For example: + +```js run +alert( '1' + 2 ); // "12" +alert( 2 + '1' ); // "21" +``` + +See, it doesn't matter whether the first operand is a string or the second one. + +Here's a more complex example: + +```js run +alert(2 + 2 + '1' ); // "41" and not "221" +``` + +Here, operators work one after another. The first `+` sums two numbers, so it returns `4`, then the next `+` adds the string `1` to it, so it's like `4 + '1' = 41`. + +The binary `+` is the only operator that supports strings in such a way. Other arithmetic operators work only with numbers and always convert their operands to numbers. + +Here's the demo for subtraction and division: + +```js run +alert( 6 - '2' ); // 4, converts '2' to a number +alert( '6' / '2' ); // 3, converts both operands to numbers +``` + +## Numeric conversion, unary + + +The plus `+` exists in two forms: the binary form that we used above and the unary form. + +The unary plus or, in other words, the plus operator `+` applied to a single value, doesn't do anything to numbers. But if the operand is not a number, the unary plus converts it into a number. + +For example: + +```js run +// No effect on numbers +let x = 1; +alert( +x ); // 1 + +let y = -2; +alert( +y ); // -2 + +*!* +// Converts non-numbers +alert( +true ); // 1 +alert( +"" ); // 0 +*/!* +``` + +It actually does the same thing as `Number(...)`, but is shorter. + +The need to convert strings to numbers arises very often. For example, if we are getting values from HTML form fields, they are usually strings. What if we want to sum them? + +The binary plus would add them as strings: + +```js run +let apples = "2"; +let oranges = "3"; + +alert( apples + oranges ); // "23", the binary plus concatenates strings +``` + +If we want to treat them as numbers, we need to convert and then sum them: + +```js run +let apples = "2"; +let oranges = "3"; + +*!* +// both values converted to numbers before the binary plus +alert( +apples + +oranges ); // 5 +*/!* + +// the longer variant +// alert( Number(apples) + Number(oranges) ); // 5 +``` + +From a mathematician's standpoint, the abundance of pluses may seem strange. But from a programmer's standpoint, there's nothing special: unary pluses are applied first, they convert strings to numbers, and then the binary plus sums them up. + +Why are unary pluses applied to values before the binary ones? As we're going to see, that's because of their *higher precedence*. + +## Operator precedence + +If an expression has more than one operator, the execution order is defined by their *precedence*, or, in other words, the default priority order of operators. + +From school, we all know that the multiplication in the expression `1 + 2 * 2` should be calculated before the addition. That's exactly the precedence thing. The multiplication is said to have *a higher precedence* than the addition. + +Parentheses override any precedence, so if we're not satisfied with the default order, we can use them to change it. For example, write `(1 + 2) * 2`. + +There are many operators in JavaScript. Every operator has a corresponding precedence number. The one with the larger number executes first. If the precedence is the same, the execution order is from left to right. + +Here's an extract from the [precedence table](https://developer.mozilla.org/en/JavaScript/Reference/operators/operator_precedence) (you don't need to remember this, but note that unary operators are higher than corresponding binary ones): + +| Precedence | Name | Sign | +|------------|------|------| +| ... | ... | ... | +| 17 | unary plus | `+` | +| 17 | unary negation | `-` | +| 16 | exponentiation | `**` | +| 15 | multiplication | `*` | +| 15 | division | `/` | +| 13 | addition | `+` | +| 13 | subtraction | `-` | +| ... | ... | ... | +| 3 | assignment | `=` | +| ... | ... | ... | + +As we can see, the "unary plus" has a priority of `17` which is higher than the `13` of "addition" (binary plus). That's why, in the expression `"+apples + +oranges"`, unary pluses work before the addition. + +## Assignment + +Let's note that an assignment `=` is also an operator. It is listed in the precedence table with the very low priority of `3`. + +That's why, when we assign a variable, like `x = 2 * 2 + 1`, the calculations are done first and then the `=` is evaluated, storing the result in `x`. + +```js +let x = 2 * 2 + 1; + +alert( x ); // 5 +``` + +### Assignment = returns a value + +The fact of `=` being an operator, not a "magical" language construct has an interesting implication. + +Most operators in JavaScript return a value. That's obvious for `+` and `-`, but also true for `=`. + +The call `x = value` writes the `value` into `x` *and then returns it*. + +Here's a demo that uses an assignment as part of a more complex expression: + +```js run +let a = 1; +let b = 2; + +*!* +let c = 3 - (a = b + 1); +*/!* + +alert( a ); // 3 +alert( c ); // 0 +``` + +In the example above, the result of expression `(a = b + 1)` is the value which was assigned to `a` (that is `3`). It is then used for further evaluations. + +Funny code, isn't it? We should understand how it works, because sometimes we see it in JavaScript libraries. + +Although, please don't write the code like that. Such tricks definitely don't make code clearer or readable. + +### Chaining assignments + +Another interesting feature is the ability to chain assignments: + +```js run +let a, b, c; + +*!* +a = b = c = 2 + 2; +*/!* + +alert( a ); // 4 +alert( b ); // 4 +alert( c ); // 4 +``` + +Chained assignments evaluate from right to left. First, the rightmost expression `2 + 2` is evaluated and then assigned to the variables on the left: `c`, `b` and `a`. At the end, all the variables share a single value. + +Once again, for the purposes of readability it's better to split such code into few lines: + +```js +c = 2 + 2; +b = c; +a = c; +``` +That's easier to read, especially when eye-scanning the code fast. + +## Modify-in-place + +We often need to apply an operator to a variable and store the new result in that same variable. + +For example: + +```js +let n = 2; +n = n + 5; +n = n * 2; +``` + +This notation can be shortened using the operators `+=` and `*=`: + +```js run +let n = 2; +n += 5; // now n = 7 (same as n = n + 5) +n *= 2; // now n = 14 (same as n = n * 2) + +alert( n ); // 14 +``` + +Short "modify-and-assign" operators exist for all arithmetical and bitwise operators: `/=`, `-=`, etc. + +Such operators have the same precedence as a normal assignment, so they run after most other calculations: + +```js run +let n = 2; + +n *= 3 + 5; + +alert( n ); // 16 (right part evaluated first, same as n *= 8) +``` + +## Increment/decrement + + + +Increasing or decreasing a number by one is among the most common numerical operations. + +So, there are special operators for it: + +- **Increment** `++` increases a variable by 1: + + ```js run no-beautify + let counter = 2; + counter++; // works the same as counter = counter + 1, but is shorter + alert( counter ); // 3 + ``` +- **Decrement** `--` decreases a variable by 1: + + ```js run no-beautify + let counter = 2; + counter--; // works the same as counter = counter - 1, but is shorter + alert( counter ); // 1 + ``` + +```warn +Increment/decrement can only be applied to variables. Trying to use it on a value like `5++` will give an error. +``` + +The operators `++` and `--` can be placed either before or after a variable. + +- When the operator goes after the variable, it is in "postfix form": `counter++`. +- The "prefix form" is when the operator goes before the variable: `++counter`. + +Both of these statements do the same thing: increase `counter` by `1`. + +Is there any difference? Yes, but we can only see it if we use the returned value of `++/--`. + +Let's clarify. As we know, all operators return a value. Increment/decrement is no exception. The prefix form returns the new value while the postfix form returns the old value (prior to increment/decrement). + +To see the difference, here's an example: + +```js run +let counter = 1; +let a = ++counter; // (*) + +alert(a); // *!*2*/!* +``` + +In the line `(*)`, the *prefix* form `++counter` increments `counter` and returns the new value, `2`. So, the `alert` shows `2`. + +Now, let's use the postfix form: + +```js run +let counter = 1; +let a = counter++; // (*) changed ++counter to counter++ + +alert(a); // *!*1*/!* +``` + +In the line `(*)`, the *postfix* form `counter++` also increments `counter` but returns the *old* value (prior to increment). So, the `alert` shows `1`. + +To summarize: + +- If the result of increment/decrement is not used, there is no difference in which form to use: + + ```js run + let counter = 0; + counter++; + ++counter; + alert( counter ); // 2, the lines above did the same + ``` +- If we'd like to increase a value *and* immediately use the result of the operator, we need the prefix form: + + ```js run + let counter = 0; + alert( ++counter ); // 1 + ``` +- If we'd like to increment a value but use its previous value, we need the postfix form: + + ```js run + let counter = 0; + alert( counter++ ); // 0 + ``` + +````smart header="Increment/decrement among other operators" +The operators `++/--` can be used inside expressions as well. Their precedence is higher than most other arithmetical operations. + +For instance: + +```js run +let counter = 1; +alert( 2 * ++counter ); // 4 +``` + +Compare with: + +```js run +let counter = 1; +alert( 2 * counter++ ); // 2, because counter++ returns the "old" value +``` + +Though technically okay, such notation usually makes code less readable. One line does multiple things -- not good. + +While reading code, a fast "vertical" eye-scan can easily miss something like `counter++` and it won't be obvious that the variable increased. + +We advise a style of "one line -- one action": + +```js run +let counter = 1; +alert( 2 * counter ); +counter++; +``` +```` + +## Bitwise operators + +Bitwise operators treat arguments as 32-bit integer numbers and work on the level of their binary representation. + +These operators are not JavaScript-specific. They are supported in most programming languages. + +The list of operators: + +- AND ( `&` ) +- OR ( `|` ) +- XOR ( `^` ) +- NOT ( `~` ) +- LEFT SHIFT ( `<<` ) +- RIGHT SHIFT ( `>>` ) +- ZERO-FILL RIGHT SHIFT ( `>>>` ) + +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/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators) article on MDN when a need arises. + +## Comma + +The comma operator `,` is one of the rarest and most unusual operators. Sometimes, it's used to write shorter code, so we need to know it in order to understand what's going on. + +The comma operator allows us to evaluate several expressions, dividing them with a comma `,`. Each of them is evaluated but only the result of the last one is returned. + +For example: + +```js run +*!* +let a = (1 + 2, 3 + 4); +*/!* + +alert( a ); // 7 (the result of 3 + 4) +``` + +Here, the first expression `1 + 2` is evaluated and its result is thrown away. Then, `3 + 4` is evaluated and returned as the result. + +```smart header="Comma has a very low precedence" +Please note that the comma operator has very low precedence, lower than `=`, so parentheses are important in the example above. + +Without them: `a = 1 + 2, 3 + 4` evaluates `+` first, summing the numbers into `a = 3, 7`, then the assignment operator `=` assigns `a = 3`, and the rest is ignored. It's like `(a = 1 + 2), 3 + 4`. +``` + +Why do we need an operator that throws away everything except the last expression? + +Sometimes, people use it in more complex constructs to put several actions in one line. + +For example: + +```js +// three operations in one line +for (*!*a = 1, b = 3, c = a * b*/!*; a < 10; a++) { + ... +} +``` + +Such tricks are used in many JavaScript frameworks. That's why we're mentioning them. But usually they don't improve code readability so we should think well before using them. diff --git a/1-js/02-first-steps/08-comparison/1-comparison-questions/solution.md b/1-js/02-first-steps/09-comparison/1-comparison-questions/solution.md similarity index 51% rename from 1-js/02-first-steps/08-comparison/1-comparison-questions/solution.md rename to 1-js/02-first-steps/09-comparison/1-comparison-questions/solution.md index de42c992a0..52ae5fb4a3 100644 --- a/1-js/02-first-steps/08-comparison/1-comparison-questions/solution.md +++ b/1-js/02-first-steps/09-comparison/1-comparison-questions/solution.md @@ -12,6 +12,7 @@ null === +"\n0\n" → false 理由: +<<<<<<< HEAD:1-js/02-first-steps/08-comparison/1-comparison-questions/solution.md 1. 明らかに true ですね。 2. 辞書の比較になるので、false です。 3. 再び辞書の比較です。`"2"` の最初の文字は `12` の最初の文字 `"1"` よりも大きいです。 @@ -19,3 +20,12 @@ null === +"\n0\n" → false 5. 厳密等価は厳密です。両側が異なる型だと false になります。 6. (4) をみてください。 7. 異なる型の厳密等価です。 +======= +1. Obviously, true. +2. Dictionary comparison, hence false. `"a"` is smaller than `"p"`. +3. Again, dictionary comparison, first char of `"2"` is greater than the first char of `"1"`. +4. Values `null` and `undefined` equal each other only. +5. Strict equality is strict. Different types from both sides lead to false. +6. Similar to `(4)`, `null` only equals `undefined`. +7. Strict equality of different types. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/09-comparison/1-comparison-questions/solution.md diff --git a/1-js/02-first-steps/09-comparison/1-comparison-questions/task.md b/1-js/02-first-steps/09-comparison/1-comparison-questions/task.md new file mode 100644 index 0000000000..3b8165d458 --- /dev/null +++ b/1-js/02-first-steps/09-comparison/1-comparison-questions/task.md @@ -0,0 +1,21 @@ +importance: 5 + +--- + +# 比較 + +<<<<<<< HEAD:1-js/02-first-steps/08-comparison/1-comparison-questions/task.md +式の結果はどうなるでしょう? +======= +What will be the result for these expressions? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/09-comparison/1-comparison-questions/task.md + +```js no-beautify +5 > 4 +"apple" > "pineapple" +"2" > "12" +undefined == null +undefined === null +null == "\n0\n" +null === +"\n0\n" +``` diff --git a/1-js/02-first-steps/09-comparison/article.md b/1-js/02-first-steps/09-comparison/article.md new file mode 100644 index 0000000000..012d359e0a --- /dev/null +++ b/1-js/02-first-steps/09-comparison/article.md @@ -0,0 +1,213 @@ +# Comparisons + +We know many comparison operators from maths. + +In JavaScript they are written like this: + +- 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. + +In this article we'll learn more about different types of comparisons, how JavaScript makes them, including important peculiarities. + +## Boolean is the result + +All comparison operators return a boolean value: + +- `true` -- means "yes", "correct" or "the truth". +- `false` -- means "no", "wrong" or "not the truth". + +For example: + +```js run +alert( 2 > 1 ); // true (correct) +alert( 2 == 1 ); // false (wrong) +alert( 2 != 1 ); // true (correct) +``` + +A comparison result can be assigned to a variable, just like any value: + +```js run +let result = 5 > 4; // assign the result of the comparison +alert( result ); // true +``` + +## String comparison + +To see whether a string is greater than another, JavaScript uses the so-called "dictionary" or "lexicographical" order. + +In other words, strings are compared letter-by-letter. + +For example: + +```js run +alert( 'Z' > 'A' ); // true +alert( 'Glow' > 'Glee' ); // true +alert( 'Bee' > 'Be' ); // true +``` + +The algorithm to compare two strings is simple: + +1. Compare the first character of both strings. +2. If the first character from the first string is greater (or less) than the other string's, then the first string is greater (or less) than the second. We're done. +3. Otherwise, if both strings' first characters are the same, compare the second characters the same way. +4. Repeat until the end of either string. +5. If both strings end at the same length, then they are equal. Otherwise, the longer string is greater. + +In the examples above, the comparison `'Z' > 'A'` gets to a result at the first step while the strings `"Glow"` and `"Glee"` are compared character-by-character: + +1. `G` is the same as `G`. +2. `l` is the same as `l`. +3. `o` is greater than `e`. Stop here. The first string is greater. + +```smart header="Not a real dictionary, but Unicode order" +The comparison algorithm given above is roughly equivalent to the one used in dictionaries or phone books, but it's not exactly the same. + +For instance, case matters. A capital letter `"A"` is not equal to the lowercase `"a"`. Which one is greater? The lowercase `"a"`. Why? Because the lowercase character has a greater index in the internal encoding table JavaScript uses (Unicode). We'll get back to specific details and consequences of this in the chapter . +``` + +## Comparison of different types + +When comparing values of different types, JavaScript converts the values to numbers. + +For example: + +```js run +alert( '2' > 1 ); // true, string '2' becomes a number 2 +alert( '01' == 1 ); // true, string '01' becomes a number 1 +``` + +For boolean values, `true` becomes `1` and `false` becomes `0`. + +For example: + +```js run +alert( true == 1 ); // true +alert( false == 0 ); // true +``` + +````smart header="A funny consequence" +It is possible that at the same time: + +- Two values are equal. +- One of them is `true` as a boolean and the other one is `false` as a boolean. + +For example: + +```js run +let a = 0; +alert( Boolean(a) ); // false + +let b = "0"; +alert( Boolean(b) ); // true + +alert(a == b); // true! +``` + +From JavaScript's standpoint, this result is quite normal. An equality check converts values using the numeric conversion (hence `"0"` becomes `0`), while the explicit `Boolean` conversion uses another set of rules. +```` + +## Strict equality + +A regular equality check `==` has a problem. It cannot differentiate `0` from `false`: + +```js run +alert( 0 == false ); // true +``` + +The same thing happens with an empty string: + +```js run +alert( '' == false ); // true +``` + +This happens because operands of different types are converted to numbers by the equality operator `==`. An empty string, just like `false`, becomes a zero. + +What to do if we'd like to differentiate `0` from `false`? + +**A strict equality operator `===` checks the equality without type conversion.** + +In other words, if `a` and `b` are of different types, then `a === b` immediately returns `false` without an attempt to convert them. + +Let's try it: + +```js run +alert( 0 === false ); // false, because the types are different +``` + +There is also a "strict non-equality" operator `!==` analogous to `!=`. + +The strict equality operator is a bit longer to write, but makes it obvious what's going on and leaves less room for errors. + +## Comparison with null and undefined + +There's a non-intuitive behavior when `null` or `undefined` are compared to other values. + +For a strict equality check `===` +: These values are different, because each of them is a different type. + + ```js run + alert( null === undefined ); // false + ``` + +For a non-strict check `==` +: There's a special rule. These two are a "sweet couple": they equal each other (in the sense of `==`), but not any other value. + + ```js run + alert( null == undefined ); // true + ``` + +For maths and other comparisons `< > <= >=` +: `null/undefined` are converted to numbers: `null` becomes `0`, while `undefined` becomes `NaN`. + +Now let's see some funny things that happen when we apply these rules. And, what's more important, how to not fall into a trap with them. + +### Strange result: null vs 0 + +Let's compare `null` with a zero: + +```js run +alert( null > 0 ); // (1) false +alert( null == 0 ); // (2) false +alert( null >= 0 ); // (3) *!*true*/!* +``` + +Mathematically, that's strange. The last result states that "`null` is greater than or equal to zero", so in one of the comparisons above it must be `true`, but they are both false. + +The reason is that an equality check `==` and comparisons `> < >= <=` work differently. Comparisons convert `null` to a number, treating it as `0`. That's why (3) `null >= 0` is true and (1) `null > 0` is false. + +On the other hand, the equality check `==` for `undefined` and `null` is defined such that, without any conversions, they equal each other and don't equal anything else. That's why (2) `null == 0` is false. + +### An incomparable undefined + +The value `undefined` shouldn't be compared to other values: + +```js run +alert( undefined > 0 ); // false (1) +alert( undefined < 0 ); // false (2) +alert( undefined == 0 ); // false (3) +``` + +Why does it dislike zero so much? Always false! + +We get these results because: + +- Comparisons `(1)` and `(2)` return `false` because `undefined` gets converted to `NaN` and `NaN` is a special numeric value which returns `false` for all comparisons. +- The equality check `(3)` returns `false` because `undefined` only equals `null`, `undefined`, and no other value. + +### Evade problems + +Why did we go over these examples? Should we remember these peculiarities all the time? Well, not really. Actually, these tricky things will gradually become familiar over time, but there's a solid way to evade problems with them: + +Just treat any comparison with `undefined/null` except the strict equality `===` with exceptional care. + +Don't use comparisons `>= > < <=` with a variable which may be `null/undefined`, unless you're really sure of what you're doing. If a variable can have these values, check for them separately. + +## Summary + +- Comparison operators return a boolean value. +- Strings are compared letter-by-letter in the "dictionary" order. +- When values of different types are compared, they get converted to numbers (with the exclusion of a strict equality check). +- The values `null` and `undefined` equal `==` each other and do not equal any other value. +- Be careful when using comparisons like `>` or `<` with variables that can occasionally be `null/undefined`. Checking for `null/undefined` separately is a good idea. diff --git a/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/solution.md b/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/solution.md index 638ce81f13..ff32354fae 100644 --- a/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/solution.md +++ b/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/solution.md @@ -1,6 +1,6 @@ ```js -result = (a + b < 4) ? 'Below' : 'Over'; +let result = (a + b < 4) ? 'Below' : 'Over'; ``` diff --git a/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md b/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md index b13126f949..5e0f647582 100644 --- a/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md +++ b/1-js/02-first-steps/10-ifelse/5-rewrite-if-question/task.md @@ -4,9 +4,15 @@ importance: 5 # 'if' を '?' で書き直しましょう +<<<<<<< HEAD 三項演算子 `'?'` を使って、この `if` を書き直してください。: +======= +Rewrite this `if` using the conditional operator `'?'`: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js +let result; + if (a + b < 4) { result = 'Below'; } else { diff --git a/1-js/02-first-steps/10-ifelse/article.md b/1-js/02-first-steps/10-ifelse/article.md index 83d368634b..cf2b29c178 100644 --- a/1-js/02-first-steps/10-ifelse/article.md +++ b/1-js/02-first-steps/10-ifelse/article.md @@ -1,14 +1,24 @@ # 条件演算子: if, '?' +<<<<<<< HEAD 時には、条件に基づき異なるアクションを実行する必要があります。 そのための `if` 文と、簡単にするための "疑問符" 演算子 `"?"` と呼ばれる条件付き評価のための条件付き(3項)演算子があります。 [cut] +======= +Sometimes, we need to perform different actions based on different conditions. + +To do that, we can use the `if` statement and the conditional operator `?`, that's also called a "question mark" operator. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## "if" 文 +<<<<<<< HEAD "if" 文は与えられた条件を評価します。結果が `true` であればコードを実行します。 +======= +The `if(...)` statement evaluates a condition in parentheses and, if the result is `true`, executes a block of code. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: @@ -20,9 +30,15 @@ if (year == 2015) alert( 'You are right!' ); */!* ``` +<<<<<<< HEAD 上の例では、条件はシンプルな等価チェックです: `year == 2015`。より複雑にすることもできます。 実行する文が複数ある場合、コードブロックを波括弧で囲む必要があります。: +======= +In the example above, the condition is a simple equality check (`year == 2015`), but it can be much more complex. + +If we want to execute more than one statement, we have to wrap our code block inside curly braces: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js if (year == 2015) { @@ -31,16 +47,29 @@ if (year == 2015) { } ``` +<<<<<<< HEAD たとえ1つの文しかない場合でも `if` を使用するときは波括弧でコードブロックを囲むことを推奨します。これは可読性を向上させます。 +======= +We recommend wrapping your code block with curly braces `{}` every time you use an `if` statement, even if there is only one statement to execute. Doing so improves readability. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## Boolean 変換 +<<<<<<< HEAD `if (…)` 文は括弧の中の式を評価し、Boolean型に変換します。 +======= +The `if (…)` statement evaluates the expression in its parentheses and converts the result to a boolean. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 チャプター の変換ルールを思い出してみましょう: +<<<<<<< HEAD - 数値 `0`, 空文字 `""`, `null`, `undefined` そして `NaN` は `false` になります。そのため、これらは "偽とみなされる" 値とよばれています。 - 他の値は `true` になるため、"真とみなされる" 値と呼ばれます。 +======= +- A number `0`, an empty string `""`, `null`, `undefined`, and `NaN` all become `false`. Because of that they are called "falsy" values. +- Other values become `true`, so they are called "truthy". +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 さて、下のコードですがこの条件は決して実行されません: @@ -50,7 +79,11 @@ if (0) { // 0 は偽 } ``` +<<<<<<< HEAD ...また、この条件は -- 常に処理されます: +======= +...and inside this condition -- it always will: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js if (1) { // 1 は真 @@ -58,7 +91,11 @@ if (1) { // 1 は真 } ``` +<<<<<<< HEAD 次のように事前評価されたBool値を `if` に通すこともできます: +======= +We can also pass a pre-evaluated boolean value to `if`, like this: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let cond = (year == 2015); // == は true または false を評価する @@ -70,11 +107,15 @@ if (cond) { ## "else" 句 +<<<<<<< HEAD `if` 文は任意の "else" ブロックを持つ場合があります。それは条件が間違っている場合に実行されます。 +======= +The `if` statement may contain an optional "else" block. It executes when the condition is false. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: ```js run -let year = prompt('In which year was ECMAScript-2015 specification published?', ''); +let year = prompt('In which year was the ECMAScript-2015 specification published?', ''); if (year == 2015) { alert( 'You guessed it right!' ); @@ -85,12 +126,16 @@ if (year == 2015) { ## いくつかの条件: "else if" +<<<<<<< HEAD いくつかの条件のパターンをテストしたい時があります。そのために `else if` 句があります。 +======= +Sometimes, we'd like to test several variants of a condition. The `else if` clause lets us do that. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: ```js run -let year = prompt('In which year was ECMAScript-2015 specification published?', ''); +let year = prompt('In which year was the ECMAScript-2015 specification published?', ''); if (year < 2015) { alert( 'Too early...' ); @@ -101,6 +146,7 @@ if (year < 2015) { } ``` +<<<<<<< HEAD 上のコードで、JavaScriptは最初に `year < 2015` をチェックします。それが偽の場合、次の条件 `year > 2015` に行きます。それでもない場合は、最後の `alert` を表示します。 複数の `else if` ブロックを持つことができます。最後の `else` は任意です。 @@ -108,6 +154,15 @@ if (year < 2015) { ## 3項演算子 '?' 条件に依存して変数へ代入を行う必要がある場合があります。 +======= +In the code above, JavaScript first checks `year < 2015`. If that is falsy, it goes to the next condition `year > 2015`. If that is also falsy, it shows the last `alert`. + +There can be more `else if` blocks. The final `else` is optional. + +## Conditional operator '?' + +Sometimes, we need to assign a variable depending on a condition. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: @@ -126,16 +181,26 @@ if (age > 18) { alert(accessAllowed); ``` +<<<<<<< HEAD いわゆる、"3項" もしくは "疑問符" 演算子は、より短く簡単に行うことができます。 演算子は疑問符 `"?"` で表されます。公式な用語 "3項" は演算子は3つのオペランドを持つことを意味します。 +======= +The so-called "conditional" or "question mark" operator lets us do that in a shorter and simpler way. + +The operator is represented by a question mark `?`. Sometimes it's called "ternary", because the operator has three operands. It is actually the one and only operator in JavaScript which has that many. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 構文は次の通りです: ```js -let result = condition ? value1 : value2 +let result = condition ? value1 : value2; ``` +<<<<<<< HEAD `condition` は評価され、もしも真であれば、`value1` が返却され、そうでなければ -- `value2` になります。 +======= +The `condition` is evaluated: if it's truthy then `value1` is returned, otherwise -- `value2`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: @@ -143,7 +208,13 @@ let result = condition ? value1 : value2 let accessAllowed = (age > 18) ? true : false; ``` +<<<<<<< HEAD 技術的には、`age > 18` の周りの括弧を省くことができます。疑問符演算子は低い優先順位を持っているので、比較 `>` の後に実行されます。そのため同じように動作します: +======= +Technically, we can omit the parentheses around `age > 18`. The question mark operator has a low precedence, so it executes after the comparison `>`. + +This example will do the same thing as the previous one: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js // 比較演算子 "age > 18" が最初に実行されます @@ -151,10 +222,17 @@ let accessAllowed = (age > 18) ? true : false; let accessAllowed = age > 18 ? true : false; ``` +<<<<<<< HEAD ...しかし、括弧はコードの可読性をより良くします。そのため、括弧を使うことが推奨されます。 ````smart 上の例では、比較自体が `true/false` を返すため、疑問符演算子を回避することが可能です。 +======= +But parentheses make the code more readable, so we recommend using them. + +````smart +In the example above, you can avoid using the question mark operator because the comparison itself returns `true/false`: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js // the same @@ -164,7 +242,11 @@ let accessAllowed = age > 18; ## 複数の '?' +<<<<<<< HEAD 連続する疑問符 `"?"` 演算子は1つ以上の条件に依存した値を返すことができます。 +======= +A sequence of question mark operators `?` can return a value that depends on more than one condition. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: ```js run @@ -178,6 +260,7 @@ let message = (age < 3) ? 'Hi, baby!' : alert( message ); ``` +<<<<<<< HEAD 最初、それが何をしているのか掴むのが難しいかもしれません。しかしよく見るとそれがただの通常の一連のテストであることがわかります。 1. 最初の疑問符は `age < 3` かどうかチェックします。 @@ -186,11 +269,21 @@ alert( message ); 4. それが真であれば -- `'Greetings!'` を返します。そうでなければ -- コロン `":"` の後に行き、`What an unusual age` を返します。 `if..else` を使った同じロジックです: +======= +It may be difficult at first to grasp what's going on. But after a closer look, we can see that it's just an ordinary sequence of tests: + +1. The first question mark checks whether `age < 3`. +2. If true -- it returns `'Hi, baby!'`. Otherwise, it continues to the expression after the colon '":"', checking `age < 18`. +3. If that's true -- it returns `'Hello!'`. Otherwise, it continues to the expression after the next colon '":"', checking `age < 100`. +4. If that's true -- it returns `'Greetings!'`. Otherwise, it continues to the expression after the last colon '":"', returning `'What an unusual age!'`. + +Here's how this looks using `if..else`: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js if (age < 3) { message = 'Hi, baby!'; -} else if (a < 18) { +} else if (age < 18) { message = 'Hello!'; } else if (age < 100) { message = 'Greetings!'; @@ -201,7 +294,11 @@ if (age < 3) { ## 非伝統的な '?' の使用 +<<<<<<< HEAD 時々、疑問符 `'?'` は `if` の置換として使われます: +======= +Sometimes the question mark `?` is used as a replacement for `if`: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run no-beautify let company = prompt('Which company created JavaScript?', ''); @@ -212,6 +309,7 @@ let company = prompt('Which company created JavaScript?', ''); */!* ``` +<<<<<<< HEAD 条件 `company == 'Netscape'` に応じて、`"?"` の後の1つ目もしくは2つ目の部分が実行されアラートが表示されます。 ここでは変数に結果を代入していません。このアイデアは条件に応じて異なるコードを実行させるものです。 @@ -221,6 +319,17 @@ let company = prompt('Which company created JavaScript?', ''); 表記は `if` よりも短いように見え、一部のプログラマには魅力的です。しかしそれは読みにくいです。 比較として `if` を使った同じコードです: +======= +Depending on the condition `company == 'Netscape'`, either the first or the second expression after the `?` gets executed and shows an alert. + +We don't assign a result to a variable here. Instead, we execute different code depending on the condition. + +**It's not recommended to use the question mark operator in this way.** + +The notation is shorter than the equivalent `if` statement, which appeals to some programmers. But it is less readable. + +Here is the same code using `if` for comparison: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run no-beautify let company = prompt('Which company created JavaScript?', ''); @@ -234,7 +343,13 @@ if (company == 'Netscape') { */!* ``` +<<<<<<< HEAD 私たちの目はコードを縦に見ていきます。複数行にまたがる構造は、長い水平な命令セットよりも理解しやすいです。 疑問符 `'?'` の考え方は、条件によって別の値を返すことです。まさにそのために使ってください。 異なるコードの枝葉を実行するために `if` があります。 +======= +Our eyes scan the code vertically. Code blocks which span several lines are easier to understand than a long, horizontal instruction set. + +The purpose of the question mark operator `?` is to return one value or another depending on its condition. Please use it for exactly that. Use `if` when you need to execute different branches of code. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/task.md b/1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/task.md index fdba6dbd82..b40532f918 100644 --- a/1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/task.md +++ b/1-js/02-first-steps/11-logical-operators/1-alert-null-2-undefined/task.md @@ -4,7 +4,11 @@ importance: 5 # OR の結果はなんでしょう? +<<<<<<< HEAD 下のコードは何を出力するでしょう? +======= +What is the code below going to output? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js alert( null || 2 || undefined ); diff --git a/1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md b/1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md index 9f45e4b68d..77428a99a5 100644 --- a/1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md +++ b/1-js/02-first-steps/11-logical-operators/2-alert-or/solution.md @@ -6,8 +6,14 @@ alert( alert(1) || 2 || alert(3) ); `alert` の呼び出しは値を返しません。また、言い換えると、 `undefined` を返します。 +<<<<<<< HEAD 1. 最初の OR `||` はその左のオペランド `alert(1)` を検査します。それは `1` の最初のメッセージを表示します。 2. `alert` は `undefined` を返すので、OR は真値を探すのに2つ目のオペランドに行きます。 3. 2つ目のペランド `2` は真値なので、実行が中止され `2` が返却されます。次に外部の alert でそれが表示されます。 +======= +1. The first OR `||` evaluates its left operand `alert(1)`. That shows the first message with `1`. +2. The `alert` returns `undefined`, so OR goes on to the second operand searching for a truthy value. +3. The second operand `2` is truthy, so the execution is halted, `2` is returned and then shown by the outer alert. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 検査は `alert(3)` に到達しないので、 `3` は現れません。 diff --git a/1-js/02-first-steps/11-logical-operators/2-alert-or/task.md b/1-js/02-first-steps/11-logical-operators/2-alert-or/task.md index d47e8079b1..e4311e3dda 100644 --- a/1-js/02-first-steps/11-logical-operators/2-alert-or/task.md +++ b/1-js/02-first-steps/11-logical-operators/2-alert-or/task.md @@ -4,7 +4,11 @@ importance: 3 # OR されたアラートの結果は何ですか? +<<<<<<< HEAD 下のコードは何を出力するでしょう? +======= +What will the code below output? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js alert( alert(1) || 2 || alert(3) ); diff --git a/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/task.md b/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/task.md index 94b47c7b0a..6f3f435a2b 100644 --- a/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/task.md +++ b/1-js/02-first-steps/11-logical-operators/3-alert-1-null-2/task.md @@ -4,7 +4,11 @@ importance: 5 # AND の結果は何? +<<<<<<< HEAD このコードは何を表示するでしょう? +======= +What is this code going to show? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js alert( 1 && null && 2 ); diff --git a/1-js/02-first-steps/11-logical-operators/5-alert-and-or/solution.md b/1-js/02-first-steps/11-logical-operators/5-alert-and-or/solution.md index 8261b19498..3eb62ec475 100644 --- a/1-js/02-first-steps/11-logical-operators/5-alert-and-or/solution.md +++ b/1-js/02-first-steps/11-logical-operators/5-alert-and-or/solution.md @@ -12,4 +12,9 @@ AND `&&` の優先順位は `||` よりも高いので、最初に実行され null || 3 || 4 ``` +<<<<<<< HEAD これの最初の真値の結果なので、`3` です。 +======= +Now the result is the first truthy value: `3`. + +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/02-first-steps/11-logical-operators/5-alert-and-or/task.md b/1-js/02-first-steps/11-logical-operators/5-alert-and-or/task.md index 0193df66a8..068ce61c45 100644 --- a/1-js/02-first-steps/11-logical-operators/5-alert-and-or/task.md +++ b/1-js/02-first-steps/11-logical-operators/5-alert-and-or/task.md @@ -4,7 +4,11 @@ importance: 5 # OR AND OR の結果 +<<<<<<< HEAD 結果はどうなるでしょう? +======= +What will the result be? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js alert( null || 2 && 3 || 4 ); diff --git a/1-js/02-first-steps/11-logical-operators/8-if-question/task.md b/1-js/02-first-steps/11-logical-operators/8-if-question/task.md index d92b499b0e..bf1cecc0e7 100644 --- a/1-js/02-first-steps/11-logical-operators/8-if-question/task.md +++ b/1-js/02-first-steps/11-logical-operators/8-if-question/task.md @@ -6,7 +6,11 @@ importance: 5 これらの `alert` で実行されるのはどれでしょう? +<<<<<<< HEAD `if(...)` の内側の式の結果はどうなるでしょう? +======= +What will the results of the expressions be inside `if(...)`? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js if (-1 || 0) alert( 'first' ); diff --git a/1-js/02-first-steps/11-logical-operators/9-check-login/solution.md b/1-js/02-first-steps/11-logical-operators/9-check-login/solution.md index 7de900619a..4b398c7250 100644 --- a/1-js/02-first-steps/11-logical-operators/9-check-login/solution.md +++ b/1-js/02-first-steps/11-logical-operators/9-check-login/solution.md @@ -9,13 +9,13 @@ if (userName == 'Admin') { if (pass == 'TheMaster') { alert( 'Welcome!' ); - } else if (pass == null) { - alert( 'Canceled.' ); + } else if (pass == '' || pass == null) { + alert( 'Canceled' ); } else { alert( 'Wrong password' ); } -} else if (userName == null) { +} else if (userName == '' || userName == null) { alert( 'Canceled' ); } else { alert( "I don't know you" ); diff --git a/1-js/02-first-steps/11-logical-operators/9-check-login/task.md b/1-js/02-first-steps/11-logical-operators/9-check-login/task.md index bcedacb062..290a52642f 100644 --- a/1-js/02-first-steps/11-logical-operators/9-check-login/task.md +++ b/1-js/02-first-steps/11-logical-operators/9-check-login/task.md @@ -2,23 +2,24 @@ importance: 3 --- -# ログインのチェック +# Check the login -`prompt` でログインを要求するコードを書いてください。 +Write the code which asks for a login with `prompt`. -もし訪問者が `"Admin"` と入力したら、パスワードのための `prompt` を出します。もし入力が空行または `key:Esc` の場合 -- "Canceled" と表示します。別の文字列の場合は -- "I don't know you" と表示します。 +If the visitor enters `"Admin"`, then `prompt` for a password, if the input is an empty line or `key:Esc` -- show "Canceled", if it's another string -- then show "I don't know you". -パスワードは次に沿ってチェックされます: +The password is checked as follows: -- ”TheMaster" と等しい場合には "Welcome!" と表示します。 -- 別の文字列の場合 -- "Wrong password" を表示します。 -- 空文字または入力がキャンセルされた場合には "Canceled." と表示します。 +- If it equals "TheMaster", then show "Welcome!", +- Another string -- show "Wrong password", +- For an empty string or cancelled input, show "Canceled" - -図: +The schema: ![](ifelse_task.svg) -入れ子の `if` ブロックを使ってください。コードの全体的な読みやすさに気をつけてください。 +Please use nested `if` blocks. Mind the overall readability of the code. + +Hint: passing an empty input to a prompt returns an empty string `''`. Pressing `key:ESC` during a prompt returns `null`. [demo] 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 23024a1aae..001451e9f3 100644 --- a/1-js/02-first-steps/11-logical-operators/article.md +++ b/1-js/02-first-steps/11-logical-operators/article.md @@ -2,13 +2,21 @@ JavaScriptには3つの論理演算子があります: `||` (OR:論理和), `&&` (AND:論理積), `!` (NOT:否定) +<<<<<<< HEAD それらは "論理" と呼ばれますが、Boolean 型だけでなく、どの型の値にも適用することができます。結果もまた任意の型になります。 +======= +Although they are called "logical", they can be applied to values of any type, not only boolean. Their result can also be of any type. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 詳細を見てみましょう: +<<<<<<< HEAD [cut] ## || (OR) +======= +## || (OR) +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 "OR" 演算子は2つの縦の記号で表現されます: @@ -16,9 +24,15 @@ JavaScriptには3つの論理演算子があります: `||` (OR:論理和), `&& result = a || b; ``` +<<<<<<< HEAD 古典的なプログラミングでは、論理和は真偽値のみを操作することを意味していました。もしもその引数のいずれかが `true` の場合、それは `true` を返します。そうでなければ `false` を返します。 JavaScriptでは、演算子は少し難解ですが強力です。最初に真偽値で起こることを見てみましょう。 +======= +In classical programming, the logical OR is meant to manipulate boolean values only. If any of its arguments are `true`, it returns `true`, otherwise it returns `false`. + +In JavaScript, the operator is a little bit trickier and more powerful. But first, let's see what happens with boolean values. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 4つの取りうる論理的な組み合わせがあります: @@ -31,9 +45,15 @@ alert( false || false ); // false ご覧の通り、両方のオペランドが `false` の場合を除き、結果は常に `true` です。 +<<<<<<< HEAD もしもオペランドが Boolean でない場合、評価のために Boolean に変換されます。 例えば、数値 `1` は `true` として扱われ、数値 `0` は `false` となります: +======= +If an operand is not a boolean, it's converted to a boolean for the evaluation. + +For instance, the number `1` is treated as `true`, the number `0` as `false`: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run if (1 || 0) { // if( true || false ) のように動作します @@ -41,7 +61,11 @@ if (1 || 0) { // if( true || false ) のように動作します } ``` +<<<<<<< HEAD ほとんどの場合、OR `||` は `if` 文の中で、与えられた条件のいずれかが正しいかを確認するのに使われます。 +======= +Most of the time, OR `||` is used in an `if` statement to test if *any* of the given conditions is `true`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: @@ -66,9 +90,15 @@ if (hour < 10 || hour > 18 || isWeekend) { } ``` +<<<<<<< HEAD ## OR は最初の真値を探します 上で描かれたロジックはいくらか古典的です。ここで JavaScriptの特別な機能を持ってきましょう。 +======= +## OR "||" finds the first truthy value + +The logic described above is somewhat classical. Now, let's bring in the "extra" features of JavaScript. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 拡張されたアルゴリズムは次の通りに動作します。 @@ -78,19 +108,32 @@ if (hour < 10 || hour > 18 || isWeekend) { result = value1 || value2 || value3; ``` +<<<<<<< HEAD OR `"||"` 演算子は次のように動きます: - 左から右にオペランドを評価します。 - それぞれのオペランドで、それを Boolean に変換します。もしも結果が `true` であれば、停止しオペランドの本来の値を返します。 - もしもすべての他のオペランドが評価された場合(i.e. すべて `偽` のとき), 最後のオペランドを返します。 +======= +The OR `||` operator does the following: + +- Evaluates operands from left to right. +- For each operand, converts it to boolean. If the result is `true`, stops and returns the original value of that operand. +- If all operands have been evaluated (i.e. all were `false`), returns the last operand. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 値は変換されていない元の形式で返却されます。 +<<<<<<< HEAD つまり、OR `"||"` のチェーンは最初に真となる値を返し、そのような値がない場合には最後のオペランドが返却されます。 +======= +In other words, a chain of OR `"||"` returns the first truthy value or the last one if no truthy value is found. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: ```js run +<<<<<<< HEAD alert( 1 || 0 ); // 1 (1 は真) alert( true || 'no matter what' ); // (true は真) @@ -106,14 +149,33 @@ alert( undefined || null || 0 ); // 0 (すべて偽、なので最後の値が 変数がいくつかある状態を想像してください。そして、それらの変数は値を持つか `null/undefined` とします。そして、今、私たちは最初のデータ(`null/undefined` ではない値)を選ぶ必要があります。 このために OR `||` が利用できます: +======= +alert( 1 || 0 ); // 1 (1 is truthy) + +alert( null || 1 ); // 1 (1 is the first truthy value) +alert( null || 0 || 1 ); // 1 (the first truthy value) + +alert( undefined || null || 0 ); // 0 (all falsy, returns the last value) +``` + +This leads to some interesting usage compared to a "pure, classical, boolean-only OR". + +1. **Getting the first truthy value from a list of variables or expressions.** + + For instance, we have `firstName`, `lastName` and `nickName` variables, all optional. + + Let's use OR `||` to choose the one that has the data and show it (or `anonymous` if nothing set): +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run - let currentUser = null; - let defaultUser = "John"; + let firstName = ""; + let lastName = ""; + let nickName = "SuperCoder"; *!* - let name = currentUser || defaultUser || "unnamed"; + alert( firstName || lastName || nickName || "Anonymous"); // SuperCoder */!* +<<<<<<< HEAD alert( name ); // "John" – 最初の真値です ``` @@ -127,30 +189,45 @@ alert( undefined || null || 0 ); // 0 (すべて偽、なので最後の値が これは、2番目の引数として与えられた式が変数への代入のような、副作用を持つ場合によく分かります。: 下の例を実行した場合、`x` は割り当てられません。: +======= + ``` - ```js run no-beautify - let x; + If all variables were falsy, `Anonymous` would show up. + +2. **Short-circuit evaluation.** +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 - *!*true*/!* || (x = 1); + Another feature of OR `||` operator is the so-called "short-circuit" evaluation. + It means that `||` processes its arguments until the first truthy value is reached, and then the value is returned immediately, without even touching the other argument. + +<<<<<<< HEAD alert(x); // undefined, なぜなら (x = 1) は評価されないからです ``` ...また、1つ目の引数が `false` の場合、 `OR` は次へ行き2つ目の評価を行い、代入をします: +======= + That 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. - ```js run no-beautify - let x; - - *!*false*/!* || (x = 1); + In the example below, only the second message is printed: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 - alert(x); // 1 + ```js run no-beautify + *!*true*/!* || alert("not printed"); + *!*false*/!* || alert("printed"); ``` +<<<<<<< HEAD 代入は単純なケースであり、他の副作用が発生する可能性があります。 ご覧のように、このようなユースケースは "`if` をするより短い方法" です。最初のオペランドは真偽値に変換され、もしもそれが偽の場合は2つ目が評価されます。 便利なときもありますが、たいていの場合は理解しやすいコードにするために、 `if` を使う方がよいでしょう。 +======= + In the first line, the OR `||` operator stops the evaluation immediately upon seeing `true`, so the `alert` isn't run. + + Sometimes, people use this feature to execute commands only if the condition on the left part is falsy. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## && (AND) @@ -160,7 +237,11 @@ AND 演算子は2つのアンパサンド `&&` で表されます: result = a && b; ``` +<<<<<<< HEAD 古典的なプログラミングでは、AND は両方のオペランドが真のときに `true` を返します。それ以外の場合は `false` です: +======= +In classical programming, AND returns `true` if both operands are truthy and `false` otherwise: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run alert( true && true ); // true @@ -176,11 +257,15 @@ let hour = 12; let minute = 30; if (hour == 12 && minute == 30) { - alert( 'Time is 12:30' ); + alert( 'The time is 12:30' ); } ``` +<<<<<<< HEAD OR のように、AND のオペランドとして任意の値が許可されています: +======= +Just as with OR, any value is allowed as an operand of AND: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run if (1 && 0) { // true && false として評価される @@ -189,7 +274,11 @@ if (1 && 0) { // true && false として評価される ``` +<<<<<<< HEAD ## AND は最初の偽値を探します +======= +## AND "&&" finds the first falsy value +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 複数のANDされた値が与えられました: @@ -197,11 +286,19 @@ if (1 && 0) { // true && false として評価される result = value1 && value2 && value3; ``` +<<<<<<< HEAD AND `"&&"` 演算子は次のように動きます: - 左から右にオペランドを評価します。 - それぞれのオペランドで、それを Boolean に変換します。もしも結果が `false` の場合、ストップしそのオペランドの本来の値を返します。 - もしもすべての他のオペランドが評価された場合(i.e. すべて `真` のとき), 最後のオペランドを返します。 +======= +The AND `&&` operator does the following: + +- Evaluates operands from left to right. +- For each operand, converts it to a boolean. If the result is `false`, stops and returns the original value of that operand. +- If all operands have been evaluated (i.e. all were truthy), returns the last operand. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 つまり、ANDは最初の偽値、またはない場合には最後の値を返します。 @@ -234,6 +331,7 @@ alert( 1 && 2 && null && 3 ); // null alert( 1 && 2 && 3 ); // 3, 最後のオペランド ``` +<<<<<<< HEAD ````smart header="AND `&&` は OR `||` の前に実行します" AND `&&` 演算子の優先順位は OR `||` よりも高いです。そのため、ORの前に実行されます。 @@ -245,6 +343,16 @@ alert( 5 || 1 && 0 ); // 5 ```` ORのように、AND `&&` 演算子は `if` に置き換えることができるときもあります。 +======= +````smart header="Precedence of AND `&&` is higher than OR `||`" +The precedence of AND `&&` operator is higher than OR `||`. + +So the code `a && b || c && d` is essentially the same as if the `&&` expressions were in parentheses: `(a && b) || (c && d)`. +```` + +````warn header="Don't replace `if` with || or &&" +Sometimes, people use the AND `&&` operator as a "shorter to write `if`". +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: @@ -254,25 +362,37 @@ let x = 1; (x > 0) && alert( 'Greater than zero!' ); ``` +<<<<<<< HEAD `&&` の右側のアクションは、その評価に到達した場合にのみ実行されます。つまり: `(x > 0)` が true の場合のみです。 +======= +The action in the right part of `&&` would execute only if the evaluation reaches it. That is, only if `(x > 0)` is true. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 なので、基本的に同じことをする別の方法があります: ```js run let x = 1; -if (x > 0) { - alert( 'Greater than zero!' ); -} +if (x > 0) alert( 'Greater than zero!' ); ``` +<<<<<<< HEAD `&&` を含むやり方は、より短いように見えます。しかし `if` はより明白で、読みやすい傾向にあります。 なので、すべての構成要素を目的に応じて使うことを推奨します。if が必要なら `if` を使います。AND が必要なら `&&` を使います。 +======= +Although, the variant with `&&` appears shorter, `if` is more obvious and tends to be a little bit more readable. So we recommend using every construct for its purpose: use `if` if we want if and use `&&` if we want AND. +```` + +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## ! (NOT) +<<<<<<< HEAD 真偽値否定演算子は感嘆符 `"!"` で表現されます。 +======= +The boolean NOT operator is represented with an exclamation sign `!`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 構文はとてもシンプルです: @@ -282,8 +402,13 @@ result = !value; 演算子は1つの引数を取り、次のようにします: +<<<<<<< HEAD 1. オペランドを真偽値型に変換します: `true/false`。 2. 逆の値を返します。 +======= +1. Converts the operand to boolean type: `true/false`. +2. Returns the inverse value. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: @@ -299,7 +424,11 @@ alert( !!"non-empty string" ); // true alert( !!null ); // false ``` +<<<<<<< HEAD つまり、最初の NOT は値を真偽値に変換しその逆を返します。そして、2つ目の NOT は再びその逆をします。最終的に、明示的な値からブール値への変換を行います。 +======= +That is, the first NOT converts the value to boolean and returns the inverse, and the second NOT inverses it again. In the end, we have a plain value-to-boolean conversion. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 少し冗長ですが同じことをする方法があります -- 組み込みの `Boolean` 関数です。: @@ -307,3 +436,5 @@ alert( !!null ); // false alert( Boolean("non-empty string") ); // true alert( Boolean(null) ); // false ``` + +The precedence of NOT `!` is the highest of all logical operators, so it always executes first, before `&&` or `||`. 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 new file mode 100644 index 0000000000..ee06d5cb7e --- /dev/null +++ b/1-js/02-first-steps/12-nullish-coalescing-operator/article.md @@ -0,0 +1,130 @@ +# Nullish coalescing operator '??' + +[recent browser="new"] + +The nullish coalescing operator `??` provides a short syntax for selecting a first "defined" variable from the list. + +The result of `a ?? b` is: +- `a` if it's not `null` or `undefined`, +- `b`, otherwise. + +So, `x = a ?? b` is a short equivalent to: + +```js +x = (a !== null && a !== undefined) ? a : b; +``` + +Here's a longer example. + +Imagine, we have a user, and there are variables `firstName`, `lastName` or `nickName` for their first name, last name and the nick name. All of them may be undefined, if the user decided not to enter any value. + +We'd like to display the user name: one of these three variables, or show "Anonymous" if nothing is set. + +Let's use the `??` operator to select the first defined one: + +```js run +let firstName = null; +let lastName = null; +let nickName = "Supercoder"; + +// show the first not-null/undefined value +*!* +alert(firstName ?? lastName ?? nickName ?? "Anonymous"); // Supercoder +*/!* +``` + +## Comparison with || + +The OR `||` operator can be used in the same way as `??`. Actually, we can replace `??` with `||` in the code above and get the same result, as it was described in the [previous chapter](info:logical-operators#or-finds-the-first-truthy-value). + +The important difference is that: +- `||` returns the first *truthy* value. +- `??` returns the first *defined* value. + +This matters a lot when we'd like to treat `null/undefined` differently from `0`. + +For example, consider this: + +```js +height = height ?? 100; +``` + +This sets `height` to `100` if it's not defined. + +Let's compare it with `||`: + +```js run +let height = 0; + +alert(height || 100); // 100 +alert(height ?? 100); // 0 +``` + +Here, `height || 100` treats zero height as unset, same as `null`, `undefined` or any other falsy value. So zero becames `100`. + +The `height ?? 100` returns `100` only if `height` is exactly `null` or `undefined`. So zero remains "as is". + +Which behavior is better depends on a particular use case. When zero height is a valid value, that we shouldn't touch, then `??` is preferrable. + +## Precedence + +The precedence of the `??` operator is rather low: `7` in the [MDN table](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table). + +So `??` is evaluated after most other operations, but before `=` and `?`. + +If we need to choose a value with `??` in a complex expression, then consider adding parentheses: + +```js run +let height = null; +let width = null; + +// important: use parentheses +let area = (height ?? 100) * (width ?? 50); + +alert(area); // 5000 +``` + +Otherwise, if we omit parentheses, `*` has the higher precedence than `??` and would run first. + +That would work be the same as: + +```js +// probably not correct +let area = height ?? (100 * width) ?? 50; +``` + +There's also a related language-level limitation. + +**Due to safety reasons, it's forbidden to use `??` together with `&&` and `||` operators.** + +The code below triggers a syntax error: + +```js run +let x = 1 && 2 ?? 3; // Syntax error +``` + +The limitation is surely debatable, but it was added to the language specification with the purpose to avoid programming mistakes, as people start to switch to `??` from `||`. + +Use explicit parentheses to work around it: + +```js run +*!* +let x = (1 && 2) ?? 3; // Works +*/!* + +alert(x); // 2 +``` + +## Summary + +- The nullish coalescing operator `??` provides a short way to choose a "defined" value from the list. + + It's used to assign default values to variables: + + ```js + // set height=100, if height is null or undefined + height = height ?? 100; + ``` + +- The operator `??` has a very low precedence, a bit higher than `?` and `=`. +- It's forbidden to use it with `||` or `&&` without explicit parentheses. diff --git a/1-js/02-first-steps/12-while-for/1-loop-last-value/solution.md b/1-js/02-first-steps/13-while-for/1-loop-last-value/solution.md similarity index 100% rename from 1-js/02-first-steps/12-while-for/1-loop-last-value/solution.md rename to 1-js/02-first-steps/13-while-for/1-loop-last-value/solution.md diff --git a/1-js/02-first-steps/12-while-for/1-loop-last-value/task.md b/1-js/02-first-steps/13-while-for/1-loop-last-value/task.md similarity index 100% rename from 1-js/02-first-steps/12-while-for/1-loop-last-value/task.md rename to 1-js/02-first-steps/13-while-for/1-loop-last-value/task.md diff --git a/1-js/02-first-steps/13-while-for/2-which-value-while/solution.md b/1-js/02-first-steps/13-while-for/2-which-value-while/solution.md new file mode 100644 index 0000000000..4953598769 --- /dev/null +++ b/1-js/02-first-steps/13-while-for/2-which-value-while/solution.md @@ -0,0 +1,30 @@ +The task demonstrates how postfix/prefix forms can lead to different results when used in comparisons. + +1. **From 1 to 4** + + ```js run + let i = 0; + while (++i < 5) alert( i ); + ``` + + The first value is `i = 1`, because `++i` first increments `i` and then returns the new value. So the first comparison is `1 < 5` and the `alert` shows `1`. + + Then follow `2, 3, 4…` -- the values show up one after another. The comparison always uses the incremented value, because `++` is before the variable. + + Finally, `i = 4` is incremented to `5`, the comparison `while(5 < 5)` fails, and the loop stops. So `5` is not shown. +2. **From 1 to 5** + + ```js run + let i = 0; + while (i++ < 5) alert( i ); + ``` + + The first value is again `i = 1`. The postfix form of `i++` increments `i` and then returns the *old* value, so the comparison `i++ < 5` will use `i = 0` (contrary to `++i < 5`). + + But the `alert` call is separate. It's another statement which executes after the increment and the comparison. So it gets the current `i = 1`. + + Then follow `2, 3, 4…` + + Let's stop on `i = 4`. The prefix form `++i` would increment it and use `5` in the comparison. But here we have the postfix form `i++`. So it increments `i` to `5`, but returns the old value. Hence the comparison is actually `while(4 < 5)` -- true, and the control goes on to `alert`. + + The value `i = 5` is the last one, because on the next step `while(5 < 5)` is false. diff --git a/1-js/02-first-steps/12-while-for/2-which-value-while/task.md b/1-js/02-first-steps/13-while-for/2-which-value-while/task.md similarity index 57% rename from 1-js/02-first-steps/12-while-for/2-which-value-while/task.md rename to 1-js/02-first-steps/13-while-for/2-which-value-while/task.md index 4acb7805c4..3bb47a68b5 100644 --- a/1-js/02-first-steps/12-while-for/2-which-value-while/task.md +++ b/1-js/02-first-steps/13-while-for/2-which-value-while/task.md @@ -2,11 +2,19 @@ importance: 4 --- +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/2-which-value-while/task.md # while でどの値が表示される? 各ループで、どの値が表示されるか、あなたの意見を書きなさい。また、それと答えを見比べてみてください。 両方のループは同じ数だけ `alert` されますか?それとも違いますか? +======= +# Which values does the while loop show? + +For every loop iteration, write down which value it outputs and then compare it with the solution. + +Both loops `alert` the same values, or not? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/2-which-value-while/task.md 1. プレフィックス形式 `++i`: diff --git a/1-js/02-first-steps/12-while-for/3-which-value-for/solution.md b/1-js/02-first-steps/13-while-for/3-which-value-for/solution.md similarity index 100% rename from 1-js/02-first-steps/12-while-for/3-which-value-for/solution.md rename to 1-js/02-first-steps/13-while-for/3-which-value-for/solution.md diff --git a/1-js/02-first-steps/12-while-for/3-which-value-for/task.md b/1-js/02-first-steps/13-while-for/3-which-value-for/task.md similarity index 100% rename from 1-js/02-first-steps/12-while-for/3-which-value-for/task.md rename to 1-js/02-first-steps/13-while-for/3-which-value-for/task.md diff --git a/1-js/02-first-steps/12-while-for/4-for-even/solution.md b/1-js/02-first-steps/13-while-for/4-for-even/solution.md similarity index 100% rename from 1-js/02-first-steps/12-while-for/4-for-even/solution.md rename to 1-js/02-first-steps/13-while-for/4-for-even/solution.md diff --git a/1-js/02-first-steps/12-while-for/4-for-even/task.md b/1-js/02-first-steps/13-while-for/4-for-even/task.md similarity index 100% rename from 1-js/02-first-steps/12-while-for/4-for-even/task.md rename to 1-js/02-first-steps/13-while-for/4-for-even/task.md diff --git a/1-js/02-first-steps/12-while-for/5-replace-for-while/solution.md b/1-js/02-first-steps/13-while-for/5-replace-for-while/solution.md similarity index 100% rename from 1-js/02-first-steps/12-while-for/5-replace-for-while/solution.md rename to 1-js/02-first-steps/13-while-for/5-replace-for-while/solution.md diff --git a/1-js/02-first-steps/12-while-for/5-replace-for-while/task.md b/1-js/02-first-steps/13-while-for/5-replace-for-while/task.md similarity index 100% rename from 1-js/02-first-steps/12-while-for/5-replace-for-while/task.md rename to 1-js/02-first-steps/13-while-for/5-replace-for-while/task.md diff --git a/1-js/02-first-steps/12-while-for/6-repeat-until-correct/solution.md b/1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md similarity index 63% rename from 1-js/02-first-steps/12-while-for/6-repeat-until-correct/solution.md rename to 1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md index a3b82c3051..c0b9208e0e 100644 --- a/1-js/02-first-steps/12-while-for/6-repeat-until-correct/solution.md +++ b/1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md @@ -9,7 +9,12 @@ do { ループ `do..while` は両方のチェックが真になるまで繰り返します。: +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/6-repeat-until-correct/solution.md 1. `num <= 100` のチェック -- つまり、入力値がまだ `100` よりも大きくない。 2. `&& num` チェックは、`num` が `null` または空文字の場合に false です。そのとき、`while` ループも停止します。 +======= +1. The check for `num <= 100` -- that is, the entered value is still not greater than `100`. +2. The check `&& num` is false when `num` is `null` or a empty string. Then the `while` loop stops too. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/6-repeat-until-correct/solution.md P.S. `num`が `null` の場合、`num <= 100` は `true` なので、2回目のチェックがなければ、ユーザーがCANCELをクリックするとループは止まらなくなります。 両方のチェックが必要です。 diff --git a/1-js/02-first-steps/12-while-for/6-repeat-until-correct/task.md b/1-js/02-first-steps/13-while-for/6-repeat-until-correct/task.md similarity index 63% rename from 1-js/02-first-steps/12-while-for/6-repeat-until-correct/task.md rename to 1-js/02-first-steps/13-while-for/6-repeat-until-correct/task.md index bf8a443602..9d91e8180b 100644 --- a/1-js/02-first-steps/12-while-for/6-repeat-until-correct/task.md +++ b/1-js/02-first-steps/13-while-for/6-repeat-until-correct/task.md @@ -4,7 +4,11 @@ importance: 5 # 入力が正しいまで繰り返す +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/6-repeat-until-correct/task.md `100` より大きい数値を入力するプロンプトを書いてください。もし訪問者が別の数値を入力したら -- 再び入力を訪ねます。 +======= +Write a loop which prompts for a number greater than `100`. If the visitor enters another number -- ask them to input again. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/6-repeat-until-correct/task.md ループは、訪問者が `100` より大きい値を入力するか、入力をキャンセル/空行の入力をするまで訪ねます。 diff --git a/1-js/02-first-steps/12-while-for/7-list-primes/solution.md b/1-js/02-first-steps/13-while-for/7-list-primes/solution.md similarity index 63% rename from 1-js/02-first-steps/12-while-for/7-list-primes/solution.md rename to 1-js/02-first-steps/13-while-for/7-list-primes/solution.md index 985de98382..c4e6b83a59 100644 --- a/1-js/02-first-steps/12-while-for/7-list-primes/solution.md +++ b/1-js/02-first-steps/13-while-for/7-list-primes/solution.md @@ -26,4 +26,8 @@ for (let i = 2; i <= n; i++) { // for each i... } ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/7-list-primes/solution.md ここには最適化の余地が沢山あります。例えば、`2` から `i` の平方根までの約数を探すことができます。しかし、とにかく、私たちが大きな間隔に対して効率的になりたいなら、アプローチを変更し、高度な数学と[Quadratic sieve](https://en.wikipedia.org/wiki/Quadratic_sieve), [General number field sieve](https://en.wikipedia.org/wiki/General_number_field_sieve)などの複雑なアルゴリズムに頼る必要があります。 +======= +There's a lot of space to optimize it. For instance, we could look for the divisors from `2` to square root of `i`. But anyway, if we want to be really efficient for large intervals, we need to change the approach and rely on advanced maths and complex algorithms like [Quadratic sieve](https://en.wikipedia.org/wiki/Quadratic_sieve), [General number field sieve](https://en.wikipedia.org/wiki/General_number_field_sieve) etc. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/7-list-primes/solution.md diff --git a/1-js/02-first-steps/12-while-for/7-list-primes/task.md b/1-js/02-first-steps/13-while-for/7-list-primes/task.md similarity index 100% rename from 1-js/02-first-steps/12-while-for/7-list-primes/task.md rename to 1-js/02-first-steps/13-while-for/7-list-primes/task.md diff --git a/1-js/02-first-steps/12-while-for/article.md b/1-js/02-first-steps/13-while-for/article.md similarity index 55% rename from 1-js/02-first-steps/12-while-for/article.md rename to 1-js/02-first-steps/13-while-for/article.md index 9d5b6e2081..b032bd5fd9 100644 --- a/1-js/02-first-steps/12-while-for/article.md +++ b/1-js/02-first-steps/13-while-for/article.md @@ -1,5 +1,6 @@ # ループ: while と for +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md 私たちはしばしば連続して何度も似たような処理を実行する必要があります。 例えば、1つずつリストから商品を出力する必要がある場合、または単に1から10の数値それぞれに同じコードを実行する場合などです。 @@ -7,6 +8,13 @@ *ループ* は複数回コードの同じ部分を繰り返す方法です。 [cut] +======= +We often need to repeat actions. + +For example, outputting goods from a list one after another or just running the same code for each number from 1 to 10. + +*Loops* are a way to repeat the same code multiple times. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md ## "while" ループ @@ -19,7 +27,11 @@ while (condition) { } ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md `condition` が `true` の間、ループの本体の `code` が実行されます。 +======= +While the `condition` is truthy, the `code` from the loop body is executed. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md 例えば、下のループは `i < 3` の間、`i` を出力します: @@ -33,11 +45,19 @@ while (i < 3) { // 0, 次に 1, 次に 2 を表示 ループ本体の1回の実行は *イテレーション* と呼ばれます。上の例のループは3回イテレーションします。 +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md もしも、上の例に `i++` がない場合、ループは (理論上は) 永遠に繰り返されます。実際には、ブラウザはこのようなループを止める方法を提供しており、サーバサイドJavaScriptではそのプロセスを殺すことができます。 任意の式または変数は、単に比較ではなくループ条件になります。それらは評価され `while` によって真偽値に変換されます。 たとえば、`while (i != 0)` をより短く書く方法として`while (i)`があります: +======= +If `i++` was missing from the example above, the loop would repeat (in theory) forever. In practice, the browser provides ways to stop such loops, and in server-side JavaScript, we can kill the process. + +Any expression or variable can be a loop condition, not just comparisons: the condition is evaluated and converted to a boolean by `while`. + +For instance, a shorter way to write `while (i != 0)` is `while (i)`: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md ```js run let i = 3; @@ -49,8 +69,13 @@ while (i) { // i が 0 になったとき、条件が偽になり、ループが } ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md ````smart header="本体が1行の場合、括弧は必須ではありません" ループの本体が1つの文である場合、括弧`{…}`を省略することができます: +======= +````smart header="Curly braces are not required for a single-line body" +If the loop body has a single statement, we can omit the curly braces `{…}`: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md ```js run let i = 3; @@ -70,7 +95,11 @@ do { } while (condition); ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md ループは最初に本体を実行します、次に条件をチェックし、真となる間実行を繰り返します。 +======= +The loop will first execute the body, then check the condition, and, while it's truthy, execute it again and again. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md 例: @@ -82,11 +111,19 @@ do { } while (i < 3); ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md この構文の形式は、条件が真になるかどうかに関わらず、**少なくとも1度** はループ本体を実行したい場合を除き、ほとんど使われません。通常は他の形式が好まれます: `while(…) {…}` +======= +This form of syntax should only be used when you want the body of the loop to execute **at least once** regardless of the condition being truthy. Usually, the other form is preferred: `while(…) {…}`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md ## "for" ループ +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md `for` ループは最も使われるものの1つです。 +======= +The `for` loop is more complex, but it's also the most commonly used loop. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md このようになります: @@ -104,16 +141,30 @@ for (let i = 0; i < 3; i++) { // 0, 次に 1, 次に 2 を表示 } ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md `for` 文を部分的に調べてみましょう: +======= +Let's examine the `for` statement part-by-part: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md | パート | | | |-------|----------|----------------------------------------------------------------------------| +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md | begin | `i = 0` | ループに入ると1度実行されます。 | | condition | `i < 3`| すべてのループのイテレーションの前にチェックされます、もしも false の場合ループを停止します。 | | step| `i++` | 各イテレーションで、条件チェックの前に本体の後に実行されます。 | | body | `alert(i)`| 条件が真の間繰り返し実行されます。 | 一般的なループアルゴリズムは次のように動作します: +======= +| begin | `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. | + +The general loop algorithm works like this: + +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md ``` begin を実行 → (if condition → body を実行し step を実行) @@ -122,9 +173,17 @@ begin を実行 → ... ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md もし初めてループを使う場合は、上の例に戻って、紙の上でステップ毎にどのように動作するかを再現してみると理解しやすいでしょう。 これが今のケースで正確に起こっていることです: +======= +That is, `begin` executes once, and then it iterates: after each `condition` test, `body` and `step` are executed. + +If you are new to loops, it could help to go back to the example and reproduce how it runs step-by-step on a piece of paper. + +Here's exactly what happens in our case: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md ```js // for (let i = 0; i < 3; i++) alert(i) @@ -140,9 +199,14 @@ if (i < 3) { alert(i); i++ } // ...終わり, 今 i == 3 なので ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md ````smart header="インライン変数宣言" ここで "カウンタ" 変数 `i` はループの中で正しく宣言されます。それは "インライン" 変数宣言と呼ばれます。 このような変数はループの中でだけ見えます。 +======= +````smart header="Inline variable declaration" +Here, the "counter" variable `i` is declared right in the loop. This is called an "inline" variable declaration. Such variables are visible only inside the loop. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md ```js run for (*!*let*/!* i = 0; i < 3; i++) { @@ -151,7 +215,11 @@ for (*!*let*/!* i = 0; i < 3; i++) { alert(i); // エラー, そのような変数はありません ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md 変数を宣言する代わりに、存在するもの使うことも出来ます: +======= +Instead of defining a variable, we could use an existing one: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md ```js run let i = 0; @@ -191,9 +259,15 @@ for (; i < 3;) { } ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md ループは `while (i < 3)` と同じになりました。 実際にはすべてを除くこともできます。それは無限ループになります: +======= +This makes the loop identical to `while (i < 3)`. + +We can actually remove everything, creating an infinite loop: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md ```js for (;;) { @@ -201,17 +275,29 @@ for (;;) { } ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md `for` の2つのセミコロン `;` は必須であることに注意してください。ない場合は構文エラーになります。 +======= +Please note that the two `for` semicolons `;` must be present. Otherwise, there would be a syntax error. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md ## ループの終わり +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md 通常、ループは条件が偽になると終了します。 しかし、いつでもループから出ることを強制することができます。そのための特別な `break` ディレクティブがあります。 例えば、以下のループはユーザに一連の数字を入力するよう求めますが、文字以外が入力されたとき "中断" します。: +======= +Normally, a loop exits when its condition becomes falsy. -```js +But we can force the exit at any time using the special `break` directive. + +For example, the loop below asks the user for a series of numbers, "breaking" when no number is entered: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md + +```js run let sum = 0; while (true) { @@ -228,16 +314,28 @@ while (true) { alert( 'Sum: ' + sum ); ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md もしもユーザが空を入力、もしくは入力をキャンセルした場合、`break` ディレクティブは行 `(*)` で有効になります。 それはループをすぐに停止し、ループ後の最初の行へ制御を渡します。つまり、`alert` です。 "必要に応じた無限ループ + `break`" の組み合わせは、ループの最初/最後ではなく、その間や本体の様々な場所で条件をチェックする必要がある状況で最適です。 +======= +The `break` directive is activated at the line `(*)` if the user enters an empty line or cancels the input. It stops the loop immediately, passing control to the first line after the loop. Namely, `alert`. + +The combination "infinite loop + `break` as needed" is great for situations when a loop's condition must be checked not in the beginning or end of the loop, but in the middle or even in several places of its body. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md ## 次のイテレーションに進む +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md `continue` ディレクティブは `break` の "軽量版" です。ループ全体はストップしません。その代わりに、現在のイテレーションを停止し、新しいイテレーションのスタートを強制します(もしも条件が真であれば)。 現在のイテレーションが完了し、次へ移動したいときに使います。 +======= +The `continue` directive is a "lighter version" of `break`. It doesn't stop the whole loop. Instead, it stops the current iteration and forces the loop to start a new one (if the condition allows). + +We can use it if we're done with the current iteration and would like to move on to the next one. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md 以下のループは奇数値だけを出力するために `continue` を使用しています: @@ -251,13 +349,20 @@ for (let i = 0; i < 10; i++) { } ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md `i` の値が偶数の場合、`continue` ディレクティブは本体の実行を停止し、`for` の次のイテレーションへ制御を渡します(次の番号で)。 したがって、`alert` は奇数値に対してのみ実行されます。 ````smart header="ディレクティブ `continue` を使うと入れ子のレベルを減らせます" 奇数値を表示するループはこのように書くこともできます: +======= +For even values of `i`, the `continue` directive stops executing the body and passes control to the next iteration of `for` (with the next number). So the `alert` is only called for odd values. -```js +````smart header="The `continue` directive helps decrease nesting" +A loop that shows odd values could look like this: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md + +```js run for (let i = 0; i < 10; i++) { if (i % 2) { @@ -267,6 +372,7 @@ for (let i = 0; i < 10; i++) { } ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md 技術的な観点からは、これは上の例と同じです。確かに、`continue` の代わりに `if` ブロックでコードをラップするだけです。 しかし、副作用として括弧のネストが1段深くなります。もしも `if` の中のコードが長い場合、全体の可読性が下がる可能性があります。 @@ -274,6 +380,15 @@ for (let i = 0; i < 10; i++) { ````warn header="`?` の右側には `break/continue` を入れないでください" 式ではない構文構造は、 `'?'` の中では使うことはできないことに注意してください。特に、ディレクティブ `break/continue` はそこでは許可されません。 +======= +From a technical point of view, this is identical to the example above. Surely, we can just wrap the code in an `if` block instead of using `continue`. + +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. +```` + +````warn header="No `break/continue` to the right side of '?'" +Please note that syntax constructs that are not expressions cannot be used with the ternary operator `?`. In particular, directives such as `break/continue` aren't allowed there. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md 例えば、このコードを考えます @@ -285,6 +400,7 @@ if (i > 5) { } ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md ...これを、疑問符を使って書き直します: ```js no-beautify @@ -295,13 +411,29 @@ if (i > 5) { これは `if` の代わりに疑問符演算子 `'?'` を使用しない別の理由です。 +======= +...and rewrite it using a question mark: + + +```js no-beautify +(i > 5) ? alert(i) : *!*continue*/!*; // continue isn't allowed here +``` + +...it stops working: there's a syntax error. + +This is just another reason not to use the question mark operator `?` instead of `if`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md ```` ## break/continue のためのラベル 時々、複数のネストしたループから一度で抜け出す必要があることがあります。 +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md 例えば、下のコードでは 座標 `(i, j)` を `(0,0)` から `(3,3)` へプロンプトするよう `i` と `j` をループします: +======= +For example, in the code below we loop over `i` and `j`, prompting for the coordinates `(i, j)` from `(0,0)` to `(2,2)`: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md ```js run no-beautify for (let i = 0; i < 3; i++) { @@ -310,8 +442,12 @@ for (let i = 0; i < 3; i++) { let input = prompt(`Value at coords (${i},${j})`, ''); +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md // 仮にここで終了して下にある Done をしたい場合にはどうすればよいでしょう? +======= + // what if we want to exit from here to Done (below)? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md } } @@ -320,8 +456,12 @@ alert('Done!'); ユーザが入力をキャンセルした場合、処理をストップする方法が必要です。 +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md `input` の後の通常の `break` は内部ループのみの終了です。それだけでは十分ではありません。 ここでラベルが助けにきます。 +======= +The ordinary `break` after `input` would only break the inner loop. That's not sufficient--labels, come to the rescue! +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md *ラベル* は、ループの前のコロンがついた識別子です: ```js @@ -330,9 +470,13 @@ labelName: for (...) { } ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md ループの中の `break ` 文はラベルまで終了にします。 次のようになります: +======= +The `break ` statement in the loop below breaks out to the label: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md ```js run no-beautify *!*outer:*/!* for (let i = 0; i < 3; i++) { @@ -350,7 +494,11 @@ labelName: for (...) { alert('Done!'); ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md 上のコードで、`break outer` は `outer` と名付けされたラベルを上に探し、そのループを抜けます。 +======= +In the code above, `break outer` looks upwards for the label named `outer` and breaks out of that loop. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md そのため、制御は `(*)` から `alert('Done!')` にまっすぐに進みます。 @@ -361,19 +509,34 @@ outer: for (let i = 0; i < 3; i++) { ... } ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md `continue` ディレクティブもラベルと一緒に使うことができます。このケースでは、実行はラベル付けされたループの次のイテレーションにジャンプします。 ````warn header="ラベルは \"goto\" ではありません" ラベルはコードの任意の場所にジャンプすることはできません。 +======= +The `continue` directive can also be used with a label. In this case, code execution jumps to the next iteration of the labeled loop. + +````warn header="Labels do not allow to \"jump\" anywhere" +Labels do not allow us to jump into an arbitrary place in the code. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md 例えば、このようにすることは出来ません: ```js +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md break label; // label にジャンプ? いいえ。 +======= +break label; // doesn't jumps to the label below +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md label: for (...) ``` +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md `break/continue` の呼び出しはループの中からだけ可能です。またラベルはそのディレクティブから上のどこかにある必要があります。 +======= +A call to `break/continue` is only possible from inside a loop and the label must be somewhere above the directive. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md ```` ## サマリ @@ -386,6 +549,12 @@ label: for (...) "無限" ループを作るために、通常は `while(true)` 構造が使われます。このようなループは他の他のループと同様に `break` ディレクティブで停止することができます。 +<<<<<<< HEAD:1-js/02-first-steps/12-while-for/article.md もしも現在のイテレーションで何もしたくなく、次のイテレーションに進みたい場合は、`continue` ディレクティブを使います。 `break/continue` はループの前のラベルをサポートします。ラベルは、ネストを抜けて外のループに行くための、 `break/continue` のための方法です。 +======= +If we don't want to do anything in the current iteration and would like to forward to the next one, we can use the `continue` directive. + +`break/continue` support labels before the loop. A label is the only way for `break/continue` to escape a nested loop to go to an outer one. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/13-while-for/article.md diff --git a/1-js/02-first-steps/14-function-basics/function_basics.png b/1-js/02-first-steps/14-function-basics/function_basics.png deleted file mode 100644 index 7eb6e11e54..0000000000 Binary files a/1-js/02-first-steps/14-function-basics/function_basics.png and /dev/null differ diff --git a/1-js/02-first-steps/14-function-basics/function_basics@2x.png b/1-js/02-first-steps/14-function-basics/function_basics@2x.png deleted file mode 100644 index e629bd712c..0000000000 Binary files a/1-js/02-first-steps/14-function-basics/function_basics@2x.png and /dev/null differ diff --git a/1-js/02-first-steps/13-switch/1-rewrite-switch-if-else/solution.md b/1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/solution.md similarity index 100% rename from 1-js/02-first-steps/13-switch/1-rewrite-switch-if-else/solution.md rename to 1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/solution.md diff --git a/1-js/02-first-steps/13-switch/1-rewrite-switch-if-else/task.md b/1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/task.md similarity index 100% rename from 1-js/02-first-steps/13-switch/1-rewrite-switch-if-else/task.md rename to 1-js/02-first-steps/14-switch/1-rewrite-switch-if-else/task.md diff --git a/1-js/02-first-steps/13-switch/2-rewrite-if-switch/solution.md b/1-js/02-first-steps/14-switch/2-rewrite-if-switch/solution.md similarity index 100% rename from 1-js/02-first-steps/13-switch/2-rewrite-if-switch/solution.md rename to 1-js/02-first-steps/14-switch/2-rewrite-if-switch/solution.md diff --git a/1-js/02-first-steps/13-switch/2-rewrite-if-switch/task.md b/1-js/02-first-steps/14-switch/2-rewrite-if-switch/task.md similarity index 100% rename from 1-js/02-first-steps/13-switch/2-rewrite-if-switch/task.md rename to 1-js/02-first-steps/14-switch/2-rewrite-if-switch/task.md diff --git a/1-js/02-first-steps/13-switch/article.md b/1-js/02-first-steps/14-switch/article.md similarity index 90% rename from 1-js/02-first-steps/13-switch/article.md rename to 1-js/02-first-steps/14-switch/article.md index 6c942a37ca..e249518692 100644 --- a/1-js/02-first-steps/13-switch/article.md +++ b/1-js/02-first-steps/14-switch/article.md @@ -4,9 +4,13 @@ これは値を複数のパターンと比較するための、よりわかりやすい方法を提供します。 +<<<<<<< HEAD:1-js/02-first-steps/13-switch/article.md [cut] ## 構文 +======= +## The syntax +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/14-switch/article.md `switch` は1つ以上の `case` ブロックを持ち、 オプションで default を持ちます。 @@ -120,7 +124,7 @@ switch (+a) { たとえば、`case 3` と `case 5` で同じコードを実行したい場合: ```js run no-beautify -let a = 2 + 2; +let a = 3; switch (a) { case 4: @@ -128,7 +132,11 @@ switch (a) { break; *!* +<<<<<<< HEAD:1-js/02-first-steps/13-switch/article.md case 3: // (*) 2つのケースをグループ化 +======= + case 3: // (*) grouped two cases +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/14-switch/article.md case 5: alert('Wrong!'); alert("Why don't you take a math class?"); @@ -152,7 +160,7 @@ switch (a) { たとえば、このコードを考えてみましょう: ```js run -let arg = prompt("Enter a value?") +let arg = prompt("Enter a value?"); switch (arg) { case '0': case '1': @@ -167,7 +175,7 @@ switch (arg) { alert( 'Never executes!' ); break; default: - alert( 'An unknown value' ) + alert( 'An unknown value' ); } ``` diff --git a/1-js/02-first-steps/14-function-basics/1-if-else-required/solution.md b/1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md similarity index 100% rename from 1-js/02-first-steps/14-function-basics/1-if-else-required/solution.md rename to 1-js/02-first-steps/15-function-basics/1-if-else-required/solution.md diff --git a/1-js/02-first-steps/14-function-basics/1-if-else-required/task.md b/1-js/02-first-steps/15-function-basics/1-if-else-required/task.md similarity index 100% rename from 1-js/02-first-steps/14-function-basics/1-if-else-required/task.md rename to 1-js/02-first-steps/15-function-basics/1-if-else-required/task.md diff --git a/1-js/02-first-steps/14-function-basics/2-rewrite-function-question-or/solution.md b/1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/solution.md similarity index 100% rename from 1-js/02-first-steps/14-function-basics/2-rewrite-function-question-or/solution.md rename to 1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/solution.md diff --git a/1-js/02-first-steps/14-function-basics/2-rewrite-function-question-or/task.md b/1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/task.md similarity index 63% rename from 1-js/02-first-steps/14-function-basics/2-rewrite-function-question-or/task.md rename to 1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/task.md index 156192196a..1012f095db 100644 --- a/1-js/02-first-steps/14-function-basics/2-rewrite-function-question-or/task.md +++ b/1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/task.md @@ -14,7 +14,7 @@ function checkAge(age) { if (age > 18) { return true; } else { - return confirm('Do you have your parents permission to access this page?'); + return confirm('Did parents allow you?'); } } ``` @@ -23,5 +23,10 @@ function checkAge(age) { `checkAge` の2つのバリアントを作ってください。: +<<<<<<< HEAD:1-js/02-first-steps/14-function-basics/2-rewrite-function-question-or/task.md 1. 疑問符演算子 `'?'` を使うケース 2. OR `||` を使うケース +======= +1. Using a question mark operator `?` +2. Using OR `||` +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/15-function-basics/2-rewrite-function-question-or/task.md diff --git a/1-js/02-first-steps/14-function-basics/3-min/solution.md b/1-js/02-first-steps/15-function-basics/3-min/solution.md similarity index 100% rename from 1-js/02-first-steps/14-function-basics/3-min/solution.md rename to 1-js/02-first-steps/15-function-basics/3-min/solution.md diff --git a/1-js/02-first-steps/14-function-basics/3-min/task.md b/1-js/02-first-steps/15-function-basics/3-min/task.md similarity index 100% rename from 1-js/02-first-steps/14-function-basics/3-min/task.md rename to 1-js/02-first-steps/15-function-basics/3-min/task.md diff --git a/1-js/02-first-steps/14-function-basics/4-pow/solution.md b/1-js/02-first-steps/15-function-basics/4-pow/solution.md similarity index 70% rename from 1-js/02-first-steps/14-function-basics/4-pow/solution.md rename to 1-js/02-first-steps/15-function-basics/4-pow/solution.md index 79eb2b442e..19fe9011fc 100644 --- a/1-js/02-first-steps/14-function-basics/4-pow/solution.md +++ b/1-js/02-first-steps/15-function-basics/4-pow/solution.md @@ -13,11 +13,9 @@ function pow(x, n) { let x = prompt("x?", ''); let n = prompt("n?", ''); -if (n <= 1) { - alert(`Power ${n} is not supported, - use an integer greater than 0`); +if (n < 1) { + alert(`Power ${n} is not supported, use a positive integer`); } else { alert( pow(x, n) ); } ``` - diff --git a/1-js/02-first-steps/14-function-basics/4-pow/task.md b/1-js/02-first-steps/15-function-basics/4-pow/task.md similarity index 93% rename from 1-js/02-first-steps/14-function-basics/4-pow/task.md rename to 1-js/02-first-steps/15-function-basics/4-pow/task.md index 651733fa70..f5d83b861f 100644 --- a/1-js/02-first-steps/14-function-basics/4-pow/task.md +++ b/1-js/02-first-steps/15-function-basics/4-pow/task.md @@ -10,7 +10,7 @@ importance: 4 ```js pow(3, 2) = 3 * 3 = 9 pow(3, 3) = 3 * 3 * 3 = 27 -pow(1, 100) = 1 * 1 * ...*1 = 1 +pow(1, 100) = 1 * 1 * ...* 1 = 1 ``` `x` と `n` を聞くプロンプトをもつ web ページを作り、`pow(x,n)` の結果を表示しなさい。 diff --git a/1-js/02-first-steps/14-function-basics/article.md b/1-js/02-first-steps/15-function-basics/article.md similarity index 72% rename from 1-js/02-first-steps/14-function-basics/article.md rename to 1-js/02-first-steps/15-function-basics/article.md index 1838baba94..2c25ce352e 100644 --- a/1-js/02-first-steps/14-function-basics/article.md +++ b/1-js/02-first-steps/15-function-basics/article.md @@ -6,10 +6,14 @@ 関数はプログラムのメインの "構成要素" です。これによりコードを繰り返すことなく何度も呼び出すことができます。 +<<<<<<< HEAD:1-js/02-first-steps/14-function-basics/article.md [cut] 私たちは既に組み込み関数の例を見ています。 `alert(message)`, `prompt(message, default)` や `confirm(question)`です。 同じように私たち自身も関数を作ることができます。 +======= +We've already seen examples of built-in functions, like `alert(message)`, `prompt(message, default)` and `confirm(question)`. But we can create functions of our own as well. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/15-function-basics/article.md ## 関数定義 @@ -23,9 +27,17 @@ function showMessage() { } ``` +<<<<<<< HEAD:1-js/02-first-steps/14-function-basics/article.md `function` キーワードが最初にきて、次に *関数名* がきます、そして括弧の中に *パラメータ* のリストがきて(上の例では空白です)、最後に関数のコード、"関数本体" です。 +======= +The `function` keyword goes first, then goes the *name of the function*, then a list of *parameters* between the parentheses (comma-separated, empty in the example above) and finally the code of the function, also named "the function body", between curly braces. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/15-function-basics/article.md -![](function_basics.png) +```js +function name(parameters) { + ...body... +} +``` 作成した関数はその関数名で呼ぶことができます: `showMessage()` @@ -44,7 +56,11 @@ showMessage(); `showMessage()` の呼び出しは、関数のコードを実行します。この例では、2度メッセージが表示されます。 +<<<<<<< HEAD:1-js/02-first-steps/14-function-basics/article.md この例は関数のメインの目的の1つを明確に示しています: コードの複製を回避する、と言うことです。 +======= +This example clearly demonstrates one of the main purposes of functions: to avoid code duplication. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/15-function-basics/article.md もしメッセージ内容、または表示方法を変更する必要がある場合、1箇所のコード(関数)を修正するだけで十分です。 @@ -104,7 +120,11 @@ showMessage(); alert( userName ); // *!*Bob*/!*, 関数によって値が変更されました ``` +<<<<<<< HEAD:1-js/02-first-steps/14-function-basics/article.md 外部の変数は、ローカル変数が存在しない場合にのみ使われます。そのため、`let` を忘れた場合、意図せず外部の変数を変更してしまう可能性があります。 +======= +The outer variable is only used if there's no local one. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/15-function-basics/article.md 同じ名前の変数が関数内に宣言されている場合は、外部変数を *隠します*。例えば、以下のコードでは関数はローカルの `userName` を使います。外部の `userName` は無視されます。 @@ -120,7 +140,11 @@ function showMessage() { alert(message); } +<<<<<<< HEAD:1-js/02-first-steps/14-function-basics/article.md // 関数は作られ独自の userName を使います +======= +// the function will create and use its own userName +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/15-function-basics/article.md showMessage(); alert( userName ); // *!*John*/!*, 変更されていません。関数は外部変数へアクセスしませんでした @@ -131,7 +155,11 @@ alert( userName ); // *!*John*/!*, 変更されていません。関数は外部 グローバル変数はどの関数からも見えます(ローカル変数により隠れていなければ)。 +<<<<<<< HEAD:1-js/02-first-steps/14-function-basics/article.md 通常、関数は自身のタスクに必要なすべての変数を宣言します。また、グローバル変数にはプロジェクトレベルのデータのみを保持するため、どこからでも見える事が重要です。現代のコードはほとんどもしくは全くグローバル変数を持ちません。ほぼすべての変数はその関数の中にあります。 +======= +It's a good practice to minimize the use of global variables. Modern code has few or no globals. Most variables reside in their functions. Sometimes though, they can be useful to store project-level data. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/15-function-basics/article.md ``` ## パラメータ @@ -206,6 +234,7 @@ function showMessage(from, text = anotherFunction()) { } ``` +<<<<<<< HEAD:1-js/02-first-steps/14-function-basics/article.md ````smart header="デフォルト値の評価" JavaScriptでは、デフォルト値はそれぞれのパラメータが与えられずに関数が呼び出されるたびに評価されます。上の例だと `anotherFunction()` は、 `text` のパラメータが与えられずに `showMessage()` が呼び出されるたびに実行されます。これはPythonのような他の言語と対照的で、Pythonはどんなデフォルト値も初期解釈のときに一度だけ評価されます。 @@ -216,32 +245,65 @@ JavaScriptでは、デフォルト値はそれぞれのパラメータが与え javascriptの古いエディションは、デフォルトパラメータをサポートしていませんでした。そのため、別の方法で実現していました。これは古いスクリプトの中で見つけることができます。 例えば、`undefined` の明示的なチェック: +======= +```smart header="Evaluation of default parameters" +In JavaScript, a default parameter is evaluated every time the function is called without the respective parameter. -```js -function showMessage(from, text) { +In the example above, `anotherFunction()` is called every time `showMessage()` is called without the `text` parameter. +``` + +### Alternative default parameters +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/15-function-basics/article.md + +Sometimes it makes sense to set default values for parameters not in the function declaration, but at a later stage, during its execution. + +To check for an omitted parameter, we can compare it with `undefined`: + +```js run +function showMessage(text) { *!* if (text === undefined) { - text = 'no text given'; + text = 'empty message'; } */!* - alert( from + ": " + text ); + alert(text); } + +showMessage(); // empty message ``` +<<<<<<< HEAD:1-js/02-first-steps/14-function-basics/article.md ...もしくは `||` 演算子: ```js function showMessage(from, text) { // text が偽の場合、text は "デフォルト" 値を取得します text = text || 'no text given'; +======= +...Or we could use the `||` operator: + +```js +// if text parameter is omitted or "" is passed, set it to 'empty' +function showMessage(text) { + text = text || 'empty'; +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/15-function-basics/article.md ... } ``` +Modern JavaScript engines support the [nullish coalescing operator](info:nullish-coalescing-operator) `??`, it's better when falsy values, such as `0`, are considered regular: -```` +```js run +// if there's no "count" parameter, show "unknown" +function showCount(count) { + alert(count ?? "unknown"); +} +showCount(0); // 0 +showCount(null); // unknown +showCount(); // unknown +``` ## 値の返却 @@ -264,13 +326,13 @@ alert( result ); // 3 ```js run function checkAge(age) { - if (age > 18) { + if (age >= 18) { *!* return true; */!* } else { *!* - return confirm('Got a permission from the parents?'); + return confirm('Do you have permission from your parents?'); */!* } } @@ -336,12 +398,32 @@ JavaScriptは `return` の後にセミコロンを想定するため、これは return*!*;*/!* (some + long + expression + or + whatever * f(a) + f(b)) ``` +<<<<<<< HEAD:1-js/02-first-steps/14-function-basics/article.md 従って、これは事実上空の返却になります。なので、値は同じ行に置く必要があります。 +======= + +So, it effectively becomes an empty return. + +If we want the returned expression to wrap across multiple lines, we should start it at the same line as `return`. Or at least put the opening parentheses there as follows: + +```js +return ( + some + long + expression + + or + + whatever * f(a) + f(b) + ) +``` +And it will work just as we expect it to. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/15-function-basics/article.md ```` ## 関数の命名 +<<<<<<< HEAD:1-js/02-first-steps/14-function-basics/article.md 関数はアクションです。そのため、それらの名前は通常は動詞です。それは簡潔にすべきですが、関数がすることをできるだけ正確に表現してください。そして、コードを読む人が正しい手がかりを得られるようにします。 +======= +Functions are actions. So their name is usually a verb. It should be brief, as accurate as possible and describe what the function does, so that someone reading the code gets an indication of what the function does. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/15-function-basics/article.md 曖昧なアクションを示す動詞のプレフィックスから関数名を始めることは広く行われています。 プレフィックスの意味についてはチーム内での合意が必要です。 @@ -374,19 +456,33 @@ checkPermission(..) // 権限をチェックし、true/false を返します このルールを破るいくつかの例です: +<<<<<<< HEAD:1-js/02-first-steps/14-function-basics/article.md - `getAge` -- 年齢を取得するとともに `警告` を表示します(取得のみをするべきです) - `createForm` -- フォームを作成して、ドキュメントに追加します(作成とその返却だけにするべきです) - `checkPermission` -- `アクセス許可/拒否` のメッセージを表示するのは良くありません(チェックを実行し、その結果を返すのみにすべきです) これらの例はプレフィックスの共通の意味を前提としています。これらが意味することは、あなたとあなたのチームで前提を決めるということです。恐らく、コードが異なる振る舞いをするのは普通なことです。しかし、プレフィックスが意味すること、プレフィックスの付いた関数ができること、できないことについてはしっかりとした理解をもっておくべきです。同じプレフィックスの関数はルールに従うべきです。そして、チームはそれを共有するべきです。 +======= +- `getAge` -- would be bad if it shows an `alert` with the age (should only get). +- `createForm` -- would be bad if it modifies the document, adding a form to it (should only create it and return). +- `checkPermission` -- would be bad if it displays the `access granted/denied` message (should only perform the check and return the result). + +These examples assume common meanings of prefixes. You and your team are free to agree on other meanings, but usually they're not much different. In any case, you should have a firm understanding of what a prefix means, what a prefixed function can and cannot do. All same-prefixed functions should obey the rules. And the team should share the knowledge. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/15-function-basics/article.md ``` ```smart header="究極的に短い関数名" *非常に頻繁に* 使われる関数は、究極的に短い名前を持っていることがあります。 +<<<<<<< HEAD:1-js/02-first-steps/14-function-basics/article.md 例えば、[jQuery](http://jquery.com) フレームワークは関数 `$` を定義しています。[LoDash](http://lodash.com/) ライブラリは、そのコアな関数として `_` を持っています。 それらは例外です。一般的に関数名は簡潔ではあるが、説明的でなければなりません。 +======= +For example, the [jQuery](http://jquery.com) framework defines a function with `$`. The [Lodash](http://lodash.com/) library has its core function named `_`. + +These are exceptions. Generally functions names should be concise and descriptive. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/15-function-basics/article.md ``` ## 関数 == コメント @@ -432,7 +528,11 @@ function isPrime(n) { } ``` +<<<<<<< HEAD:1-js/02-first-steps/14-function-basics/article.md 2つ目のパターンのほうが理解しやすいですね。コードの塊の代わりに、アクション(`isPrime`) の名前を見ます。このようなコードは *自己記述的* と呼ばれる場合があります。 +======= +The second variant is easier to understand, isn't it? Instead of the code piece we see a name of the action (`isPrime`). Sometimes people refer to such code as *self-describing*. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/15-function-basics/article.md 従って、関数はその再利用を意図していない場合でも作ることがあります。それらはコードを構造化し、読みやすくします。 @@ -446,9 +546,15 @@ function name(parameters, delimited, by, comma) { } ``` +<<<<<<< HEAD:1-js/02-first-steps/14-function-basics/article.md - パラメータとして関数に渡される値は、ローカル変数にコピーされます。 - 関数は外部の変数にアクセスすることができます。しかし、それは内側からのみ機能します。関数の外側のコードは、関数のローカル変数を見ることはできません。 - 関数は値を返すことができます。もしもそれをしなかった場合、戻りは `undefined` です。 +======= +- Values passed to a function as parameters are copied to its local variables. +- A function may access outer variables. But it works only from inside out. The code outside of the function doesn't see its local variables. +- A function can return a value. If it doesn't, then its result is `undefined`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/02-first-steps/15-function-basics/article.md コードを綺麗で理解しやすいようにするために、その関数内では外部変数ではなく、ローカル変数やパラメータを利用することを推奨します。 diff --git a/1-js/02-first-steps/16-function-expressions/article.md b/1-js/02-first-steps/16-function-expressions/article.md new file mode 100644 index 0000000000..a8ccd6c6c8 --- /dev/null +++ b/1-js/02-first-steps/16-function-expressions/article.md @@ -0,0 +1,368 @@ +# Function expressions + +In JavaScript, a function is not a "magical language structure", but a special kind of value. + +The syntax that we used before is called a *Function Declaration*: + +```js +function sayHi() { + alert( "Hello" ); +} +``` + +There is another syntax for creating a function that is called a *Function Expression*. + +It looks like this: + +```js +let sayHi = function() { + alert( "Hello" ); +}; +``` + +Here, the function is created and assigned to the variable explicitly, like any other value. No matter how the function is defined, it's just a value stored in the variable `sayHi`. + +The meaning of these code samples is the same: "create a function and put it into the variable `sayHi`". + +We can even print out that value using `alert`: + +```js run +function sayHi() { + alert( "Hello" ); +} + +*!* +alert( sayHi ); // shows the function code +*/!* +``` + +Please note that the last line does not run the function, because there are no parentheses after `sayHi`. There are programming languages where any mention of a function name causes its execution, but JavaScript is not like that. + +In JavaScript, a function is a value, so we can deal with it as a value. The code above shows its string representation, which is the source code. + +Surely, a function is a special value, in the sense that we can call it like `sayHi()`. + +But it's still a value. So we can work with it like with other kinds of values. + +We can copy a function to another variable: + +```js run no-beautify +function sayHi() { // (1) create + alert( "Hello" ); +} + +let func = sayHi; // (2) copy + +func(); // Hello // (3) run the copy (it works)! +sayHi(); // Hello // this still works too (why wouldn't it) +``` + +Here's what happens above in detail: + +1. The Function Declaration `(1)` creates the function and puts it into the variable named `sayHi`. +2. Line `(2)` copies it into the variable `func`. Please note again: there are no parentheses after `sayHi`. If there were, then `func = sayHi()` would write *the result of the call* `sayHi()` into `func`, not *the function* `sayHi` itself. +3. Now the function can be called as both `sayHi()` and `func()`. + +Note that we could also have used a Function Expression to declare `sayHi`, in the first line: + +```js +let sayHi = function() { + alert( "Hello" ); +}; + +let func = sayHi; +// ... +``` + +Everything would work the same. + + +````smart header="Why is there a semicolon at the end?" +You might wonder, why does Function Expression have a semicolon `;` at the end, but Function Declaration does not: + +```js +function sayHi() { + // ... +} + +let sayHi = function() { + // ... +}*!*;*/!* +``` + +The answer is simple: +- There's no need for `;` at the end of code blocks and syntax structures that use them like `if { ... }`, `for { }`, `function f { }` etc. +- A Function Expression is used inside the statement: `let sayHi = ...;`, as a value. It's not a code block, but rather an assignment. The semicolon `;` is recommended at the end of statements, no matter what the value is. So the semicolon here is not related to the Function Expression itself, it just terminates the statement. +```` + +## Callback functions + +Let's look at more examples of passing functions as values and using function expressions. + +We'll write a function `ask(question, yes, no)` with three parameters: + +`question` +: Text of the question + +`yes` +: Function to run if the answer is "Yes" + +`no` +: Function to run if the answer is "No" + +The function should ask the `question` and, depending on the user's answer, call `yes()` or `no()`: + +```js run +*!* +function ask(question, yes, no) { + if (confirm(question)) yes() + else no(); +} +*/!* + +function showOk() { + alert( "You agreed." ); +} + +function showCancel() { + alert( "You canceled the execution." ); +} + +// usage: functions showOk, showCancel are passed as arguments to ask +ask("Do you agree?", showOk, showCancel); +``` + +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 function usually draws a nice-looking question window. But that's another story. + +**The arguments `showOk` and `showCancel` of `ask` are called *callback functions* or just *callbacks*.** + +The idea is that we pass a function and expect it to be "called back" later if necessary. In our case, `showOk` becomes the callback for "yes" answer, and `showCancel` for "no" answer. + +We can use Function Expressions to write the same function much shorter: + +```js run no-beautify +function ask(question, yes, no) { + if (confirm(question)) yes() + else no(); +} + +*!* +ask( + "Do you agree?", + function() { alert("You agreed."); }, + function() { alert("You canceled the execution."); } +); +*/!* +``` + +Here, functions are declared right inside the `ask(...)` call. They have no name, and so are called *anonymous*. Such functions are not accessible outside of `ask` (because they are not assigned to variables), but that's just what we want here. + +Such code appears in our scripts very naturally, it's in the spirit of JavaScript. + +```smart header="A function is a value representing an \"action\"" +Regular values like strings or numbers represent the *data*. + +A function can be perceived as an *action*. + +We can pass it between variables and run when we want. +``` + + +## Function Expression vs Function Declaration + +Let's formulate the key differences between Function Declarations and Expressions. + +First, the syntax: how to differentiate between them in the code. + +- *Function Declaration:* a function, declared as a separate statement, in the main code flow. + + ```js + // Function Declaration + function sum(a, b) { + return a + b; + } + ``` +- *Function Expression:* a function, created inside an expression or inside another syntax construct. Here, the function is created at the right side of the "assignment expression" `=`: + + ```js + // Function Expression + let sum = function(a, b) { + return a + b; + }; + ``` + +The more subtle difference is *when* a function is created by the JavaScript engine. + +**A Function Expression is created when the execution reaches it and is usable only from that moment.** + +Once the execution flow passes to the right side of the assignment `let sum = function…` -- here we go, the function is created and can be used (assigned, called, etc. ) from now on. + +Function Declarations are different. + +**A Function Declaration can be called earlier than it is defined.** + +For example, a global Function Declaration is visible in the whole script, no matter where it is. + +That's due to internal algorithms. When JavaScript prepares to run the script, it first looks for global Function Declarations in it and creates the functions. We can think of it as an "initialization stage". + +And after all Function Declarations are processed, the code is executed. So it has access to these functions. + +For example, this works: + +```js run refresh untrusted +*!* +sayHi("John"); // Hello, John +*/!* + +function sayHi(name) { + alert( `Hello, ${name}` ); +} +``` + +The Function Declaration `sayHi` is created when JavaScript is preparing to start the script and is visible everywhere in it. + +...If it were a Function Expression, then it wouldn't work: + +```js run refresh untrusted +*!* +sayHi("John"); // error! +*/!* + +let sayHi = function(name) { // (*) no magic any more + alert( `Hello, ${name}` ); +}; +``` + +Function Expressions are created when the execution reaches them. That would happen only in the line `(*)`. Too late. + +Another special feature of Function Declarations is their block scope. + +**In strict mode, when a Function Declaration is within a code block, it's visible everywhere inside that block. But not outside of it.** + +For instance, let's imagine that we need to declare a function `welcome()` depending on the `age` variable that we get during runtime. And then we plan to use it some time later. + +If we use Function Declaration, it won't work as intended: + +```js run +let age = prompt("What is your age?", 18); + +// conditionally declare a function +if (age < 18) { + + function welcome() { + alert("Hello!"); + } + +} else { + + function welcome() { + alert("Greetings!"); + } + +} + +// ...use it later +*!* +welcome(); // Error: welcome is not defined +*/!* +``` + +That's because a Function Declaration is only visible inside the code block in which it resides. + +Here's another example: + +```js run +let age = 16; // take 16 as an example + +if (age < 18) { +*!* + welcome(); // \ (runs) +*/!* + // | + function welcome() { // | + alert("Hello!"); // | Function Declaration is available + } // | everywhere in the block where it's declared + // | +*!* + welcome(); // / (runs) +*/!* + +} else { + + function welcome() { + alert("Greetings!"); + } +} + +// Here we're out of curly braces, +// so we can not see Function Declarations made inside of them. + +*!* +welcome(); // Error: welcome is not defined +*/!* +``` + +What can we do to make `welcome` visible outside of `if`? + +The correct approach would be to use a Function Expression and assign `welcome` to the variable that is declared outside of `if` and has the proper visibility. + +This code works as intended: + +```js run +let age = prompt("What is your age?", 18); + +let welcome; + +if (age < 18) { + + welcome = function() { + alert("Hello!"); + }; + +} else { + + welcome = function() { + alert("Greetings!"); + }; + +} + +*!* +welcome(); // ok now +*/!* +``` + +Or we could simplify it even further using a question mark operator `?`: + +```js run +let age = prompt("What is your age?", 18); + +let welcome = (age < 18) ? + function() { alert("Hello!"); } : + function() { alert("Greetings!"); }; + +*!* +welcome(); // ok now +*/!* +``` + + +```smart header="When to choose Function Declaration versus Function Expression?" +As a rule of thumb, when we need to declare a function, the first 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. + +That's also better for readability, as it's easier to look up `function f(…) {…}` in the code than `let f = function(…) {…};`. Function Declarations are more "eye-catching". + +...But if a Function Declaration does not suit us for some reason, or we need a conditional declaration (we've just seen an example), then Function Expression should be used. +``` + +## Summary + +- Functions are values. They can be assigned, copied or declared in any place of the code. +- If the function is declared as a separate statement in the main code flow, that's called a "Function Declaration". +- If the function is created as a part of an expression, it's called a "Function Expression". +- Function Declarations are processed before the code block is executed. They are visible everywhere in the block. +- Function Expressions are created when the execution flow reaches them. + +In most cases when we need to declare a function, a Function Declaration is preferable, because it is visible prior to the declaration itself. That gives us more flexibility in code organization, and is usually more readable. + +So we should use a Function Expression only when a Function Declaration is not fit for the task. We've seen a couple of examples of that in this chapter, and will see more in the future. diff --git a/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/solution.md b/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/solution.md new file mode 100644 index 0000000000..3ea1124739 --- /dev/null +++ b/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/solution.md @@ -0,0 +1,17 @@ + +```js run +function ask(question, yes, no) { + if (confirm(question)) yes() + else no(); +} + +ask( + "Do you agree?", +*!* + () => alert("You agreed."), + () => alert("You canceled the execution.") +*/!* +); +``` + +Looks short and clean, right? diff --git a/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/task.md b/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/task.md new file mode 100644 index 0000000000..2f44db27e4 --- /dev/null +++ b/1-js/02-first-steps/17-arrow-functions-basics/1-rewrite-arrow/task.md @@ -0,0 +1,17 @@ + +# Rewrite with arrow functions + +Replace Function Expressions with arrow functions in the code below: + +```js run +function ask(question, yes, no) { + if (confirm(question)) yes() + else no(); +} + +ask( + "Do you agree?", + function() { alert("You agreed."); }, + function() { alert("You canceled the execution."); } +); +``` 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 new file mode 100644 index 0000000000..e0fb5bda58 --- /dev/null +++ b/1-js/02-first-steps/17-arrow-functions-basics/article.md @@ -0,0 +1,111 @@ +# Arrow functions, the basics + +There's another very simple and concise syntax for creating functions, that's often better than Function Expressions. + +It's called "arrow functions", because it looks like this: + +```js +let func = (arg1, arg2, ...argN) => expression +``` + +...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. + +In other words, it's the shorter version of: + +```js +let func = function(arg1, arg2, ...argN) { + return expression; +}; +``` + +Let's see a concrete example: + +```js run +let sum = (a, b) => a + b; + +/* This arrow function is a shorter form of: + +let sum = function(a, b) { + return a + b; +}; +*/ + +alert( sum(1, 2) ); // 3 +``` + +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. + +- If we have only one argument, then parentheses around parameters can be omitted, making that even shorter. + + For example: + + ```js run + *!* + let double = n => n * 2; + // roughly the same as: let double = function(n) { return n * 2 } + */!* + + alert( double(3) ); // 6 + ``` + +- If there are no arguments, parentheses will be empty (but they should be present): + + ```js run + let sayHi = () => alert("Hello!"); + + sayHi(); + ``` + +Arrow functions can be used in the same way as Function Expressions. + +For instance, to dynamically create a function: + +```js run +let age = prompt("What is your age?", 18); + +let welcome = (age < 18) ? + () => alert('Hello') : + () => alert("Greetings!"); + +welcome(); +``` + +Arrow functions may appear unfamiliar and not very readable at first, but that quickly changes as the eyes get used to the structure. + +They are very convenient for simple one-line actions, when we're just too lazy to write many words. + +## Multiline arrow functions + +The examples above took arguments from the left of `=>` and evaluated the right-side expression with them. + +Sometimes we need something a little bit more complex, like multiple expressions or statements. It is also possible, but we should enclose them in curly braces. Then use a normal `return` within them. + +Like this: + +```js run +let sum = (a, b) => { // the curly brace opens a multiline function + let result = a + b; +*!* + return result; // if we use curly braces, then we need an explicit "return" +*/!* +}; + +alert( sum(1, 2) ); // 3 +``` + +```smart header="More to come" +Here we praised arrow functions for brevity. But that's not all! + +Arrow functions have other interesting features. + +To study them in-depth, we first need to get to know some other aspects of JavaScript, so we'll return to arrow functions later in the chapter . + +For now, we can already use arrow functions for one-line actions and callbacks. +``` + +## Summary + +Arrow functions are handy 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. +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. diff --git a/1-js/02-first-steps/18-javascript-specials/article.md b/1-js/02-first-steps/18-javascript-specials/article.md new file mode 100644 index 0000000000..91be0aa454 --- /dev/null +++ b/1-js/02-first-steps/18-javascript-specials/article.md @@ -0,0 +1,284 @@ +# JavaScript specials + +This chapter briefly recaps the features of JavaScript that we've learned by now, paying special attention to subtle moments. + +## Code structure + +Statements are delimited with a semicolon: + +```js run no-beautify +alert('Hello'); alert('World'); +``` + +Usually, a line-break is also treated as a delimiter, so that would also work: + +```js run no-beautify +alert('Hello') +alert('World') +``` + +That's called "automatic semicolon insertion". Sometimes it doesn't work, for instance: + +```js run +alert("There will be an error after this message") + +[1, 2].forEach(alert) +``` + +Most codestyle guides agree that we should put a semicolon after each statement. + +Semicolons are not required after code blocks `{...}` and syntax constructs with them like loops: + +```js +function f() { + // no semicolon needed after function declaration +} + +for(;;) { + // no semicolon needed after the loop +} +``` + +...But even if we can put an "extra" semicolon somewhere, that's not an error. It will be ignored. + +More in: . + +## Strict mode + +To fully enable all features of modern JavaScript, we should start scripts with `"use strict"`. + +```js +'use strict'; + +... +``` + +The directive must be at the top of a script or at the beginning of a function body. + +Without `"use strict"`, everything still works, but some features behave in the old-fashion, "compatible" way. We'd generally prefer the modern behavior. + +Some modern features of the language (like classes that we'll study in the future) enable strict mode implicitly. + +More in: . + +## Variables + +Can be declared using: + +- `let` +- `const` (constant, can't be changed) +- `var` (old-style, will see later) + +A variable name can include: +- Letters and digits, but the first character may not be a digit. +- Characters `$` and `_` are normal, on par with letters. +- Non-Latin alphabets and hieroglyphs are also allowed, but commonly not used. + +Variables are dynamically typed. They can store any value: + +```js +let x = 5; +x = "John"; +``` + +There are 8 data types: + +- `number` for both floating-point and integer numbers, +- `bigint` for integer numbers of arbitrary length, +- `string` for strings, +- `boolean` for logical values: `true/false`, +- `null` -- a type with a single value `null`, meaning "empty" or "does not exist", +- `undefined` -- a type with a single value `undefined`, meaning "not assigned", +- `object` and `symbol` -- for complex data structures and unique identifiers, we haven't learnt them yet. + +The `typeof` operator returns the type for a value, with two exceptions: +```js +typeof null == "object" // error in the language +typeof function(){} == "function" // functions are treated specially +``` + +More in: and . + +## Interaction + +We're using a browser as a working environment, so basic UI functions will be: + +[`prompt(question, [default])`](mdn:api/Window/prompt) +: Ask a `question`, and return either what the visitor entered or `null` if they clicked "cancel". + +[`confirm(question)`](mdn:api/Window/confirm) +: Ask a `question` and suggest to choose between Ok and Cancel. The choice is returned as `true/false`. + +[`alert(message)`](mdn:api/Window/alert) +: Output a `message`. + +All these functions are *modal*, they pause the code execution and prevent the visitor from interacting with the page until they answer. + +For instance: + +```js run +let userName = prompt("Your name?", "Alice"); +let isTeaWanted = confirm("Do you want some tea?"); + +alert( "Visitor: " + userName ); // Alice +alert( "Tea wanted: " + isTeaWanted ); // true +``` + +More in: . + +## Operators + +JavaScript supports the following operators: + +Arithmetical +: Regular: `* + - /`, also `%` for the remainder and `**` for power of a number. + + The binary plus `+` concatenates strings. And if any of the operands is a string, the other one is converted to string too: + + ```js run + alert( '1' + 2 ); // '12', string + alert( 1 + '2' ); // '12', string + ``` + +Assignments +: There is a simple assignment: `a = b` and combined ones like `a *= 2`. + +Bitwise +: Bitwise operators work with 32-bit integers at the lowest, bit-level: see the [docs](mdn:/JavaScript/Reference/Operators/Bitwise_Operators) when they are needed. + +Conditional +: The only operator with three parameters: `cond ? resultA : resultB`. If `cond` is truthy, returns `resultA`, otherwise `resultB`. + +Logical operators +: Logical AND `&&` and OR `||` perform short-circuit evaluation and then return the value where it stopped (not necessary `true`/`false`). Logical NOT `!` converts the operand to boolean type and returns the inverse value. + +Nullish coalescing operator +: The `??` operator provides a way to choose a defined value from a list of variables. The result of `a ?? b` is `a` unless it's `null/undefined`, then `b`. + +Comparisons +: Equality check `==` for values of different types converts them to a number (except `null` and `undefined` that equal each other and nothing else), so these are equal: + + ```js run + alert( 0 == false ); // true + alert( 0 == '' ); // true + ``` + + Other comparisons convert to a number as well. + + The strict equality operator `===` doesn't do the conversion: different types always mean different values for it. + + Values `null` and `undefined` are special: they equal `==` each other and don't equal anything else. + + Greater/less comparisons compare strings character-by-character, other types are converted to a number. + +Other operators +: There are few others, like a comma operator. + +More in: , , , . + +## Loops + +- We covered 3 types of loops: + + ```js + // 1 + while (condition) { + ... + } + + // 2 + do { + ... + } while (condition); + + // 3 + for(let i = 0; i < 10; i++) { + ... + } + ``` + +- The variable declared in `for(let...)` loop is visible only inside the loop. But we can also omit `let` and reuse an existing variable. +- Directives `break/continue` allow to exit the whole loop/current iteration. Use labels to break nested loops. + +Details in: . + +Later we'll study more types of loops to deal with objects. + +## The "switch" construct + +The "switch" construct can replace multiple `if` checks. It uses `===` (strict equality) for comparisons. + +For instance: + +```js run +let age = prompt('Your age?', 18); + +switch (age) { + case 18: + alert("Won't work"); // the result of prompt is a string, not a number + break; + + case "18": + alert("This works!"); + break; + + default: + alert("Any value not equal to one above"); +} +``` + +Details in: . + +## Functions + +We covered three ways to create a function in JavaScript: + +1. Function Declaration: the function in the main code flow + + ```js + function sum(a, b) { + let result = a + b; + + return result; + } + ``` + +2. Function Expression: the function in the context of an expression + + ```js + let sum = function(a, b) { + let result = a + b; + + return result; + }; + ``` + +3. Arrow functions: + + ```js + // expression at the right side + let sum = (a, b) => a + b; + + // or multi-line syntax with { ... }, need return here: + let sum = (a, b) => { + // ... + return a + b; + } + + // without arguments + let sayHi = () => alert("Hello"); + + // with a single argument + let double = n => n * 2; + ``` + + +- Functions may have local variables: those declared inside its body. Such variables are only visible inside the function. +- Parameters can have default values: `function sum(a = 1, b = 2) {...}`. +- Functions always return something. If there's no `return` statement, then the result is `undefined`. + +Details: see , . + +## More to come + +That was a brief list of JavaScript features. As of now we've studied only basics. Further in the tutorial you'll find more specials and advanced features of JavaScript. 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 ca709ddcfb..104f94a2b9 100644 --- a/1-js/03-code-quality/01-debugging-chrome/article.md +++ b/1-js/03-code-quality/01-debugging-chrome/article.md @@ -2,6 +2,7 @@ より複雑なコードを書く前に、デバッグについて話しましょう。 +<<<<<<< HEAD すべてのモダンブラウザや、その他多くの環境は "デバッグ" をサポートしています。 -- 開発者ツールを使うことで、エラーの発見と修正がはるかに簡単になります。 ここでは、恐らくこの観点では最も機能が充実している Chrome を使います。 @@ -9,17 +10,31 @@ [cut] ## "sources" ペイン +======= +[Debugging](https://en.wikipedia.org/wiki/Debugging) is the process of finding and fixing errors within a script. All modern browsers and most other environments support debugging tools -- a special UI in developer tools that makes debugging much easier. It also allows to trace the code step by step to see what exactly is going on. + +We'll be using Chrome here, because it has enough features, most other browsers have a similar process. + +## The "Sources" panel +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 Chromeのバージョンによっては少し違って見えるかもしれませんが、そこが何かは明白でしょう。 +<<<<<<< HEAD - Chromeの [example page](debugging/index.html) を開きます。 - `key:F12` (Mac: `key:Cmd+Opt+I`) で開発者ツールをONにします。 - `source` ペインを選択します。 +======= +- Open the [example page](debugging/index.html) in Chrome. +- Turn on developer tools with `key:F12` (Mac: `key:Cmd+Opt+I`). +- Select the `Sources` panel. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 もしもこの画面を見るのが初めてであれば、見ておくべきものがあります: ![](chrome-open-sources.svg) +<<<<<<< HEAD トグルボタン はファイルを表示するタブを開きます。 それをクリックして、`index.html` 、次にツリービューの `hello.js` を選択しましょう。ここで表示される内容は次の通りです: @@ -34,35 +49,74 @@ Chromeのバージョンによっては少し違って見えるかもしれま 同じトグル を再びクリックすること、リソースの一覧やコードを隠すことができます。 ## コンソール +======= +The toggler button opens the tab with files. + +Let's click it and select `hello.js` in the tree view. Here's what should show up: + +![](chrome-tabs.svg) + +The Sources panel has 3 parts: + +1. The **File Navigator** pane lists HTML, JavaScript, CSS and other files, including images that are attached to the page. Chrome extensions may appear here too. +2. The **Code Editor** pane shows the source code. +3. The **JavaScript Debugging** pane is for debugging, we'll explore it soon. + +Now you could click the same toggler again to hide the resources list and give the code some space. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 `Esc` を押すとコンソールが下に表示されます。そこでコマンドを入力し、`key:Enter` をするとコマンドを実行することができます。 +<<<<<<< HEAD 実行結果は下に表示されます。 +======= +If we press `key:Esc`, then a console opens below. We can type commands there and press `key:Enter` to execute. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例えば、ここでは `1+2 ` は `3` になり、`hello("debugger")` は何も返さないので、結果は `undefined` です: ![](chrome-sources-console.svg) +<<<<<<< HEAD ## ブレイクポイント +======= +![](chrome-sources-console.svg) +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 [example page](debugging/index.html) のコードの中で何が起こっているのか見てみましょう。`hello.js` で、行番号 `4` をクリックします。コードではなく、右にある `"4"` の数字です。 +<<<<<<< HEAD これでブレイクポイントがセットできました。行 `8` の数字もクリックしましょう。 +======= +Let's examine what's going on within the code of the [example page](debugging/index.html). In `hello.js`, click at line number `4`. Yes, right on the `4` digit, not on the code. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 このようになるはずです(青はあなたがクリックした場所です): ![](chrome-sources-breakpoint.svg) +<<<<<<< HEAD *ブレイクポイント* はデバッガが自動でJavaScriptの実行を停止するコードのポイントです。 +======= +![](chrome-sources-breakpoint.svg) +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 コードが停止している間、現在の変数を検査したり、コンソールでコマンドを実行することができます。つまり、そこでデバッグができます。 右のペインでは、常にブレイクポイントの一覧を見ることができます。色々なファイルで多くのブレイクポイントを持っているときに役に立ちます。それらは次のようなことができます: +<<<<<<< HEAD - コード中のブレイクポイントに素早く移動する(右ペインで移動したいブレイクポイントをクリック) - チェックを外すことで、一時的にブレイクポイントを無効にする - 右クリックから削除を選択することで、ブレイクポイントを削除する - ...など +======= +We can always find a list of breakpoints in the right panel. That's useful when we have many breakpoints in various files. It allows us to: +- Quickly jump to the breakpoint in the code (by clicking on it in the right panel). +- Temporarily disable the breakpoint by unchecking it. +- Remove the breakpoint by right-clicking and selecting Remove. +- ...And so on. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```smart header="条件付きのブレイクポイント" 行番号の *右クリック* で *条件付きの* ブレイクポイントを作ることができます。与えられた式が真の場合にのみトリガします。 @@ -72,7 +126,11 @@ Chromeのバージョンによっては少し違って見えるかもしれま ## デバッガコマンド +<<<<<<< HEAD 次のように、`debugger` コマンドを使うことでもコードを停止することができます: +======= +We can also pause the code by using the `debugger` command in it, like this: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js function hello(name) { @@ -92,11 +150,19 @@ function hello(name) { 今回の例では、`hello()` はページ読み込み中に呼び出されるので、デバッガを起動する最も簡単な方法はページを再読込することです。なので、 `key:F5` (Windows, Linux)または `key:Cmd+R` (Mac) を押しましょう。 +<<<<<<< HEAD ブレイクポイントがセットされているので、実行は4行目で一時停止します。: +======= +In our example, `hello()` is called during the page load, so the easiest way to activate the debugger (after we've set the breakpoints) is to reload the page. So let's press `key:F5` (Windows, Linux) or `key:Cmd+R` (Mac). +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ![](chrome-sources-debugger-pause.svg) +<<<<<<< HEAD 右側にある情報のドロップダウンを開いてください(矢印のラベルがついています)。現在のコードの状態を調べることができます: +======= +![](chrome-sources-debugger-pause.svg) +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 1. **`Watch` -- 任意の式の現在の値を表示します。** @@ -108,7 +174,12 @@ function hello(name) { スタックの項目をクリックすると、デバッガは該当のコードにジャンプし、すべての変数も同様に調べられます。 +<<<<<<< HEAD 3. **`Scope` -- 現在の変数。** +======= + If you click on a stack item (e.g. "anonymous"), the debugger jumps to the corresponding code, and all its variables can be examined as well. +3. **`Scope` -- current variables.** +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 `Local` はローカル関数の変数を表示します。また、ソース上でもハイライト表示されたそれらの値を見ることができます。 @@ -120,14 +191,22 @@ function hello(name) { スクリプトを *追跡* してみましょう。 +<<<<<<< HEAD 右ペインの上部にそのボタンがあります。 -- 実行の継続, ホットキー `key:F8`. : 実行を再開します。もしも他にブレイクポイントがなければ、そのまま実行が継続され、デバッガの制御から外れます。 +======= +There are buttons for it at the top of the right panel. Let's engage them. + + -- "Resume": continue the execution, hotkey `key:F8`. +: Resumes the execution. If there are no additional breakpoints, then the execution just continues and the debugger loses control. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 次の図は、それを行った後に見える画面です: ![](chrome-sources-debugger-trace-1.svg) +<<<<<<< HEAD 実行は再開され、`say()` の中の別のブレイクポイントに到達し、そこで一時停止します。右の "Call stack" を見てください。もう一度呼び出すことで増えています。私たちは、今 `say()` の中にいます。 @@ -145,32 +224,77 @@ function hello(name) { -- エラー発生時の自動一時停止の有効/無効 : 有効にして開発者ツールを開いている場合、スクリプトエラーが起きると実行が自動で一時停止します。そして、何が間違っていたかを知るために変数を分析することができます。なので、スクリプトがエラーで死んだ場合は、どこで死んでその時どんなコンテキストであるかを確認するため、デバッガを起動しこのオプションを有効にしてページを再読込しましょう。 +======= + + The execution has resumed, reached another breakpoint inside `say()` and paused there. Take a look at the "Call Stack" at the right. It has increased by one more call. We're inside `say()` now. + + -- "Step": run the next command, hotkey `key:F9`. +: Run the next statement. If we click it now, `alert` will be shown. + + Clicking this again and again will step through all script statements one by one. + + -- "Step over": run the next command, but *don't go into a function*, hotkey `key:F10`. +: Similar to the previous the "Step" command, but behaves differently if the next statement is a function call. That is: not a built-in, like `alert`, but a function of our own. + + The "Step" command goes into it and pauses the execution at its first line, while "Step over" executes the nested function call invisibly, skipping the function internals. + + The execution is then paused immediately after that function. + + That's good if we're not interested to see what happens inside the function call. + + -- "Step into", hotkey `key:F11`. +: That's similar to "Step", but behaves differently in case of asynchronous function calls. If you're only starting to learn JavaScript, then you can ignore the difference, as we don't have asynchronous calls yet. + + For the future, just note that "Step" command ignores async actions, such as `setTimeout` (scheduled function call), that execute later. The "Step into" goes into their code, waiting for them if necessary. See [DevTools manual](https://developers.google.com/web/updates/2018/01/devtools#async) for more details. + + -- "Step out": continue the execution till the end of the current function, hotkey `key:Shift+F11`. +: Continue the execution and stop it at the very last line of the current function. That's handy when we accidentally entered a nested call using , but it does not interest us, and we want to continue to its end as soon as possible. + + -- enable/disable all breakpoints. +: That button does not move the execution. Just a mass on/off for breakpoints. + + -- enable/disable automatic pause in case of an error. +: When enabled, and the developer tools is open, a script error automatically pauses the execution. Then we can analyze variables 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. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```smart header="Continue to here" コードの行で右クリックすると、"Continue to here" と呼ばれる素晴らしい選択肢を持つコンテキストメニューが開きます。 +<<<<<<< HEAD これは複数のステップを進めたいが、ブレイクポイントをセットするのが面倒なときに便利です。 +======= +That's handy when we want to move multiple steps forward to the line, but we're too lazy to set a breakpoint. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` ## ロギング +<<<<<<< HEAD コンソールに何かを出力するために `console.log` 関数があります。 +======= +To output something to console from our code, there's `console.log` function. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例えば、これはコンソールに `0` から `4` までの値を出力します: ```js run // 見るにはコンソールを開いてください for (let i = 0; i < 5; i++) { - console.log("value", i); + console.log("value,", i); } ``` +<<<<<<< HEAD コンソールの中なので、通常のユーザはその出力を見ることはありません。見るためには、開発者ツールのコンソールタブを開くか、開発者ツールの別のタブで `key:Esc` を押します。 :下にコンソールが表示されます。 +======= +Regular users don't see that output, it is in the console. To see it, either open the Console panel of developer tools or press `key:Esc` while in another panel: that opens the console at the bottom. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 コードに十分なログを仕込んでいれば、デバッガなしで何が行われているか知ることができます。 ## サマリ +<<<<<<< HEAD これまで見てきた通り、スクリプトを一時停止するには主に3つの方法があります。 1. ブレイクポイント 2. `debugger` 構文 @@ -179,7 +303,21 @@ for (let i = 0; i < 5; i++) { これらにより変数を検査し実行が間違っている場所を確認することができます。 ここで説明した以上に、開発者ツールには多くのオプションがあります。完全なマニュアルは です。 +======= +As we can see, there are three main ways to pause a script: +1. A breakpoint. +2. The `debugger` statements. +3. An error (if dev tools are open and the button is "on"). + +When paused, we can debug - examine variables and trace the code to see where the execution goes wrong. + +There are many more options in developer tools than covered here. The full manual is at . +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 このチャプターの情報はデバッグを始めるには十分ですが、今後、特にブラウザの作業が多い場合は、上記のサイトを見て開発者ツールのより高度な機能を調べてください。 +<<<<<<< HEAD また、開発者ツールの色んな場所をクリックすることで何が表示されるかを見ることが出来ます。恐らくそれは開発者ツールを学ぶのに最も近道です。同様に右クリックも忘れないように! +======= +Oh, and also you can click at various places of dev tools and just see what's showing up. That's probably the fastest route to learn dev tools. Don't forget about the right click and context menus! +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/03-code-quality/01-debugging-chrome/head.html b/1-js/03-code-quality/01-debugging-chrome/head.html index f219b0af18..615326c08e 100644 --- a/1-js/03-code-quality/01-debugging-chrome/head.html +++ b/1-js/03-code-quality/01-debugging-chrome/head.html @@ -1,8 +1,8 @@ diff --git a/1-js/03-code-quality/01-debugging-chrome/largeIcons.svg b/1-js/03-code-quality/01-debugging-chrome/largeIcons.svg new file mode 100644 index 0000000000..83303365bd --- /dev/null +++ b/1-js/03-code-quality/01-debugging-chrome/largeIcons.svg @@ -0,0 +1,1472 @@ + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a + b + c + d + e + f + g + h + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + + + + + + + + + + + + + + + + + + + diff --git a/1-js/03-code-quality/01-debugging-chrome/toolbarButtonGlyphs.svg b/1-js/03-code-quality/01-debugging-chrome/toolbarButtonGlyphs.svg deleted file mode 100644 index 5bdf20a83a..0000000000 --- a/1-js/03-code-quality/01-debugging-chrome/toolbarButtonGlyphs.svg +++ /dev/null @@ -1,1035 +0,0 @@ - -image/svg+xml \ No newline at end of file diff --git a/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md b/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md index 60a22707d1..eee48446e1 100644 --- a/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md +++ b/1-js/03-code-quality/02-coding-style/1-style-errors/solution.md @@ -2,6 +2,7 @@ あなたは次のような事に気づけます: ```js no-beautify +<<<<<<< HEAD function pow(x,n) // <- 引数の間にスペースがない { // <- 別の行に波括弧がある let result=1; // <- = の両側にスペースがない @@ -15,11 +16,30 @@ let x=prompt("x?",''), n=prompt("n?",'') // <-- 技術的には可能ですが, if (n<0) // <- (n < 0) の中にスペースがありません。また、その上に余分な行があるべきです。 { // <- 波括弧が別の行に分かれています // 下は -- 1行が長いです。2行に分けたほうがよいです +======= +function pow(x,n) // <- no space between arguments +{ // <- figure bracket on a separate line + let result=1; // <- no spaces before or after = + for(let i=0;i>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 alert(`Power ${n} is not supported, please enter an integer number greater than zero`); } else // <- "} else {" のように1行で書いたほうがいいです。 { +<<<<<<< HEAD alert(pow(x,n)) // spaces と ; がありません。 +======= + alert(pow(x,n)) // no spaces and missing ; +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 } ``` 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 ffc202327d..0b9b43fae7 100644 --- a/1-js/03-code-quality/02-coding-style/article.md +++ b/1-js/03-code-quality/02-coding-style/article.md @@ -1,16 +1,28 @@ +<<<<<<< HEAD # コーディングスタイル +======= +# Coding Style +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 私たちのコードはできるだけ綺麗で読みやすいものでなければなりません。 +<<<<<<< HEAD それはまさにプログラミングの芸術です -- 複雑な処理を正しく、人が読める形でコーディングすることです。 それを助ける一つが、良いコードスタイルです。 [cut] +======= +That is actually the art of programming -- to take a complex task and code it in a way that is both correct and human-readable. A good code style greatly assists in that. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## 構文 +<<<<<<< HEAD ルールに基づいたチートシート(より詳細は下)です: +======= +Here is a cheat sheet with some suggested rules (see below for more details): +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ![](code-style.svg) -![](figure-bracket-style.png) +### Line Length +No one likes to read a long horizontal line of code. It's best practice to split them. + +<<<<<<< HEAD まとめると: - 本当に短いコードであれば、`if (cond) return null` のように1行が許容されます:。 - しかし、複数の文がある場合には、通常は括弧内の各文ごとに行を分けるのが良いです。 @@ -85,17 +124,52 @@ if (n < 0) { 行の最大長は制限されるべきです。誰も横に長い行は好きではありません。それよりも行を分ける方が良いです。 行の最大長はチームで決められますが、通常は 80 もしくは 120 文字です。 +======= +For example: +```js +// backtick quotes ` allow to split the string into multiple lines +let str = ` + ECMA International's TC39 is a group of JavaScript developers, + implementers, academics, and more, collaborating with the community + to maintain and evolve the definition of JavaScript. +`; +``` + +And, for `if` statements: + +```js +if ( + id === 123 && + moonPhase === 'Waning Gibbous' && + zodiacSign === 'Libra' +) { + letTheSorceryBegin(); +} +``` + +The maximum line length should be agreed upon at the team-level. It's usually 80 or 120 characters. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ### インデント 2つのタイプのインデントがあります。: +<<<<<<< HEAD - **水平なインデント: 2(4)個のスペース** 水平なインデントは 2 または 4 つのスペース、もしくは "タブ" 記号を使います。どれを選ぶかは好みの問題です。最近はスペースが一般的です。 タブよりもスペースの方がよい点の1つは、スペースは "タブ" 記号よりもより柔軟なインデントの設定ができることです。 例えば、このように、開始の括弧に対して引数を並べることができます: +======= +- **Horizontal indents: 2 or 4 spaces.** + + A horizontal indentation is made using either 2 or 4 spaces or the horizontal tab symbol (key `key:Tab`). Which one to choose is an old holy war. Spaces are more common nowadays. + + One advantage of spaces over tabs is that spaces allow more flexible configurations of indents than the tab symbol. + + For instance, we can align the arguments with the opening bracket, like this: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js no-beautify show(parameters, @@ -108,9 +182,15 @@ if (n < 0) { } ``` +<<<<<<< HEAD - **垂直のインデント: コードを論理ブロックに分割するための空行** 1つの関数の中でさえ、しばしば論理的な塊に分割されます。下の例では、変数の初期化、メインのループと結果返却は垂直に分かれています。: +======= +- **Vertical indents: empty lines for splitting code into logical blocks.** + + Even a single function can often be divided into logical blocks. In the example below, the initialization of variables, the main loop and returning the result are split vertically: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js function pow(x, n) { @@ -126,6 +206,7 @@ if (n < 0) { コードがより読みやすくするために新しい行を挿入しましょう。垂直インデントなしで、コードの行が9行を超えるべきではありません。 +<<<<<<< HEAD ### セミコロン セミコロンは、たとえ省略できるとしても各文の末尾に存在するべきです。 @@ -141,6 +222,23 @@ if (n < 0) { `if(..) { ... }` で余分なネストを避けるために、ループで["continue"](info:while-for#continue)ディレクティブを使うことは、時には良いアイデアです。: 次の代わりに: +======= +### Semicolons + +A semicolon should be present after each statement, even if it could possibly be skipped. + +There are languages where a semicolon is truly optional and it is rarely used. In JavaScript, though, there are cases where a line break is not interpreted as a semicolon, leaving the code vulnerable to errors. See more about that in the chapter . + +If you're an experienced JavaScript programmer, you may choose a no-semicolon code style like [StandardJS](https://standardjs.com/). Otherwise, it's best to use semicolons to avoid possible pitfalls. The majority of developers put semicolons. + +### Nesting Levels + +Try to avoid nesting code too many levels deep. + +For example, in the loop, it's sometimes a good idea to use the [`continue`](info:while-for#continue) directive to avoid extra nesting. + +For example, instead of adding a nested `if` conditional like this: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js for (let i = 0; i < 10; i++) { @@ -163,7 +261,11 @@ for (let i = 0; i < 10; i++) { 例えば、下の2つの構造は同一です。 +<<<<<<< HEAD 1つ目: +======= +Option 1: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js function pow(x, n) { @@ -181,7 +283,11 @@ function pow(x, n) { } ``` +<<<<<<< HEAD 2つ目: +======= +Option 2: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js function pow(x, n) { @@ -200,6 +306,7 @@ function pow(x, n) { } ``` +<<<<<<< HEAD ...`n < 0` というエッジケースは早い段階で処理されるため、余分なネストがないメインのコードフローとなります。そのため、2つ目はより読みやすいです。 ## コードの下の関数 @@ -207,6 +314,15 @@ function pow(x, n) { もしいくつかの "ヘルパー関数"と、それを使うコードを書く場合、それらを配置する方法が3つあります。 1. ヘルパー関数を使うコードの上に関数を記述する: +======= +The second one is more readable because the "special case" of `n < 0` is handled early on. Once the check is done we can move on to the "main" code flow without the need for additional nesting. + +## Function Placement + +If you are writing several "helper" functions and the code that uses them, there are three ways to organize the functions. + +1. Declare the functions *above* the code that uses them: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js // *!*関数宣言*/!* @@ -235,8 +351,12 @@ function pow(x, n) { setHandler(elem); walkAround(); +<<<<<<< HEAD // --- *!*ヘルパー関数*/!* --- +======= + // --- *!*helper functions*/!* --- +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 function createElement() { ... } @@ -249,10 +369,15 @@ function pow(x, n) { ... } ``` +<<<<<<< HEAD 3. ミックス: 初めて使われる場所で関数を記述する +======= +3. Mixed: a function is declared where it's first used. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 たいていの場合、2つ目がより好まれます。 +<<<<<<< HEAD なぜなら、コードを読むとき、私たちは最初に "何をするか" を知りたいからです。コードが最初にくるとその情報を得ることができます。そしてそれらの関数名が行うべきことに相応しいものであれば、関数の中身を読む必要は全くないかもしれません。 ## スタイルガイド @@ -264,11 +389,25 @@ function pow(x, n) { もちろん、チームは自分たちのスタイルガイドを作ることができます。 ただしほとんどの場合、必要ありません。既に多くの実証済みの選択肢があるので、これらのうちの1つを採用するのが通常は最善の策です。 例えば: +======= +That's because when reading code, we first want to know *what it does*. If the code goes first, then it becomes clear from the start. Then, maybe we won't need to read the functions at all, especially if their names are descriptive of what they actually do. + +## Style Guides + +A style guide contains general rules about "how to write" code, e.g. which quotes to use, how many spaces to indent, the maximal line length, etc. A lot of minor things. + +When all members of a team use the same style guide, the code looks uniform, regardless of which team member wrote it. -- [Google JavaScript Style Guide](https://google.github.io/styleguide/javascriptguide.xml) +Of course, a team can always write their own style guide, but usually there's no need to. There are many existing guides to choose from. + +Some popular choices: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 + +- [Google JavaScript Style Guide](https://google.github.io/styleguide/jsguide.html) - [Airbnb JavaScript Style Guide](https://github.com/airbnb/javascript) - [Idiomatic.JS](https://github.com/rwaldron/idiomatic.js) - [StandardJS](https://standardjs.com/) +<<<<<<< HEAD - (他にもあります) あなたが新米の開発者であれば、この章の始めにあるチートシートから始めるとよいでしょう。その後、他のスタイルガイドを参照し、一般的な原則を知った上で最も好きなものを選択するのが良いでしょう。 @@ -282,6 +421,19 @@ function pow(x, n) { なので、たとえ "コードスタイル" に固執したくない場合でも、それを導入することを推奨します。それらはタイポを見つけるのに役立ち -- それだけで既に十分です。 もっとも知られているツールは: +======= +- (plus many more) + +If you're a novice developer, start with the cheat sheet at the beginning of this chapter. Then you can browse other style guides to pick up more ideas and decide which one you like best. + +## Automated Linters + +Linters are tools that can automatically check the style of your code and make improving suggestions. + +The great thing about them is that style-checking can also find some bugs, like typos in variable or function names. Because of this feature, using a linter is recommended even if you don't want to stick to one particular "code style". + +Here are some well-known linting tools: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 - [JSLint](http://www.jslint.com/) -- 最初の linter の1つ - [JSHint](http://www.jshint.com/) -- JSLint よりも多くの設定が可能 @@ -289,15 +441,28 @@ function pow(x, n) { これらどれでも利用できます。著者は [ESLint](http://eslint.org/) を使ってます。 +<<<<<<< HEAD ほとんどの linter はエディタに統合されます: エディタのプラグインを有効にし、スタイルの設定をするだけです。 +======= +Most linters are integrated with many popular editors: just enable the plugin in the editor and configure the style. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例えば、ESLint では次のようなことをします。: +<<<<<<< HEAD 1. [Node.JS](https://nodejs.org/) をインストールします。 2. `npm install -g eslint` コマンドで ESLint をインストールします(npm は Node.JS パッケージインストーラです) 3. あなたのJavaScriptプロジェクト(すべてのファイルを含むフォルダ)のルートに `.ellintrc` という名前の設定ファイルを作ります `.eslintrc` の例です: +======= +1. Install [Node.js](https://nodejs.org/). +2. Install ESLint with the command `npm install -g eslint` (npm is a JavaScript package installer). +3. Create a config file named `.eslintrc` in the root of your JavaScript project (in the folder that contains all your files). +4. Install/enable the plugin for your editor that integrates with ESLint. The majority of editors have one. + +Here's an example of an `.eslintrc` file: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js { @@ -309,11 +474,12 @@ function pow(x, n) { }, "rules": { "no-console": 0, - }, - "indent": 2 + "indent": ["warning", 2] + } } ``` +<<<<<<< HEAD ここで、ディレクティブ `"extends"` は "eslint:recommended" の設定に基づいていることを示し、次に我々自身の設定を指定します。 次に、ESLint と統合されたエディタで、プラグインのインストール/有効化をします。多くのエディタはそれを持っています。 @@ -325,11 +491,26 @@ function pow(x, n) { そのような理由から、たとえスタイルについて関心がなくても、linter を利用することを強く勧めます。 また、特定のIDEは組み込みの linter をサポートしています。それも良いですが、ESLintの方がより柔軟なチューニングが可能です。 +======= +Here the directive `"extends"` denotes that the configuration is based on the "eslint:recommended" set of settings. After that, we specify our own. + +It is also possible to download style rule sets from the web and extend them instead. See for more details about installation. + +Also certain IDEs have built-in linting, which is convenient but not as customizable as ESLint. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## サマリ +<<<<<<< HEAD このチャプターとスタイルガイドのすべての構文ルールは、可読性を高めるのが狙いなので、すべて議論の余地があります。 私たちが "より良く書くための方法" について考えるとき、唯一の基準は "コードをより読みやすく理解しやすくすること、エラーを回避するのに役立つこと" です。それがスタイルを選んだり、どちらがより良いかを議論する時に心に留めておく重要なことです。 それに関して最新の考えを知るためにスタイルガイドを読み、あなたが見つけた最高のアイデアに従いましょう。 +======= +All syntax rules described in this chapter (and in the style guides referenced) aim to increase the readability of your code. All of them are debatable. + +When we think about writing "better" code, the questions we should ask ourselves are: "What makes the code more readable and easier to understand?" and "What can help us avoid errors?" These are the main things to keep in mind when choosing and debating code styles. + +Reading popular style guides will allow you to keep up to date with the latest ideas about code style trends and best practices. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/03-code-quality/02-coding-style/figure-bracket-style.png b/1-js/03-code-quality/02-coding-style/figure-bracket-style.png deleted file mode 100644 index 112c2803ed..0000000000 Binary files a/1-js/03-code-quality/02-coding-style/figure-bracket-style.png and /dev/null differ diff --git a/1-js/03-code-quality/02-coding-style/figure-bracket-style@2x.png b/1-js/03-code-quality/02-coding-style/figure-bracket-style@2x.png deleted file mode 100644 index ce6e75c4dd..0000000000 Binary files a/1-js/03-code-quality/02-coding-style/figure-bracket-style@2x.png and /dev/null differ diff --git a/1-js/03-code-quality/03-comments/article.md b/1-js/03-code-quality/03-comments/article.md index 544379c343..62bc6bf760 100644 --- a/1-js/03-code-quality/03-comments/article.md +++ b/1-js/03-code-quality/03-comments/article.md @@ -4,7 +4,11 @@ 通常はそれを使用して、どうやって/なぜそのコードが動作するのかを説明します。 +<<<<<<< HEAD 一見、コメントすることは当たり前かもしれませんが、プログラム初心者は間違った思い込みをすることがあります。 +======= +At first sight, commenting might be obvious, but novices in programming often use them wrongly. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## 悪いコメント @@ -18,7 +22,11 @@ complex; code; ``` +<<<<<<< HEAD しかし良いコードでは、このような "説明的な" コメントは最小限にすべきです。真面目にそれらがなくても理解しやすいコードにするべきです。 +======= +But in good code, the amount of such "explanatory" comments should be minimal. Seriously, the code should be easy to understand without them. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 それに関して素晴らしいルールがあります。"もしもコードがコメントを必要とするほど不明瞭な場合、書き直すべきかもしれません"。 @@ -113,12 +121,17 @@ function addJuice(container) { 改めて言いますが、関数自身が何が行われているのかを伝えているので、コメントすることは何もありません。また分割するとコードの構造はより良くなります。各関数がすること、何を引数として取り、何を返すのかは明白です。 +<<<<<<< HEAD 現実では、完全に "説明的な" コメントを避けることはできません。複雑なアルゴリズムがあり、その最適化のための賢明な "微調整" がコードの中で行われることがあります。しかし、一般的にはコードをシンプルで自己記述的に保つよう努めるべきです。 +======= +In reality, we can't totally avoid "explanatory" comments. There are complex algorithms. And there are smart "tweaks" for purposes of optimization. But generally we should try to keep the code simple and self-descriptive. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## 良いコメント これまでの通り、説明的なコメントは通常良くありません。ではどんなコメントが良いのでしょう? +<<<<<<< HEAD アーキテクチャの説明をする : 高水準のコンポーネントの概要、相互作用の方法、様々な状況での制御フローを説明します... つまり -- コードの俯瞰図です。それは高水準のアーキテクチャ図のための特別な言語[UML](http://wikipedia.org/wiki/Unified_Modeling_Language)があります。これは間違いなく学ぶ価値があります。 @@ -147,6 +160,36 @@ function addJuice(container) { タスクがこのように解決されるのはなぜか? : 書かれていることは重要です。が、何が起こっていることを理解するためには、*書かれていないこと* がより重要かもしれません。なぜそのタスクがこの方法で正しく解決されるのか?コードは回答しません。 +======= +Describe the architecture +: Provide a high-level overview of components, how they interact, what's the control flow in various situations... In short -- the bird's eye view of the code. There's a special language [UML](http://wikipedia.org/wiki/Unified_Modeling_Language) to build high-level architecture diagrams explaining the code. Definitely worth studying. + +Document function parameters and usage +: There's a special syntax [JSDoc](http://en.wikipedia.org/wiki/JSDoc) to document a function: usage, parameters, returned value. + +For instance: +```js +/** + * Returns x raised to the n-th power. + * + * @param {number} x The number to raise. + * @param {number} n The power, must be a natural number. + * @return {number} x raised to the n-th power. + */ +function pow(x, n) { + ... +} +``` + +Such comments allow us to understand the purpose of the function and use it the right way without looking in its code. + +By the way, many editors like [WebStorm](https://www.jetbrains.com/webstorm/) can understand them as well and use them to provide autocomplete and some automatic code-checking. + +Also, there are tools like [JSDoc 3](https://github.com/jsdoc3/jsdoc) that can generate HTML-documentation from the comments. You can read more information about JSDoc at . + +Why is the task solved this way? +: What's written is important. But what's *not* written may be even more important to understand what's going on. Why is the task solved exactly this way? The code gives no answer. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 もしそのタスクを解決する方法が多数ある場合、なぜこれを選んだのでしょう?特に、それが最も明白なものではないとき。 @@ -157,12 +200,21 @@ function addJuice(container) { 解決策を説明するコメントはとても重要です。それらは正しい方向で開発を続けるのに役立ちます。 +<<<<<<< HEAD コードの捉えにくい特徴はある?それらはどこで使われる? : もしもコードが捉えにくく、紛らわしいものがある場合にはきっとコメントする価値があります。 +======= +Any subtle features of the code? Where they are used? +: If the code has anything subtle and counter-intuitive, it's definitely worth commenting. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## サマリ +<<<<<<< HEAD よい開発者であることを示す重要な指標は、コメントです: 何を書くか、また、何を書かないかさえ、指標となります。 +======= +An important sign of a good developer is comments: their presence and even their absence. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 よいコメントはコードを上手く維持し、時間が経った後でそこに戻ったときにも効果的に使えるようにします。 @@ -172,9 +224,16 @@ function addJuice(container) { - 関数の使用方法 - 重要な解決策、特にそれが一目瞭然でないとき +<<<<<<< HEAD **コメントを避ける:** - "どのようにコードが動くか" そして "それが何をするか" を伝える - コードを、コメントを必要としないような、シンプルで自己記述的にすることが不可能な場合にのみ置きます。 +======= +**Avoid comments:** + +- That tell "how code works" and "what it does". +- Put them in only if it's impossible to make the code so simple and self-descriptive that it doesn't require them. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 コメントはJSDoc3のような自動文書化ツールにも使われます: それらはコメントを解釈し、HTML-docs(または別の形式の文書)を生成します。 diff --git a/1-js/03-code-quality/04-ninja-code/article.md b/1-js/03-code-quality/04-ninja-code/article.md index 76639820f1..3de5043c11 100644 --- a/1-js/03-code-quality/04-ninja-code/article.md +++ b/1-js/03-code-quality/04-ninja-code/article.md @@ -1,5 +1,6 @@ # 忍者コード +<<<<<<< HEAD ```quote author="孔子" 子曰く、学びて思わざれば則ち罔し(くらし)、思いて学ばざれば則ち殆し(あやうし)。 ``` @@ -7,17 +8,37 @@ 過去のプログラマ忍者は、コード管理者泣かせのトリックを使いました。 レビューアは、テストタスクでそれらを探します。 新米の開発者は、プログラマ忍者よりもそれらのトリックを使うことがあります。 +======= + +```quote author="Confucius" +Learning without thought is labor lost; thought without learning is perilous. +``` + +Programmer ninjas of the past used these tricks to sharpen the mind of code maintainers. + +Code review gurus look for them in test tasks. + +Novice developers sometimes use them even better than programmer ninjas. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 これらを注意深く読んで、あなたが誰であるかを知ってください -- 忍者、初心者、またはコードレビューアでしょうか? -[cut] +<<<<<<< HEAD ```warn header="諷刺" ここに書いてあるのは悪いコードを書き込むルールです。 多くの人が忍者の道を辿ろうとしますが、これらの方法で成功することはほとんどありません。 ``` ## 簡潔が肝心(Brevity is the soul of wit) +======= +```warn header="Irony detected" +Many try to follow ninja paths. Few succeed. +``` + + +## Brevity is the soul of wit +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 できるだけコードを短くしましょう。あなたがどれだけ賢いかを示しましょう。 @@ -30,9 +51,15 @@ i = i ? i < 0 ? Math.max(0, len + i) : i : 0; ``` +<<<<<<< HEAD すごいですよね?もしあなたがこのように書いたら、この行を見て `i` の値が何かを理解しようとする開発者は、愉快な時間を過ごすことになります。そして、あなたのところに来て、答えを求めるでしょう。 より短いことが常により良いと教えましょう。彼を忍者の道に導きましょう。 +======= +Cool, right? If you write like that, a developer who comes across this line and tries to understand what is the value of `i` is going to have a merry time. Then come to you, seeking for an answer. + +Tell them that shorter is always better. Initiate them into the paths of ninja. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## 一文字の変数 @@ -40,13 +67,23 @@ i = i ? i < 0 ? Math.max(0, len + i) : i : 0; 道は隠れたもので、名も無い。それ唯、道は善くゆとりを与え、且つ、成すものだ。 ``` +<<<<<<< HEAD より速くコード化するためのもう1つの方法は、あらゆる場所で、`a`, `b` や `c` のように1文字の変数名を使うことです。 森の中の忍者のように、短い変数はコードの中で消えます。エディタの "検索" を使って見つけることはできません。たとえできたとしても、`a` や `b` が意味することを "解読" することはできないでしょう。 +======= +Another way to code faster is to use single-letter variable names everywhere. Like `a`, `b` or `c`. + +A short variable disappears in the code like a real ninja in the forest. No one will be able to find it using "search" of the editor. And even if someone does, they won't be able to "decipher" what the name `a` or `b` means. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ...しかし、例外があります。本物の忍者は決して `"for"` ループのカウンタに `i` を使いません。色々な所で使いますが、ここでは使いません。見回すと、より多くのエキゾチックな文字があります。例えば `x` または `y` です。 +<<<<<<< HEAD ループ本体が 1-2 ページ(できればより長くする)の場合は、ループカウンタとしてのエキゾチックな変数は特に効果があります。そのループを深く見ている人は、変数名 `x` がループカウンタであることはすぐには分からないでしょう。 +======= +An exotic variable as a loop counter is especially cool if the loop body takes 1-2 pages (make it longer if you can). Then if someone looks deep inside the loop, they won't be able to quickly figure out that the variable named `x` is the loop counter. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## 略語を使用する @@ -76,17 +113,31 @@ i = i ? i < 0 ? Math.max(0, len + i) : i : 0; ...しかし、もし `data` が既に使われていたらどうしましょう? その時は `value` を試みてみましょう、それもまた普遍的です。結局、変数は最終的に *値* を得るので。 +<<<<<<< HEAD - **変数をその型で命名する: `str`, `num`...** 試してみましょう。若い忍者は不思議に思うかもしれません -- このような名前は本当に忍者のためになるのでしょうか?はい、その通りです。 確かに、変数名は中身に何があるかを意味しています: 文字列、数値またはそれ以外の何か。しかし外部からこのコードを理解しようとするとき、実際にはまったく情報がないことに驚くでしょう。 +======= + Give them a try. A young initiate may wonder -- are such names really useful for a ninja? Indeed, they are! + + Sure, the variable name still means something. It says what's inside the variable: a string, a number or something else. But when an outsider tries to understand the code, they'll be surprised to see that there's actually no information at all! And will ultimately fail to alter your well-thought code. + + The value type is easy to find out by debugging. But what's the meaning of the variable? Which string/number does it store? + + There's just no way to figure out without a good meditation! +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 実際、値の型はデバッグで簡単にわかります。しかし変数が意味するものが何か?どの文字列/数値が格納されるのか?相当の熟慮なしでそれを理解する方法はありません。 - **...しかし、これ以上このような名前がなかったら?** 単に数値を付け足します: `data1, item2, elem5`... +<<<<<<< HEAD ## 注意力テスト +======= +Only a truly attentive programmer should be able to understand your code. But how to check that? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 本当に気が利くプログラマだけがあなたのコードを理解できます。しかし、どうやってそれをチェックしましょう? @@ -131,7 +182,11 @@ i = i ? i < 0 ? Math.max(0, len + i) : i : 0; 関数では、パラメータとして渡された変数だけを使用しようとしてください。 +<<<<<<< HEAD そうすれば、変数 *now* に入っているものを正確に特定するのは本当に難しくなります。また、それがどこから来るのかも。直感の弱い人は1行ずつコードを解析し、すべてのコードのブランチの変更を追跡する必要があります。 +======= +That would make it really hard to identify what's exactly in the variable *now*. And also where it comes from. The purpose is to develop the intuition and memory of a person reading the code. A person with weak intuition would have to analyze the code line-by-line and track the changes through every code branch. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 **そのアプローチの高度のパターンは、値をループや関数の途中で、こっそり (!) 似たものに置き換えることです。** @@ -147,9 +202,15 @@ function ninjaFunction(elem) { } ``` +<<<<<<< HEAD 関数の後半で、`elem` を使いたい仲間のプログラマは驚くでしょう... デバッグのときにだけ。コードを調べた後、自分が clone に対して処理をしていることに気づくでしょう。 経験豊富な忍者に対しても、殺人的に効果的です。 +======= +A fellow programmer who wants to work with `elem` in the second half of the function will be surprised... Only during the debugging, after examining the code they will find out that they're working with a clone! + +Seen in code regularly. Deadly effective even against an experienced ninja. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## 楽しみのためのアンダースコア @@ -163,7 +224,12 @@ function ninjaFunction(elem) { みんなにあなたの存在がどれだけ壮大かを見せてください! `superElement`, `megaFrame` や `niceItem` のような名前はきっと読者を啓発します。 +<<<<<<< HEAD 確かに、変数名には `super..`, `mega..`, `nice..` などが書かれています。が、その一方で -- それらはその詳細を何も示しません。読者はその隠された意味を探すために時間を割くかもしれません。 +======= +Indeed, from one hand, something is written: `super..`, `mega..`, `nice..` But from the other hand -- that brings no details. A reader may decide to look for a hidden meaning and meditate for an hour or two of their paid working time. + +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## 外部の変数と重ね合わせる @@ -172,7 +238,11 @@ function ninjaFunction(elem) { 暗闇に身を置く者は、明るい所の細々とした事を区別することができる。 ``` +<<<<<<< HEAD 関数の内側と外側で同じ変数名を使ってください。簡単で努力は不要です。 +======= +Use same names for variables inside and outside a function. As simple. No efforts to invent new names. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let *!*user*/!* = authenticateUser(); @@ -187,7 +257,14 @@ function render() { } ``` +<<<<<<< HEAD `render` の内側へジャンプしてきたプログラマは、恐らくローカルの `user` が外の `user` を隠していることに気づかないでしょう。 +======= +A programmer who jumps inside the `render` will probably fail to notice that there's a local `user` shadowing the outer one. + +Then they'll try to work with `user` assuming that it's the external variable, the result of `authenticateUser()`... The trap is sprung! Hello, debugger... + +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 そして、外部変数、`authenticateUser()` の結果であるという想定で `user` を使って処理しようと試みるでしょう... トラップが飛び出しました! デバッガーの出番です... @@ -195,7 +272,11 @@ function render() { 何も変えないように見える関数があります。 `isReady()`, `checkPermission()`, `findTags()`... これらの関数は、外側のものを何も変えることなく、データを計算したり、見つけて返したりすると想定されています。つまり、"副作用" なしです。 +<<<<<<< HEAD **本当に美しいトリックは、メインの処理に加えて "役立つ" アクションを追加することです。** +======= +An expression of dazed surprise on the face of your colleague when they see a function named `is..`, `check..` or `find...` changing something -- will definitely broaden your boundaries of reason. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 `is..`, `check`, または `find..` と名づけられた関数が何かを変更すると、同僚の驚きの表情は、きっとあなたの理性のたがを広げるでしょう。 @@ -220,7 +301,11 @@ function render() { **複数のアクションを1つに結合すると、あなたのコードを再利用から守ります。** +<<<<<<< HEAD 想像してみてください。emailのチェックだけ行い、メッセージを出力したくない開発者を。両方を行うあなたの関数 `validateEmail(email)` は彼にはマッチしません。そのため、彼はそれについて何かを尋ねるようなことはしないので、あなたの作業が中断させられることはありません。 +======= +Imagine, another developer wants only to check the email, and not output any message. Your function `validateEmail(email)` that does both will not suit them. So they won't break your meditation by asking anything about it. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## サマリ diff --git a/1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/solution.md b/1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/solution.md index 9fb040e01e..6cca940890 100644 --- a/1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/solution.md +++ b/1-js/03-code-quality/05-testing-mocha/3-pow-test-wrong/solution.md @@ -4,7 +4,11 @@ この方法で書くほうが簡単な場合もありますが、エラーが起きた時、何が間違っていたのかが明らかではありません。 +<<<<<<< HEAD もし複雑な実行フローの中でエラーが起きた場合、その時のデータを把握する必要があります。実際に *テストをデバッグ* しなければならなくなります。 +======= +If an error happens in the middle of a complex execution flow, then we'll have to figure out the data at that point. We'll actually have to *debug the test*. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 テストを、入出力が明白に書かれた複数の `it` ブロックに崩す方がはるかに良いです。 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 48b87c7cb5..3a7b2298db 100644 --- a/1-js/03-code-quality/05-testing-mocha/article.md +++ b/1-js/03-code-quality/05-testing-mocha/article.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD # mocha による自動テスト 多くのタスクがある場合、自動テストが使用されます。 @@ -5,6 +6,11 @@ それは実際には開発者の "最低限の教育" の一部です。 [cut] +======= +# Automated testing with Mocha + +Automated testing will be used in further tasks, and it's also widely used in real projects. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## なぜテストが必要なのでしょうか? @@ -22,14 +28,26 @@ これは非常に典型的なパターンです。何かを開発するとき、多くのユースケースの可能性を心に留めます。しかし、全ての変更のたびに手動ですべてをチェックするのをプログラマに期待するのは難しいです。なので、何か1つを直すと別の何かを壊してしまうことは容易に起こります。 +<<<<<<< HEAD **自動テストは、実際のコードに加えてテストが別々に書かれていることを意味します。これにより、それらのテストは簡単に実行でき、すべての主要なユースケースをチェックすることができます。** +======= +**Automated testing means that tests are written separately, in addition to the code. They run our functions in various ways and compare results with the expected.** +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## ビヘイビア駆動開発(BDD) +<<<<<<< HEAD [ビヘイビア駆動開発](http://en.wikipedia.org/wiki/Behavior-driven_development),もしくは BDD と呼ばれるテクニックを使ってみましょう。そのアプローチは多くのプロジェクトで使われています。なお、BDDは単なるテストについてのものではありません。それ以上です。 +======= +Let's start with a technique named [Behavior Driven Development](http://en.wikipedia.org/wiki/Behavior-driven_development) or, in short, BDD. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 **BDD には3つのことがあります。テスト、ドキュメント、そして例です。** +<<<<<<< HEAD +======= +To understand BDD, we'll examine a practical case of development. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 言葉は十分です。例を見てみましょう。 @@ -39,9 +57,13 @@ このタスクは例です: JavaScriptでは既にそれをするための `**` 演算子があります。が、ここではより複雑なタスクに対しても同様に適応が可能な *開発フロー* に集中します。 +<<<<<<< HEAD 私たちは、`pow` のコードを作成する前に、関数が何をすべきかを考えます。 このようなことに関する記述は *仕様*、もしくはスペックと呼ばれ、次のようになります: +======= +Such description is called a *specification* or, in short, a spec, and contains descriptions of use cases together with tests for them, like this: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js describe("pow", function() { @@ -56,22 +78,36 @@ describe("pow", function() { 上記の通り、仕様は三つの主要な構成要素を持っています: `describe("title", function() { ... })` +<<<<<<< HEAD : 何の機能を記述しているか。"ワーカー" -- `it` のブロックのことです、をグループ化するために使います。このケースでは、関数 `pow` について記述しています。 `it("title", function() { ... })` : `it` のタイトルでは、特定のユースケースを人間が読めるように記述し、2つ目の引数は、それをテストするための関数です。 +======= +: What functionality we're describing. In our case we're describing the function `pow`. Used to group "workers" -- the `it` blocks. + +`it("use case description", function() { ... })` +: In the title of `it` we *in a human-readable way* describe the particular use case, and the second argument is a function that tests it. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 `assert.equal(value1, value2)` : `it` ブロックの中のコードです。もし実装が正しければエラーなく実行されます。 +<<<<<<< HEAD 関数 `assert.*` は`pow`が期待通り動作するかをチェックするために使われます。ここでは、その1つを使っています -- `assert.equal`。それは引数を比較し、等しくない場合にエラーを返します。ここでは `pow(2, 3)` の結果が `8` と等しいかをチェックします。 他のタイプの比較やチェックもたくさんあります。 +======= + Functions `assert.*` are used to check whether `pow` works as expected. Right here we're using one of them -- `assert.equal`, it compares arguments and yields an error if they are not equal. Here it checks that the result of `pow(2, 3)` equals `8`. There are other types of comparisons and checks, that we'll add later. + +The specification can be executed, and it will run the test specified in `it` block. We'll see that later. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## 開発フロー 開発フローは通常このようになります: +<<<<<<< HEAD 1. 最も基本的な機能のテストと一緒に、初期仕様が書かれます。 2. 初期の実装がされます。 3. それが動くかを確認するため、テストフレームワークである [Mocha](http://mochajs.org/) (より詳細はこの後) を実行します。エラーが表示されます。すべてが動作するまで修正を行います。 @@ -79,10 +115,25 @@ describe("pow", function() { 5. まだ実装でサポートされていない可能性のある、より多くのユースケースを仕様(テスト)に追加します。テストは失敗し始めます。 6. 3に戻り、テストのエラーが無くなるまで実装を更新します。 7. 機能が完成するまで3-6のステップを繰り返します。 +======= +1. An initial spec is written, with tests for the most basic functionality. +2. An initial implementation is created. +3. To check whether it works, we run the testing framework [Mocha](http://mochajs.org/) (more details soon) that runs the spec. While the functionality is not complete, errors are displayed. We make corrections until everything works. +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. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 上で分かる通り、開発は *反復* です。仕様を書き、それを実装し、テストが通ることを確認し、さらにテストを書いて、それらが動作することを確認します。最終的に、動作する実装とテストができ上がります。 +<<<<<<< HEAD 私たちのケースでは、最初のステップは完了です: `pow` の初期仕様を持っています。なので実装していきましょう。が、その前にテストが動作すること(テスト自体は失敗しますが)を試してみましょう。 +======= +Let's see this development flow in our practical case. + +The first step is already complete: we have an initial spec for `pow`. Now, before making the implementation, let's use few JavaScript libraries to run the tests, just to see that they are working (they will all fail). +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## アクションの仕様 @@ -99,7 +150,11 @@ describe("pow", function() { ```html src="index.html" ``` +<<<<<<< HEAD ページは4つのパートに分かれています: +======= +The page can be divided into five parts: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 1. `` -- テストのためのサードパーティーのライブラリやスタイルの追加 2. テストするための関数の ` diff --git a/1-js/03-code-quality/05-testing-mocha/pow-2.view/test.js b/1-js/03-code-quality/05-testing-mocha/pow-2.view/test.js index 9a2f8fde7e..c803f0e619 100644 --- a/1-js/03-code-quality/05-testing-mocha/pow-2.view/test.js +++ b/1-js/03-code-quality/05-testing-mocha/pow-2.view/test.js @@ -4,8 +4,8 @@ describe("pow", function() { assert.equal(pow(2, 3), 8); }); - it("3 raised to power 3 is 27", function() { - assert.equal(pow(3, 3), 27); + it("3 raised to power 4 is 81", function() { + assert.equal(pow(3, 4), 81); }); }); diff --git a/1-js/03-code-quality/05-testing-mocha/pow-4.view/test.js b/1-js/03-code-quality/05-testing-mocha/pow-4.view/test.js index 10a032d03a..e5ce2ce433 100644 --- a/1-js/03-code-quality/05-testing-mocha/pow-4.view/test.js +++ b/1-js/03-code-quality/05-testing-mocha/pow-4.view/test.js @@ -1,6 +1,6 @@ describe("pow", function() { - describe("raises x to power n", function() { + describe("raises x to power 3", function() { function makeTest(x) { let expected = x * x * x; diff --git a/1-js/03-code-quality/05-testing-mocha/pow-full.view/test.js b/1-js/03-code-quality/05-testing-mocha/pow-full.view/test.js index a5a3459795..75ff5e99fd 100644 --- a/1-js/03-code-quality/05-testing-mocha/pow-full.view/test.js +++ b/1-js/03-code-quality/05-testing-mocha/pow-full.view/test.js @@ -1,6 +1,6 @@ describe("pow", function() { - describe("raises x to power n", function() { + describe("raises x to power 3", function() { function makeTest(x) { let expected = x * x * x; diff --git a/1-js/03-code-quality/05-testing-mocha/pow-nan.view/test.js b/1-js/03-code-quality/05-testing-mocha/pow-nan.view/test.js index a5a3459795..75ff5e99fd 100644 --- a/1-js/03-code-quality/05-testing-mocha/pow-nan.view/test.js +++ b/1-js/03-code-quality/05-testing-mocha/pow-nan.view/test.js @@ -1,6 +1,6 @@ describe("pow", function() { - describe("raises x to power n", function() { + describe("raises x to power 3", function() { function makeTest(x) { let expected = x * x * x; diff --git a/1-js/03-code-quality/06-polyfills/article.md b/1-js/03-code-quality/06-polyfills/article.md index 56b48b5ccd..6a897d1a83 100644 --- a/1-js/03-code-quality/06-polyfills/article.md +++ b/1-js/03-code-quality/06-polyfills/article.md @@ -20,10 +20,15 @@ JavaScriptエンジンのチームは何を最初に実装するかについて 実際には、Babelには2つのパートがあります: +<<<<<<< HEAD 1. 1つ目はトランスパイラのプログラムで、コードを書き直します。開発者は自身のPC上でそれを実行します。するとコードが古い標準仕様のものに書き直されます。そして、コードはWebサイトにデリバリされます。[webpack](http://webpack.github.io/) や [brunch](http://brunch.io/) のような現代のプロジェクトのビルドシステムは、すべてのコード変更時に自動でトランスパイラを実行する手段を提供しています。そのため、私たち側で時間を取ることはありません。 +======= +1. First, the transpiler program, which rewrites the code. The developer runs it on their own computer. It rewrites the code into the older standard. And then the code is delivered to the website for users. Modern project build systems like [webpack](http://webpack.github.io/) provide means to run transpiler automatically on every code change, so that it's very easy to integrate into development process. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 2. 2つ目は polyfillです。 +<<<<<<< HEAD トランスパイラはコードを書き直すので、構文機能はカバーされます。しかし、新しい関数のためには、それを実装する特別なスクリプトを書く必要があります。JavaScriptは非常に動的な言語であり、スクリプトは新しい機能を追加するだけでなく、組み込みの機能を変更することもできます。こうして、現代の標準に従って動作するようにすることができます。 ギャップを "埋めて"、欠けている実装を加えるスクリプトとして、"polyfill" という用語があります。 @@ -35,6 +40,18 @@ JavaScriptエンジンのチームは何を最初に実装するかについて 従って、私たちはトランスパイラをセットアップし、古いエンジンが最新の機能をサポートするように polyfill を追加する必要があります。 もし、私たちが最新のエンジンを対象とし、どこでもサポートされているもの以外の機能を使わないのであれば、Babelを使う必要はありません。 +======= + New language features may include new built-in functions and syntax constructs. + The transpiler rewrites the code, transforming syntax constructs into older ones. But as for new built-in functions, we need to implement them. JavaScript is a highly dynamic language, scripts may add/modify any functions, so that they behave according to the modern standard. + + A script that updates/adds new functions is called "polyfill". It "fills in" the gap and adds missing implementations. + + Two interesting polyfills are: + - [core js](https://github.com/zloirock/core-js) that supports a lot, allows to include only needed features. + - [polyfill.io](http://polyfill.io) service that provides a script with polyfills, depending on the features and user's browser. + +So, if we're going to use modern language features, a transpiler and a polyfill are necessary. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## チュートリアルの例 @@ -50,9 +67,16 @@ alert('Press the "Play" button in the upper-right corner to run'); ```` ```offline +<<<<<<< HEAD オフライン版で呼んでいるのであれば、例は実行できませんが、通常動作します :) ``` [Chrome Canary](https://www.google.com/chrome/browser/canary.html) はすべての例に対して上手く動きます。他の最新のブラウザもほとんど大丈夫です。 本番では、Babelを使ってコードを最近のブラウザに適した形に変換できるので、このような制限はありません。コードはどこでも動くでしょう。 +======= +As you're reading the offline version, in PDF examples are not runnable. In EPUB some of them can run. +``` + +Google Chrome is usually the most up-to-date with language features, good to run bleeding-edge demos without any transpilers, but other modern browsers also work fine. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js b/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js index e7f63284f9..db3283e49a 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js +++ b/1-js/04-object-basics/01-object/3-is-empty/_js.view/solution.js @@ -1,7 +1,7 @@ function isEmpty(obj) { for (let key in obj) { - // if the loop has started, there is a prorty + // if the loop has started, there is a property return false; } return true; -} \ No newline at end of file +} diff --git a/1-js/04-object-basics/01-object/3-is-empty/solution.md b/1-js/04-object-basics/01-object/3-is-empty/solution.md index 297c3af8a3..dc7e92c215 100644 --- a/1-js/04-object-basics/01-object/3-is-empty/solution.md +++ b/1-js/04-object-basics/01-object/3-is-empty/solution.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD 単にオブジェクトをループし、少なくとも1つプロパティがある場合にはすぐに `return false` を返します。 ```js @@ -8,3 +9,6 @@ function isEmpty(obj) { return true; } ``` +======= +Just loop over the object and `return false` immediately if there's at least one property. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/04-object-basics/01-object/article.md b/1-js/04-object-basics/01-object/article.md index 05521051aa..e07bba4b03 100644 --- a/1-js/04-object-basics/01-object/article.md +++ b/1-js/04-object-basics/01-object/article.md @@ -1,15 +1,25 @@ # オブジェクト +<<<<<<< HEAD チャプター で学んだ通り、JavaScriptには7つの型があります。そのうち6つは "プリミティブ" と呼ばれています。なぜなら、それらは1つの値だけを持つからです(文字列、数値、など任意の値になります)。 +======= +As we know from the chapter , there are eight data types in JavaScript. Seven of them are called "primitive", because their values contain only a single thing (be it a string or a number or whatever). +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 一方で、オブジェクトは様々なデータと、より複雑なエンティティのキー付けされた集合を保持するために使われます。JavaScriptでは、オブジェクトは言語のほぼすべての面で関連します。そのため、まず最初にオブジェクトを理解する必要があります。 +<<<<<<< HEAD [cut] オブジェクトは波括弧 `{…}`と任意の *プロパティ* の一覧から成ります。プロパティは "key:value" のペアで、`key` は文字列(もしくは"プロパティ名"と呼ばれます)で、`value` は何でも構いません。 オブジェクトは、署名されたファイルを持つキャビネットとしてイメージすることができます。すべてのデータは、キーによってそのファイルの中に格納されます。ファイルを名前で検索したり、ファイルの追加や削除は簡単です。 +======= +An object can be created with figure brackets `{…}` with an optional list of *properties*. A property is a "key: value" pair, where `key` is a string (also called a "property name"), and `value` can be anything. + +We can imagine an object as a cabinet with signed files. Every piece of data is stored in its file by the key. It's easy to find a file by its name or add/remove a file. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ![](object.svg) @@ -51,7 +61,11 @@ let user = { // オブジェクト プロパティ値へは、ドット表記を使ってアクセスすることができます。: ```js +<<<<<<< HEAD // オブジェクトのフィールドを取得: +======= +// get property values of the object: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 alert( user.name ); // John alert( user.age ); // 30 ``` @@ -85,15 +99,46 @@ let user = { ![](object-user-props.svg) +<<<<<<< HEAD ````smart header="末尾のカンマ" このリストの最後のプロパティはカンマで終わることがあります: +======= +The last property in the list may end with a comma: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let user = { name: "John", age: 30*!*,*/!* } ``` +<<<<<<< HEAD これは、「末尾」または「ぶら下がり」のカンマと呼ばれます。 これがあると、すべての行が同じ表記になるため、プロパティの追加/削除/移動が簡単になります。 +======= +That is called a "trailing" or "hanging" comma. Makes it easier to add/remove/move around properties, because all lines become alike. + +````smart header="Object with const can be changed" +Please note: an object declared as `const` *can* be modified. + +For instance: + +```js run +const user = { + name: "John" +}; + +*!* +user.name = "Pete"; // (*) +*/!* + +alert(user.name); // Pete +``` + +It might seem that the line `(*)` would cause an error, but no. The `const` fixes the value of `user`, but not its contents. + +The `const` would give an error only if we try to set `user=...` as a whole. + +There's another way to make constant object properties, we'll cover it later in the chapter . +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```` ## 角括弧 @@ -105,10 +150,17 @@ let user = { user.likes birds = true ``` +<<<<<<< HEAD これは、ドットはキーが有効な変数識別子であることが必要なためです。 代わりに、任意の文字列で動作する "角括弧表記" を使います: +======= +JavaScript doesn't understand that. It thinks that we address `user.likes`, and then gives a syntax error when comes across unexpected `birds`. +The dot requires the key to be a valid variable identifier. That implies: contains no spaces, doesn't start with a digit and doesn't include special characters (`$` and `_` are allowed). +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 + +There's an alternative "square bracket notation" that works with any string: ```js run let user = {}; @@ -134,7 +186,11 @@ let key = "likes birds"; user[key] = true; ``` +<<<<<<< HEAD ここで、変数 `key` は実行時に計算されるかもしれないし、ユーザの入力に依存するかもしれません。そして、プロパティにアクセスするときにそれを使います。これは素晴らしい柔軟性をもたらします。ドット表記の場合、同じようにはできません。 +======= +Here, the variable `key` may be calculated at run-time or depend on the user input. And then we use it to access the property. That gives us a great deal of flexibility. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: @@ -150,10 +206,25 @@ let key = prompt("What do you want to know about the user?", "name"); alert( user[key] ); // John ("name" が入力された場合) ``` +The dot notation cannot be used in a similar way: + +```js run +let user = { + name: "John", + age: 30 +}; + +let key = "name"; +alert( user.key ) // undefined +``` ### 算出プロパティ +<<<<<<< HEAD オブジェクトリテラルでは、角括弧を使うことができます。それは *算出プロパティ* と呼ばれます。 +======= +We can use square brackets in an object literal, when creating an object. That's called *computed properties*. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: @@ -195,6 +266,7 @@ let bag = { そのため、プロパティ名を知っていて単純な場合であれば、ドットが使われます。そして、もしより複雑な何かが必要なとき、角括弧に切り替えます。 +<<<<<<< HEAD ````smart header="予約語はプロパティ名として使用可能です" @@ -233,6 +305,11 @@ alert(obj.__proto__); // [object Object], 期待通りには動作しません ## プロパティの短縮構文 実際のコードでは、既存の変数をプロパティ名の値として使用することがよくあります。 +======= +## Property value shorthand + +In real code we often use existing variables as values for property names. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例えば: @@ -240,8 +317,13 @@ alert(obj.__proto__); // [object Object], 期待通りには動作しません function makeUser(name, age) { return { name: name, +<<<<<<< HEAD age: age // ...他のプロパティ +======= + age: age, + // ...other properties +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 }; } @@ -257,8 +339,13 @@ alert(user.name); // John function makeUser(name, age) { *!* return { +<<<<<<< HEAD name, // name: name と同じ age // age: age と同じ +======= + name, // same as name: name + age, // same as age: age +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 // ... }; */!* @@ -274,9 +361,63 @@ let user = { }; ``` +<<<<<<< HEAD ## 存在チェック 注目すべきオブジェクトの機能は、どんなプロパティへもアクセスできることです。プロパティが存在しない場合でもエラーにはなりません! 存在しないプロパティへのアクセスは、単に `undefined` を返します。これはプロパティが存在するかどうかを確認する非常に一般的な方法です -- その値を取得し、 undefined と比較します。: +======= + +## Property names limitations + +As we already know, a variable cannot have a name equal to one of language-reserved words like "for", "let", "return" etc. + +But for an object property, there's no such restriction: + +```js run +// these properties are all right +let obj = { + for: 1, + let: 2, + return: 3 +}; + +alert( obj.for + obj.let + obj.return ); // 6 +``` + +In short, there are no limitations on property names. They can be any strings or symbols (a special type for identifiers, to be covered later). + +Other types are automatically converted to strings. + +For instance, a number `0` becomes a string `"0"` when used as a property key: + +```js run +let obj = { + 0: "test" // same as "0": "test" +}; + +// both alerts access the same property (the number 0 is converted to string "0") +alert( obj["0"] ); // test +alert( obj[0] ); // test (same property) +``` + +There's a minor gotcha with a special property named `__proto__`. We can't set it to a non-object value: + +```js run +let obj = {}; +obj.__proto__ = 5; // assign a number +alert(obj.__proto__); // [object Object] - the value is an object, didn't work as intended +``` + +As we see from the code, the assignment to a primitive `5` is ignored. + +We'll cover the special nature of `__proto__` in [subsequent chapters](info:prototype-inheritance), and suggest the [ways to fix](info:prototype-methods) such behavior. + +## Property existence test, "in" operator + +A notable feature of objects in JavaScript, compared to many other languages, is that it's possible to access any property. There will be no error if the property doesn't exist! + +Reading a non-existing property just returns `undefined`. So we can easily test whether the property exists: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let user = {}; @@ -284,7 +425,11 @@ let user = {}; alert( user.noSuchProperty === undefined ); // true は "そのようなプロパティはありません" を意味する ``` +<<<<<<< HEAD プロパティの存在チェックのための特別な演算子 `"in"` もあります。 +======= +There's also a special operator `"in"` for that. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 構文は次の通りです: ```js @@ -302,17 +447,30 @@ alert( "blabla" in user ); // false, user.blabla は存在しない `in` の左側は *プロパティ名* である必要があることに注意してください。通常それは引用符で囲まれた文字列です。 +<<<<<<< HEAD もし引用符を除いた場合、テストされる実際のプロパティ名を持つ変数であることを意味します。例えば: +======= +If we omit quotes, that means a variable, it should contain the actual name to be tested. For instance: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let user = { age: 30 }; let key = "age"; +<<<<<<< HEAD alert( *!*key*/!* in user ); // true, キーから名前を取り、そのプロパティをチェック ``` ````smart header="`undefined` を格納しているプロパティに \"in\" を使う" 通常、厳密等価演算子 `"=== undefined"` チェックは正しく動作します。しかし、それが失敗する特別なケースがあります。 `"in"` は正しく動作します。 +======= +alert( *!*key*/!* in user ); // true, property "age" exists +``` + +Why does the `in` operator exist? Isn't it enough to compare against `undefined`? + +Well, most of the time the comparison with `undefined` works fine. But there's a special case when it fails, but `"in"` works correctly. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 それは、オブジェクトのプロパティは存在するが、`undefined` が格納されているときです: @@ -326,11 +484,17 @@ alert( obj.test ); // これは undefined, なので - このようなプロパ alert( "test" in obj ); // true, プロパティは存在します! ``` +<<<<<<< HEAD 上のコードでは、プロパティ `obj.test` は技術的には存在します。なので、 `in` 演算子は正しく動いています。 このようなシチュエーションは非常にまれです。なぜなら `undefined` は通常代入されないからです。殆どの場合、"不明" または "空" の値として `null` を使います。 ```` +======= +In the code above, the property `obj.test` technically exists. So the `in` operator works right. + +Situations like this happen very rarely, because `undefined` should not be explicitly assigned. We mostly use `null` for "unknown" or "empty" values. So the `in` operator is an exotic guest in the code. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## "for..in" ループ @@ -340,8 +504,13 @@ alert( "test" in obj ); // true, プロパティは存在します! 構文: ```js +<<<<<<< HEAD for(key in object) { // オブジェクトプロパティの各キーに対して本体を実行 +======= +for (key in object) { + // executes the body for each key among object properties +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 } ``` @@ -354,7 +523,7 @@ let user = { isAdmin: true }; -for(let key in user) { +for (let key in user) { // keys alert( key ); // name, age, isAdmin // values for the keys @@ -364,12 +533,20 @@ for(let key in user) { すべての "for" 構造は、ここでの `let key` のように、ループ内でループする変数を宣言することに留意してください。 +<<<<<<< HEAD また、ここでの `key` の代わりに、別の変数名を使うこともできます。例えば、`"for(let prop in obj)"` もまた広く使われています。 +======= +Also, we could use another variable name here instead of `key`. For instance, `"for (let prop in obj)"` is also widely used. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ### オブジェクトの順序付け +<<<<<<< HEAD オブジェクトは順序付けられますか?つまり、オブジェクトをループするとき、追加したのと同じ順序ですべてのプロパティを取得しますか?それを保証することはできるでしょうか? +======= +Are objects ordered? In other words, if we loop over an object, do we get all properties in the same order they were added? Can we rely on this? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 回答は、"特別な方法で順序付けられます"。: 整数値のプロパティはソートされます、それ以外は作成した順になります。以下、その詳細です。 @@ -385,7 +562,7 @@ let codes = { }; *!* -for(let code in codes) { +for (let code in codes) { alert(code); // 1, 41, 44, 49 } */!* @@ -406,10 +583,17 @@ for(let code in codes) { したがって、"49" は整数のプロパティ名です。なぜなら、整数の数に変換されて戻っても、それは変わらないからです。 しかし、 "+49"と "1.2"はそうではありません: ```js run +<<<<<<< HEAD // Math.trunc は小数部を取り除く組み込み関数 alert( String(Math.trunc(Number("49"))) ); // "49", 同じ, 整数プロパティ alert( String(Math.trunc(Number("+49"))) ); // "49", 同じではない ⇒ 非整数プロパティ alert( String(Math.trunc(Number("1.2"))) ); // "1", 同じではない ⇒ 非整数プロパティ +======= +// Math.trunc is a built-in function that removes the decimal part +alert( String(Math.trunc(Number("49"))) ); // "49", same, integer property +alert( String(Math.trunc(Number("+49"))) ); // "49", not same "+49" ⇒ not integer property +alert( String(Math.trunc(Number("1.2"))) ); // "1", not same "1.2" ⇒ not integer property +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` ```` @@ -443,13 +627,14 @@ let codes = { "+1": "USA" }; -for(let code in codes) { +for (let code in codes) { alert( +code ); // 49, 41, 44, 1 } ``` これで意図した通りに動作します。 +<<<<<<< HEAD ## 参照をコピーする オブジェクトとプリミティブの基本的な違いの1つは、オブジェクトは "参照によって" 格納、コピーされることです。 @@ -707,6 +892,9 @@ alert(clone.sizes.width); // 51, 他方から変更した結果が見えます ## サマリ +======= +## Summary +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 オブジェクトはいくつかの特別な機能を持つ連想配列です。 @@ -718,6 +906,7 @@ alert(clone.sizes.width); // 51, 他方から変更した結果が見えます - ドット表記: `obj.property` - 角括弧表記: `obj["property"]`。角括弧は変数からキーを取ることもできます。`obj[varWithKey]` のように。 +<<<<<<< HEAD 追加の演算子: - プロパティを削除: `delete obj.prop` - 与えられたキーを持つプロパティの存在チェック: `"key" in obj` @@ -726,6 +915,12 @@ alert(clone.sizes.width); // 51, 他方から変更した結果が見えます オブジェクトは、参照によって代入やコピーがされます。つまり、変数は "オブジェクトの値" ではなく、 値への "参照" (メモリ上のアドレス)を格納します。従って、このような変数をコピーしたり、それを関数の引数として渡すと、オブジェクトではなく参照がコピーされます。 コピーされた参照(プロパティの追加/削除など)によるすべての操作は、同じ単一のオブジェクトに対して実行されます。 "本当のコピー" (クローン) をするためには、`Object.assign` または [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep) を使います。 +======= +Additional operators: +- To delete a property: `delete obj.prop`. +- To check if a property with the given key exists: `"key" in obj`. +- To iterate over an object: `for (let key in obj)` loop. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 このチャプターで学んだのは、"普通のオブジェクト"、あるいは単に "オブジェクト" と呼ばれています。 @@ -738,4 +933,8 @@ JavaScriptには他にも多くの種類のオブジェクトがあります: 後で勉強しますが、それらは特別な機能を持っています。また、それらは "Array型" もしくは "Data型" と言われることがありますが、形式的には自身の型ではなく、単一の「オブジェクト」データ型に属しています。 そして、それをさまざまな方法で拡張しています。 +<<<<<<< HEAD Javascript のオブジェクトはとても強力です。ここでは本当に巨大なトピックのほんの始まりを学びました。この後に続くチャプターでは、オブジェクトをより深く見ていき、それらについてもっと学んでいきます。 +======= +Objects in JavaScript are very powerful. Here we've just scratched the surface of a topic that is really huge. We'll be closely working with objects and learning more about them in further parts of the tutorial. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/04-object-basics/02-object-copy/article.md b/1-js/04-object-basics/02-object-copy/article.md new file mode 100644 index 0000000000..c888722326 --- /dev/null +++ b/1-js/04-object-basics/02-object-copy/article.md @@ -0,0 +1,228 @@ +# Object copying, references + +One of the fundamental differences of objects vs primitives is that they are stored and copied "by reference". + +Primitive values: strings, numbers, booleans -- are assigned/copied "as a whole value". + +For instance: + +```js +let message = "Hello!"; +let phrase = message; +``` + +As a result we have two independent variables, each one is storing the string `"Hello!"`. + +![](variable-copy-value.svg) + +Objects are not like that. + +**A variable stores not the object itself, but its "address in memory", in other words "a reference" to it.** + +Here's the picture for the object: + +```js +let user = { + name: "John" +}; +``` + +![](variable-contains-reference.svg) + +Here, the object is stored somewhere in memory. And the variable `user` has a "reference" to it. + +**When an object variable is copied -- the reference is copied, the object is not duplicated.** + +For instance: + +```js no-beautify +let user = { name: "John" }; + +let admin = user; // copy the reference +``` + +Now we have two variables, each one with the reference to the same object: + +![](variable-copy-reference.svg) + +We can use any variable to access the object and modify its contents: + +```js run +let user = { name: 'John' }; + +let admin = user; + +*!* +admin.name = 'Pete'; // changed by the "admin" reference +*/!* + +alert(*!*user.name*/!*); // 'Pete', changes are seen from the "user" reference +``` + +The example above demonstrates that there is only one object. As if we had a cabinet with two keys and used one of them (`admin`) to get into it. Then, if we later use another key (`user`) we can see changes. + +## Comparison by reference + +The equality `==` and strict equality `===` operators for objects work exactly the same. + +**Two objects are equal only if they are the same object.** + +Here two variables reference the same object, thus they are equal: + +```js run +let a = {}; +let b = a; // copy the reference + +alert( a == b ); // true, both variables reference the same object +alert( a === b ); // true +``` + +And here two independent objects are not equal, even though both are empty: + +```js run +let a = {}; +let b = {}; // two independent objects + +alert( a == b ); // false +``` + +For comparisons like `obj1 > obj2` or for a comparison against a primitive `obj == 5`, objects are converted to primitives. We'll study how object conversions work very soon, but to tell the truth, such comparisons occur very rarely, usually as a result of a coding mistake. + +## 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? Create an independent copy, a clone? + +That's also doable, but a little bit more difficult, because there's no built-in method for that in JavaScript. Actually, that's rarely needed. Copying by reference is good most of the time. + +But if we really want that, then we need to 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 +``` + +Also we can use the method [Object.assign](mdn:js/Object/assign) for that. + +The syntax is: + +```js +Object.assign(dest, [src1, src2, src3...]) +``` + +- The first argument `dest` is a target object. +- Further arguments `src1, ..., srcN` (can be as many as needed) are source objects. +- It copies the properties of all source objects `src1, ..., srcN` into the target `dest`. In other words, properties of all arguments starting from the second are copied into the first object. +- The call returns `dest`. + +For instance, we can use it to merge several objects into one: +```js +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 } +``` + +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 replace `for..in` loop for simple cloning: + +```js +let user = { + name: "John", + age: 30 +}; + +*!* +let clone = Object.assign({}, user); +*/!* +``` + +It copies all properties of `user` into the empty object and returns it. + +## Nested cloning + +Until now we assumed that all properties of `user` are primitive. But properties can be references to other objects. What to do with them? + +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 the `user.sizes` is an object, it will be copied by reference. So `clone` and `user` will share the same sizes: + +Like this: + +```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++; // change a property from one place +alert(clone.sizes.width); // 51, see the result from the other one +``` + +To fix that, we should use the 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". + +There's a standard algorithm for deep cloning that handles the case above and more complex cases, called the [Structured cloning algorithm](https://html.spec.whatwg.org/multipage/structured-data.html#safe-passing-of-structured-data). + +We can use recursion to implement it. Or, not to 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 + +Objects are assigned and copied by reference. In other words, a variable stores not the "object value", but a "reference" (address in memory) for the value. So copying such a variable or passing it as a function argument copies that reference, not the object. + +All operations via copied references (like adding/removing properties) are performed on the same single object. + +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, such as [_.cloneDeep(obj)](https://lodash.com/docs#cloneDeep). diff --git a/1-js/04-object-basics/02-object-copy/variable-contains-reference.svg b/1-js/04-object-basics/02-object-copy/variable-contains-reference.svg new file mode 100644 index 0000000000..a59c9210ea --- /dev/null +++ b/1-js/04-object-basics/02-object-copy/variable-contains-reference.svg @@ -0,0 +1 @@ +username \ No newline at end of file diff --git a/1-js/04-object-basics/02-object-copy/variable-copy-reference.svg b/1-js/04-object-basics/02-object-copy/variable-copy-reference.svg new file mode 100644 index 0000000000..5d0bc15944 --- /dev/null +++ b/1-js/04-object-basics/02-object-copy/variable-copy-reference.svg @@ -0,0 +1 @@ +useradminname \ No newline at end of file diff --git a/1-js/04-object-basics/02-object-copy/variable-copy-value.svg b/1-js/04-object-basics/02-object-copy/variable-copy-value.svg new file mode 100644 index 0000000000..e09f521fea --- /dev/null +++ b/1-js/04-object-basics/02-object-copy/variable-copy-value.svg @@ -0,0 +1 @@ +"Hello!"message"Hello!"phrase \ No newline at end of file diff --git a/1-js/04-object-basics/02-garbage-collection/article.md b/1-js/04-object-basics/03-garbage-collection/article.md similarity index 81% rename from 1-js/04-object-basics/02-garbage-collection/article.md rename to 1-js/04-object-basics/03-garbage-collection/article.md index ce5931f4a3..32d6bb98e3 100644 --- a/1-js/04-object-basics/02-garbage-collection/article.md +++ b/1-js/04-object-basics/03-garbage-collection/article.md @@ -4,9 +4,13 @@ JavaScriptのメモリ管理は、自動で私たちの目には見えないよ 何かがもう必要なくなったとき、何が起こるでしょう?JavaScriptエンジンはどのようにそれを検出し、クリーンアップするのでしょうか? +<<<<<<< HEAD:1-js/04-object-basics/02-garbage-collection/article.md [cut] ## 到達性 +======= +## Reachability +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/03-garbage-collection/article.md JavaScriptのメモリ管理の主要なコンセプトは、*到達性* です。 @@ -156,11 +160,19 @@ John と Ann はまだリンクされているのは明らかです。両方は 次の "ガベージコレクション" のステップは定期的に実行されます: +<<<<<<< HEAD:1-js/04-object-basics/02-garbage-collection/article.md - ガベージコレクタはルートを取得し、 それらを "マーク" します(覚えます)。 - 次に、そこからの全ての参照へ訪れ、"マーク" します。 - 次に、マークされたオブジェクトへアクセスし、*それらの* 参照をマークします。訪問されたすべてのオブジェクトは記憶されているので、将来同じオブジェクトへは2度訪問しないようにします。 - ...そしてまだ訪れていない参照(ルートから到達可能)があるまで行います。 - マークされたオブジェクトを除いた、すべてのオブジェクトが削除されます。 +======= +- The garbage collector takes roots and "marks" (remembers) them. +- Then it visits and "marks" all references from them. +- Then it visits marked objects and marks *their* references. All visited objects are remembered, so as not to visit the same object twice in the future. +- ...And so on until every reachable (from the roots) references are visited. +- All objects except marked ones are removed. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/03-garbage-collection/article.md 例えば、我々のオブジェクト構造はこのように見えます: @@ -184,9 +196,15 @@ John と Ann はまだリンクされているのは明らかです。両方は ![](garbage-collection-5.svg) +<<<<<<< HEAD:1-js/04-object-basics/02-garbage-collection/article.md ガベージコレクションは、このような考え方で実行されます。 JavaScriptエンジンは多くの最適化を適用して実行を高速化し、実行に影響を与えません。 +======= +We can also imagine the process as spilling a huge bucket of paint from the roots, that flows through all references and marks all reachable objects. The unmarked ones are then removed. + +That's the concept of how garbage collection works. JavaScript engines apply many optimizations to make it run faster and not affect the execution. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/03-garbage-collection/article.md これらは最適化のいくつかです: @@ -194,7 +212,11 @@ JavaScriptエンジンは多くの最適化を適用して実行を高速化し - **インクリメンタルコレクション** -- 多くのオブジェクトがある場合、1度に全てのオブジェクトの集合をマークしようとすると、時間がかかってしまい、実行時に目に見える遅延を引き起こす可能性があります。なので、エンジンはガベージコレクションを小さく分割します。そしてそれらのピースが1つずつ、別々に実行されます。変更を追跡するため、多少の追加の記憶域を必要とはしますが、大きな遅延ではなく多くの小さな遅延になります。 - **アイドルタイムコレクション** -- ガベージコレクタは、CPUがアイドル状態のときにのみ実行を試み、実行への影響を減らします。 +<<<<<<< HEAD:1-js/04-object-basics/02-garbage-collection/article.md ガベージコレクションアルゴリズムには他にも最適化や加減があります。ここでそれらも説明したいのですが、止めておかなくてはいけません。なぜなら、エンジンによって、調整方法やテクニックの使い方がバラバラだからです。 そして、さらに重要なのは、エンジンの開発に伴って状況が変化するため、実際に必要がない場合には「先立って」深く進んでいくことはそれほど価値はありません。 もちろん、それが純粋な興味であれば、参照すると良いいくつかのリンクが下にあります。 +======= +There exist other optimizations and flavours of garbage collection algorithms. As much as I'd like to describe them here, I have to hold off, because different engines implement different tweaks and techniques. And, what's even more important, things change as engines develop, so studying deeper "in advance", without a real need is probably not worth that. Unless, of course, it is a matter of pure interest, then there will be some links for you below. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/03-garbage-collection/article.md ## サマリ @@ -210,6 +232,10 @@ JavaScriptエンジンは多くの最適化を適用して実行を高速化し もしあなたが低レベルのプログラミングに慣れている場合、V8のガベージコレクションに関するより詳細な情報はこの記事[A tour of V8: Garbage Collection](http://jayconrod.com/posts/55/a-tour-of-v8-garbage-collection).にあります。 +<<<<<<< HEAD:1-js/04-object-basics/02-garbage-collection/article.md [V8 blog](http://v8project.blogspot.com/) には、メモリ管理の変更に関する記事も随時掲載されています。 ガベージコレクションを学ぶには、V8の内部について一般的に学習し、V8エンジニアの一人として働いていた [Vyacheslav Egorov](http://mrale.ph) のブログを読むとよいでしょう。 "V8", それはインターネット上の記事で最もよくカバーされるからです。 他のエンジンでは、多くのアプローチは似ていますが、ガベージコレクションは多くの点で異なります。 +======= +[V8 blog](https://v8.dev/) also publishes articles about changes in memory management from time to time. Naturally, to learn the garbage collection, you'd better prepare by learning about V8 internals in general and read the blog of [Vyacheslav Egorov](http://mrale.ph) who worked as one of V8 engineers. I'm saying: "V8", because it is best covered with articles in the internet. For other engines, many approaches are similar, but garbage collection differs in many aspects. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/03-garbage-collection/article.md 低レベルの最適化が必要な場合は、エンジンに関する深い知識が必要です。 あなたが言語に精通した後の次のステップとしてそれを計画することが賢明でしょう。 diff --git a/1-js/04-object-basics/03-garbage-collection/family-delete-refs.svg b/1-js/04-object-basics/03-garbage-collection/family-delete-refs.svg new file mode 100644 index 0000000000..2ae1f664cb --- /dev/null +++ b/1-js/04-object-basics/03-garbage-collection/family-delete-refs.svg @@ -0,0 +1 @@ +<global variable>ObjectObjectwifefamilyname: "John"name: "Ann"motherObjectfatherhusband \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/family-no-family.svg b/1-js/04-object-basics/03-garbage-collection/family-no-family.svg new file mode 100644 index 0000000000..655d1982e3 --- /dev/null +++ b/1-js/04-object-basics/03-garbage-collection/family-no-family.svg @@ -0,0 +1 @@ +<global>ObjectObjectfatherwifename: "John"name: "Ann"motherObjecthusbandfamily: null \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/family-no-father-2.svg b/1-js/04-object-basics/03-garbage-collection/family-no-father-2.svg new file mode 100644 index 0000000000..11f4ada355 --- /dev/null +++ b/1-js/04-object-basics/03-garbage-collection/family-no-father-2.svg @@ -0,0 +1 @@ +Objectfamilyname: "Ann"motherObject<global> \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/family-no-father.svg b/1-js/04-object-basics/03-garbage-collection/family-no-father.svg new file mode 100644 index 0000000000..b76c868e04 --- /dev/null +++ b/1-js/04-object-basics/03-garbage-collection/family-no-father.svg @@ -0,0 +1 @@ +ObjectObjectwifefamilyname: "John"name: "Ann"motherObject<global> \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/family.svg b/1-js/04-object-basics/03-garbage-collection/family.svg new file mode 100644 index 0000000000..bec2f4ddcb --- /dev/null +++ b/1-js/04-object-basics/03-garbage-collection/family.svg @@ -0,0 +1 @@ +ObjectObjectfatherwifefamilyname: "John"name: "Ann"motherObjecthusband<global variable> \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/garbage-collection-1.svg b/1-js/04-object-basics/03-garbage-collection/garbage-collection-1.svg new file mode 100644 index 0000000000..2563c8185a --- /dev/null +++ b/1-js/04-object-basics/03-garbage-collection/garbage-collection-1.svg @@ -0,0 +1 @@ +<global> \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/garbage-collection-2.svg b/1-js/04-object-basics/03-garbage-collection/garbage-collection-2.svg new file mode 100644 index 0000000000..acd5025e9c --- /dev/null +++ b/1-js/04-object-basics/03-garbage-collection/garbage-collection-2.svg @@ -0,0 +1 @@ +<global> \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/garbage-collection-3.svg b/1-js/04-object-basics/03-garbage-collection/garbage-collection-3.svg new file mode 100644 index 0000000000..4421ec7846 --- /dev/null +++ b/1-js/04-object-basics/03-garbage-collection/garbage-collection-3.svg @@ -0,0 +1 @@ +<global> \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/garbage-collection-4.svg b/1-js/04-object-basics/03-garbage-collection/garbage-collection-4.svg new file mode 100644 index 0000000000..74adc81351 --- /dev/null +++ b/1-js/04-object-basics/03-garbage-collection/garbage-collection-4.svg @@ -0,0 +1 @@ +<global> \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/garbage-collection-5.svg b/1-js/04-object-basics/03-garbage-collection/garbage-collection-5.svg new file mode 100644 index 0000000000..abb127ab23 --- /dev/null +++ b/1-js/04-object-basics/03-garbage-collection/garbage-collection-5.svg @@ -0,0 +1 @@ +<global>unreachables \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/memory-user-john-admin.svg b/1-js/04-object-basics/03-garbage-collection/memory-user-john-admin.svg new file mode 100644 index 0000000000..dc4cce1c7f --- /dev/null +++ b/1-js/04-object-basics/03-garbage-collection/memory-user-john-admin.svg @@ -0,0 +1 @@ +username: "John"Objectadmin<global> \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/memory-user-john-lost.svg b/1-js/04-object-basics/03-garbage-collection/memory-user-john-lost.svg new file mode 100644 index 0000000000..e75b8d465e --- /dev/null +++ b/1-js/04-object-basics/03-garbage-collection/memory-user-john-lost.svg @@ -0,0 +1 @@ +name: "John"Objectuser: null<global> \ No newline at end of file diff --git a/1-js/04-object-basics/03-garbage-collection/memory-user-john.svg b/1-js/04-object-basics/03-garbage-collection/memory-user-john.svg new file mode 100644 index 0000000000..0191e3f07d --- /dev/null +++ b/1-js/04-object-basics/03-garbage-collection/memory-user-john.svg @@ -0,0 +1 @@ +username: "John"Object<global> \ No newline at end of file diff --git a/1-js/04-object-basics/04-object-methods/2-check-syntax/solution.md b/1-js/04-object-basics/04-object-methods/2-check-syntax/solution.md deleted file mode 100644 index 10713083c4..0000000000 --- a/1-js/04-object-basics/04-object-methods/2-check-syntax/solution.md +++ /dev/null @@ -1,37 +0,0 @@ -**エラーです**! - -やってみましょう: - -```js run -let user = { - name: "John", - go: function() { alert(this.name) } -} - -(user.go)() // error! -``` - -ほとんどのブラウザでのエラーメッセージは何を間違えているのか理解できません。 - -**`user = {...}` の後にセミコロンがないため、エラーになります。** - -JavaScript 括弧 `(user.go)()` の前にはセミコロンを想定していないので、このようにコードを解釈します: - -```js no-beautify -let user = { go:... }(user.go)() -``` - -そして、このようなジョイント式は構文的にはオブジェクト `{ go: ...}` を引数 `(user.go)` をもつ関数として呼びだすことができます。また、それは `let user` と同じ行で起こります。なので、`user` オブジェクトはまだ定義されていないのでエラーになります。 - -セミコロンを挿入すると、すべてうまく行きます。: - -```js run -let user = { - name: "John", - go: function() { alert(this.name) } -}*!*;*/!* - -(user.go)() // John -``` - -`(user.go)` の周りの括弧はここではなにもしないことに注意してください。通常それらは操作の順番のために設定されますが、ここではドット `.` がとにかく最初に動作するので影響がありません。セミコロンだけが関係します。 diff --git a/1-js/04-object-basics/04-object-methods/4-object-property-this/solution.md b/1-js/04-object-basics/04-object-methods/4-object-property-this/solution.md index 6ef536ba8e..284543bb5d 100644 --- a/1-js/04-object-basics/04-object-methods/4-object-property-this/solution.md +++ b/1-js/04-object-basics/04-object-methods/4-object-property-this/solution.md @@ -14,16 +14,39 @@ let user = makeUser(); alert( user.ref.name ); // Error: Cannot read property 'name' of undefined ``` +<<<<<<< HEAD これは `this` をセットするルールがオブジェクトリテラルを見ないためです。 ここで `makeUser()` の中の `this` 値は `undefined` です。なぜなら、関数として呼ばれており、メソッドではないためです。 また、オブジェクトリテラル自身は `this` に影響しません。`this` の値は関数全体で、コードブロックやオブジェクトリテラルはそれに影響しません。 +======= +That's because rules that set `this` do not look at object definition. Only the moment of call matters. + +Here the value of `this` inside `makeUser()` is `undefined`, because it is called as a function, not as a method with "dot" syntax. + +The value of `this` is one for the whole function, code blocks and object literals do not affect it. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 従って、`ref: this` は実際にはその関数の現在の `this` を取ります。 +<<<<<<< HEAD これは反対のケースです: +======= +We can rewrite the function and return the same `this` with `undefined` value: + +```js run +function makeUser(){ + return this; // this time there's no object literal +} + +alert( makeUser().name ); // Error: Cannot read property 'name' of undefined +``` +As you can see the result of `alert( makeUser().name )` is the same as the result of `alert( user.ref.name )` from the previous example. + +Here's the opposite case: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run function makeUser() { @@ -42,4 +65,8 @@ let user = makeUser(); alert( user.ref().name ); // John ``` +<<<<<<< HEAD これは動作します。なぜなら `user.ref()` はメソッドだからです。そして `this` の値はドット `.` の前のオブジェクトがセットされます。 +======= +Now it works, because `user.ref()` is a method. And the value of `this` is set to the object before dot `.`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/04-object-basics/04-object-methods/7-calculator/solution.md b/1-js/04-object-basics/04-object-methods/7-calculator/solution.md index 22c4bf187c..459997624e 100644 --- a/1-js/04-object-basics/04-object-methods/7-calculator/solution.md +++ b/1-js/04-object-basics/04-object-methods/7-calculator/solution.md @@ -1,6 +1,5 @@ - -```js run demo +```js run demo solution let calculator = { sum() { return this.a + this.b; @@ -20,4 +19,3 @@ calculator.read(); alert( calculator.sum() ); alert( calculator.mul() ); ``` - 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 316202853b..41a0412944 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 @@ -1,6 +1,6 @@ 解決策はすべての呼び出しでオブジェクト自身を返すことです。 -```js run +```js run demo let ladder = { step: 0, up() { 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 3947559b05..5032031a59 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 @@ -30,7 +30,11 @@ ladder.down(); ladder.showStep(); // 1 ``` +<<<<<<< HEAD `up` と `down` のコードを修正して、連鎖可能な呼び出しができるようにしてください。: +======= +Modify the code of `up`, `down` and `showStep` to make the calls chainable, like this: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js ladder.up().up().down().showStep(); // 1 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 5a0c421a90..555cb972fa 100644 --- a/1-js/04-object-basics/04-object-methods/article.md +++ b/1-js/04-object-basics/04-object-methods/article.md @@ -13,11 +13,17 @@ let user = { アクションは、JavaScriptではプロパティの中で関数で表現されます。 +<<<<<<< HEAD [cut] ## メソッド例 スタートとして、`user` が Hello と言うようにしましょう: +======= +## Method examples + +For a start, let's teach the `user` to say hello: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let user = { @@ -62,10 +68,17 @@ user.sayHi = sayHi; user.sayHi(); // Hello! ``` +<<<<<<< HEAD ```smart header="オブジェクト指向プログラミング" エンティティを表現するためにオブジェクトを使ってコードを書くとき、それは、[object-oriented programming](https://en.wikipedia.org/wiki/Object-oriented_programming), 略すと "OOP" とばれます。 OOPは大きなものであり、それ自体の興味深い科学です。 正しいエンティティを選択するにはどうすればいいですか? どのようにそれらの間の相互作用を整理しますか?それはアーキテクチャーであり、それらは E.Gamma, R.Helm, R.Johnson, J.Vissides による"Design Patterns: Elements of Reusable Object-Oriented Software" または G.Booch による "Object-Oriented Analysis and Design with Applications" などのような、そのトピックについての素晴らしい本があります。私たちは、チャプター の後半でそのトピックの表面について触れます。 +======= +```smart header="Object-oriented programming" +When we write our code using objects to represent entities, that's called [object-oriented programming](https://en.wikipedia.org/wiki/Object-oriented_programming), in short: "OOP". + +OOP is a big thing, an interesting science of its own. How to choose the right entities? How to organize the interaction between them? That's architecture, and there are great books on that topic, like "Design Patterns: Elements of Reusable Object-Oriented Software" by E. Gamma, R. Helm, R. Johnson, J. Vissides or "Object-Oriented Analysis and Design with Applications" by G. Booch, and more. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` ### メソッドの短縮表現 @@ -74,14 +87,19 @@ OOPは大きなものであり、それ自体の興味深い科学です。 正 ```js // これらのオブジェクトは同じことをします -let user = { +user = { sayHi: function() { alert("Hello"); } }; +<<<<<<< HEAD // メソッド簡略化はスッキリ見えますね let user = { +======= +// method shorthand looks better, right? +user = { +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 *!* sayHi() { // "sayHi: function()" と同じです */!* @@ -113,6 +131,7 @@ let user = { sayHi() { *!* + // "this" is the "current object" alert(this.name); */!* } @@ -168,9 +187,15 @@ admin.sayHi(); // Whoops! sayHi() の中で古い名前が使われました! ## "this" はバインドされていません +<<<<<<< HEAD JavaScriptでは、 "this" キーワードは他のほとんどのプログラミング言語とは異なる振る舞いをします。まず、どの関数にでも使えます。 このようなコードも構文エラーにはなりません: +======= +In JavaScript, keyword `this` behaves unlike most other programming languages. It can be used in any function. + +There's no syntax error in the following example: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js function sayHi() { @@ -178,9 +203,15 @@ function sayHi() { } ``` +<<<<<<< HEAD `this` の値は実行時に評価されます。そしてそれは何にでもなれます。 例えば、異なるオブジェクトから呼ばれた場合、同じ関数でも異なる "this" を持つ可能性があります: +======= +The value of `this` is evaluated during the run-time, depending on the context. + +For instance, here the same function is assigned to two different objects and has different "this" in the calls: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let user = { name: "John" }; @@ -191,7 +222,11 @@ function sayHi() { } *!* +<<<<<<< HEAD // 2つのオブジェクトで同じ関数を使う +======= +// use the same function in two objects +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 user.f = sayHi; admin.f = sayHi; */!* @@ -204,7 +239,14 @@ admin.f(); // Admin (this == admin) admin['f'](); // Admin (ドットでも角括弧でも問題なくメソッドにアクセスできます) ``` +<<<<<<< HEAD 実際、オブジェクトまったくなしで関数を呼び出すこともできます: +======= +The rule is simple: if `obj.f()` is called, then `this` is `obj` during the call of `f`. So it's either `user` or `admin` in the example above. + +````smart header="Calling without an object: `this == undefined`" +We can even call the function without an object at all: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run function sayHi() { @@ -216,13 +258,21 @@ sayHi(); // undefined このケースでは、 strict モードでは `this` は `undefined` になります。もし `this.name` にアクセスしようとするとエラーになります。 +<<<<<<< HEAD 非 strict モード(誰かが `use strict` を忘れた場合)では、このようなケースでは `this` の値は *グローバルオブジェクト* (ブラウザでは `window`, 後ほど学びます)になります。これは `"use strict"` が修正した歴史的な振る舞いです。 一般的に、オブジェクトなしで `this` を使う関数の呼び出しは、普通ではなくプログラム上の誤りであることに注意してください。もし関数が `this` を持っていたら、それは通常オブジェクトコンテキストで呼ばれることを意味しています。 +======= +In non-strict mode the value of `this` in such case will be the *global object* (`window` in a browser, we'll get to it later in the chapter [](info:global-object)). This is a historical behavior that `"use strict"` fixes. + +Usually such call is a programming error. If there's `this` inside a function, it expects to be called in an object context. +```` +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```smart header="バインドしていない `this` の結果" もしあなたが別のプログラミング言語から来ていたら、恐らく "`this` のバインド" の考えに慣れているでしょう。それは、オブジェクトに定義されたメソッドは常にそのオブジェクトを参照する `this` を持っている、と言うものです。 +<<<<<<< HEAD JavaScriptでは、 `this` は "自由" です。その値は実行時に評価され、メソッドが宣言されている場所には依存せず、 "ドットの前の" オブジェクトが何であるか、に依存します。 実行時に評価される `this` の概念はプラスとマイナス両方を持っています。一方では、関数は異なるオブジェクトで再利用することができます。他方では、より大きな柔軟性はミスを導きやすいです。 @@ -321,6 +371,16 @@ hi(); // Error, this は undefined なので なので、結果として、`this` の値は、関数がドット `obj.method()`、もしくは角括弧 `obj[method]()`構文を使って直接呼び出された場合のみ正しく渡されます。このチュートリアルの後半では、func.bind() など、この問題を解決するためのさまざまな方法を学びます。 ## アロー関数は "this" を持ちません +======= +In JavaScript `this` is "free", its value is evaluated at call-time and does not depend on where the method was declared, but rather on what object is "before the dot". + +The concept of run-time evaluated `this` has both pluses and minuses. On the one hand, a function can be reused for different objects. On the other hand, the greater flexibility creates more possibilities for mistakes. + +Here our position is not to judge whether this language design decision is good or bad. We'll understand how to work with it, how to get benefits and avoid problems. +``` + +## Arrow functions have no "this" +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 アロー関数は特別です: それらは "自身の" `this` を持ちません。もしこのような関数で `this` を参照した場合、外部の "通常の" 関数から取得されます。 @@ -347,9 +407,16 @@ user.sayHi(); // Ilya - メソッドを使うと、オブジェクトは `object.doSomething()` のように "振る舞う" ことができます。 - メソッドはオブジェクトを `this` で参照することができます。 +<<<<<<< HEAD `this` の値は実行時に定義されます。 - 関数が宣言されている場合、`this` を使うことができますが、その `this` は関数が呼び出されるまで値を持っていません。 - その関数はオブジェクト間でコピーできます。 - 関数が "メソッド" 構文で呼び出されたとき: `object.method()`, 呼び出し中の `this` の値は、`object` です。 +======= +The value of `this` is defined at run-time. +- When a function is declared, it may use `this`, but that `this` has no value until the function is called. +- A function can be copied between objects. +- When a function is called in the "method" syntax: `object.method()`, the value of `this` during the call is `object`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 アロー関数は特別であることに注意してください: それは `this` を持っていません。`this` がアロー関数の中でアクセスされるとき、それは外側から取得されます。 diff --git a/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/solution.md b/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/solution.md index e8a8e4af7e..8e27cef517 100644 --- a/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/solution.md +++ b/1-js/04-object-basics/06-constructor-new/1-two-functions-one-object/solution.md @@ -2,7 +2,11 @@ もし関数がオブジェクトを返す場合、`new` は `this` の代わりにそれを返します。 +<<<<<<< HEAD なので、例えば、同じ外部で定義されたオブジェクト `obj` を返すことで実現できます。: +======= +So they can, for instance, return the same externally defined object `obj`: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run no-beautify let obj = {}; diff --git a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/solution.md b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/solution.md index e5583c5d01..86bb65416d 100644 --- a/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/solution.md +++ b/1-js/04-object-basics/06-constructor-new/2-calculator-constructor/solution.md @@ -1,5 +1,3 @@ - - ```js run demo function Calculator() { diff --git a/1-js/04-object-basics/06-constructor-new/3-accumulator/task.md b/1-js/04-object-basics/06-constructor-new/3-accumulator/task.md index 13821c5439..cf5420bf2f 100644 --- a/1-js/04-object-basics/06-constructor-new/3-accumulator/task.md +++ b/1-js/04-object-basics/06-constructor-new/3-accumulator/task.md @@ -16,10 +16,19 @@ importance: 5 これはそのコードのデモです: ```js +<<<<<<< HEAD let accumulator = new Accumulator(1); // 初期値 1 accumulator.read(); // ユーザの入力値の加算 accumulator.read(); // ユーザの入力値の加算 alert(accumulator.value); // それらの値の合計を表示 +======= +let accumulator = new Accumulator(1); // initial value 1 + +accumulator.read(); // adds the user-entered value +accumulator.read(); // adds the user-entered value + +alert(accumulator.value); // shows the sum of these values +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` [demo] 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 70d43bbde4..4da8d0329b 100644 --- a/1-js/04-object-basics/06-constructor-new/article.md +++ b/1-js/04-object-basics/06-constructor-new/article.md @@ -4,9 +4,13 @@ それは、コンストラクタ関数と `"new"` 演算子を使うことで実現できます。 +<<<<<<< HEAD [cut] ## コンストラクタ 関数 +======= +## Constructor function +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 コンストラクタ関数は技術的には通常の関数です。それには2つの慣習があります: @@ -29,7 +33,11 @@ alert(user.name); // Jack alert(user.isAdmin); // false ``` +<<<<<<< HEAD `new User(...)` として関数が実行されたとき、次のようなステップになります: +======= +When a function is executed with `new`, it does the following steps: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 1. 新しい空のオブジェクトが作られ、 `this` に代入されます。 2. 関数本体を実行します。通常は `this` を変更し、それに新しいプロパティを追加します。 @@ -53,7 +61,11 @@ function User(name) { } ``` +<<<<<<< HEAD なので、`new User("Jack")` の結果は次と同じオブジェクトです: +======= +So `let user = new User("Jack")` gives the same result as: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let user = { @@ -84,7 +96,15 @@ let user = new function() { コンストラクタはどこにも保存されず、単に作られて呼び出されただけなので2度は呼び出せません。なので、このやり方は将来再利用することなく、単一のオブジェクトを構成するコードをカプセル化することを目指しています。 ```` +<<<<<<< HEAD ## 二重構文コンストラクタ: new.target +======= +## Constructor mode test: new.target + +```smart header="Advanced stuff" +The syntax from this section is rarely used, skip it unless you want to know everything. +``` +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 関数の中では、`new.target` プロパティを使うことで、それが `new` で呼ばれたかそうでないかを確認することができます。 @@ -95,14 +115,32 @@ function User() { alert(new.target); } +<<<<<<< HEAD // new なし: +======= +// without "new": +*!* +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 User(); // undefined +*/!* +<<<<<<< HEAD // new あり: +======= +// with "new": +*!* +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 new User(); // function User { ... } +*/!* ``` +<<<<<<< HEAD これは、 `new` の場合と、通常呼び出し両方の構文が同じように動作するようにするために使用できます: +======= +That can be used inside the function to know whether it was called with `new`, "in constructor mode", or without it, "in regular mode". + +We can also make both `new` and regular calls to do the same, like this: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run function User(name) { @@ -117,7 +155,13 @@ let john = User("John"); // new User へのリダイレクト alert(john.name); // John ``` +<<<<<<< HEAD このアプローチは、構文をより柔軟にするためにライブラリの中で使われることがあります。が、恐らくどこへでもこれを使うのは良いことではありません。なぜなら、 `new` を省略すると、何をしているのかが少し分かりにくくなるからです。 `new` があれば、新しいオブジェクトが作られることを知ることができます。 +======= +This approach is sometimes used in libraries to make the syntax more flexible. So that people may call the function with or without `new`, and it still works. + +Probably not a good thing to use everywhere though, because omitting `new` makes it a bit less obvious what's going on. With `new` we all know that the new object is being created. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## コンストラクタからの返却 @@ -125,8 +169,13 @@ alert(john.name); // John しかし、もし `return` 文があった場合はどうなるでしょう。ルールはシンプルです: +<<<<<<< HEAD - もし `return` がオブジェクトと一緒に呼ばれた場合、`this` の代わりにそれを返します。 - もし `return` がプリミティブと一緒に呼ばれた場合、それは無視されます。 +======= +- If `return` is called with an object, then the object is returned instead of `this`. +- If `return` is called with a primitive, it's ignored. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 言い換えると、オブエジェクトの`return` はそのオブジェクトを返し、それ以外のケースでは `this` が返却されます。 @@ -137,10 +186,17 @@ function BigUser() { this.name = "John"; +<<<<<<< HEAD return { name: "Godzilla" }; // <-- オブジェクトを返す } alert( new BigUser().name ); // Godzilla, オブジェクトを取得 ^^ +======= + return { name: "Godzilla" }; // <-- returns this object +} + +alert( new BigUser().name ); // Godzilla, got that object +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` また、これは空の `return` の例です(`return` の後に プリミティブを置いた場合も同じです) @@ -150,10 +206,14 @@ function SmallUser() { this.name = "John"; +<<<<<<< HEAD return; // 実行が終了し, this を返す // ... +======= + return; // <-- returns this +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 } alert( new SmallUser().name ); // John @@ -204,7 +264,13 @@ john = { */ ``` +<<<<<<< HEAD ## サマリ +======= +To create complex objects, there's a more advanced syntax, [classes](info:classes), that we'll cover later. + +## Summary +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 - コンストラクタ関数、もしくは手短にコンストラクタ、は通常の関数ですが大文字から始まる名前を持つと言う共通の合意があります。 - コンストラクタ関数は `new` を使ってのみ呼び出されるべきです。この呼び出しは、最初に空の `this` を作成し、最後に追加された `this` を返すことを意味します。 @@ -216,5 +282,9 @@ JavaScript は多くの組み込みのオブジェクトでコンストラクタ ```smart header="オブジェクト, 我々は戻ってきます!" このチャプターでは、オブジェクトとコンストラクタについての基礎のみを説明しています。これらは、次のチャプターでデータ型と関数についてより深く学ぶために不可欠です。 +<<<<<<< HEAD それを学んだ後、チャプター では、オブジェクトに戻り、継承やクラスを含めそれらを詳細に説明します。 +======= +After we learn that, we return to objects and cover them in-depth in the chapters and . +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` diff --git a/1-js/04-object-basics/07-optional-chaining/article.md b/1-js/04-object-basics/07-optional-chaining/article.md new file mode 100644 index 0000000000..89363e4325 --- /dev/null +++ b/1-js/04-object-basics/07-optional-chaining/article.md @@ -0,0 +1,176 @@ + +# Optional chaining '?.' + +[recent browser="new"] + +The optional chaining `?.` is an error-proof way to access nested object properties, even if an intermediate property doesn't exist. + +## The problem + +If you've just started to read the tutorial and learn JavaScript, maybe the problem hasn't touched you yet, but it's quite common. + +For example, some of our users have addresses, but few did not provide them. Then we can't safely read `user.address.street`: + +```js run +let user = {}; // the user happens to be without address + +alert(user.address.street); // Error! +``` + +Or, in the web development, we'd like to get an information about an element on the page, but it may not exist: + +```js run +// Error if the result of querySelector(...) is null +let html = document.querySelector('.my-element').innerHTML; +``` + +Before `?.` appeared in the language, the `&&` operator was used to work around that. + +For example: + +```js run +let user = {}; // user has no address + +alert( user && user.address && user.address.street ); // undefined (no error) +``` + +AND'ing the whole path to the property ensures that all components exist, but is cumbersome to write. + +## Optional chaining + +The optional chaining `?.` stops the evaluation and returns `undefined` if the part before `?.` is `undefined` or `null`. + +Further in this article, for brevity, we'll be saying that something "exists" if it's not `null` and not `undefined`. + + +Here's the safe way to access `user.address.street`: + +```js run +let user = {}; // user has no address + +alert( user?.address?.street ); // undefined (no error) +``` + +Reading the address with `user?.address` works even if `user` object doesn't exist: + +```js run +let user = null; + +alert( user?.address ); // undefined + +alert( user?.address.street ); // undefined +alert( user?.address.street.anything ); // undefined +``` + +Please note: the `?.` syntax works exactly where it's placed, not any further. + +In the last two lines the evaluation stops immediately after `user?.`, never accessing further properties. But if the `user` actually exists, then the further intermediate properties, such as `user.address` must exist. + +```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 be there, but `address` is optional, then `user.address?.street` would be better. + +So, if `user` happens to be undefined due to a mistake, we'll know about it and fix it. Otherwise, coding errors can be silenced where not appropriate, and become more difficult to debug. +``` + +````warn header="The variable before `?.` must exist" +If there's no variable `user`, then `user?.anything` triggers an error: + +```js run +// ReferenceError: user is not defined +user?.address; +``` +The optional chaining only tests for `null/undefined`, doesn't interfere with any other language mechanics. +```` + +## Short-circuiting + +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: + +```js run +let user = null; +let x = 0; + +user?.sayHi(x++); // nothing happens + +alert(x); // 0, value not incremented +``` + +## Other cases: ?.(), ?.[] + +The optional chaining `?.` is not an operator, but a special syntax construct, that also works with functions and square brackets. + +For example, `?.()` is used to call a function that may not exist. + +In the code below, some of our users have `admin` method, and some don't: + +```js run +let user1 = { + admin() { + alert("I am admin"); + } +} + +let user2 = {}; + +*!* +user1.admin?.(); // I am admin +user2.admin?.(); +*/!* +``` + +Here, in both lines we first use the dot `.` to get `admin` property, because the user object must exist, so it's safe read from it. + +Then `?.()` checks the left part: if the admin function exists, then it runs (for `user1`). Otherwise (for `user2`) 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. + +```js run +let user1 = { + firstName: "John" +}; + +let user2 = null; // Imagine, we couldn't authorize the user + +let key = "firstName"; + +alert( user1?.[key] ); // John +alert( user2?.[key] ); // undefined + +alert( user1?.[key]?.something?.not?.existing); // undefined +``` + +Also we can use `?.` with `delete`: + +```js run +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: + +```js run +// the idea of the code below is to write user.name, if user exists + +user?.name = "John"; // Error, doesn't work +// because it evaluates to undefined = "John" +``` + +## Summary + +The `?.` syntax has three forms: + +1. `obj?.prop` -- returns `obj.prop` if `obj` exists, otherwise `undefined`. +2. `obj?.[prop]` -- returns `obj[prop]` if `obj` exists, otherwise `undefined`. +3. `obj?.method()` -- calls `obj.method()` if `obj` exists, otherwise returns `undefined`. + +As we can see, all of them are straightforward and simple to use. The `?.` checks the left part for `null/undefined` and allows the evaluation to proceed if it's not so. + +A chain of `?.` allows to safely access nested properties. + +Still, we should apply `?.` carefully, only where it's ok that the left part doesn't to exist. + +So that it won't hide programming errors from us, if they occur. diff --git a/1-js/04-object-basics/03-symbol/article.md b/1-js/04-object-basics/08-symbol/article.md similarity index 61% rename from 1-js/04-object-basics/03-symbol/article.md rename to 1-js/04-object-basics/08-symbol/article.md index 62a7ddadff..abda8bc3e7 100644 --- a/1-js/04-object-basics/03-symbol/article.md +++ b/1-js/04-object-basics/08-symbol/article.md @@ -3,13 +3,21 @@ 仕様によると、オブジェクトのプロパティのキーは文字列型、もしくはシンボル型のいずれかです。数値ではなく、真偽値でもなく、文字列またはシンボル、それら2つの型だけです。 +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md 私たちはこれまで文字列だけ見てきました。今シンボルが我々に与えてくれるアドバンテージを見てみましょう。 [cut] +======= +Till now we've been using only strings. Now let's see the benefits that symbols can give us. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md ## シンボル +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md "シンボル" 値はユニークな識別子を表現します。 +======= +A "symbol" represents a unique identifier. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md このタイプの値は、`Symbol()` を使って作ることができます: @@ -18,7 +26,11 @@ let id = Symbol(); ``` +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md また、シンボルに説明を与えることもでき(シンボル名と呼びます)、デバッグ目的で便利です。 +======= +Upon creation, we can give symbol a description (also called a symbol name), mostly useful for debugging purposes: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md ```js // id は "id" という説明を持つ symbol です @@ -52,7 +64,13 @@ alert(id); // TypeError: Cannot convert a Symbol value to a string */!* ``` +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md もし本当にシンボルを表示したい場合は、このように `toString()` を呼ぶ必要があります: +======= +That's a "language guard" against messing up, because strings and symbols are fundamentally different and should not accidentally convert one into another. + +If we really want to show a symbol, we need to explicitly call `.toString()` on it, like here: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md ```js run let id = Symbol("id"); *!* @@ -60,19 +78,42 @@ alert(id.toString()); // Symbol(id), これは動作します */!* ``` +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md これは、文字列とシンボルが根本的に異なるものであり、それを変換すべきではないため、混乱を避けるための「言語によるガード」です。 +======= +Or get `symbol.description` property to show the description only: +```js run +let id = Symbol("id"); +*!* +alert(id.description); // id +*/!* +``` + +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md ```` ## "隠れた" プロパティ +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md シンボルを使うと、オブジェクトに "隠れた" プロパティを作ることができます。他のコードがアクセスしたり上書きしたりすることはありません。 例えば、オブジェクト `user` に "識別子" を格納したい場合、そのキーとしてシンボルを使うことができます: +======= +Symbols allow us to create "hidden" properties of an object, that no other part of code can accidentally access or overwrite. + +For instance, if we're working with `user` objects, that belong to a third-party code. We'd like to add identifiers to them. + +Let's use a symbol key for it: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md ```js run -let user = { name: "John" }; +let user = { // belongs to another code + name: "John" +}; + let id = Symbol("id"); +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md user[id] = "ID Value"; alert( user[id] ); // キーとして symbol を使ってデータにアクセスできます ``` @@ -82,6 +123,18 @@ alert( user[id] ); // キーとして symbol を使ってデータにアクセ それを知るため、より深い例を作ってみましょう。 別のスクリプトが、独自の目的のために自身の "id" プロパティを `user` の中に持ちたいとします。それは別のJavaScriptライブラリの場合もあり、スクリプトは完全にお互いを認識していない状況とします。 +======= +user[id] = 1; + +alert( user[id] ); // we can access the data using the symbol as the key +``` + +What's the benefit of using `Symbol("id")` over a string `"id"`? + +As `user` objects belongs to another code, and that code also works with them, we shouldn't just add any fields to it. That's unsafe. But a symbol cannot be accessed accidentally, the third-party code probably won't even see it, so it's probably all right to do. + +Also, imagine that another script wants to have its own identifier inside `user`, for its own purposes. That may be another JavaScript library, so that the scripts are completely unaware of each other. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md そして、そのスクリプトは自身の `Symbol("id")` を作ります。: @@ -92,13 +145,20 @@ let id = Symbol("id"); user[id] = "Their id value"; ``` +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md たとえ同じ名前でもシンボルは常に異なるため、衝突は起こりません。 今、同じ目的のためにシンボルの代わりに文字列 `"id"` を使ったとすると、衝突が発生する *かもしれません*。 +======= +There will be no conflict between our and their identifiers, because symbols are always different, even if they have the same name. + +...But if we used a string `"id"` instead of a symbol for the same purpose, then there *would* be a conflict: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md ```js run let user = { name: "John" }; +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md // 我々のスクリプトは "id" プロパティを使います user.id = "ID Value"; @@ -106,12 +166,27 @@ user.id = "ID Value"; user.id = "Their id value" // boom! 上書きされます! 同僚に危害を加えるつもりはありませんでした。が、してしまいました! +======= +// Our script uses "id" property +user.id = "Our id value"; + +// ...Another script also wants "id" for its purposes... + +user.id = "Their id value" +// Boom! overwritten by another script! +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md ``` ### リテラルのシンボル +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md オブジェクトリテラルの中でシンボルを使いたい場合は、角括弧で囲む必要があります。 このように: +======= +If we want to use a symbol in an object literal `{...}`, we need square brackets around it. + +Like this: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md ```js let id = Symbol("id"); @@ -119,7 +194,11 @@ let id = Symbol("id"); let user = { name: "John", *!* +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md [id]: 123 // 単に "id: 123" ではありません +======= + [id]: 123 // not "id: 123" +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md */!* }; ``` @@ -147,7 +226,11 @@ for (let key in user) alert(key); // name, age (no symbols) alert( "Direct: " + user[id] ); ``` +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md これは一般的な "隠れている" というコンセプトの一部です。もし別のスクリプトかライブラリが我々のオブジェクトをループした際に、予期せずシンボリックプロパティにアクセスすることはありません。 +======= +`Object.keys(user)` 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. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md 一方で、[Object.assign](mdn:js/Object/assign) は文字列とシンボルプロパティ両方をコピーします; @@ -164,6 +247,7 @@ alert( clone[id] ); // 123 ここにはパンドラの箱はありません。これは設計されたものです。この考えは、オブジェクトをクローンしたりマージするとき、通常 *全ての* プロパティがコピーされることを望みます( `id` のようなシンボルも含めて)。 +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md ````smart header="他の型のプロパティキーは文字列に強制されます" オブジェクトでは、キーとして文字列かシンボルのみを使うことができます。他の型は文字列に変換されます。 @@ -185,10 +269,19 @@ alert( obj[0] ); // test (同じプロパティ) これまで見てきたように、通常はたとえ同じ名前であったとしてもすべてのシンボルは異なります。しかし、時には同じ名前のシンボルを同じエンティティにしたいときがあります。 例えば、我々のアプリケーションの異なる部分が、正確に同じプロパテイを意味するシンボル `"id"` にアクセスしたいとします。 +======= +## Global symbols + +As we've seen, usually all symbols are different, even if they have the same name. But sometimes we want same-named symbols to be same entities. For instance, different parts of our application want to access symbol `"id"` meaning exactly the same property. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md それを達成するために、*グローバルシンボルレジストリ* があります。その中でシンボルを作り、後でそれらにアクセスすることができます。同じ名前への繰り返しアクセスは、まったく同じシンボルを返すことが保証されます。 +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md レジストリ内でシンボルを作ったり読み込むためには、`Symbol.for(key)` を使います。 +======= +In order to read (create if absent) a symbol from the registry, use `Symbol.for(key)`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md これは、グローバルレジストリのチェックを呼び出し、もし `key` として記述されたシンボルが存在する場合には、それを返します。そうでない場合には、新しいシンボル `Symbol(key)` を作り、与えられた `key` で、レジストリ内に格納されます。 @@ -198,7 +291,11 @@ alert( obj[0] ); // test (同じプロパティ) // グローバルレジストリから読む let id = Symbol.for("id"); // symbol が存在しない場合、作られます +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md // 再度読み込み +======= +// read it again (maybe from another part of the code) +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md let idAgain = Symbol.for("id"); // 同じシンボル @@ -221,22 +318,41 @@ JavaScriptでは、ご覧の通りそれはグローバルシンボルのこと 例: ```js run +// get symbol by name let sym = Symbol.for("name"); let sym2 = Symbol.for("id"); +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md // symbol から name を取得 +======= +// get name by symbol +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md alert( Symbol.keyFor(sym) ); // name alert( Symbol.keyFor(sym2) ); // id ``` +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md `Symbol.keyFor` は内部ではそのシンボルのキーを探すためにグローバルシンボルレジストリを使っています。従って、非グローバルのものに対しては動作しません。もしシンボルが非グローバルの場合、見つけることはできず、`undefined` を返します。 +======= +The `Symbol.keyFor` internally uses the global symbol registry to look up the key for the symbol. So it doesn't work for non-global symbols. If the symbol is not global, it won't be able to find it and returns `undefined`. + +That said, any symbols have `description` property. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md 例: ```js run -alert( Symbol.keyFor(Symbol.for("name")) ); // name, global symbol +let globalSymbol = Symbol.for("name"); +let localSymbol = Symbol("name"); + +alert( Symbol.keyFor(globalSymbol) ); // name, global symbol +alert( Symbol.keyFor(localSymbol) ); // undefined, not global +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md alert( Symbol.keyFor(Symbol("name2")) ); // undefined, 引数はグローバルシンボルではありません +======= +alert( localSymbol.description ); // name +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md ``` ## システムシンボル @@ -259,17 +375,32 @@ JavaScriptが内部的に使用する多くの "システム" シンボルが存 `Symbol` はプリミティブ型で、ユニークな識別子のためのものです。 +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md シンボルはオプションの記述と合わせて呼ばれる `Symbol()` で生成されます。 シンボルは、たとえ同じ名前を持ったとしても常に異なった値です。もし同じ名前のシンボルを同じものにしたいなら、グローバルレジストリを使う必要があります: `Symbol.for(key)` は名前として `key` をもつグローバルシンボルを返します(必要なら作ります)。`Symbol.for` の複数回の呼び出しは全く同じシンボルを返します。 +======= +Symbols are created with `Symbol()` call with an optional description (name). + +Symbols are always different values, even if they have the same name. If we want same-named symbols to be equal, then we should use the global registry: `Symbol.for(key)` returns (creates if needed) a global symbol with `key` as the name. Multiple calls of `Symbol.for` with the same `key` return exactly the same symbol. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md シンボルは2つの主なユースケースがあります: +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md 1. "隠れた" オブジェクトのプロパティ。 もし別のスクリプト、またはライブラリに "属している" オブジェクトにプロパティを追加したい場合、シンボルを作り、プロパティのキーとしてそれを使うことができます。シンボリックなプロパティは `for..in` には現れないため、リストされることはありません。また、直接アクセスされることもありません。なぜなら、別のスクリプトは我々のシンボルを持っていないため、そのアクションに介入することはできません。 +======= +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. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md 従って、シンボリックプロパティを使うことで、必要なオブジェクトに何かを "こっそり" 隠すことができます。そしてそれは他人には見えません。 2. `Symbol.*` としてアクセス可能なJavaScriptで使われている多くのシステムシンボルがあります。いくつかの組み込みの振る舞いを変更するためにそれらを使うことができます。例えば、チュートリアルの後半で[iterables](info:iterable)のための `Symbol.iterator`, [object-to-primitive conversion](info:object-toprimitive)を設定するための `Symbol.toPrimitive` などを使います。 +<<<<<<< HEAD:1-js/04-object-basics/03-symbol/article.md 技術的には、シンボルは100%隠れる訳ではありません。全てのシンボルを取得する組み込み関数[Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) があります。また、シンボリックなものも含めてオブジェクトの *全ての* キーを返す[Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys)と呼ばれる関数もあります。なので、それらは本当に隠れてはいません。しかしほとんどのライブラリや組み込み関数、構文構造は共通の合意に忠実です。そして、前述の方法を明示的に呼び出す人は、それらがやっていることをよく理解しているでしょう。 +======= +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. So they are not really hidden. But most libraries, built-in functions and syntax constructs don't use these methods. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/04-object-basics/08-symbol/article.md diff --git a/1-js/04-object-basics/09-object-toprimitive/article.md b/1-js/04-object-basics/09-object-toprimitive/article.md new file mode 100644 index 0000000000..f6b715ce56 --- /dev/null +++ b/1-js/04-object-basics/09-object-toprimitive/article.md @@ -0,0 +1,255 @@ + +# Object to primitive conversion + +What happens when objects are added `obj1 + obj2`, subtracted `obj1 - obj2` or printed using `alert(obj)`? + +In that case, objects are auto-converted to primitives, and then the operation is carried out. + +In the chapter we've seen the rules for numeric, string and boolean conversions of primitives. But we left a gap for objects. Now, as we know about methods and symbols it becomes possible to fill it. + +1. All objects are `true` in a boolean context. There are 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 like `alert(obj)` and in similar contexts. + +## ToPrimitive + +We can fine-tune string and numeric conversion, using special object methods. + +There are three variants of type conversion, so-called "hints", 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`: + + ```js + // output + alert(obj); + + // using object as a property key + anotherObj[obj] = 123; + ``` + +`"number"` +: For an object-to-number conversion, like when we're doing maths: + + ```js + // explicit conversion + let num = Number(obj); + + // maths (except binary plus) + let n = +obj; // unary plus + let delta = date1 - date2; + + // less/greater comparison + let greater = user1 > user2; + ``` + +`"default"` +: Occurs in rare cases when the operator is "not sure" what type to expect. + + For instance, binary plus `+` can work both with strings (concatenates them) and numbers (adds them), so both strings and numbers would do. So if the a binary plus gets an object as an argument, it uses the `"default"` hint to convert it. + + Also, if an object is compared using `==` with a string, number or a symbol, it's also unclear which conversion should be done, so the `"default"` hint is used. + + ```js + // binary plus uses the "default" hint + let total = obj1 + obj2; + + // obj == number uses the "default" hint + if (user == 1) { ... }; + ``` + + The greater and less comparison operators, such as `<` `>`, can work with both strings and numbers too. Still, they use the `"number"` hint, not `"default"`. That's for historical reasons. + + In practice though, we don't need to remember these peculiar details, because 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 can do the same. + +```smart header="No `\"boolean\"` hint" +Please note -- there are only three hints. It's that simple. + +There is no "boolean" hint (all objects are `true` in boolean context) or anything else. And if we treat `"default"` and `"number"` the same, like most built-ins do, then there are only two conversions. +``` + +**To do the conversion, JavaScript tries to find and call three object methods:** + +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 `obj.toString()` and `obj.valueOf()`, whatever exists. +3. Otherwise if hint is `"number"` or `"default"` + - try `obj.valueOf()` and `obj.toString()`, whatever exists. + +## Symbol.toPrimitive + +Let's start from the first method. There's a built-in symbol named `Symbol.toPrimitive` that should be used to name the conversion method, like this: + +```js +obj[Symbol.toPrimitive] = function(hint) { + // must return a primitive value + // hint = one of "string", "number", "default" +}; +``` + +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 + +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. + +If there's no `Symbol.toPrimitive` then JavaScript tries to find them and try in the order: + +- `toString -> valueOf` for "string" hint. +- `valueOf -> toString` otherwise. + +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]`. + +And 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. + +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. + +## Return types + +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 a 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` *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: +1. The object is converted to a primitive (using the rules described above). +2. If the resulting primitive isn't of the right type, it's 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) + +The specification describes explicitly which operator uses which hint. There are very few operators that "don't know what to expect" and use the `"default"` hint. Usually for built-in objects `"default"` hint is handled the same way as `"number"`, so in practice the last two are often merged together. + +The conversion algorithm is: + +1. Call `obj[Symbol.toPrimitive](hint)` if the method exists, +2. Otherwise if hint is `"string"` + - try `obj.toString()` and `obj.valueOf()`, whatever exists. +3. Otherwise if hint is `"number"` or `"default"` + - try `obj.valueOf()` and `obj.toString()`, whatever exists. + +In practice, it's often enough to implement only `obj.toString()` as a "catch-all" method for all conversions that return a "human-readable" representation of an object, for logging or debugging purposes. diff --git a/1-js/05-data-types/01-primitives-methods/1-string-new-property/solution.md b/1-js/05-data-types/01-primitives-methods/1-string-new-property/solution.md index 7e3040e84a..c1f129c270 100644 --- a/1-js/05-data-types/01-primitives-methods/1-string-new-property/solution.md +++ b/1-js/05-data-types/01-primitives-methods/1-string-new-property/solution.md @@ -9,12 +9,19 @@ str.test = 5; // (*) alert(str.test); ``` +<<<<<<< HEAD 結果は2種類あります:: 1. `undefined` 2. エラー +======= +Depending on whether you have `use strict` or not, the result may be: +1. `undefined` (no strict mode) +2. An error (strict mode). +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 なぜでしょう? `(*)` で何が起きているのかもう一度見てみましょう: +<<<<<<< HEAD 1. `str` のプロパティにアクセスされたとき、"ラッパーオブジェクト" が作られます。 2. プロパティの操作はそこで行われます。なので、オブエジェクトは `test` プロパティを取得します。 3. 操作が終了し、"ラッパーオブジェクト" は消えます。 @@ -22,9 +29,18 @@ alert(str.test); なので、最後の行では `str` はそのプロパティへのトレースを持っていません。 しかし、ブラウザによっては、プログラマをさらに制限し、プロパティをプリミティブに割り当てることを禁止することもあります。そのため実際には `(*)` でエラーになることがあります。しかし、それは仕様からは少し離れています。 +======= +1. When a property of `str` is accessed, a "wrapper object" is created. +2. In strict mode, writing into it is an error. +3. Otherwise, the operation with the property is carried on, the object gets the `test` property, but after that the "wrapper object" disappears, so in the last line `str` has no trace of the property. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 **この例は、プリミティブがオブジェクトではないことを明確に示しています。** +<<<<<<< HEAD それらは単にデータを格納することができません。 すべてのプロパティ/メソッド操作は一時オブジェクトのヘルプによって実行されています。 +======= +They can't store additional data. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 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 6d69942f1e..7e7f0713b8 100644 --- a/1-js/05-data-types/01-primitives-methods/article.md +++ b/1-js/05-data-types/01-primitives-methods/article.md @@ -1,5 +1,6 @@ # プリミティブのメソッド +<<<<<<< HEAD JavaScriptはプリミティブ(文字列、数値など)をオブジェクトのように扱うことができます。 また、それらはメソッドも提供しています。この後すぐに学んでいきますが、最初にどのように動作するのか確認しましょう。なぜなら、プリミティブはオブジェクトではないからです(このチャプターでそれをさらに明確にしていきます)。 @@ -7,9 +8,15 @@ JavaScriptはプリミティブ(文字列、数値など)をオブジェクト [cut] プリミティブとオブジェクトの主な違いを見ていきましょう。 +======= +JavaScript allows us to work with primitives (strings, numbers, etc.) as if they were objects. They also provide methods to call as such. We will study those soon, but first we'll see how it works because, of course, primitives are not objects (and here we will make it even clearer). + +Let's look at the key distinctions between primitives and objects. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 プリミティブ +<<<<<<< HEAD - プリミティブ型の値です。 - プリミティブ型は6つあります: `string`, `number`, `boolean`, `symbol`, `null`, `undefined` @@ -19,6 +26,17 @@ JavaScriptはプリミティブ(文字列、数値など)をオブジェクト - `{}` で作ることができます。例えば: `{name: "John", age: 30}`。JavaScriptでは他の種類のオブジェクトもあります。関数もオブジェクトです。 オブジェクトの最も良いところの1つは、そのプロパティの1つとして関数を保持することができることです: +======= +- Is a value of a primitive type. +- There are 7 primitive types: `string`, `number`, `bigint`, `boolean`, `symbol`, `null` and `undefined`. + +An object + +- Is capable of storing multiple values as properties. +- Can be created with `{}`, for instance: `{name: "John", age: 30}`. There are other kinds of objects in JavaScript: functions, for example, are objects. + +One of the best things about objects is that we can store a function as one of its properties. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let john = { @@ -33,11 +51,19 @@ john.sayHi(); // Hi buddy! 上の例では、`sayHi` メソッドをもつ `john` オブジェクトを作りました。 +<<<<<<< HEAD 日付、エラー、HTML要素などで動作するような、多くの組み込みのオブジェクトが既に存在し、それらは異なるプロパティとメソッドを持っています。 +======= +Many built-in objects already exist, such as those that work with dates, errors, HTML elements, etc. They have different properties and methods. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 しかし、これらの機能にはコストがかかります! +<<<<<<< HEAD オブジェクトはプリミティブよりも "重い" です。内部の仕組みをサポートするために追加のリソースを必要とします。しかし、プロパティやメソッドはプログラミングをする上で非常に有用であり、JavaScriptエンジンはそれらの負担を減らすために最適化を試みます。 +======= +Objects are "heavier" than primitives. They require additional resources to support the internal machinery. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## オブジェクトとしてのプリミティブ @@ -48,13 +74,23 @@ JavaScriptの作成者が直面するパラドックスは次の通りです。: 解決策は少々野暮ですが次の通りです: +<<<<<<< HEAD 1. プリミティブは依然としてプリミティブです。要望どおり、単一の値です。 2. 言語は、文字列、数値、真偽値そしてシンボルのメソッドやプロパティにアクセスすることができます。 3. 必要に応じて、追加の機能を提供する特別な "オブジェクトラッパー" が作られ、その後破棄されます。 +======= +1. Primitives are still primitive. A single value, as desired. +2. The language allows access to methods and properties of strings, numbers, booleans and symbols. +3. In order for that to work, a special "object wrapper" that provides the extra functionality is created, and then is destroyed. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 "オブジェクトラッパー" はプリミティブ型毎に異なり、`String`, `Number`, `Boolean`, `Symbol` と呼ばれます。従って、それらは異なるメソッドのセットを提供します。 +<<<<<<< HEAD 例えば、大文字化された文字列を返す [str.toUpperCase()](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) というメソッドがあります。 +======= +For instance, there exists a string method [str.toUpperCase()](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) that returns a capitalized `str`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 次のように動作します: @@ -85,26 +121,40 @@ alert( n.toFixed(2) ); // 1.23 具体的なメソッドはチャプター で見ましょう。 +<<<<<<< HEAD ````warn header="コンストラクタ `String/Number/Boolean` は内部でのみ利用します" Javaなどの言語は `new Number(1)` または `new Boolean(false)` のような構文を使うことで明示的にプリミティブのための "ラッパーオブジェクト" を作ることが出来ます。 +======= +````warn header="Constructors `String/Number/Boolean` are for internal use only" +Some languages like Java allow us to explicitly create "wrapper objects" for primitives using a syntax like `new Number(1)` or `new Boolean(false)`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 JavaScriptにおいても、歴史的な理由から可能ですが、強く *推奨しません*。いくつかの場所で物事がおかしなことになっていくでしょう。 例: ```js run -alert( typeof 1 ); // "number" +alert( typeof 0 ); // "number" -alert( typeof new Number(1) ); // "object"! +alert( typeof new Number(0) ); // "object"! ``` +<<<<<<< HEAD 続いて、`zero` がオブジェクトなので、alert が実行されます: +======= +Objects are always truthy in `if`, so here the alert will show up: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let zero = new Number(0); +<<<<<<< HEAD if (zero) { // zero は true, オブジェクトだからです alert( "zero is truthy?!?" ); +======= +if (zero) { // zero is true, because it's an object + alert( "zero is truthy!?!" ); +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 } ``` diff --git a/1-js/05-data-types/02-number/3-repeat-until-number/_js.view/test.js b/1-js/05-data-types/02-number/3-repeat-until-number/_js.view/test.js index 219fa8068e..6bd0123dba 100644 --- a/1-js/05-data-types/02-number/3-repeat-until-number/_js.view/test.js +++ b/1-js/05-data-types/02-number/3-repeat-until-number/_js.view/test.js @@ -18,7 +18,7 @@ describe("readNumber", function() { assert.strictEqual(readNumber(), 0); }); - it("continues the loop unti meets a number", function() { + it("continues the loop until meets a number", function() { prompt.onCall(0).returns("not a number"); prompt.onCall(1).returns("not a number again"); prompt.onCall(2).returns("1"); @@ -35,4 +35,4 @@ describe("readNumber", function() { assert.isNull(readNumber()); }); -}); \ No newline at end of file +}); diff --git a/1-js/05-data-types/02-number/8-random-min-max/solution.md b/1-js/05-data-types/02-number/8-random-min-max/solution.md index c12a46d74d..0378379dec 100644 --- a/1-js/05-data-types/02-number/8-random-min-max/solution.md +++ b/1-js/05-data-types/02-number/8-random-min-max/solution.md @@ -2,8 +2,13 @@ 2つのステージでそれができます: +<<<<<<< HEAD 1. `max - min` と 0..1 からのランダム値を掛けると、取りうる値の範囲は 0..1 から 0..max - min まで増加します。 2. ここで、`min` を足すと、取りうる範囲は `min` から `max` になります。 +======= +1. If we multiply a random number from 0..1 by `max-min`, then the interval of possible values increases `0..1` to `0..max-min`. +2. Now if we add `min`, the possible interval becomes from `min` to `max`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 関数: diff --git a/1-js/05-data-types/02-number/8-random-min-max/task.md b/1-js/05-data-types/02-number/8-random-min-max/task.md index 754c072514..f9e06d6601 100644 --- a/1-js/05-data-types/02-number/8-random-min-max/task.md +++ b/1-js/05-data-types/02-number/8-random-min-max/task.md @@ -15,5 +15,8 @@ alert( random(1, 5) ); // 1.2345623452 alert( random(1, 5) ); // 3.7894332423 alert( random(1, 5) ); // 4.3435234525 ``` +<<<<<<< HEAD ベースとして、[previous task](info:task/random-min-max) の解法が使えます。 +======= +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/05-data-types/02-number/9-random-int-min-max/solution.md b/1-js/05-data-types/02-number/9-random-int-min-max/solution.md index 932550ec3c..dcaf62924e 100644 --- a/1-js/05-data-types/02-number/9-random-int-min-max/solution.md +++ b/1-js/05-data-types/02-number/9-random-int-min-max/solution.md @@ -27,7 +27,11 @@ alert( randomInteger(1, 3) ); # 正しい解法 +<<<<<<< HEAD このタスクを正しく解く方法はたくさんあります。一例は、区間の端を調整することです。同じ区間となるように、値を `0.5 から 3.5` の間で生成します。そうすると境界値の発生確率が上がります: +======= +There are many correct solutions to the task. One of them is to adjust interval borders. To ensure the same intervals, we can generate values from `0.5 to 3.5`, thus adding the required probabilities to the edges: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run *!* diff --git a/1-js/05-data-types/02-number/9-random-int-min-max/task.md b/1-js/05-data-types/02-number/9-random-int-min-max/task.md index 2cf9b1e4cb..06ec7f2c0f 100644 --- a/1-js/05-data-types/02-number/9-random-int-min-max/task.md +++ b/1-js/05-data-types/02-number/9-random-int-min-max/task.md @@ -11,7 +11,16 @@ importance: 2 動作例: ```js +<<<<<<< HEAD alert( random(1, 5) ); // 1 alert( random(1, 5) ); // 3 alert( random(1, 5) ); // 5 ``` +======= +alert( randomInteger(1, 5) ); // 1 +alert( randomInteger(1, 5) ); // 3 +alert( randomInteger(1, 5) ); // 5 +``` + +You can use the solution of the [previous task](info:task/random-min-max) as the base. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/05-data-types/02-number/article.md b/1-js/05-data-types/02-number/article.md index c5106e1c94..50ab3f284f 100644 --- a/1-js/05-data-types/02-number/article.md +++ b/1-js/05-data-types/02-number/article.md @@ -1,8 +1,18 @@ # 数値 +<<<<<<< HEAD JavaScript では、全ての数値は "倍精度" として知られる64ビットフォーマット[IEEE-754](http://en.wikipedia.org/wiki/IEEE_754-1985) で格納されます。 このチャプターでは、数値について現在知っていることをおさらいしならがら、より発展させて行きましょう。 +======= +In modern JavaScript, there are two types of numbers: + +1. Regular numbers in JavaScript are stored in 64-bit format [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754-2008_revision), 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, to represent integers of arbitrary length. They are sometimes needed, because a regular number can't exceed 253 or be less than -253. As bigints are used in few special areas, we devote them a special chapter . + +So here we'll talk about regular numbers. Let's expand our knowledge of them. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## 数値を書く多くの方法 @@ -12,7 +22,11 @@ JavaScript では、全ての数値は "倍精度" として知られる64ビッ let billion = 1000000000; ``` +<<<<<<< HEAD しかし、実際には間違えやすいので、通常は何度もゼロを書くのを避けます。また我々は怠け者です。10億を `"1bn"` としたり、73億を `"7.3bn"` と書いたりします。大きな数値を表現する場合には大抵これが当てはまります。 +======= +But in real life, we usually avoid writing a long string of zeroes as it's easy to mistype. Also, we are lazy. We will usually write something like `"1bn"` for a billion or `"7.3bn"` for 7 billion 300 million. The same is true for most large numbers. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 JavaScriptでは、数値に文字 `"e"` を追加し、ゼロの数を指定することで数値を短くします。: @@ -29,17 +43,28 @@ alert( 7.3e9 ); // 73 億 (7,300,000,000) 1.23e6 = 1.23 * 1000000 ``` +<<<<<<< HEAD 今度は非常に小さい数値を書いてみましょう。1マイクロ秒(100万分の1秒): +======= +Now let's write something very small. Say, 1 microsecond (one millionth of a second): +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let ms = 0.000001; ``` +<<<<<<< HEAD 先程書いたように、`"e"` が役立ちます。明示的にゼロを書くのを避けたい場合、このように書くことができます: ```js let ms = 1e-6; // 1 から左にゼロを6つ +======= +Just like before, using `"e"` can help. If we'd like to avoid writing the zeroes explicitly, we could say the same as: + +```js +let ms = 1e-6; // six zeroes to the left from 1 +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` `0.000001` の中のゼロの数は6つです。なので `1e-6` になります。 @@ -152,7 +177,11 @@ alert( num.toString(2) ); // 11111111 alert( Math.floor(num * 100) / 100 ); // 1.23456 -> 123.456 -> 123 -> 1.23 ``` +<<<<<<< HEAD 2. メソッド [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) は点の後の数字を "n" 桁に丸め、結果の文字列表現を返します。 +======= +2. The method [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed) rounds the number to `n` digits after the point and returns a string representation of the result. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let num = 12.34; @@ -171,14 +200,22 @@ alert( num.toString(2) ); // 11111111 ```js run let num = 12.34; +<<<<<<< HEAD alert( num.toFixed(5) ); // "12.34000", 正確に5桁になるよう 0 が追加されます +======= + alert( num.toFixed(5) ); // "12.34000", added zeroes to make exactly 5 digits +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` 単項プラス、または `Number()` 呼び出しを使うことで、数値に変換することができます: `+num.toFixed(5)` ## 精密でない計算 +<<<<<<< HEAD 内部的には、数値は 64bit フォーマット[IEEE-754](http://en.wikipedia.org/wiki/IEEE_754-1985)で表現されるため、正確に 64bit で数値を格納できます。: そのうち 52bit が数字の格納のために使われ、11bit が 小数点の位置で(整数値のときゼロです。)、 1bit は符号です。 +======= +Internally, a number is represented in 64-bit format [IEEE-754](https://en.wikipedia.org/wiki/IEEE_754-2008_revision), 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 (they are zero for integer numbers), and 1 bit is for the sign. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 もし、数値が長すぎる場合、64bitの記憶域をオーバーフローし、無限大になる可能性があります: @@ -194,7 +231,11 @@ alert( 1e500 ); // Infinity alert( 0.1 + 0.2 == 0.3 ); // *!*false*/!* ``` +<<<<<<< HEAD 上記の通り、もし `0.1` と `0.2` の合計が `0.3` かどうかをチェックした場合、`false` になります。 +======= +That's right, if we check whether the sum of `0.1` and `0.2` is `0.3`, we get `false`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 奇妙です! `0.3` でないのなら、何なのでしょう? @@ -202,19 +243,33 @@ alert( 0.1 + 0.2 == 0.3 ); // *!*false*/!* alert( 0.1 + 0.2 ); // 0.30000000000000004 ``` +<<<<<<< HEAD なんと! ここには誤った比較よりも多くの驚きがあります。もしもe-ショッピングのサイトを作っており、訪問者が `$0.10` と `$0.20` の商品をカートに入れたと想像してください。注文の総額は `$0.30000000000000004` になります。誰もがそれに驚くでしょう。 +======= +Ouch! There are more consequences than an incorrect comparison here. 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. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 しかし、なぜこのようなことが起こるのでしょうか? +<<<<<<< HEAD 数値はバイナリ形式で、1と0の並びでメモリ上に格納されます。しかし10進数でシンプルに見える `0.1`、` 0.2` のような小数は、バイナリ形式では終わることのない小数です。 言い換えると、`0.1` とは何でしょう?それは 1 を 10 で割った `1/10` です。10進数では、このような数値は簡単に表現できます。 それと `1/3` を比較してみてください。これは無限の小数 `0.33333(3)` になります。 +======= +A number is stored in memory in its binary form, a sequence of bits - ones and zeroes. But fractions like `0.1`, `0.2` that look simple in the decimal numeric system are actually unending fractions in their binary form. + +In other words, what is `0.1`? It is one divided by ten `1/10`, one-tenth. In decimal numeral system such numbers are easily representable. Compare it to one-third: `1/3`. It becomes an endless fraction `0.33333(3)`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 従って、`10` の累乗による除算は 10進数では上手く動作することが保証されますが、`3` による除算は保証されていません。同じ理由で、2進数では、`2` の累乗による除算は動作することが保証されていますが、 `1/10` は無限の2進数の小数になります。 2進数を使って、 *正確な 0.1* または *正確な 0.2* を格納する方法はありません。ちょうど、10進数で 1/3 を小数で正確に表現できないように。 +<<<<<<< HEAD 数値形式 IEEE-754 は、可能な限り近い数値に丸めてこれを解決します。 これらの丸めルールでは、通常 "小さな精度損失" は見ることができないので、数値は `0.3` と表示されます。 しかし、損失は依然として存在することに注意してください。 +======= +The numeric format IEEE-754 solves this by rounding to the nearest possible number. These rounding rules normally don't allow us to see that "tiny precision loss", but it exists. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 これは次のようにして見ることができます: ```js run @@ -228,40 +283,66 @@ alert( 0.1.toFixed(20) ); // 0.10000000000000000555 ```smart header="JavaScript だけではありません" 同じ問題は多くの他のプログラミング言語で存在します。 +<<<<<<< HEAD PHP, Java, C, Perl, Ruby は全く同じ結果を返します。なぜならそれらは同じ数値形式に基づいているためです。 ``` この問題を回避できるのでしょうか?もちろん、幾つかの方法があります; 1. メソッド[toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed)により結果を丸めることができます: +======= +PHP, Java, C, Perl, Ruby give exactly the same result, because they are based on the same numeric format. +``` - ```js run - let sum = 0.1 + 0.2; - alert( sum.toFixed(2) ); // 0.30 - ``` +Can we work around the problem? Sure, the most reliable method is to round the result with the help of a method [toFixed(n)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toFixed): +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 +```js run +let sum = 0.1 + 0.2; +alert( sum.toFixed(2) ); // 0.30 +``` + +<<<<<<< HEAD `toFixed` は常に文字列を返すことに注意してください。それは小数点の後2桁となることを保証します。実際、e-ショッピングを持っていて `$0.30` を表示するときに便利です。それ以外のケースでは、数値に変換するために単項プラスを使うことができます。 +======= +Please note that `toFixed` always returns a string. It ensures that it has 2 digits after the decimal point. That's actually convenient if we have an e-shopping and need to show `$0.30`. For other cases, we can use the unary plus to coerce it into a number: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 - ```js run - let sum = 0.1 + 0.2; - alert( +sum.toFixed(2) ); // 0.3 - ``` +```js run +let sum = 0.1 + 0.2; +alert( +sum.toFixed(2) ); // 0.3 +``` +<<<<<<< HEAD 2. 一時的に数値を整数に変換し、その後戻す方法があります。 このように動作します: +======= +We also can temporarily multiply the numbers by 100 (or a bigger number) to turn them into integers, do the maths, and then divide back. Then, as we're doing maths with integers, the error somewhat decreases, but we still get it on division: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 - ```js run - alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3 - ``` +```js run +alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3 +alert( (0.28 * 100 + 0.14 * 100) / 100); // 0.4200000000000001 +``` +<<<<<<< HEAD `0.1 * 10 = 1` と `0.2 * 10 = 2` をするとき、両方の数値は整数になり、精度損失がなくなるため、これは正しく動作します。 3. もしもショップを扱っている場合、最も抜本的な解決策はセントで全ての価格を格納し、全く小数を使わないことです。しかし、30% のディスカウントを適用するとどうなるでしょうか?実際には、完全に回避することはほぼ不可能なので、上記の解決法はこの落とし穴を回避するのに役立ちます。 +======= +So, multiply/divide approach reduces the error, but doesn't remove it totally. + +Sometimes we could try to evade fractions at all. Like if we're dealing with a shop, then we can store prices in cents instead of dollars. But what if we apply a discount of 30%? In practice, totally evading fractions is rarely possible. Just round them to cut "tails" when needed. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ````smart header="興味深いこと" これを試してみてください: ```js run +<<<<<<< HEAD // Hello! 自己増加する数値です! +======= +// Hello! I'm a self-increasing number! +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 alert( 9999999999999999 ); // shows 10000000000000000 ``` @@ -273,11 +354,16 @@ JavaScriptはこのようなイベントではエラーをトリガーしませ ```smart header="2つのゼロ" 数値の内部表現のもう一つの面白い結果は、2つのゼロ、すなわち `0` と `-0` の存在です。 +<<<<<<< HEAD 記号は1ビットで表現されるため、すべての数字は、0を含めて正または負になります。 +======= +That's because a sign is represented by a single bit, so it can be set or not set for any number including a zero. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ほとんどの場合、区別は気になりません。なぜなら演算子はそれらを同じものとして扱うためです。 ``` +<<<<<<< HEAD ## テスト: isFinite と isNaN @@ -285,6 +371,14 @@ JavaScriptはこのようなイベントではエラーをトリガーしませ - `Infinite` (と `-Infinite`) は何よりも大きい(小さい)特別な数値です。 - `NaN` はエラーを表現します。 +======= +## Tests: isFinite and isNaN + +Remember these two special numeric values? + +- `Infinity` (and `-Infinity`) is a special numeric value that is greater (less) than anything. +- `NaN` represents an error. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 これらは `number` 型に属しますが、 "通常の" 数値ではないため、それらをチェックするための特別な関数があります: @@ -323,12 +417,21 @@ alert( isFinite(num) ); ```smart header="`Object.is` を使った比較" +<<<<<<< HEAD 値を `===` のように比較する特別な組み込みメソッド [Object.is](mdn:js/Object/is) があります。これは2つの特殊なケースではより信頼できます: 1. `NaN` でうまく動作します: `Object.is(NaN, NaN) === true`、これは良いことです。 2. 値 `0` と `-0` は異なります: `Object.is(0, -0) === false`、重要ではありませんが、技術的にはそれらは異なる値です。 上記以外の全てのケースでは、`Object.is(a, b)` は `a === b` と同じです。 +======= +There is a special built-in method [`Object.is`](mdn:js/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 true, because internally the number has a sign bit that may be different even if all other bits are zeroes. + +In all other cases, `Object.is(a, b)` is the same as `a === b`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 この比較の方法は JavaScriptの仕様でしばしば使われます。内部のアルゴリズムが2つの値が正確に同じかを比較する必要があるとき、`Object.is` (内部的には[SameValue](https://tc39.github.io/ecma262/#sec-samevalue)と呼ばれます)を使います。 ``` @@ -348,7 +451,11 @@ alert( +"100px" ); // NaN そのために `parseInt` と `parseFloat` があります。 +<<<<<<< HEAD それらはできるだけ文字列から数値を "読み込み" ます。エラーが起きると、収集された数値が返されます。関数 `parseInt` は整数を返し、一方で、`parseFloat` は浮動小数を返します: +======= +They "read" a number from a string until they can't. In case of an error, the gathered number is returned. The function `parseInt` returns an integer, whilst `parseFloat` will return a floating-point number: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run alert( parseInt('100px') ); // 100 @@ -406,20 +513,41 @@ JavaScript は数学関数と定数の小さなライブラリを含む組み込 alert( Math.pow(2, 10) ); // 2 in power 10 = 1024 ``` +<<<<<<< HEAD [docs for the Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) にある三角法など、`Math` オブジェクトにはより多くの関数や定数があります。 ## サマリ +======= +There are more functions and constants in `Math` object, including trigonometry, which you can find in the [docs for the Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) object. + +## Summary + +To write numbers with many zeroes: + +- Append `"e"` with the zeroes count to the number. Like: `123e6` is the same as `123` with 6 zeroes `123000000`. +- A negative number after `"e"` causes the number to be divided by 1 with given zeroes. E.g. `123e-6` means `0.000123` (`123` millionths). +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 大きな数値を書く場合: +<<<<<<< HEAD - 数値へ加えるゼロの数と一緒に `"e"` を付け加えます。このように: `123e6` は `123` と 6つのゼロです。 - `"e"` の後の負の値は、1と与えられたゼロの数で数値を除算します。 +======= +- Can write numbers directly in hex (`0x`), octal (`0o`) and binary (`0b`) systems. +- `parseInt(str, base)` parses the string `str` into an integer in numeral system with given `base`, `2 ≤ base ≤ 36`. +- `num.toString(base)` converts a number to a string in the numeral system with the given `base`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 異なる数値体系の場合: +<<<<<<< HEAD - 16進数(`0x`)、8進数(`0o`)や2進数(`0b`) で直接数値を書くことが出来ます。 - `parseInt(str, base)` は `2 ≤ base ≤ 36` の間の任意の数値システムの整数を解析します。 - `num.toString(base)` は数値を、与えられた `base` を基数とした数値システムの文字列に変換します。 +======= +- Use `parseInt/parseFloat` for the "soft" conversion, which reads a number from a string and then returns the value they could read before the error. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 `12pt` や `100px` のような値を数値に変換する場合: @@ -427,9 +555,13 @@ JavaScript は数学関数と定数の小さなライブラリを含む組み込 分数の場合: +<<<<<<< HEAD - `Math.floor`, `Math.ceil`, `Math.trunc`, `Math.round` または `num.toFixed(precision)` を使って丸めます。 - 分数を扱う際に精度の低下があることを覚えておいてください。 より多くの算術関数: - 必要なとき、[Math](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Math) を見てください。このライブラリはとても小さいですが、基本で必要なものはカバーしています。 +======= +- 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. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 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 73c5daac77..f9f7ac83a2 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 @@ -6,7 +6,11 @@ JavaScript では文字列はイミュータブル(不変)なので、最初の let newStr = str[0].toUpperCase() + str.slice(1); ``` +<<<<<<< HEAD が、そこには少し問題があります。`str` が空の場合、`str[0]` は未定義です。なのでエラーになります。 +======= +There's a small problem though. If `str` is empty, then `str[0]` is `undefined`, and as `undefined` doesn't have the `toUpperCase()` method, we'll get an error. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ここでは2つのバリアントがあります: @@ -15,7 +19,7 @@ let newStr = str[0].toUpperCase() + str.slice(1); これは2つ目のバリアントです: -```js run +```js run demo function ucFirst(str) { if (!str) return str; diff --git a/1-js/05-data-types/03-string/1-ucfirst/task.md b/1-js/05-data-types/03-string/1-ucfirst/task.md index 63a519726d..77de11630d 100644 --- a/1-js/05-data-types/03-string/1-ucfirst/task.md +++ b/1-js/05-data-types/03-string/1-ucfirst/task.md @@ -2,7 +2,11 @@ importance: 5 --- +<<<<<<< HEAD # 最初の文字を大文字にする +======= +# Uppercase the first character +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 最初の文字を大文字化して文字列 `str` を返す関数 `ucFirst(str)` を書いてください。例: diff --git a/1-js/05-data-types/03-string/2-check-spam/solution.md b/1-js/05-data-types/03-string/2-check-spam/solution.md index bbd5d734f4..ccaab143dc 100644 --- a/1-js/05-data-types/03-string/2-check-spam/solution.md +++ b/1-js/05-data-types/03-string/2-check-spam/solution.md @@ -1,6 +1,10 @@ +<<<<<<< HEAD 検索で大文字と小文字を区別しないようにするには、文字列を小文字にしてから検索してみましょう: +======= +To make the search case-insensitive, let's bring the string to lower case and then search: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 -```js run +```js run demo function checkSpam(str) { let lowerStr = str.toLowerCase(); diff --git a/1-js/05-data-types/03-string/2-check-spam/task.md b/1-js/05-data-types/03-string/2-check-spam/task.md index 3b94840816..396ff1071d 100644 --- a/1-js/05-data-types/03-string/2-check-spam/task.md +++ b/1-js/05-data-types/03-string/2-check-spam/task.md @@ -4,7 +4,11 @@ importance: 5 # スパムのチェック +<<<<<<< HEAD もし `str` に 'viagra' または 'XXX' を含む場合には `true` を、それ以外の場合には `false` を返す関数 `checkSpam(str)` を書きなさい。 +======= +Write a function `checkSpam(str)` that returns `true` if `str` contains 'viagra' or 'XXX', otherwise `false`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 この関数は大文字と小文字を区別する必要はありません。: diff --git a/1-js/05-data-types/03-string/3-truncate/_js.view/test.js b/1-js/05-data-types/03-string/3-truncate/_js.view/test.js index c252f16bee..9914923315 100644 --- a/1-js/05-data-types/03-string/3-truncate/_js.view/test.js +++ b/1-js/05-data-types/03-string/3-truncate/_js.view/test.js @@ -1,5 +1,5 @@ describe("truncate", function() { - it("truncate the long string to the given lenth (including the ellipsis)", function() { + it("truncate the long string to the given length (including the ellipsis)", function() { assert.equal( truncate("What I'd like to tell on this topic is:", 20), "What I'd like to te…" @@ -13,4 +13,4 @@ describe("truncate", function() { ); }); -}); \ No newline at end of file +}); diff --git a/1-js/05-data-types/03-string/3-truncate/solution.md b/1-js/05-data-types/03-string/3-truncate/solution.md index 141601b320..cbf1330b7c 100644 --- a/1-js/05-data-types/03-string/3-truncate/solution.md +++ b/1-js/05-data-types/03-string/3-truncate/solution.md @@ -2,7 +2,7 @@ 省略記号に1つのユニコード文字を使っていることに注意してください。3つのドットではありません。 -```js run +```js run demo function truncate(str, maxlength) { return (str.length > maxlength) ? str.slice(0, maxlength - 1) + '…' : str; diff --git a/1-js/05-data-types/03-string/4-extract-currency/solution.md b/1-js/05-data-types/03-string/4-extract-currency/solution.md index 41754192ad..dfd95f996c 100644 --- a/1-js/05-data-types/03-string/4-extract-currency/solution.md +++ b/1-js/05-data-types/03-string/4-extract-currency/solution.md @@ -1,5 +1,8 @@ +<<<<<<< HEAD ```js run function extractCurrencyValue(str) { return +str.slice(1); } ``` +======= +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/05-data-types/03-string/article.md b/1-js/05-data-types/03-string/article.md index f280ad55c3..349de3125f 100644 --- a/1-js/05-data-types/03-string/article.md +++ b/1-js/05-data-types/03-string/article.md @@ -4,9 +4,13 @@ JavaScriptでは、テキストデータは文字列として格納されます 文字列の内部のフォーマットは常に [UTF-16](https://en.wikipedia.org/wiki/UTF-16) であり、ページのエンコーディングとは関係ありません。 +<<<<<<< HEAD [cut] ## 引用符 +======= +## Quotes +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 引用符の種類を思い出してみましょう。 @@ -19,7 +23,11 @@ let double = "double-quoted"; let backticks = `backticks`; ``` +<<<<<<< HEAD シングルとダブルクォートは本質的に同じです。しかしながら、バッククォートは文字列の中に関数呼び出しを含む任意の式を埋め込むことができます。 +======= +Single and double quotes are essentially the same. Backticks, however, allow us to embed any expression into the string, by wrapping it in `${…}`: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run function sum(a, b) { @@ -41,20 +49,35 @@ let guestList = `Guests: alert(guestList); // 複数行でのゲストのリスト ``` +<<<<<<< HEAD 同じ方法でシングル、またはダブルクォートを使おうとすると、エラーになります: +======= +Looks natural, right? But single or double quotes do not work this way. + +If we use them and try to use multiple lines, there'll be an error: + +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run -let guestList = "Guests: // Error: Unexpected token ILLEGAL +let guestList = "Guests: // Error: Unexpected token ILLEGAL * John"; ``` シングルクォートとダブルクォートは、複数行の文字列の必要性が考慮されていないときの言語仕様策定によるものです。 バッククォートは後で登場したもので、より汎用性があります。 +<<<<<<< HEAD また、バッククォートは最初のバッククォートの前に "テンプレート関数" を指定することができます。構文は次のようになります: func`string`。 関数 `func` は自動的に呼ばれ、文字列と埋め込まれた式を受け取り、それらを処理することができます。[docs](mdn:/JavaScript/Reference/Template_literals#Tagged_template_literals) で、これに関してより知ることができます。これは "タグ付きテンプレートリテラル" と呼ばれます。この機能により、文字列をカスタムテンプレートやその他の機能に簡単にラップできますが、ほとんど使用されません。 ## 特殊文字 `\n` と書かれた、いわゆる "改行文字" を使うことで、シングルクォートで複数行の文字列を作ることが可能です。 +======= +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 is called "tagged templates". This feature makes it easier to implement custom templating, but is rarely used in practice. You can read more about it in the [manual](mdn:/JavaScript/Reference/Template_literals#Tagged_templates). + +## Special characters + +It is still possible to create multiline strings with single and double quotes by using a so-called "newline character", written as `\n`, which denotes a line break: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let guestList = "Guests:\n * John\n * Pete\n * Mary"; @@ -62,6 +85,7 @@ let guestList = "Guests:\n * John\n * Pete\n * Mary"; alert(guestList); // 複数行のゲストのリスト ``` +<<<<<<< HEAD 例えば、これら2つの行は同じように表現されます: ```js run @@ -73,9 +97,27 @@ World` ); ``` あまり一般的でない他の "特殊文字" もあります。これはその一覧です: +======= +For example, these two lines are equal, just written differently: + +```js run +let str1 = "Hello\nWorld"; // two lines using a "newline symbol" + +// two lines using a normal newline and backticks +let str2 = `Hello +World`; + +alert(str1 == str2); // true +``` + +There are other, less common "special" characters. + +Here's the full list: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 | 文字 | 説明 | |-----------|-------------| +<<<<<<< HEAD |`\b`|バックスペース| |`\f`|改ページ| |`\n`|改行| @@ -83,18 +125,38 @@ World` ); |`\t`|タブ| |`\uNNNN`|`\u00A9` のような16進コード `NNNN` を持つユニコード記号 -- これは、著作権記号 `©` のユニコードです。 正確に4桁の16進数でなければなりません。| |`\u{NNNNNNNN}`|いくつかの珍しい文字は、2つのユニコード記号でエンコードされ、4バイトまで使用されます。 この長いユニコードでは、周囲に括弧が必要です。| +======= +|`\n`|New line| +|`\r`|Carriage return: not used alone. Windows text files use a combination of two characters `\r\n` to represent a line break. | +|`\'`, `\"`|Quotes| +|`\\`|Backslash| +|`\t`|Tab| +|`\b`, `\f`, `\v`| Backspace, Form Feed, Vertical Tab -- kept for compatibility, not used nowadays. | +|`\xXX`|Unicode character with the given hexadecimal unicode `XX`, e.g. `'\x7A'` is the same as `'z'`.| +|`\uXXXX`|A unicode symbol with the hex code `XXXX` in UTF-16 encoding, for instance `\u00A9` -- is a unicode for the copyright symbol `©`. It must be exactly 4 hex digits. | +|`\u{X…XXXXXX}` (1 to 6 hex characters)|A unicode symbol with the given UTF-32 encoding. Some rare characters are encoded with two unicode symbols, taking 4 bytes. This way we can insert long codes. | +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ユニコードの例です: ```js run alert( "\u00A9" ); // © +<<<<<<< HEAD alert( "\u{20331}" ); // 佫, 中国の象形文字 (long unicode) alert( "\u{1F60D}" ); // 😍, スマイル記号 (another long unicode) +======= +alert( "\u{20331}" ); // 佫, a rare Chinese hieroglyph (long unicode) +alert( "\u{1F60D}" ); // 😍, a smiling face symbol (another long unicode) +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` すべての特殊文字はバックスラッシュ `\` で始まります。それは "エスケープ文字" とも呼ばれます。 +<<<<<<< HEAD また、文字列の中に引用符を挿入したいときにも使います。 +======= +We might also use it if we wanted to insert a quote into the string. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: @@ -104,7 +166,11 @@ alert( 'I*!*\'*/!*m the Walrus!' ); // *!*I'm*/!* the Walrus! 上で見るように、内側の引用符の前にバックスラッシュ `\'` を追加しないといけません。そうしないと、文字列の終わりだと認識されるためです。 +<<<<<<< HEAD もちろん、これは囲っているものと同じ引用符を使う場合についてです。なので、よりよい解決策は、ダブルクォートかバッククォートを代わりに使うことです: +======= +Of course, only to the quotes that are the same as the enclosing ones need to be escaped. So, as a more elegant solution, we could switch to double quotes or backticks instead: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run alert( `I'm the Walrus!` ); // I'm the Walrus! @@ -120,9 +186,15 @@ alert( `I'm the Walrus!` ); // I'm the Walrus! alert( `The backslash: \\` ); // The backslash: \ ``` +<<<<<<< HEAD ## 文字列長 `length` プロパティは文字列の長さを持ちます: +======= +## String length + +The `length` property has the string length: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run alert( `My\n`.length ); // 3 @@ -133,7 +205,11 @@ alert( `My\n`.length ); // 3 ```warn header="`length` はプロパティです" いくつかの他の言語について知っている人は、単なる `str.length` の代わりに `str.length()` と呼び間違えることがありますが、それは動作しません。 +<<<<<<< HEAD `str.length` は数値プロパティであり、関数ではないことに注意してください。その後に括弧をつける必要はありません。 +======= +Please note that `str.length` is a numeric property, not a function. There is no need to add parenthesis after it. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` ## 文字へのアクセス @@ -190,7 +266,11 @@ alert( str[0] ); // 動きません ```js run let str = 'Hi'; +<<<<<<< HEAD str = 'h' + str[1]; // 文字列を置換 +======= +str = 'h' + str[1]; // replace the string +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 alert( str ); // hi ``` @@ -243,8 +323,11 @@ let str = 'Widget with id'; alert( str.indexOf('id', 2) ) // 12 ``` +<<<<<<< HEAD すべての出現箇所が知りたい場合は、ループの中で `indexOf` を使います。前回マッチした後の位置から新しい呼び出しを行います: - +======= +If we're interested in all occurrences, we can run `indexOf` in a loop. Every new call is made with the position after the previous match: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let str = 'As sly as a fox, as strong as an ox'; @@ -275,8 +358,13 @@ while ((pos = str.indexOf(target, pos + 1)) != -1) { */!* ``` +<<<<<<< HEAD ```smart header="`str.lastIndexOf(pos)`" 文字列の最後から最初に向かって探す類似のメソッド [str.lastIndexOf(pos)](mdn:js/String/lastIndexOf) もあります。 +======= +```smart header="`str.lastIndexOf(substr, position)`" +There is also a similar method [str.lastIndexOf(substr, position)](mdn:js/String/lastIndexOf) that searches from the end of a string to its beginning. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 それは逆の順序でマッチする対象を列挙します。 ``` @@ -305,10 +393,18 @@ if (str.indexOf("Widget") != -1) { } ``` +<<<<<<< HEAD ````smart header="ビットの NOT トリック" ここで使われている古いトリックの1つは `~` 演算子の [bitwise NOT](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_NOT) です。それは、数値を 32bit 整数に変換し(もし存在すれば小数部分を除いて)、その2進数表現のすべてのビットを反転します。 32ビット整数の場合、 `〜n` は(IEEE-754形式のため) `-(n+1)` と全く同じ意味です。 +======= +#### The bitwise NOT trick + +One of the old tricks used here is the [bitwise NOT](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Bitwise_NOT) `~` operator. It converts the number to a 32-bit integer (removes the decimal part if exists) and then reverses all bits in its binary representation. + +In practice, that means a simple thing: for 32-bit integers `~n` equals `-(n+1)`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: @@ -321,9 +417,15 @@ alert( ~-1 ); // 0, -(-1+1) と同じです */!* ``` +<<<<<<< HEAD 上の通り、`~n` は、 `n == -1` のときだけゼロになります。 なので、`if ( ~str.indexOf("...") )` のテストは `indexOf` の結果が `-1` でない場合は true です。つまり、マッチするものがあるとき、です。 +======= +As we can see, `~n` is zero only if `n == -1` (that's for any 32-bit signed integer `n`). + +So, the test `if ( ~str.indexOf("...") )` is truthy only if the result of `indexOf` is not `-1`. In other words, when there is a match. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 `indexOf` チェックの短縮形として使われます: @@ -337,8 +439,16 @@ if (~str.indexOf("Widget")) { 通常、言語機能を明白でない方法で使用することは推奨されませんが、このトリックは昔のコードでは広く使われています。なので、これは理解しておきましょう。 +<<<<<<< HEAD 覚えておきましょう: `if (~str.indexOf(...))` は "もし見つかったら" と読みます。 ```` +======= +Just remember: `if (~str.indexOf(...))` reads as "if found". + +To be precise though, as big numbers are truncated to 32 bits by `~` operator, there exist other numbers that give `0`, the smallest is `~4294967295=0`. That makes such check is correct only if a string is not that long. + +Right now we can see this trick only in the old code, as modern JavaScript provides `.includes` method (see below). +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ### includes, startsWith, endsWith @@ -355,15 +465,25 @@ alert( "Hello".includes("Bye") ); // false `str.includes` の任意の2つ目の引数は、検索開始の位置です: ```js run +<<<<<<< HEAD alert( "Midget".includes("id") ); // true alert( "Midget".includes("id", 3) ); // false, 位置 3 から見ると、"id" はありません +======= +alert( "Widget".includes("id") ); // true +alert( "Widget".includes("id", 3) ); // false, from position 3 there is no "id" +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` メソッド [str.startsWith](mdn:js/String/startsWith) と [str.endsWith](mdn:js/String/endsWith) は、それらの名前が指すことを正確に行います: ```js run +<<<<<<< HEAD alert( "Widget".startsWith("Wid") ); // true, "Widget" は "Wid" で始まります alert( "Widget".endsWith("get") ); // true, "Widget" は "get" で終わります +======= +alert( "Widget".startsWith("Wid") ); // true, "Widget" starts with "Wid" +alert( "Widget".endsWith("get") ); // true, "Widget" ends with "get" +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` ## 部分文字列を取得する @@ -385,7 +505,11 @@ JavaScriptでは、部分文字列を取得する3つの方法があります: ` ```js run let str = "st*!*ringify*/!*"; +<<<<<<< HEAD alert( str.slice(2) ); // ringify, 2つ目の位置から最後まで +======= + alert( str.slice(2) ); // 'ringify', from the 2nd position till the end +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` `start/end` は負の値も指定可能です。これは、位置が文字列の末尾からカウントされることを意味します: @@ -393,11 +517,15 @@ JavaScriptでは、部分文字列を取得する3つの方法があります: ` ```js run let str = "strin*!*gif*/!*y"; +<<<<<<< HEAD // 右から4番目から始まり、右から1つ目まで alert( str.slice(-4, -1) ); // gif +======= + // start at the 4th position from the right, end at the 1st from the right + alert( str.slice(-4, -1) ); // 'gif' +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` - `str.substring(start [, end])` : `start` と `end` の *間* の文字列の一部を返します。 @@ -405,7 +533,6 @@ JavaScriptでは、部分文字列を取得する3つの方法があります: ` 例: - ```js run let str = "st*!*ring*/!*ify"; @@ -421,7 +548,6 @@ JavaScriptでは、部分文字列を取得する3つの方法があります: ` slice とは違い負の値はサポートされていません。それらは `0` として扱われます。 - `str.substr(start [, length])` : `start` から与えられた `length` 分の、文字列の一部を返します。 @@ -429,20 +555,29 @@ JavaScriptでは、部分文字列を取得する3つの方法があります: ` ```js run let str = "st*!*ring*/!*ify"; +<<<<<<< HEAD alert( str.substr(2, 4) ); // ring, 2の位置から 4文字取得します +======= + alert( str.substr(2, 4) ); // 'ring', from the 2nd position get 4 characters +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` 最初の引数は、末尾からカウントするために負の値にもできます: ```js run let str = "strin*!*gi*/!*fy"; +<<<<<<< HEAD alert( str.substr(-4, 2) ); // gi, 4の位置から 2文字取得します +======= + alert( str.substr(-4, 2) ); // 'gi', from the 4th position get 2 characters +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` 混乱しないよう、これらのメソッドについておさらいしましょう: | メソッド | 選択対象... | 負の値 | |--------|-----------|-----------| +<<<<<<< HEAD | `slice(start, end)` | `start` から `end` まで | 負の値を許可します | | `substring(start, end)` | `start` と `end` の間 | 負の値は `0` 扱いです | | `substr(start, length)` | `start` から `length` 文字を取得 | 負の `start` を許可します | @@ -452,6 +587,16 @@ JavaScriptでは、部分文字列を取得する3つの方法があります: ` これらすべて使えます。正確には、`substr` は小さな欠点があります: それは コアなJavaScriptの仕様ではなく、主に歴史的な理由から存在するブラウザ専用の機能を扱う Annex B で説明されています。なので、非ブラウザ環境ではサポートされていない可能性があります。ただ、実際にはほぼどこでも動作しています。 著者はほとんどのケースで `slice` を使っています。 +======= +| `slice(start, end)` | from `start` to `end` (not including `end`) | allows negatives | +| `substring(start, end)` | between `start` and `end` | negative values mean `0` | +| `substr(start, length)` | from `start` get `length` characters | allows negative `start` | + +```smart header="Which one to choose?" +All of them can do the job. Formally, `substr` has a minor drawback: it is described not in the core JavaScript specification, but in Annex B, which covers browser-only features that exist mainly for historical reasons. So, non-browser environments may fail to support it. But in practice it works everywhere. + +Of the other two variants, `slice` is a little bit more flexible, it allows negative arguments and shorter to write. So, it's enough to remember solely `slice` of these three methods. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` ## 文字列比較 @@ -514,30 +659,54 @@ alert( str ); // ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜ ``` +<<<<<<< HEAD わかりますか?大文字が最初で、その後少し特殊文字があり、その後に小文字です。 +======= +See? Capital characters go first, then a few special ones, then lowercase characters, and `Ö` near the end of the output. + +Now it becomes obvious why `a > Z`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 これで、なぜ `a > Z` なのかが明らかになりました。 文字は、その数値コードで比較されます。より大きいコードは、その文字はより大きいことを意味します。`a` (97) のコードは、`Z` (90) よりも大きいです。 +<<<<<<< HEAD - 全ての小文字は大文字の後に来ます。なぜなら、それらのコードはより大きいためです。 - `Ö` のような、基本のアルファベットとは別扱いの文字がいくつかあります。ここでは、そのコードは `a` から `z` のどの文字よりも大きいです。 ### 正しい比較 文字列比較をするための "正しい" アルゴリズムは見た目より複雑です。なぜなら、アルファベットは言語によって異なるためです。異なるアルファベットでは、同じようにみえる文字でも異なって位置することがあります。 +======= +### Correct comparisons + +The "right" algorithm to do string comparisons is more complex than it may seem, because alphabets are different for different languages. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 なので、ブラウザは比較する言語を知る必要があります。 +<<<<<<< HEAD 幸運なことに、全ての現代のブラウザ (IE10 は追加のライブラリ [Intl.JS](https://github.com/andyearnshaw/Intl.js/) を必要とします)は国際標準 [ECMA 402](http://www.ecma-international.org/ecma-402/1.0/ECMA-402.pdf) をサポートします。 +======= +Luckily, all modern browsers (IE10- requires the additional library [Intl.js](https://github.com/andyearnshaw/Intl.js/)) support the internationalization standard [ECMA-402](http://www.ecma-international.org/ecma-402/1.0/ECMA-402.pdf). +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 それは次のルールに従った、異なる言語で文字列を比較するための特殊なメソッドを提供します。 +<<<<<<< HEAD [str.localeCompare(str2)](mdn:js/String/localeCompare) 呼び出し: - 言語規則に従って、`str` が `str2` より大きい場合、`1` を返します。 - `str` が `str2` より小さい場合は `-1` を返します。 - それらが等価な場合は `0` を返します。 +======= +The call [str.localeCompare(str2)](mdn:js/String/localeCompare) returns an integer indicating whether `str` is less, equal or greater than `str2` according to the language rules: + +- Returns a negative number if `str` is less than `str2`. +- Returns a positive number if `str` is greater than `str2`. +- Returns `0` if they are equivalent. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: @@ -545,19 +714,32 @@ alert( str ); alert( 'Österreich'.localeCompare('Zealand') ); // -1 ``` +<<<<<<< HEAD このメソッドは [the documentation](mdn:js/String/localeCompare) で指定されている2つの追加の引数を持ちます。これにより言語を指定することができ(デフォルトは環境から判断されます)、大文字と小文字や、`"a"` と `"á"` が同じように扱われるなどの追加のルールを設定することができます。 +======= +This method actually has two additional arguments specified in [the documentation](mdn:js/String/localeCompare), which allows it to specify the language (by default taken from the environment, letter order depends on the language) and setup additional rules like case sensitivity or should `"a"` and `"á"` be treated as the same etc. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## 内部, Unicode +<<<<<<< HEAD ```warn header="高度な知識" このセクションでは、文字列の内部構造について詳しく説明します。 この知識は、絵文字、珍しい数学的な象形文字やその他の珍しい記号を扱う予定の場合に便利です。 +======= +```warn header="Advanced knowledge" +The section goes deeper into string internals. This knowledge will be useful for you if you plan to deal with emoji, rare mathematical or hieroglyphic characters or other rare symbols. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 それらをサポートする予定がない場合には、このセクションはスキップしてもOKです。 ``` ### サロゲートペア +<<<<<<< HEAD ほとんどの記号は2バイトのコードを持っています。 ほとんどのヨーロッパ言語、数字、さらには象形文字の多くの文字は、2バイト表現です。 +======= +All frequently used characters have 2-byte codes. Letters in most european languages, numbers, and even most hieroglyphs, have a 2-byte representation. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 しかし、2バイトの組み合わせは 65536 通りしか許されず、すべての記号を表現するには十分ではありません。なので、非常に珍しい記号は "サロゲートペア" と呼ばれる2バイト文字のペアでエンコードされています。 @@ -566,7 +748,7 @@ alert( 'Österreich'.localeCompare('Zealand') ); // -1 ```js run alert( '𝒳'.length ); // 2, MATHEMATICAL SCRIPT CAPITAL X alert( '😂'.length ); // 2, FACE WITH TEARS OF JOY -alert( '𩷶'.length ); // 2, a rare chinese hieroglyph +alert( '𩷶'.length ); // 2, a rare Chinese hieroglyph ``` JavaScriptが作られたとき、サロゲートペアは存在しなかったため、言語として正しく処理されていないことに注意してください! @@ -575,7 +757,11 @@ JavaScriptが作られたとき、サロゲートペアは存在しなかった `String.fromCodePoint` と `str.codePointAt` はサロゲートペアを正しく扱う稀なメソッドです。それらは最近言語に登場しました。それまでは、 [String.fromCharCode](mdn:js/String/fromCharCode) と [str.charCodeAt](mdn:js/String/charCodeAt) だけでした。それらのメソッドは実際には `fromCodePoint/codePointAt` と同じですが、サロゲートペアでは上手く動きません。 +<<<<<<< HEAD しかし、サロゲートペアは2つの文字として扱われるため、記号を取得するのが難しい場合があります: +======= +Getting a symbol can be tricky, because surrogate pairs are treated as two characters: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run alert( '𝒳'[0] ); // 見知らぬ記号... @@ -603,7 +789,11 @@ alert( '𝒳'.charCodeAt(1).toString(16) ); // dcb3, 0xdc00 と 0xdfff の間 例えば、文字 `a` は `àáâäãåā` のベースの文字です。最も一般的な "複合" 文字は、UTF-16テーブルに独自のコードを持っています。 しかし、可能な組み合わせが多すぎるため、これがすべてではありません。 +<<<<<<< HEAD 任意の複合文字をサポートするため、UTF-16 ではいくつかのユニコード文字を使うことができます。ベース文字とそれを "装飾" する1つまたは複数の "マーク" 文字です。 +======= +To support arbitrary compositions, UTF-16 allows us to use several unicode characters: the base character followed by one or many "mark" characters that "decorate" it. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 たとえば、 `S` の後に特別な "上にドット" 文字(コード `\u0307`)が続く場合、それは Ṡ として表示されます。 @@ -626,10 +816,17 @@ alert( 'S\u0307\u0323' ); // Ṩ 例: ```js run +<<<<<<< HEAD alert( 'S\u0307\u0323' ); // Ṩ, S + 上のドット + 下のドット alert( 'S\u0323\u0307' ); // Ṩ, S + 下のドット + 上のドット +======= +let s1 = 'S\u0307\u0323'; // Ṩ, S + dot above + dot below +let s2 = 'S\u0323\u0307'; // Ṩ, S + dot below + dot above +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 + +alert( `s1: ${s1}, s2: ${s2}` ); -alert( 'S\u0307\u0323' == 'S\u0323\u0307' ); // false +alert( s1 == s2 ); // false though the characters look identical (?!) ``` これを解決するために、それぞれの文字を1つの "標準の" 形にする "ユニコード正規化" アルゴリズムがあります。 @@ -648,10 +845,15 @@ alert( "S\u0307\u0323".normalize().length ); // 1 alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true ``` +<<<<<<< HEAD 実際には、これは必ずしもそうではありません。理由は、記号 `Ṩ` は "十分に一般的" なので、UTF-16 の作成者がそれをメインテーブルに含め、コードを与えたからです。 +======= +In reality, this is not always the case. The reason being that the symbol `Ṩ` is "common enough", so UTF-16 creators included it in the main table and gave it the code. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 正規化ルールやバリアントについてもっと学びたい場合、それらはユニコード標準 [Unicode Normalization Forms](http://www.unicode.org/reports/tr15/) の付録に記載されています。が、ほとんど実践的な目的においては、このセクションの内容で十分です。 +<<<<<<< HEAD ## サマリ @@ -663,11 +865,31 @@ alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true - 文字列を小文字/大文字にするために、`toLowerCase/toUpperCase` を使います。 - シンプルなチェックで、部分文字列を探すためには `indexOf` または `includes/startsWith/endsWith` を使います。 - 言語に従って文字列を比較するためには、`localeCompare` を使います。そうでない場合は、文字コードで比較されます。 +======= +## Summary + +- There are 3 types of quotes. Backticks allow a string to span multiple lines and embed expressions `${…}`. +- Strings in JavaScript are encoded using UTF-16. +- We can use special characters like `\n` and insert letters by their unicode using `\u...`. +- To get a character, use: `[]`. +- 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. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 文字列には、その他いくつかの役立つメソッドがあります: +<<<<<<< HEAD - `str.trim()` -- 文字列の最初と最後のスペースを除去します。 - `str.repeat(n)` -- 文字列を `n` 回繰り返します。 - などなど。詳細は [manual](mdn:js/String) を見てください。 文字列もまた、正規表現で検索/置換をするメソッドを持っています。しかし、そのトピックは別のチャプターでするのがふさわしいので、後ほど戻ってきましょう。 +======= +- `str.trim()` -- removes ("trims") spaces from the beginning and end of the string. +- `str.repeat(n)` -- repeats the string `n` times. +- ...and more to be found in the [manual](mdn:js/String). + +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 . +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/05-data-types/04-array/10-maximal-subarray/_js.view/test.js b/1-js/05-data-types/04-array/10-maximal-subarray/_js.view/test.js index 143ad53451..b44e76fe7e 100644 --- a/1-js/05-data-types/04-array/10-maximal-subarray/_js.view/test.js +++ b/1-js/05-data-types/04-array/10-maximal-subarray/_js.view/test.js @@ -30,4 +30,8 @@ describe("getMaxSubSum", function() { it("maximal subsum of [-1, -2] equals 0", function() { assert.equal(getMaxSubSum([-1, -2]), 0); }); -}); \ No newline at end of file + + it("maximal subsum of [2, -8, 5, -1, 2, -3, 2] equals 6", function() { + assert.equal(getMaxSubSum([2, -8, 5, -1, 2, -3, 2]), 6); + }); +}); 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 8858a62064..17cffff0a4 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 @@ -1,4 +1,8 @@ +<<<<<<< HEAD # 遅い解法 +======= +# Slow solution +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 すべての可能性のあるサブ合計を計算することができます。 @@ -29,8 +33,13 @@ -9 -9 + 11 +<<<<<<< HEAD // -11 から開始 -11 +======= +// Starting from 11 +11 +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` コードは実際には入れ子のループです: 配列要素に対する外部ループ、および現在の要素で始まる内部カウントのサブ合計です。 @@ -59,7 +68,11 @@ alert( getMaxSubSum([100, -9, 2, -3, 5]) ); // 100 この解法は [O(n2)](https://en.wikipedia.org/wiki/Big_O_notation) の時間の複雑さを持っています。言い換えると、もし配列のサイズが2倍に増加すると、アルゴリズムは4倍長くなります。 +<<<<<<< HEAD 大きな配列(1000, 10000 またはより多くのアイテム)に対しては、このようなアルゴリズムは深刻なレベルで低速になる可能性があります。 +======= +For big arrays (1000, 10000 or more items) such algorithms can lead to a serious sluggishness. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 # 早い解法 @@ -67,7 +80,7 @@ alert( getMaxSubSum([100, -9, 2, -3, 5]) ); // 100 説明にあまりピンとこない場合は、コードを参照してください、それは十分短いです: -```js run +```js run demo function getMaxSubSum(arr) { let maxSum = 0; let partialSum = 0; diff --git a/1-js/05-data-types/04-array/10-maximal-subarray/task.md b/1-js/05-data-types/04-array/10-maximal-subarray/task.md index c57bc9c504..07cd46b5dc 100644 --- a/1-js/05-data-types/04-array/10-maximal-subarray/task.md +++ b/1-js/05-data-types/04-array/10-maximal-subarray/task.md @@ -8,6 +8,7 @@ importance: 2 タスクは次の通りです: アイテムの最大合計で `arr` の連続した部分配列を探します。 +<<<<<<< HEAD そのような返却をする関数 `getMaxSubSum(arr)` を書いてください。 例えば: @@ -19,6 +20,19 @@ getMaxSubSum([-1, 2, 3, -9, *!*11*/!*]) = 11 getMaxSubSum([-2, -1, *!*1, 2*/!*]) = 3 getMaxSubSum([*!*100*/!*, -9, 2, -3, 5]) = 100 getMaxSubSum([*!*1, 2, 3*/!*]) = 6 (すべて) +======= +Write the function `getMaxSubSum(arr)` that will return that sum. + +For instance: + +```js +getMaxSubSum([-1, *!*2, 3*/!*, -9]) == 5 (the sum of highlighted items) +getMaxSubSum([*!*2, -1, 2, 3*/!*, -9]) == 6 +getMaxSubSum([-1, 2, 3, -9, *!*11*/!*]) == 11 +getMaxSubSum([-2, -1, *!*1, 2*/!*]) == 3 +getMaxSubSum([*!*100*/!*, -9, 2, -3, 5]) == 100 +getMaxSubSum([*!*1, 2, 3*/!*]) == 6 (take all) +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` もしすべてのアイテムが負値の場合、何も取らないことを意味します(サブ配列は空)、なので合計はゼロです: @@ -27,4 +41,8 @@ getMaxSubSum([*!*1, 2, 3*/!*]) = 6 (すべて) getMaxSubSum([-1, -2, -3]) = 0 ``` +<<<<<<< HEAD 早い解法を考えてみてください。: 可能なら [O(n2)](https://en.wikipedia.org/wiki/Big_O_notation) もしくは O(n) です。 +======= +Please try to think of a fast solution: [O(n2)](https://en.wikipedia.org/wiki/Big_O_notation) or even O(n) if you can. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/05-data-types/04-array/2-create-array/solution.md b/1-js/05-data-types/04-array/2-create-array/solution.md index eec9055e7c..f032b55f0c 100644 --- a/1-js/05-data-types/04-array/2-create-array/solution.md +++ b/1-js/05-data-types/04-array/2-create-array/solution.md @@ -5,6 +5,6 @@ let styles = ["Jazz", "Blues"]; styles.push("Rock-n-Roll"); styles[Math.floor((styles.length - 1) / 2)] = "Classics"; alert( styles.shift() ); -styles.unshift("Rap", "Reggie"); +styles.unshift("Rap", "Reggae"); ``` 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 11f8330de9..a14b588116 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 @@ -16,7 +16,7 @@ importance: 5 ```js no-beautify Jazz, Blues -Jazz, Bues, Rock-n-Roll +Jazz, Blues, Rock-n-Roll Jazz, Classics, Rock-n-Roll Classics, Rock-n-Roll Rap, Reggae, Classics, Rock-n-Roll diff --git a/1-js/05-data-types/04-array/3-call-array-this/solution.md b/1-js/05-data-types/04-array/3-call-array-this/solution.md index 68ff2ed50f..47e881c79b 100644 --- a/1-js/05-data-types/04-array/3-call-array-this/solution.md +++ b/1-js/05-data-types/04-array/3-call-array-this/solution.md @@ -9,7 +9,7 @@ arr.push(function() { alert( this ); }) -arr[2](); // "a","b",function +arr[2](); // a,b,function(){...} ``` 配列は 3つの値をもっています: 初期に2つを持っているのに加えて、関数です。 diff --git a/1-js/05-data-types/04-array/article.md b/1-js/05-data-types/04-array/article.md index ac68697517..3fcf7b5473 100644 --- a/1-js/05-data-types/04-array/article.md +++ b/1-js/05-data-types/04-array/article.md @@ -1,14 +1,26 @@ +<<<<<<< HEAD # 配列 オブジェクトを使用すると、キー付きの値のコレクションを格納することができます。 しかし、実査には頻繁に *順序付されたコレクション* が必要であることがわかります。それは、1つ目、2つ目、3つ目... と言った要素であり、例えばユーザ、商品、HTML要素など何かのリストを格納します。 +======= +# Arrays + +Objects allow you to store keyed collections of values. That's fine. + +But quite often we find that we need an *ordered collection*, where we have a 1st, a 2nd, a 3rd element and so on. For example, we need that to store a list of something: users, goods, HTML elements etc. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ここでオブジェクトを使うのは便利ではありません。なぜなら、オブジェクトには要素の順序を管理するためのメソッドは提供されていないからです。既存のリストの "間に" 新しいプロパティを挿入することはできません。オブジェクトはこのように使うものではありません。 +<<<<<<< HEAD 順序付けされたコレクションを格納するために、`Array` と呼ばれる特別なデータ構造があります。 [cut] +======= +There exists a special data structure named `Array`, to store ordered collections. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## 宣言 @@ -81,8 +93,13 @@ arr[3](); // hello ``` +<<<<<<< HEAD ````smart header="末尾のカンマ" 配列は、オブジェクトのようにカンマで終わる場合があります: +======= +````smart header="Trailing comma" +An array, just like an object, may end with a comma: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let fruits = [ "Apple", @@ -97,7 +114,11 @@ let fruits = [ ## pop/push, shift/unshift メソッド +<<<<<<< HEAD [キュー(queue)](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)) は配列で最も一般的に使われるものの1つです。コンピュータ・サイエンスでは、これは2つの操作をサポートする要素の順序付きコレクションを意味します。: +======= +A [queue](https://en.wikipedia.org/wiki/Queue_(abstract_data_type)) is one of the most common uses of an array. In computer science, this means an ordered collection of elements which supports two operations: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 - `push` は要素を末尾に追加します。 - `shift` は最初から要素を取得し、2番目の要素が1番目になるようにキューを進めます。 @@ -106,9 +127,15 @@ let fruits = [ 配列は両方の操作をサポートします。 +<<<<<<< HEAD 実践では、非常に頻繁にこれを見ます。例えば画面に表示が必要なメッセージのキューです。 配列の別のユースケースもあります -- [スタック(stack)](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)) と呼ばれるデータ構造です。 +======= +In practice we need it very often. For example, a queue of messages that need to be shown on-screen. + +There's another use case for arrays -- the data structure named [stack](https://en.wikipedia.org/wiki/Stack_(abstract_data_type)). +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 これは2つの操作をサポートします。 @@ -123,9 +150,15 @@ let fruits = [ スタックの場合、最新のプッシュされたアイテムが最初に受け取られます。これはLIFO(Last-In-First-Out)の原則とも呼ばれます。 キューの場合、FIFO(First-In-First-Out)があります。 +<<<<<<< HEAD JavaScriptの配列は、キューとスタックどちらとしても動作します。これらの要素を使用すると、要素を先頭または最後に追加/削除することができます。 コンピュータサイエンスでは、それを許可するデータ構造を[両端キュー/デック(deque)](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). +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 **配列の末尾で動作するメソッド:** @@ -158,7 +191,7 @@ JavaScriptの配列は、キューとスタックどちらとしても動作し `shift` : 配列の先頭の要素を抽出して返します。: - ```js + ```js run let fruits = ["Apple", "Orange", "Pear"]; alert( fruits.shift() ); // Apple を削除し alert する @@ -169,7 +202,7 @@ JavaScriptの配列は、キューとスタックどちらとしても動作し `unshift` : 配列の先頭に要素を追加します。: - ```js + ```js run let fruits = ["Orange", "Pear"]; fruits.unshift('Apple'); @@ -191,11 +224,19 @@ alert( fruits ); ## 内部詳細 +<<<<<<< HEAD 配列は特別な種類のオブジェクトです。プロパティ `arr[0]` にアクセスするために使う角括弧は、実際にはオブジェクト構文から来ています。数字がキーとして使用されます。 +======= +An array is a special kind of object. The square brackets used to access a property `arr[0]` actually come from the object syntax. That's essentially the same as `obj[key]`, where `arr` is the object, while numbers are used as keys. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 配列はデータの順序付きコレクションと、`length` プロパティを処理する特別なメソッドを提供するようオブジェクトを拡張します。しかし、コアではまだオブジェクトです。 +<<<<<<< HEAD JavaScriptには7つの基本タイプしかないことに注意してください。 配列はオブジェクトであるため、オブジェクトのように動作します。 +======= +Remember, there are only 7 basic types in JavaScript. Array is an object and thus behaves like an object. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例えば、これは参照としてコピーされます: @@ -205,6 +246,11 @@ let fruits = ["Banana"] let arr = fruits; // 参照によるコピー (2つの変数は同じ配列を参照する) alert( arr === fruits ); // true +<<<<<<< HEAD +======= + +arr.push("Pear"); // modify the array by reference +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 arr.push("Pear"); // 参照から配列を変更する @@ -231,9 +277,15 @@ fruits.age = 25; // 任意の名前でプロパティを作成します 配列の誤った使い方: +<<<<<<< HEAD - `arr.test = 5` のように非数値プロパティを追加する。 - 穴を作る: `arr[0]` を追加した後、`arr[1000]` を追加する(その間は無し)。 - 逆順で配列を埋める: `arr[1000]`, `arr[999]` など。 +======= +- Add a non-numeric property like `arr.test = 5`. +- Make holes, like: add `arr[0]` and then `arr[1000]` (and nothing between them). +- Fill the array in the reverse order, like `arr[1000]`, `arr[999]` and so on. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 *順序付きデータ* を処理するための特別な構造として配列があると考えてください。配列はそのための特別なメソッドを提供します。配列は連続した順序付きデータを処理するため、JavaScriptエンジン内部で注意深くチューニングされています。このために配列を使ってください。そして、任意のキーが必要なときは、通常のオブジェクト `{}` が必要な可能性が高いです。 @@ -322,7 +374,11 @@ for (let key in arr) { ブラウザや他の環境では *配列のように見える* いわゆる "配列のような" オブジェクトがあります。つまり、それらは `length` とインデックスプロパティを持っています。しかし、それらは通常は必要のない他の非数値プロパティやメソッドも持っています。`for..in` ループはそれらもリストします。なので、もし配列のようなオブジェクトを処理する必要があるとき、それらの "余分な" プロパティが問題になる場合があります。 +<<<<<<< HEAD 2. `for..in` ループは配列ではなく、汎用オブジェクトに対して最適化されているため、10から100倍遅くなります。もちろんそれでもとても速いです。高速化はボトルネックの場合にのみ問題なり、それ以外ではさほど重要でないこともあります。しかしそれでも私たちは違いに気をつけるべきです。 +======= +2. The `for..in` loop is optimized for generic objects, not arrays, and thus is 10-100 times slower. Of course, it's still very fast. The speedup may only matter in bottlenecks. But still we should be aware of the difference. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 一般的に、配列に対しては `for..in` は使うべきではありません。 @@ -340,7 +396,11 @@ fruits[123] = "Apple"; alert( fruits.length ); // 124 ``` +<<<<<<< HEAD 通常、そのように配列を使わないことに注意してください。 +======= +Note that we usually don't use arrays like that. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 `length` プロパティの別の興味深い点は、書き込み可能と言う点です。 @@ -371,7 +431,11 @@ let arr = *!*new Array*/!*("Apple", "Pear", "etc"); もし数値の1つの引数で `new Array` が呼ばれたとき、*アイテムはありませんが、与えられた長さを持った* 配列が作られます。 +<<<<<<< HEAD それがどのように墓穴を掘るか見てみましょう: +======= +Let's see how one can shoot themself in the foot: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let arr = new Array(2); // [2] の配列を作成しますか? @@ -387,7 +451,11 @@ alert( arr.length ); // length は 2 です ## 多次元配列 +<<<<<<< HEAD 配列は配列も持つことができます。我々は行列を格納するために、それを多次元配列として使うことができます。: +======= +Arrays can have items that are also arrays. We can use it for multidimensional arrays, for example to store matrices: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let matrix = [ @@ -396,7 +464,11 @@ let matrix = [ [7, 8, 9] ]; +<<<<<<< HEAD alert( matrix[1][1] ); // 中央の要素 +======= +alert( matrix[1][1] ); // 5, the central element +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` ## toString @@ -432,7 +504,11 @@ alert( "1,2" + 1 ); // "1,21" ## サマリ +<<<<<<< HEAD 配列はオブジェクトの特別な種類であり、順序付けされたデータ項目を格納するのに適しています。 +======= +Array is a special kind of object, suited to storing and managing ordered data items. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 - 宣言: @@ -444,21 +520,39 @@ alert( "1,2" + 1 ); // "1,21" let arr = new Array(item1, item2...); ``` +<<<<<<< HEAD `new Array(number)` への呼び出しは与えられた長さの配列を作りますが、要素を持ちません。 +======= + The call to `new Array(number)` creates an array with the given length, but without elements. + +- The `length` property is the array length or, to be precise, its last numeric index plus one. It is auto-adjusted by array methods. +- If we shorten `length` manually, the array is truncated. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 - `length` プロパティは配列の長さです。正確にはその最後の数値インデックスに1を加えたものです。それは配列のメソッドにより、自動的に調整されます。 - もし手動で `length` を短くした場合、配列は切り捨てられます。 +<<<<<<< HEAD 以下の操作で配列を両端キュー(deque)として使用できます。: +======= +- `push(...items)` adds `items` to the end. +- `pop()` removes the element from the end and returns it. +- `shift()` removes the element from the beginning and returns it. +- `unshift(...items)` adds `items` to the beginning. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 - `push(...items)` は `items` を末尾に追加します。 - `pop()` は末尾の要素を削除し、それを返します。 - `shift()` は先頭の要素を削除し、それを返します。 - `unshift(...items)` はアイテムを先頭に追加します。 +<<<<<<< HEAD 配列の要素をループするために: - `for (let i=0; i で配列に戻り、追加、削除、要素の抽出や配列のソートと言ったより多くのメソッドを学びます。 +======= +We will return to arrays and study more methods to add, remove, extract elements and sort arrays in the chapter . +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/solution.js b/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/solution.js index 024d6d6c2b..490f570ada 100644 --- a/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/solution.js +++ b/1-js/05-data-types/05-array-methods/1-camelcase/_js.view/solution.js @@ -1,8 +1,10 @@ function camelize(str) { return str - .split('-') // my-long-word -> ['my', 'long', 'word'] - .map( + .split('-') // splits 'my-long-word' into array ['my', 'long', 'word'] + .map( + // capitalizes first letters of all array items except the first one + // converts ['my', 'long', 'word'] into ['my', 'Long', 'Word'] (word, index) => index == 0 ? word : word[0].toUpperCase() + word.slice(1) - ) // ['my', 'long', 'word'] -> ['my', 'Long', 'Word'] - .join(''); // ['my', 'Long', 'Word'] -> myLongWord + ) + .join(''); // joins ['my', 'Long', 'Word'] into 'myLongWord' } diff --git a/1-js/05-data-types/05-array-methods/10-average-age/task.md b/1-js/05-data-types/05-array-methods/10-average-age/task.md index be85200aa4..e72c461e00 100644 --- a/1-js/05-data-types/05-array-methods/10-average-age/task.md +++ b/1-js/05-data-types/05-array-methods/10-average-age/task.md @@ -4,7 +4,11 @@ importance: 4 # 平均年齢の取得 +<<<<<<< HEAD プロパティ `age` をもつオブジェクtの配列を取得し、その平均を取得する関数 `getAverageAge(users)` を書いてください。 +======= +Write the function `getAverageAge(users)` that gets an array of objects with property `age` and returns the average age. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 平均の公式は `(age1 + age2 + ... + ageN) / N` です。 diff --git a/1-js/05-data-types/05-array-methods/11-array-unique/solution.md b/1-js/05-data-types/05-array-methods/11-array-unique/solution.md index fffcaf26de..8cd4017567 100644 --- a/1-js/05-data-types/05-array-methods/11-array-unique/solution.md +++ b/1-js/05-data-types/05-array-methods/11-array-unique/solution.md @@ -2,7 +2,7 @@ - 各アイテムに対して、返却する配列がすでにそれを持っているかをチェックします。 - もしそうであれば無視し、持っていなければ結果に追加します。 -```js run +```js run demo function unique(arr) { let result = []; @@ -36,4 +36,8 @@ JavaScriptエンジンは非常に高速なので、それ自体は問題では 従って、この解答は小さい配列の場合にのみ良いです。 +<<<<<<< HEAD さらにチャプター では、それを最適化する方法を見ていきます。 +======= +Further in the chapter we'll see how to optimize it. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/test.js b/1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/test.js index 02299e307e..d3f2925072 100644 --- a/1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/test.js +++ b/1-js/05-data-types/05-array-methods/12-reduce-object/_js.view/test.js @@ -8,13 +8,21 @@ describe("groupById", function() { ]; assert.deepEqual(groupById(users), { +<<<<<<< HEAD john: {id: 'john', name: "John Smith", age: 20} +======= + john: {id: 'john', name: "John Smith", age: 20}, +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ann: {id: 'ann', name: "Ann Smith", age: 24}, pete: {id: 'pete', name: "Pete Peterson", age: 31}, }); }); it("works with an empty array", function() { +<<<<<<< HEAD +======= + users = []; +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 assert.deepEqual(groupById(users), {}); }); }); 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 b75c28352a..5f1ef9fba3 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 @@ -2,6 +2,7 @@ importance: 4 --- +<<<<<<< HEAD # 配列からキー付けされたオブジェクトを作成する `{id:..., name:..., age... }` といった形式でユーザの配列を受け取ったとしましょう。 @@ -9,6 +10,15 @@ importance: 4 これから、`id` をキーとし、配列項目を値としたオブジェクトを作成する関数 `groupById(arr)` を作成してください。 例: +======= +# Create keyed object from array + +Let's say we received an array of users in the form `{id:..., name:..., age... }`. + +Create a function `groupById(arr)` that creates an object from it, with `id` as the key, and array items as values. + +For example: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let users = [ @@ -20,18 +30,33 @@ let users = [ let usersById = groupById(users); /* +<<<<<<< HEAD // 呼び出し後はこのようになります: usersById = { john: {id: 'john', name: "John Smith", age: 20} +======= +// after the call we should have: + +usersById = { + john: {id: 'john', name: "John Smith", age: 20}, +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ann: {id: 'ann', name: "Ann Smith", age: 24}, pete: {id: 'pete', name: "Pete Peterson", age: 31}, } */ ``` +<<<<<<< HEAD このような関数はサーバデータを扱う際に非常に便利です。 このタスクでは `id` はユニークであるとします。同じ `id` を持つ配列項目はありません。 この解法では配列の `.reduce` メソッドを使用してください。 +======= +Such function is really handy when working with server data. + +In this task we assume that `id` is unique. There may be no two array items with the same `id`. + +Please use array `.reduce` method in the solution. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/05-data-types/05-array-methods/2-filter-range/solution.md b/1-js/05-data-types/05-array-methods/2-filter-range/solution.md index e69de29bb2..73993a07a0 100644 --- a/1-js/05-data-types/05-array-methods/2-filter-range/solution.md +++ b/1-js/05-data-types/05-array-methods/2-filter-range/solution.md @@ -0,0 +1,14 @@ +```js run demo +function filterRange(arr, a, b) { + // added brackets around the expression for better readability + return arr.filter(item => (a <= item && item <= b)); +} + +let arr = [5, 3, 8, 1]; + +let filtered = filterRange(arr, 1, 4); + +alert( filtered ); // 3,1 (matching values) + +alert( arr ); // 5,3,8,1 (not modified) +``` diff --git a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/solution.js b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/solution.js index 61cda126b6..488db3755b 100644 --- a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/solution.js +++ b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/_js.view/solution.js @@ -1,5 +1,4 @@ - function filterRangeInPlace(arr, a, b) { for (let i = 0; i < arr.length; i++) { @@ -12,4 +11,4 @@ function filterRangeInPlace(arr, a, b) { } } -} \ No newline at end of file +} diff --git a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/solution.md b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/solution.md index e69de29bb2..36e3130ff0 100644 --- a/1-js/05-data-types/05-array-methods/3-filter-range-in-place/solution.md +++ b/1-js/05-data-types/05-array-methods/3-filter-range-in-place/solution.md @@ -0,0 +1,21 @@ +```js run demo +function filterRangeInPlace(arr, a, b) { + + for (let i = 0; i < arr.length; i++) { + let val = arr[i]; + + // remove if outside of the interval + if (val < a || val > b) { + arr.splice(i, 1); + i--; + } + } + +} + +let arr = [5, 3, 8, 1]; + +filterRangeInPlace(arr, 1, 4); // removed the numbers except from 1 to 4 + +alert( arr ); // [3, 1] +``` diff --git a/1-js/05-data-types/05-array-methods/4-sort-back/task.md b/1-js/05-data-types/05-array-methods/4-sort-back/task.md index a965b70180..04e83270fd 100644 --- a/1-js/05-data-types/05-array-methods/4-sort-back/task.md +++ b/1-js/05-data-types/05-array-methods/4-sort-back/task.md @@ -2,12 +2,20 @@ importance: 4 --- +<<<<<<< HEAD # 逆の順序でソートする +======= +# Sort in decreasing order +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let arr = [5, 2, 1, -10, 8]; +<<<<<<< HEAD // ... 逆順でソートをするあなたのコード +======= +// ... your code to sort it in decreasing order +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 alert( arr ); // 8, 5, 2, 1, -10 ``` diff --git a/1-js/05-data-types/05-array-methods/6-calculator-extendable/_js.view/solution.js b/1-js/05-data-types/05-array-methods/6-calculator-extendable/_js.view/solution.js index 50c40e8042..45ef1619da 100644 --- a/1-js/05-data-types/05-array-methods/6-calculator-extendable/_js.view/solution.js +++ b/1-js/05-data-types/05-array-methods/6-calculator-extendable/_js.view/solution.js @@ -1,6 +1,6 @@ function Calculator() { - let methods = { + this.methods = { "-": (a, b) => a - b, "+": (a, b) => a + b }; @@ -12,14 +12,14 @@ function Calculator() { op = split[1], b = +split[2] - if (!methods[op] || isNaN(a) || isNaN(b)) { + if (!this.methods[op] || isNaN(a) || isNaN(b)) { return NaN; } - return methods[op](a, b); + return this.methods[op](a, b); } this.addMethod = function(name, func) { - methods[name] = func; + this.methods[name] = func; }; } diff --git a/1-js/05-data-types/05-array-methods/6-calculator-extendable/solution.md b/1-js/05-data-types/05-array-methods/6-calculator-extendable/solution.md index f916fe2af2..ebe0714cfb 100644 --- a/1-js/05-data-types/05-array-methods/6-calculator-extendable/solution.md +++ b/1-js/05-data-types/05-array-methods/6-calculator-extendable/solution.md @@ -1,3 +1,3 @@ -- メソッドの格納方法に注意してください。それらは単に内部オブジェクトに追加されています。 -- すべてのテストと数値変換は `calculate` メソッドで行われます。将来より複雑な式をサポートするために拡張されるかもしれません。 +- Please note how methods are stored. They are simply added to `this.methods` property. +- All tests and numeric conversions are done in the `calculate` method. In future it may be extended to support more complex expressions. diff --git a/1-js/05-data-types/05-array-methods/6-calculator-extendable/task.md b/1-js/05-data-types/05-array-methods/6-calculator-extendable/task.md index c46ffa4c55..e0d302f4ce 100644 --- a/1-js/05-data-types/05-array-methods/6-calculator-extendable/task.md +++ b/1-js/05-data-types/05-array-methods/6-calculator-extendable/task.md @@ -2,24 +2,24 @@ importance: 5 --- -# 拡張可能な計算機を作る +# Create an extendable calculator -"拡張可能な" 計算機オブジェクトを作るコンストラクタ関数 `Calculator` を作りなさい。 +Create a constructor function `Calculator` that creates "extendable" calculator objects. -タスクは2つのパートから構成されます。 +The task consists of two parts. -1. 最初に フォーマット "数値 演算子 数値" (スペース区切り) で、`"1 + 2"` のような文字列を取り、結果を返すメソッド `calculate(str)` メソッドを実装します。それはプラス `+` と マイナス `-` を理解できるようにしてください。 +1. First, implement the method `calculate(str)` that takes a string like `"1 + 2"` in the format "NUMBER operator NUMBER" (space-delimited) and returns the result. Should understand plus `+` and minus `-`. - 使い方の例: + Usage example: ```js let calc = new Calculator; alert( calc.calculate("3 + 7") ); // 10 ``` -2. 次に、計算機に新しい操作を教えるメソッド `addOperator(name, func)` を追加します。操作 `name` と、それを実装する2つの引数を持つ関数 `func(a,b)` を取ります。 +2. Then add the method `addMethod(name, func)` that teaches the calculator a new operation. It takes the operator `name` and the two-argument function `func(a,b)` that implements it. - 例えば、乗算 `*`, 除算 `/` やべき乗 `**`: + For instance, let's add the multiplication `*`, division `/` and power `**`: ```js let powerCalc = new Calculator; @@ -31,6 +31,6 @@ importance: 5 alert( result ); // 8 ``` -- このタスクではかっこや複雑な表現は不要です。 -- 数字と演算子は、正確に1つのスペースで区切られます。 -- 追加したい場合にエラー処理があるかもしれません。 +- No parentheses or complex expressions in this task. +- The numbers and the operator are delimited with exactly one space. +- There may be error handling if you'd like to add it. diff --git a/1-js/05-data-types/05-array-methods/8-sort-objects/solution.md b/1-js/05-data-types/05-array-methods/8-sort-objects/solution.md index ad4e790cee..b4b022ecf5 100644 --- a/1-js/05-data-types/05-array-methods/8-sort-objects/solution.md +++ b/1-js/05-data-types/05-array-methods/8-sort-objects/solution.md @@ -1,17 +1,23 @@ ```js run no-beautify +<<<<<<< HEAD function sortByName(arr) { arr.sort((a, b) => b.name > a.name ? 1 : -1); +======= +function sortByAge(arr) { + arr.sort((a, b) => a.age > b.age ? 1 : -1); +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 } let john = { name: "John", age: 25 }; let pete = { name: "Pete", age: 30 }; let mary = { name: "Mary", age: 28 }; -let arr = [ john, pete, mary ]; +let arr = [ pete, john, mary ]; -sortByName(arr); +sortByAge(arr); // now sorted is: [john, mary, pete] +alert(arr[0].name); // John alert(arr[1].name); // Mary +alert(arr[2].name); // Pete ``` - diff --git a/1-js/05-data-types/05-array-methods/8-sort-objects/task.md b/1-js/05-data-types/05-array-methods/8-sort-objects/task.md index d153c09617..5ff3ba3eae 100644 --- a/1-js/05-data-types/05-array-methods/8-sort-objects/task.md +++ b/1-js/05-data-types/05-array-methods/8-sort-objects/task.md @@ -2,9 +2,15 @@ importance: 5 --- +<<<<<<< HEAD # ソートオブジェクト プロパティ `name` を持つオブジェクトの配列を取得し、それをソートする関数 `sortByName(users)` を書いてください。 +======= +# Sort users by age + +Write the function `sortByAge(users)` that gets an array of objects with the `age` property and sorts them by `age`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: @@ -13,10 +19,12 @@ let john = { name: "John", age: 25 }; let pete = { name: "Pete", age: 30 }; let mary = { name: "Mary", age: 28 }; -let arr = [ john, pete, mary ]; +let arr = [ pete, john, mary ]; -sortByName(arr); +sortByAge(arr); // now: [john, mary, pete] +alert(arr[0].name); // John alert(arr[1].name); // Mary +alert(arr[2].name); // Pete ``` diff --git a/1-js/05-data-types/05-array-methods/9-shuffle/solution.md b/1-js/05-data-types/05-array-methods/9-shuffle/solution.md index 25bdb9630c..28f547a35d 100644 --- a/1-js/05-data-types/05-array-methods/9-shuffle/solution.md +++ b/1-js/05-data-types/05-array-methods/9-shuffle/solution.md @@ -45,7 +45,11 @@ for (let key in count) { } ``` +<<<<<<< HEAD 結果例は次の通りです(V8, 2017/7): +======= +An example result (depends on JS engine): +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js 123: 250706 @@ -67,8 +71,19 @@ for (let key in count) { ```js function shuffle(array) { for (let i = array.length - 1; i > 0; i--) { +<<<<<<< HEAD let j = Math.floor(Math.random() * (i + 1)); // 0 から i のランダムなインデックス [array[i], array[j]] = [array[j], array[i]]; // 要素を入れ替えます +======= + let j = Math.floor(Math.random() * (i + 1)); // random index from 0 to i + + // swap elements array[i] and array[j] + // we use "destructuring assignment" syntax to achieve that + // you'll find more details about that syntax in later chapters + // same can be written as: + // let t = array[i]; array[i] = array[j]; array[j] = t + [array[i], array[j]] = [array[j], array[i]]; +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 } } ``` 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 5c9c411056..46cf374b2d 100644 --- a/1-js/05-data-types/05-array-methods/article.md +++ b/1-js/05-data-types/05-array-methods/article.md @@ -2,9 +2,13 @@ 配列は多くのメソッドを提供します。分かりやすくするために、このチャプターではグループに分けて説明します。 +<<<<<<< HEAD [cut] ## アイテムの追加/削除 +======= +## Add/remove items +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 私たちは既に先頭または末尾にアイテムを追加/削除するメソッドを知っています: @@ -13,7 +17,11 @@ - `shift()` は先頭の要素を削除し、それを返します。 - `unshift(...items)` はアイテムを先頭に追加します。 +<<<<<<< HEAD 他にもいくつかあります。 +======= +Here are a few others. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ### splice @@ -38,7 +46,11 @@ alert( arr.length ); // 3 なので、特別なメソッドを使用する必要があります。 +<<<<<<< HEAD [arr.splice(str)](mdn:js/Array/splice) メソッドは、配列用のスイス製アーミーナイフです。それは何でもすることができます: 追加、削除、また要素の挿入も。 +======= +The [arr.splice(start)](mdn:js/Array/splice) method is a swiss army knife for arrays. It can do everything: insert, remove and replace elements. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 構文: @@ -121,29 +133,38 @@ alert( arr ); // 1,2,3,4,5 構文: ```js -arr.slice(start, end) +arr.slice([start], [end]) ``` +<<<<<<< HEAD 開始インデックス `"start"` から `"end"` (`"end"` は含みません)のすべてのアイテムをコピーした新しい配列を返します。`start` と `end` はともに負値になることができます。そのときは、配列の末尾からの位置が想定されます。 `str.slice` のように動作しますが、部分文字列の代わりに部分配列を作ります。 +======= +It returns a new array copying to it all items from index `start` to `end` (not including `end`). Both `start` and `end` can be negative, in that case position from array end is assumed. + +It's similar to a string method `str.slice`, but instead of substrings it makes subarrays. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: ```js run -let str = "test"; let arr = ["t", "e", "s", "t"]; -alert( str.slice(1, 3) ); // es -alert( arr.slice(1, 3) ); // e,s +alert( arr.slice(1, 3) ); // e,s (copy from 1 to 3) -alert( str.slice(-2) ); // st -alert( arr.slice(-2) ); // s,t +alert( arr.slice(-2) ); // s,t (copy from -2 till the end) ``` +We can also call it without arguments: `arr.slice()` creates a copy of `arr`. That's often used to obtain a copy for further transformations that should not affect the original array. + ### concat +<<<<<<< HEAD メソッド [arr.concat](mdn:js/Array/concat) は配列を他の配列またはアイテムと結合します。 +======= +The method [arr.concat](mdn:js/Array/concat) creates a new array that includes values from other arrays and additional items. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 構文: @@ -155,13 +176,18 @@ arr.concat(arg1, arg2...) 結果は `arr`, 次に `arg1`, `arg2` などのアイテムを含む新しい配列を返します。 +<<<<<<< HEAD もし、引数が配列、もしくは `Symbol.isConcatSpreadable` プロパティを持っている場合、その全ての要素がコピーされます。そうでない場合、引数自体がコピーされます。 +======= +If an argument `argN` is an array, then all its elements are copied. Otherwise, the argument itself is copied. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: ```js run let arr = [1, 2]; +<<<<<<< HEAD // arr と [3,4] をマージ alert( arr.concat([3, 4])); // 1,2,3,4 @@ -173,6 +199,19 @@ alert( arr.concat([3, 4], 5, 6)); // 1,2,3,4,5,6 ``` 通常は、配列から要素をコピーするだけです。それ以外のオブジェクトでは、配列のように見えたとしても、全体として追加されます: +======= +// create an array from: arr and [3,4] +alert( arr.concat([3, 4]) ); // 1,2,3,4 + +// create an array from: arr and [3,4] and [5,6] +alert( arr.concat([3, 4], [5, 6]) ); // 1,2,3,4,5,6 + +// create an array from: arr and [3,4], then add values 5 and 6 +alert( arr.concat([3, 4], 5, 6) ); // 1,2,3,4,5,6 +``` + +Normally, it only copies elements from arrays. Other objects, even if they look like arrays, are added as a whole: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let arr = [1, 2]; @@ -183,10 +222,13 @@ let arrayLike = { }; alert( arr.concat(arrayLike) ); // 1,2,[object Object] -//[1, 2, arrayLike] ``` +<<<<<<< HEAD ...しかし、もし配列のようなオブジェクトが `Symbol.isConcatSpreadable` プロパティを持つ場合、代わりにその要素が追加されます: +======= +...But if an array-like object has a special `Symbol.isConcatSpreadable` property, then it's treated as an array by `concat`: its elements are added instead: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let arr = [1, 2]; @@ -203,6 +245,7 @@ let arrayLike = { alert( arr.concat(arrayLike) ); // 1,2,something,else ``` +<<<<<<< HEAD ## イテレート/反復: forEach [arr.forEach](mdn:js/Array/forEach) メソッドは配列の全要素に対して関数を実行することができます。 @@ -235,14 +278,54 @@ arr.forEach(function(item, index, array) { ## 配列での検索 これらは、配列で何かを探すためのメソッドです。 +======= +## Iterate: forEach + +The [arr.forEach](mdn:js/Array/forEach) method allows to run a function for every element of the array. + +The syntax: +```js +arr.forEach(function(item, index, array) { + // ... do something with item +}); +``` + +For instance, this shows each element of the array: + +```js run +// for each element call alert +["Bilbo", "Gandalf", "Nazgul"].forEach(alert); +``` + +And this code is more elaborate about their positions in the target array: + +```js run +["Bilbo", "Gandalf", "Nazgul"].forEach((item, index, array) => { + alert(`${item} is at index ${index} in ${array}`); +}); +``` + +The result of the function (if it returns any) is thrown away and ignored. + + +## Searching in array + +Now let's cover methods that search in an array. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ### indexOf/lastIndexOf and includes メソッド [arr.indexOf](mdn:js/Array/indexOf), [arr.lastIndexOf](mdn:js/Array/lastIndexOf) と [arr.includes](mdn:js/Array/includes) は文字列の場合と同じ構文を持ち、基本的に同じことを行いますが、文字の代わりにアイテムを操作します: +<<<<<<< HEAD - `arr.indexOf(item, from)` はインデックス `from` から `item` を探し、見つかった場所のインデックスを返します。そうでない場合は `-1` になります。 - `arr.lastIndexOf(item, from)` は同じですが、右から左に見ていきます。 - `arr.includes(item, from)` はインデックス `from` から `item` を探し、見つかった場合、`true` を返します。 +======= +- `arr.indexOf(item, from)` -- looks for `item` starting from index `from`, and returns the index where it was found, otherwise `-1`. +- `arr.lastIndexOf(item, from)` -- same, but looks for from right to left. +- `arr.includes(item, from)` -- looks for `item` starting from index `from`, returns `true` if found. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: @@ -260,7 +343,11 @@ alert( arr.includes(1) ); // true もしも含んでいるかをチェックしたいが、正確なインデックスは不要なときは、`arr.includes` が好ましいです。 +<<<<<<< HEAD また、`includes` の非常に小さな違いは、`indexOf/lastIndexOf` と違い、`NaN` を正しく処理することができます: +======= +Also, a very minor difference of `includes` is that it correctly handles `NaN`, unlike `indexOf/lastIndexOf`: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run const arr = [NaN]; @@ -272,16 +359,29 @@ alert( arr.includes(NaN) );// true (正しい) オブジェクトの配列を持っていることを想像してください。特定条件を持つオブジェクトをどのようにして見つけますか? +<<<<<<< HEAD ここで [arr.find](mdn:js/Array/find) メソッドが便利です。 +======= +Here the [arr.find(fn)](mdn:js/Array/find) method comes in handy. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 構文はこうです: ```js let result = arr.find(function(item, index, array) { +<<<<<<< HEAD // item が探しているものであれば true を返すようにします }); ``` 関数は配列の要素毎に繰り返し呼ばれます: +======= + // if true is returned, item is returned and iteration is stopped + // for falsy scenario returns undefined +}); +``` + +The function is called for elements of the array, one after another: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 - `item` は要素です。 - `index` はインデックスです。 @@ -305,20 +405,37 @@ alert(user.name); // John 現実の世界では、オブジェクトの配列は一般的なことです。なので、 `find` メソッドは非常に役立ちます。 +<<<<<<< HEAD 例の中では1つの引数、関数 `item => item.id == 1` で `find` を行っている点に注意してください。`find` の他のパラメータは殆ど使われません。 [arr.findIndex](mdn:js/Array/findIndex) メソッドは基本的に同じです。が、要素自体ではなく要素が見つかったインデックスを返します。 +======= +Note that in the example we provide to `find` the function `item => item.id == 1` with one argument. That's typical, other arguments of this function are rarely used. + +The [arr.findIndex](mdn:js/Array/findIndex) method is essentially the same, but it returns the index where the element was found instead of the element itself and `-1` is returned when nothing is found. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ### filter `find` メソッドは、関数が `true` を返すようにする単一の(最初の)要素を探します。 もしそれが多い場合、[arr.filter(fn)](mdn:js/Array/filter) を使います。 +<<<<<<< HEAD 構文は大体 `find` と同じですが、マッチした要素の配列を返します: ```js let results = arr.filter(function(item, index, array) { // item がフィルタを通過する場合はtrueを返します +======= +If there may be many, we can use [arr.filter(fn)](mdn:js/Array/filter). + +The syntax is similar to `find`, but `filter` returns an array of all matching elements: + +```js +let results = arr.filter(function(item, index, array) { + // if true item is pushed to results and the iteration continues + // returns empty array if nothing found +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 }); ``` @@ -337,14 +454,21 @@ let someUsers = users.filter(item => item.id < 3); alert(someUsers.length); // 2 ``` +<<<<<<< HEAD ## 配列を変換する このセクションでは、配列を変換または並び替える方法について説明します。 +======= +## Transform an array + +Let's move on to methods that transform and reorder an array. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ### map [arr.map](mdn:js/Array/map) メソッドは最も便利なものの1つで、よく使われます。 +<<<<<<< HEAD 構文: ```js @@ -356,22 +480,45 @@ let result = arr.map(function(item, index, array) { これは、配列の各要素で関数を呼び出し、結果の配列を返します。 例えば、ここでは各要素をその長さに変換します: +======= +It calls the function for each element of the array and returns the array of results. + +The syntax is: + +```js +let result = arr.map(function(item, index, array) { + // returns the new value instead of item +}); +``` + +For instance, here we transform each element into its length: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run -let lengths = ["Bilbo", "Gandalf", "Nazgul"].map(item => item.length) +let lengths = ["Bilbo", "Gandalf", "Nazgul"].map(item => item.length); alert(lengths); // 5,7,6 ``` ### sort(fn) +<<<<<<< HEAD メソッド [arr.sort](mdn:js/Array/sort) は配列を *決まった位置に* ソートします。 +======= +The call to [arr.sort()](mdn:js/Array/sort) sorts the array *in place*, changing its element order. + +It also returns the sorted array, but the returned value is usually ignored, as `arr` itself is modified. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: ```js run let arr = [ 1, 2, 15 ]; +<<<<<<< HEAD // このメソッドは arr の内容を並べ替え(てそれを返します) +======= +// the method reorders the content of arr +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 arr.sort(); alert( arr ); // *!*1, 15, 2*/!* @@ -383,20 +530,32 @@ alert( arr ); // *!*1, 15, 2*/!* **アイテムは、デフォルトでは文字列としてソートされます。** +<<<<<<< HEAD 文字通り、すべての要素は文字列に変換され、比較されます。なので、辞書編集順序が適用され、実際には `"2" > "15"` となります。 私たち独自のソート順を使うためには、`arr.sort()` の引数として、2つの引数をもつ関数を指定する必要があります。 関数はこのように動作する必要があります: +======= +Literally, all elements are converted to strings for comparisons. For strings, lexicographic ordering is applied and indeed `"2" > "15"`. + +To use our own sorting order, we need to supply a function as the argument of `arr.sort()`. + +The function should compare two arbitrary values and return: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js function compare(a, b) { - if (a > b) return 1; - if (a == b) return 0; - if (a < b) return -1; + if (a > b) return 1; // if the first value is greater than the second + if (a == b) return 0; // if values are equal + if (a < b) return -1; // if the first value is less than the second } ``` +<<<<<<< HEAD 例: +======= +For instance, to sort as numbers: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run function compareNumeric(a, b) { @@ -416,9 +575,15 @@ alert(arr); // *!*1, 2, 15*/!* これで意図したとおりに動作します。 +<<<<<<< HEAD 立ち止まって何が起きているのか考えてみましょう。`arr` は何でも配列にすることができます。それは数値や文字列、html要素やその他何でも含まれる可能性があります。私たちは *何かの* セットを持っています。それらをソートするためには、要素を比較する方法を知っている *順序付け関数* が必要です。 デフォルトは文字列です。 `arr.sort(fn)` メソッドは組み込みでソートアルゴリズムの実装を持っています。私たちはそれが正確にどのように動作するかについては気にする必要はありません (殆どの場合、最適化された[クイックソート](https://en.wikipedia.org/wiki/Quicksort) です)。配列の要素を見ていき、提供された関数を使ってその要素を比較し、並べ替えます。私たちに必要なのは、比較を行う `fn` を提供することだけです。 +======= +Let's step aside and think what's happening. The `arr` can be array of anything, right? It may contain numbers or strings or objects or whatever. We have a set of *some items*. To sort it, we need an *ordering function* that knows how to compare its elements. The default is a string order. + +The `arr.sort(fn)` method implements a generic sorting algorithm. We don't need to care how it internally works (an optimized [quicksort](https://en.wikipedia.org/wiki/Quicksort) most of the time). It will walk the array, compare its elements using the provided function and reorder them, all we need is to provide the `fn` which does the comparison. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ところで、もしどの要素が比較されているかを知りたいとき、`alert` をしても問題ありません: @@ -428,7 +593,11 @@ alert(arr); // *!*1, 2, 15*/!* }); ``` +<<<<<<< HEAD アルゴリズムは処理の中で複数回要素を比較しますが、できるだけ回数を少なくしようとします。 +======= +The algorithm may compare an element with multiple others in the process, but it tries to make as few comparisons as possible. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ````smart header="比較関数は任意の数を返すことがあります" 実際には、比較関数は正の数を「より大きい」、負の数を「より小さい」として返せば十分です。 @@ -444,14 +613,39 @@ alert(arr); // *!*1, 2, 15*/!* ``` ```` +<<<<<<< HEAD ````smart header="ベストなアロー関数" [アロー関数](info:function-expressions-arrows#arrow-functions) を覚えていますか? すっきりしたソートを書くために使えます。: +======= +````smart header="Arrow functions for the best" +Remember [arrow functions](info:arrow-functions-basics)? We can use them here for neater sorting: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js arr.sort( (a, b) => a - b ); ``` +<<<<<<< HEAD これは、他の上で書いているより長いバージョンとまったく同じように動作します。 +======= +This works exactly the same as the longer version above. +```` + +````smart header="Use `localeCompare` for strings" +Remember [strings](info:string#correct-comparisons) comparison algorithm? It compares letters by their codes by default. + +For many alphabets, it's better to use `str.localeCompare` method to correctly sort letters, such as `Ö`. + +For example, let's sort a few countries in German: + +```js run +let countries = ['Österreich', 'Andorra', 'Vietnam']; + +alert( countries.sort( (a, b) => a > b ? 1 : -1) ); // Andorra, Vietnam, Österreich (wrong) + +alert( countries.sort( (a, b) => a.localeCompare(b) ) ); // Andorra,Österreich,Vietnam (correct!) +``` +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```` ### reverse @@ -471,7 +665,11 @@ alert( arr ); // 5,4,3,2,1 ### split と join +<<<<<<< HEAD ここでは現実世界でのシチュエーションを考えます。私たちはメッセージングアプリを書いており、利用者はカンマ区切りで受信者のリスト(`John, Pete, Mary`)を入力します。しかし、我々にとっては、1つの文字列よりも名前の配列の方がはるかに扱いやすいです。それを得る方法は? +======= +Here's the situation from real life. We are writing a messaging app, and the person enters the comma-delimited list of receivers: `John, Pete, Mary`. But for us an array of names would be much more comfortable than a single string. How to get it? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 [str.split(delim)](mdn:js/String/split) メソッドは、まさにそれをします。与えられた区切り文字 `delim` で文字列を配列に分割します。 @@ -505,21 +703,29 @@ alert( str.split('') ); // t,e,s,t ``` ```` +<<<<<<< HEAD [arr.join(str)](mdn:js/Array/join) は `split` と逆を行います。`arr` のアイテムを `str` で繋いだ文字列を作ります。 +======= +The call [arr.join(glue)](mdn:js/Array/join) does the reverse to `split`. It creates a string of `arr` items joined by `glue` between them. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: ```js run let arr = ['Bilbo', 'Gandalf', 'Nazgul']; -let str = arr.join(';'); +let str = arr.join(';'); // glue the array into a string using ; alert( str ); // Bilbo;Gandalf;Nazgul ``` ### reduce/reduceRight +<<<<<<< HEAD 配列に対して繰り返し処理が必要なときは、`forEach` を使うことができます。 +======= +When we need to iterate over an array -- we can use `forEach`, `for` or `for..of`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 各要素のデータを反復して返す必要があるときには、`map`を使うことができます。 @@ -528,11 +734,12 @@ alert( str ); // Bilbo;Gandalf;Nazgul 構文: ```js -let value = arr.reduce(function(previousValue, item, index, arr) { +let value = arr.reduce(function(accumulator, item, index, array) { // ... -}, initial); +}, [initial]); ``` +<<<<<<< HEAD 関数は各要素に適用されます。あなたはよく知られている引数に気づくかもしれません。2つ目から始まる引数は次の通りです: - `item` -- 現在の配列の項目です。 @@ -542,10 +749,30 @@ let value = arr.reduce(function(previousValue, item, index, arr) { これまでのところ、`forEach/map` のようです。しかし、もう1つ引数があります: - `previousValue` -- 前の関数の呼び出し結果です。最初の呼び出しは `initial` です。 +======= +The function is applied to all array elements one after another and "carries on" its result to the next call. + +Arguments: + +- `accumulator` -- is the result of the previous function call, equals `initial` the first time (if `initial` is provided). +- `item` -- is the current array item. +- `index` -- is its position. +- `array` -- is the array. + +As function is applied, the result of the previous function call is passed to the next one as the first argument. + +So, the first argument is essentially the accumulator that stores the combined result of all previous executions. And at the end it becomes the result of `reduce`. + +Sounds complicated? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 これを掴むための最も簡単な方法は、例を見る、です。 +<<<<<<< HEAD ここでは、1行で配列の合計を取得します。 +======= +Here we get a sum of an array in one line: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let arr = [1, 2, 3, 4, 5]; @@ -555,23 +782,40 @@ let result = arr.reduce((sum, current) => sum + current, 0); alert(result); // 15 ``` +<<<<<<< HEAD ここでは、2つの引数だけを使用する `reduce` の最も一般的なバリアントを使用しました。 +======= +The function passed to `reduce` uses only 2 arguments, that's typically enough. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 +<<<<<<< HEAD 何が起きているか、詳細を見てみましょう。 +======= +1. On the first run, `sum` is the `initial` value (the last argument of `reduce`), equals `0`, and `current` is the first array element, equals `1`. So the function result is `1`. +2. On the second run, `sum = 1`, we add the second array element (`2`) to it and return. +3. On the 3rd run, `sum = 3` and we add one more element to it, and so on... +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 1. 最初の実行で `sum` は initial 値(`reduce` の最後の引数)であり、 `0` と等価です。そして、 `current` は最初の配列要素で `1` になります。従って、結果は `1` です。 2. 2回目の実行では、`sum = 1` で、2つ目の配列要素(`2`)をそれに足して返します。 3. 3回目の実行では、`sum = 3` で、それに1つ要素を足します。それが続きます。 +<<<<<<< HEAD 計算のフロー: ![](reduce.svg) また、次のテーブルでは、各行は次の配列要素の関数呼び出しを表しています。 +======= +![](reduce.svg) + +Or in the form of a table, where each row represents a function call on the next array element: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 -| |`sum`|`current`|`result`| +| |`sum`|`current`|result| |---|-----|---------|---------| +<<<<<<< HEAD |最初の呼び出し|`0`|`1`|`1`| |2回目の呼び出し|`1`|`2`|`3`| |3回目の呼び出し|`3`|`3`|`6`| @@ -579,6 +823,15 @@ alert(result); // 15 |5回目の呼び出し|`10`|`5`|`15`| これらから分かるように、前の呼び出しの結果は次の実行のときの最初の引数になっています。 +======= +|the first call|`0`|`1`|`1`| +|the second call|`1`|`2`|`3`| +|the third call|`3`|`3`|`6`| +|the fourth call|`6`|`4`|`10`| +|the fifth call|`10`|`5`|`15`| + +Here we can clearly see how the result of the previous call becomes the first argument of the next one. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 また、 initial 値を省略することもできます。: @@ -607,11 +860,20 @@ let arr = []; arr.reduce((sum, current) => sum + current); ``` +<<<<<<< HEAD 従って、常に初期値を指定することをおすすめします。 [arr.reduceRight](mdn:js/Array/reduceRight) メソッドも同じをことを行いますが、右から左に実行します。 ## Array.isArray +======= +So it's advised to always specify the initial value. + +The method [arr.reduceRight](mdn:js/Array/reduceRight) does the same, but goes from right to left. + + +## Array.isArray +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 配列は別の言語の型を形成しません。 それらはオブジェクトに基づいています。 @@ -648,35 +910,58 @@ arr.map(func, thisArg); `thisArg` パラメータの値は `func` での `this` になります。 +<<<<<<< HEAD 例えば、ここではオブジェクトメソッドをフィルタとして使用し、`thisArg` が役立ちます。: +======= +For example, here we use a method of `army` object as a filter, and `thisArg` passes the context: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run -let user = { - age: 18, - younger(otherUser) { - return otherUser.age < this.age; +let army = { + minAge: 18, + maxAge: 27, + canJoin(user) { + return user.age >= this.minAge && user.age < this.maxAge; } }; let users = [ - {age: 12}, {age: 16}, - {age: 32} + {age: 20}, + {age: 23}, + {age: 30} ]; *!* +<<<<<<< HEAD // user より若いすべてのユーザを見つけます let youngerUsers = users.filter(user.younger, user); +======= +// find users, for who army.canJoin returns true +let soldiers = users.filter(army.canJoin, army); +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 */!* -alert(youngerUsers.length); // 2 +alert(soldiers.length); // 2 +alert(soldiers[0].age); // 20 +alert(soldiers[1].age); // 23 ``` +<<<<<<< HEAD 上の呼び出しでは、フィルタとして `user.younger` を使い、そのコンテキストとして `user` を提供しています。もしもコンテキストを提供しなかった場合、`users.filter(user.younger)` はスタンドアロン関数として `this=undefined` で `user.younger` を呼び出します。それは即時エラーを意味します。 +======= +If in the example above we used `users.filter(army.canJoin)`, then `army.canJoin` would be called as a standalone function, with `this=undefined`, thus leading to an instant error. + +A call to `users.filter(army.canJoin, army)` can be replaced with `users.filter(user => army.canJoin(user))`, that does the same. The former is used more often, as it's a bit easier to understand for most people. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## サマリ +<<<<<<< HEAD 配列メソッドの チートシート です: +======= +A cheat sheet of array methods: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 - 要素の追加/削除をする場合: - `push(...items)` -- アイテムを末尾に追加します, @@ -693,6 +978,7 @@ alert(youngerUsers.length); // 2 - `find/filter(func)` -- 関数を介して要素をフィルタリングし、`true` を返す最初の/すべての値を返します。 - `findIndex` は `find` のようですが、値の代わりにインデックスを返します。 +<<<<<<< HEAD - 配列を変換するには: - `map(func)` -- すべての要素に対して `func` を呼び出した結果から新しい配列を作成します。 - `sort(func)` -- 配列を適切な位置でソートし、それを返します。 @@ -705,6 +991,20 @@ alert(youngerUsers.length); // 2 - さらに: - `Array.isArray(arr)` は `arr` が配列かどうかをチェックします。 +======= +- To iterate over elements: + - `forEach(func)` -- calls `func` for every element, does not return anything. + +- To transform the array: + - `map(func)` -- creates a new array from results of calling `func` for every element. + - `sort(func)` -- sorts the array in-place, then returns it. + - `reverse()` -- reverses the array in-place, then returns it. + - `split/join` -- convert a string to array and back. + - `reduce(func, initial)` -- calculate a single value over the array by calling `func` for each element and passing an intermediate result between the calls. + +- Additionally: + - `Array.isArray(arr)` checks `arr` for being an array. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 `sort`, `reverse` と `splice` メソッドは、配列自身を変更することに注意してください。 @@ -720,8 +1020,16 @@ alert(youngerUsers.length); // 2 完全なリストは [manual](mdn:js/Array) を見てください。 +<<<<<<< HEAD 初めてみたとき、多くのメソッドがあり覚えるのがとても難しいように見えるかもしれません。しかし、実際にはそう見えるよりもはるかに簡単です。 チートシートを見て、それらを認識してください。 それから、このチャプターのタスクで練習してください。そうすれば配列メソッドの経験を積むことができます。 今後、配列で何かをする必要があるとき、どうやればいいか分からないときはいつでもここに来て、 チートシート を見て正しいメソッドを見つけてください。例はあなたが正しくそのメソッドを使うのに役立つでしょう。使っていると自然とそれらのメソッドを覚えていくでしょう。 +======= +From the first sight it may seem that there are so many methods, quite difficult to remember. But actually that's much easier. + +Look through the cheat sheet just to be aware of them. Then solve the tasks of this chapter to practice, so that you have experience with array methods. + +Afterwards whenever you need to do something with an array, and you don't know how -- come here, look at the cheat sheet and find the right method. Examples will help you to write it correctly. Soon you'll automatically remember the methods, without specific efforts from your side. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/05-data-types/06-iterable/article.md b/1-js/05-data-types/06-iterable/article.md index b960719b4f..6ef061eb68 100644 --- a/1-js/05-data-types/06-iterable/article.md +++ b/1-js/05-data-types/06-iterable/article.md @@ -1,19 +1,30 @@ # 反復可能なオブジェクト +<<<<<<< HEAD *反復可能な(iterables)* オブジェクトは配列の汎化です。これは、`for..of` ループで任意のオブジェクトを使用できるようにするための概念です。 もちろん、配列は反復可能です。しかし、他にも多くの組み込みオブジェクトがあり、それらも同様に反復可能です。例えば、文字列も反復可能です。後で分かりますが、多くの組み込みの演算子やメソッドはそれらに依存しています。 もしオブジェクトが何かの集合(リスト、セット)を表す場合、`for..of` はそれをループ処理するのに最適な構文です。それでは、それを動作させる方法を見てみましょう。 +======= +*Iterable* objects is a generalization of arrays. That's a concept that allows us to make any object useable in a `for..of` loop. + +Of course, Arrays are iterable. But there are many other built-in objects, that are iterable as well. For instance, strings are also iterable. + +If an object isn't technically an array, but represents a collection (list, set) of something, then `for..of` is a great syntax to loop over it, so let's see how to make it work. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 -[cut] ## Symbol.iterator 私たち自身で実際に作ってみると、反復可能(iterables) の概念を簡単に掴む事ができます。 +<<<<<<< HEAD 例えば、配列ではありませんが、`for..of` に適したオブジェクトを持っています。 +======= +For instance, we have an object that is not an array, but looks suitable for `for..of`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 数値の間隔を表す `range` オブジェクトのように: @@ -29,12 +40,21 @@ let range = { `range` を 反復可能(iterable) にするために (`for..of` を動作させるために)は、`Symbol.iterator` (このための特別な組み込みのシンボルです)という名前のメソッドをオブジェクトに追加する必要があります。 +<<<<<<< HEAD - `for..of` が始まると、そのメソッドを呼び出します(なければエラーになります)。 - メソッドは *iterator* (メソッド `next` をもつオブジェクト)を返さなければいけません。 - `for..of` が次の値を必要とするとき、そのオブジェクトの `next()` を呼びます。 - `next()` の結果は `{done: Boolean, value: any}` の形式でなければなりません。そして `done=true` は繰り返しが終わったことを示します。そうでない場合は、`value` は新しい値である必要があります。 これは `range` の完全な実装です: +======= +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 iteration is finished, otherwise `value` is the next value. + +Here's the full implementation for `range` with remarks: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let range = { @@ -45,7 +65,12 @@ let range = { // 1. for..of の呼び出しは、最初にこれを呼び出します range[Symbol.iterator] = function() { +<<<<<<< HEAD // 2. ...これは iterator を返します: +======= + // ...it returns the iterator object: + // 2. Onward, for..of works only with this iterator, asking it for next values +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 return { current: this.from, last: this.to, @@ -68,10 +93,17 @@ for (let num of range) { } ``` +<<<<<<< HEAD 反復可能(iterables)の中心的な機能に注意してください。: 重要な関心の分離があります。 - `range` 自身は `next()` メソッドを持っていません。 - 代わりに、別のオブジェクト、いわゆる "イテレータ" は `range[Symbol.iterator]()` の呼び出しで生成され、反復を処理します。 +======= +Please note the core feature of iterables: separation of concerns. + +- The `range` itself does not have the `next()` method. +- Instead, another object, a so-called "iterator" is created by the call to `range[Symbol.iterator]()`, and its `next()` generates values for the iteration. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 従って、反復オブジェクトは反復処理されるオブジェクトから分離されています。 @@ -103,10 +135,19 @@ for (let num of range) { } ``` +<<<<<<< HEAD 今、`range[Symbol.iterator]()` は `range` オブジェクト自身を返します: それは必要な `next()` メソッドを持ち、`this.current` で現在の反復の状況を覚えています。場合によってはそれでも問題ありません。欠点は、オブジェクトに対して同時に2つの `for..of` ループを実行することは不可能だということです。: イテレータ が1つしかないので、オブジェクトは繰り返し状態を共有します。 ```smart header="無限のイテレータ" 無限の イテレータ もまた実行可能です。例えば、 `range.to = Infinity` で、`range` が無限大になります。または、擬似乱数の無限のシーケンスを生成する反復可能なオブジェクトを作ることができます。これもまた役立つことがあります。 +======= +Now `range[Symbol.iterator]()` returns the `range` object itself: it has the necessary `next()` method and remembers the current iteration progress in `this.current`. Shorter? Yes. And sometimes that's fine too. + +The downside is that now it's impossible to have two `for..of` loops running over the object simultaneously: they'll share the iteration state, because there's only one iterator -- the object itself. But two parallel for-ofs is a rare thing, even in async scenarios. + +```smart header="Infinite iterators" +Infinite iterators are also possible. For instance, the `range` becomes infinite for `range.to = Infinity`. Or we can make an iterable object that generates an infinite sequence of pseudorandom numbers. Also can be useful. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 `next` には制限はなく、より多くの値を返すことができますが、これは正常です。 @@ -122,11 +163,20 @@ for (let num of range) { ```js run for (let char of "test") { +<<<<<<< HEAD alert( char ); // t, 次に e, 次に s, そして t } ``` そしてサロゲートペアも正しく動作します! +======= + // triggers 4 times: once for each character + alert( char ); // t, then e, then s, then t +} +``` + +And it works correctly with surrogate pairs! +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let str = '𝒳😂'; @@ -137,11 +187,17 @@ for (let char of str) { ## イテレータを明示的に呼び出す +<<<<<<< HEAD 通常、iterables の内部は外部のコードからは隠れています。`for..of` ループがあり、それが動作します。それだけを知っておけば問題ありません。 しかし、もう少し深く理解するために、明示的なイテレータの作り方を見てみましょう。 `for..of` と同じ方法で文字列を反復処理しますが、直接呼び出しをします。このコードは文字列のイテレータを取得し、それを "手動" で呼び出します。: +======= +For deeper understanding let's see how to use an iterator explicitly. + +We'll iterate over a string in exactly the same way as `for..of`, but with direct calls. This code creates a string iterator and gets values from it "manually": +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let str = "Hello"; @@ -149,7 +205,9 @@ let str = "Hello"; // for (let char of str) alert(char); // と同じことをしています +*!* let iterator = str[Symbol.iterator](); +*/!* while (true) { let result = iterator.next(); @@ -167,7 +225,13 @@ while (true) { - *反復可能(Iterables)* は上で説明したように、`Symbol.iterator` メソッドを実装したオブジェクトです。 - *配列ライク(Array-likes)* は、インデックスと `length` を持ったオブジェクトです。なので、これらは配列のように見えます。 +<<<<<<< HEAD もちろん、それらの特性は組み合わせることができます。例えば、文字列は 反復可能(iterable) (`for..of` が動作する) であり、かつ 配列ライク(array-like) (数値インデックスと `length` を持っています) です。 +======= +When we use JavaScript for practical tasks in browser or other environments, we may meet objects that are iterables or array-likes, or both. + +For instance, strings are both iterable (`for..of` works on them) and array-like (they have numeric indexes and `length`). +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 しかし、反復可能(iterable) は 配列ライク(array-like) でない可能性があります。そして、同じように 配列ライク(array-like) も 反復可能(iterable) でない場合があります。 @@ -188,11 +252,19 @@ for (let item of arrayLike) {} */!* ``` +<<<<<<< HEAD それらの共通点は、反復可能(iterable) と 配列ライク(array-like) は両方とも通常の *配列ではなく*、`push` や `pop` などのメソッドを持っていません。もしもこのようなオブジェクトを持っていて、配列のように処理したい場合には不便です。 ## Array.from それらを結びつける共通のメソッド [Array.from](mdn:js/Array/from) があります。これは 反復可能(iterable) または 配列ライク(array-like) な値を引数に取り、そこから "本当の" `Array` を作ります。それ以降、配列のメソッドを呼べるようになります。 +======= +Both iterables and array-likes are usually *not arrays*, they don't have `push`, `pop` etc. That's rather inconvenient if we have such an object and want to work with it as with an array. E.g. we would like to work with `range` using array methods. How to achieve that? + +## Array.from + +There's a universal method [Array.from](mdn:js/Array/from) that takes an iterable or array-like value and makes a "real" `Array` from it. Then we can call array methods on it. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: @@ -209,7 +281,11 @@ let arr = Array.from(arrayLike); // (*) alert(arr.pop()); // World (メソッドが動作します) ``` +<<<<<<< HEAD 行 `(*)` の `Array.from` はオブジェクトを取り出し、反復可能(iterable) か 配列ライク(array-like) なのか調べ、新しい配列を作りすべてのアイテムをコピーします。 +======= +`Array.from` at the line `(*)` takes the object, examines it for being an iterable or array-like, then makes a new array and copies all items to it. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 反復可能(iterable) でも同じことが起こります: @@ -219,12 +295,20 @@ let arr = Array.from(range); alert(arr); // 1,2,3,4,5 (配列の toString 変換が機能します) ``` +<<<<<<< HEAD `Array.from` の完全な構文では、オプションで "マッピング" 関数を指定できます: +======= +The full syntax for `Array.from` also allows us to provide an optional "mapping" function: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js Array.from(obj[, mapFn, thisArg]) ``` +<<<<<<< HEAD 2つ目の引数 `mapFn` は、配列に追加する前に各要素に適用する関数であり、`thisArg` はそこでの `this` を指定できます。 +======= +The optional second argument `mapFn` can be a function that will be applied to each element before adding it to the array, and `thisArg` allows us to set `this` for it. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: @@ -265,7 +349,11 @@ for (let char of str) { alert(chars); ``` +<<<<<<< HEAD ...が、より短く書けます。 +======= +...But it is shorter. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 サロゲートを意識した `slice` を実装することもできます: @@ -278,14 +366,28 @@ let str = '𝒳😂𩷶'; alert( slice(str, 1, 3) ); // 😂𩷶 +<<<<<<< HEAD // ネイティブメソッドはサロゲートペアをサポートしていません alert( str.slice(1, 3) ); // ゴミ (異なるサロゲートペアの片割れです) +======= +// the native method does not support surrogate pairs +alert( str.slice(1, 3) ); // garbage (two pieces from different surrogate pairs) +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` ## サマリ +<<<<<<< HEAD `for..of` が使えるオブジェクトは *反復可能(iterable)* と呼ばれます。 +======= +- Technically, iterables must implement the method named `Symbol.iterator`. + - The result of `obj[Symbol.iterator]` is called an *iterator*. It handles the further iteration process. + - An iterator must have the method named `next()` that returns an object `{done: Boolean, value: any}`, here `done:true` denotes the end of the iteration process, otherwise the `value` is the next value. +- The `Symbol.iterator` method is called automatically by `for..of`, but we also can do it directly. +- Built-in iterables like strings or arrays, also implement `Symbol.iterator`. +- String iterator knows about surrogate pairs. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 - 技術的には、反復可能は `Symbol.iterator` と呼ばれるメソッドを実装しなければなりません。 - `obj[Symbol.iterator]` の結果は *イテレータ* と呼ばれます。それは、さらなる反復処理を行います。 @@ -294,8 +396,16 @@ alert( str.slice(1, 3) ); // ゴミ (異なるサロゲートペアの片割れ - 文字列や配列のような組み込みの iterables もまた、`Symbol.iterator` を実装しています。 - 文字列の イテレータ はサロゲートペアが考慮できます。 +<<<<<<< HEAD インデックス付きのプロパティと `length` をもつオブジェクトは *配列ライク(array-like)* と呼ばれます。このようなオブジェクトは他のプロパティやメソッドを持つことができますが、配列の組み込みメソッドは持っていません。 +======= +Objects that have indexed properties and `length` are called *array-like*. Such objects may also have other properties and methods, but lack the built-in methods of arrays. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 もしも仕様の内側を見ていくと、多くの組み込みメソッドは、"本当の" 配列の代わりに 反復可能(iterable) または 配列ライク(array-like) で動作することを想定していることがわかるでしょう。なぜなら、それらはより抽象的なためです。 +<<<<<<< HEAD `Array.from(obj[, mapFn, thisArg])` は 反復可能(iterable) または 配列ライク(array-like) な `obj` の実際の `Array` を作成し、その後配列のメソッドを使えるようになります。オプションの引数 `mapFn` と `thisArg` は、各項目に関数を適用することを可能にします。 +======= +`Array.from(obj[, mapFn, thisArg])` makes a real `Array` of an iterable or array-like `obj`, and we can then use array methods on it. The optional arguments `mapFn` and `thisArg` allow us to apply a function to each item. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/05-data-types/07-map-set/01-array-unique-map/task.md b/1-js/05-data-types/07-map-set/01-array-unique-map/task.md index ba9fadc3f9..d68030032e 100644 --- a/1-js/05-data-types/07-map-set/01-array-unique-map/task.md +++ b/1-js/05-data-types/07-map-set/01-array-unique-map/task.md @@ -2,13 +2,13 @@ importance: 5 --- -# ユニークな配列メンバのフィルタをする +# Filter unique array members -`arr` は配列としてます。 +Let `arr` be an array. -`arr` のユニークなアイテムを持つ配列を返す関数 `unique(arr)` を作成してください。 +Create a function `unique(arr)` that should return an array with unique items of `arr`. -例: +For instance: ```js function unique(arr) { @@ -22,6 +22,6 @@ let values = ["Hare", "Krishna", "Hare", "Krishna", alert( unique(values) ); // Hare, Krishna, :-O ``` -P.S ここでは文字列が使われていますが、任意の型の値にすることができます。 +P.S. Here strings are used, but can be values of any type. -P.P.S. ユニークな値を格納するために `Set` を使ってください。 +P.P.S. Use `Set` to store unique values. diff --git a/1-js/05-data-types/07-map-set/02-filter-anagrams/solution.md b/1-js/05-data-types/07-map-set/02-filter-anagrams/solution.md index f69d0e0a56..1606751852 100644 --- a/1-js/05-data-types/07-map-set/02-filter-anagrams/solution.md +++ b/1-js/05-data-types/07-map-set/02-filter-anagrams/solution.md @@ -1,6 +1,6 @@ -すべてのアナグラムを見つけるために、すべての単語を文字に分割してソートしましょう。文字でソートしたとき、すべてのアナグラムは同じです。 +To find all anagrams, let's split every word to letters and sort them. When letter-sorted, all anagrams are same. -例: +For instance: ``` nap, pan -> anp @@ -9,14 +9,14 @@ cheaters, hectares, teachers -> aceehrst ... ``` -文字でソートされたバリアントをマップキーとして使用して、各キーごとに1つの値しか格納しません。: +We'll use the letter-sorted variants as map keys to store only one value per each key: ```js run function aclean(arr) { let map = new Map(); for (let word of arr) { - // 単語を文字で分割し、ソートして結合し直します + // split the word by letters, sort them and join back *!* let sorted = word.toLowerCase().split('').sort().join(''); // (*) */!* @@ -31,35 +31,35 @@ let arr = ["nap", "teachers", "cheaters", "PAN", "ear", "era", "hectares"]; alert( aclean(arr) ); ``` -文字ソートは行 `(*)` での呼び出しチェーンで行われています。 +Letter-sorting is done by the chain of calls in the line `(*)`. -便利のために、複数行に分割しましょう: +For convenience let's split it into multiple lines: ```js -let sorted = arr[i] // PAN +let sorted = word // PAN .toLowerCase() // pan .split('') // ['p','a','n'] .sort() // ['a','n','p'] .join(''); // anp ``` -2つの異なる単語 `'PAN'` と `'nap'` は同じ文字デソートされた形式 `'anp'` になります。 +Two different words `'PAN'` and `'nap'` receive the same letter-sorted form `'anp'`. -次の行は単語をマップにセットしています。: +The next line put the word into the map: ```js map.set(sorted, word); ``` -同じ文字でソートされた単語がもう一度あった場合には、マップ内の同じキーで前の値を上書きします。なので、私たちはいつも文字形式毎に最大1つの単語を持ちます。 +If we ever meet a word the same letter-sorted form again, then it would overwrite the previous value with the same key in the map. So we'll always have at maximum one word per letter-form. -最後に、`Array.from(map.values())` でマップの値の反復をし(結果の中でキーは必要ありません)、それらの配列を返却します。 +At the end `Array.from(map.values())` takes an iterable over map values (we don't need keys in the result) and returns an array of them. -ここでは、`Map` の代わりに通常のオブジェクトを使うこともできます。なぜならキーが文字列だからです。 +Here we could also use a plain object instead of the `Map`, because keys are strings. -その場合の解答は次のようになります: +That's how the solution can look: -```js run +```js run demo function aclean(arr) { let obj = {}; @@ -68,7 +68,7 @@ function aclean(arr) { obj[sorted] = arr[i]; } - return Array.from(Object.values(obj)); + return Object.values(obj); } let arr = ["nap", "teachers", "cheaters", "PAN", "ear", "era", "hectares"]; diff --git a/1-js/05-data-types/07-map-set/02-filter-anagrams/task.md b/1-js/05-data-types/07-map-set/02-filter-anagrams/task.md index b2ee492c74..731fd2c256 100644 --- a/1-js/05-data-types/07-map-set/02-filter-anagrams/task.md +++ b/1-js/05-data-types/07-map-set/02-filter-anagrams/task.md @@ -2,11 +2,11 @@ importance: 4 --- -# アナグラムをフィルタする +# Filter anagrams -[アナグラム](https://en.wikipedia.org/wiki/Anagram) は同じ文字を同じ数だけ持っていますが、異なる順序である単語です。 +[Anagrams](https://en.wikipedia.org/wiki/Anagram) are words that have the same number of same letters, but in different order. -例えば: +For instance: ``` nap - pan @@ -14,9 +14,9 @@ ear - are - era cheaters - hectares - teachers ``` -アナグラムで整理された配列を返す関数 `aclean(arr)` を書いてください。 +Write a function `aclean(arr)` that returns an array cleaned from anagrams. -例: +For instance: ```js let arr = ["nap", "teachers", "cheaters", "PAN", "ear", "era", "hectares"]; @@ -24,4 +24,5 @@ let arr = ["nap", "teachers", "cheaters", "PAN", "ear", "era", "hectares"]; alert( aclean(arr) ); // "nap,teachers,ear" or "PAN,cheaters,era" ``` -すべてのアナグラム・グループから、どれかは問いませんが1つの単語だけ残してください。 +From every anagram group should remain only one word, no matter which one. + diff --git a/1-js/05-data-types/07-map-set/03-iterable-keys/solution.md b/1-js/05-data-types/07-map-set/03-iterable-keys/solution.md index 69a35a1255..7310d1d36f 100644 --- a/1-js/05-data-types/07-map-set/03-iterable-keys/solution.md +++ b/1-js/05-data-types/07-map-set/03-iterable-keys/solution.md @@ -1,7 +1,8 @@ -これは、`map.keys()` は配列ではなく、反復可能(iterable) を返すためです。 +That's because `map.keys()` returns an iterable, but not an array. + +We can convert it into an array using `Array.from`: -`Array.from` を使うことで、それを配列に変換できます: ```js run let map = new Map(); diff --git a/1-js/05-data-types/07-map-set/03-iterable-keys/task.md b/1-js/05-data-types/07-map-set/03-iterable-keys/task.md index 2e1e5932ca..25c74bfc20 100644 --- a/1-js/05-data-types/07-map-set/03-iterable-keys/task.md +++ b/1-js/05-data-types/07-map-set/03-iterable-keys/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# 反復可能(iterable)なキー +# Iterable keys -私たちは `map.keys()` の配列を取得し、その結果を使って処理を続けたいです(マップ自体とは別に)。 +We'd like to get an array of `map.keys()` in a variable and then do apply array-specific methods to it, e.g. `.push`. -が、問題があります。: +But that doesn't work: ```js run let map = new Map(); @@ -16,9 +16,9 @@ map.set("name", "John"); let keys = map.keys(); *!* -// Error: numbers.push is not a function +// Error: keys.push is not a function keys.push("more"); */!* ``` -なぜでしょう?`key.push` が機能するためにはコードをどのように直せばよいでしょう? +Why? How can we fix the code to make `keys.push` work? 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 d0a65116da..bf296aea59 100644 --- a/1-js/05-data-types/07-map-set/article.md +++ b/1-js/05-data-types/07-map-set/article.md @@ -1,4 +1,5 @@ +<<<<<<< HEAD # Map と Set 今や、私たちは次のような複雑なデータ構造を知っています: @@ -23,50 +24,118 @@ - `map.size` -- 現在の要素の数です. 例: +======= +# Map and Set + +Now we've learned about the following complex data structures: + +- Objects for storing keyed collections. +- Arrays for storing ordered collections. + +But that's not enough for real life. That's why `Map` and `Set` also exist. + +## Map + +[Map](mdn:js/Map) is a collection of keyed data items, just like an `Object`. But the main difference is that `Map` allows keys of any type. + +Methods and properties are: + +- `new Map()` -- creates the map. +- `map.set(key, value)` -- stores the value by the key. +- `map.get(key)` -- returns the value by the key, `undefined` if `key` doesn't exist in map. +- `map.has(key)` -- returns `true` if the `key` exists, `false` otherwise. +- `map.delete(key)` -- removes the value by the key. +- `map.clear()` -- removes everything from the map. +- `map.size` -- returns the current element count. + +For instance: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let map = new Map(); +<<<<<<< HEAD map.set('1', 'str1'); // 文字列キー map.set(1, 'num1'); // 数値キー map.set(true, 'bool1'); // 真偽値キー // 通常のオブジェクトを覚えていますか?キーを文字列に変換していました。 // Map は型を維持します。なので、これらは別ものです: +======= +map.set('1', 'str1'); // a string key +map.set(1, 'num1'); // a numeric key +map.set(true, 'bool1'); // a boolean key + +// remember the regular Object? it would convert keys to string +// Map keeps the type, so these two are different: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 alert( map.get(1) ); // 'num1' alert( map.get('1') ); // 'str1' alert( map.size ); // 3 ``` +<<<<<<< HEAD 上の通り、オブジェクトとは違い、キーは文字列には変換されません。任意の型のキーが利用可能です。 **Map はキーとしてオブジェクトを使うこともできます。** 例: +======= +As we can see, unlike objects, keys are not converted to strings. Any type of key is possible. + +```smart header="`map[key]` isn't the right way to use a `Map`" +Although `map[key]` also works, e.g. we can set `map[key] = 2`, this is treating `map` as a plain JavaScript object, so it implies all corresponding limitations (no object keys and so on). + +So we should use `map` methods: `set`, `get` and so on. +``` + +**Map can also use objects as keys.** + +For instance: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let john = { name: "John" }; +<<<<<<< HEAD // 各ユーザに対し、訪問回数を保持しましょう let visitsCountMap = new Map(); // john は map のキーです +======= +// for every user, let's store their visits count +let visitsCountMap = new Map(); + +// john is the key for the map +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 visitsCountMap.set(john, 123); alert( visitsCountMap.get(john) ); // 123 ``` +<<<<<<< HEAD オブジェクトをキーとして使用することは、最も注目に値する重要な `Map` の機能の1つです。文字列キーの場合、`Object` で問題ありませんが、オブジェクトキーの場合はそうではありません。 やってみましょう: +======= +Using objects as keys is one of most notable and important `Map` features. For string keys, `Object` can be fine, but not for object keys. + +Let's try: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let john = { name: "John" }; +<<<<<<< HEAD let visitsCountObj = {}; // オブジェクトを用意 visitsCountObj[john] = 123; // john オブジェクトをキーとして使用 +======= +let visitsCountObj = {}; // try to use an object + +visitsCountObj[john] = 123; // try to use john object as the key +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 *!* // That's what got written! @@ -74,6 +143,7 @@ alert( visitsCountObj["[object Object]"] ); // 123 */!* ``` +<<<<<<< HEAD `visitsCountObj` はオブジェクトなので、`john` などのすべてのキーを文字列に変換します。そのため、文字列キー `"[object Object]"` となります。間違いなくこれは望むものではありません。 @@ -87,6 +157,18 @@ alert( visitsCountObj["[object Object]"] ); // 123 ````smart header="チェーン" `map.set` 呼び出しは map 自身を返すので、呼び出しを "チェーン" することができます: +======= +As `visitsCountObj` is an object, it converts all keys, such as `john` to strings, so we've got the string key `"[object Object]"`. Definitely not what we want. + +```smart header="How `Map` compares keys" +To test keys for equivalence, `Map` uses the algorithm [SameValueZero](https://tc39.github.io/ecma262/#sec-samevaluezero). It is roughly the same as strict equality `===`, but the difference is that `NaN` is considered equal to `NaN`. So `NaN` can be used as the key as well. + +This algorithm can't be changed or customized. +``` + +````smart header="Chaining" +Every `map.set` call returns the map itself, so we can "chain" the calls: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js map.set('1', 'str1') @@ -95,6 +177,7 @@ map.set('1', 'str1') ``` ```` +<<<<<<< HEAD ## Map での繰り返し/ループ `map` でループするためには3つのメソッドがあります: @@ -104,6 +187,18 @@ map.set('1', 'str1') - `map.entries()` -- エントリ `[key, value]` の iterable を返します。これは `for..of` でデフォルトで使われます。 例: +======= + +## Iteration over Map + +For looping over a `map`, there are 3 methods: + +- `map.keys()` -- returns an iterable for keys, +- `map.values()` -- returns an iterable for values, +- `map.entries()` -- returns an iterable for entries `[key, value]`, it's used by default in `for..of`. + +For instance: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let recipeMap = new Map([ @@ -112,16 +207,26 @@ let recipeMap = new Map([ ['onion', 50] ]); +<<<<<<< HEAD // キー(野菜)の反復 for (let vegetable of recipeMap.keys()) { alert(vegetable); // cucumber, tomateos, onion } // 値(量)の反復 +======= +// iterate over keys (vegetables) +for (let vegetable of recipeMap.keys()) { + alert(vegetable); // cucumber, tomatoes, onion +} + +// iterate over values (amounts) +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 for (let amount of recipeMap.values()) { alert(amount); // 500, 350, 50 } +<<<<<<< HEAD // [key, value] エントリーの反復 for (let entry of recipeMap) { // recipeMap.entries() と同じ alert(entry); // cucumber,500 (など) @@ -135,17 +240,42 @@ for (let entry of recipeMap) { // recipeMap.entries() と同じ それに加えて、`Map` は `Array` と同じように、組み込みの `forEach` メソッドを持っています。 ```js +======= +// iterate over [key, value] entries +for (let entry of recipeMap) { // the same as of recipeMap.entries() + alert(entry); // cucumber,500 (and so on) +} +``` + +```smart header="The insertion order is used" +The iteration goes in the same order as the values were inserted. `Map` preserves this order, unlike a regular `Object`. +``` + +Besides that, `Map` has a built-in `forEach` method, similar to `Array`: + +```js +// runs the function for each (key, value) pair +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 recipeMap.forEach( (value, key, map) => { alert(`${key}: ${value}`); // cucumber: 500 etc }); ``` +<<<<<<< HEAD ## Object.entries: オブジェクトから Map を生成 `Map` を生成する時、キー/値のペアをもつ配列(または別の反復可能(iterable)) を渡すことができます: ```js // [key, value] ペアの配列 +======= +## Object.entries: Map from Object + +When a `Map` is created, we can pass an array (or another iterable) with key/value pairs for initialization, like this: + +```js run +// array of [key, value] pairs +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 let map = new Map([ ['1', 'str1'], [1, 'num1'], @@ -155,9 +285,15 @@ let map = new Map([ alert( map.get('1') ); // str1 ``` +<<<<<<< HEAD オブジェクトのキー/値のペアの配列を、その形式で返す組み込みのメソッド [Object.entries(obj)](mdn:js/Object/entries) があります。 なので、次のようにオブジェクトから map の初期化をすることができます: +======= +If we have a plain object, and we'd like to create a `Map` from it, then we can use built-in method [Object.entries(obj)](mdn:js/Object/entries) that returns an array of key/value pairs for an object exactly in that format. + +So we can create a map from an object like this: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let obj = { @@ -172,6 +308,7 @@ let map = new Map(Object.entries(obj)); alert( map.get('name') ); // John ``` +<<<<<<< HEAD ここで、`Object.entries` はキー/値のペアの配列を返します: `[ ["name","John"], ["age", 30] ]`。これは `Map` が必要とするものです。 ## Object.fromEntries: Map から オブジェクト @@ -179,6 +316,16 @@ alert( map.get('name') ); // John つい先程、通常のオブジェクトから `Object.entries(obj)` を使用して `Map` を作成する方法を見ました。 逆のことをする `Object.fromEntries` メソッドもあります。: `[key, value]` ペアの配列が与えられ、そこからオブジェクトを作成します: +======= +Here, `Object.entries` returns the array of key/value pairs: `[ ["name","John"], ["age", 30] ]`. That's what `Map` needs. + + +## Object.fromEntries: Object from Map + +We've just seen how to create `Map` from a plain object with `Object.entries(obj)`. + +There's `Object.fromEntries` method that does the reverse: given an array of `[key, value]` pairs, it creates an object from them: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let prices = Object.fromEntries([ @@ -187,16 +334,28 @@ let prices = Object.fromEntries([ ['meat', 4] ]); +<<<<<<< HEAD // prices = { banana: 1, orange: 2, meat: 4 } +======= +// now prices = { banana: 1, orange: 2, meat: 4 } +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 alert(prices.orange); // 2 ``` +<<<<<<< HEAD `Map` から通常のオブジェクトを取得する際に `Object.fromEntries` が使えます。 E.g. `Map` にデータを保持しているが、通常のオブジェクトを期待するサードパーティのコードにわたす必要がある場合。 やってみましょう: +======= +We can use `Object.fromEntries` to get a plain object from `Map`. + +E.g. we store the data in a `Map`, but we need to pass it to a 3rd-party code that expects a plain object. + +Here we go: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let map = new Map(); @@ -205,22 +364,36 @@ map.set('orange', 2); map.set('meat', 4); *!* +<<<<<<< HEAD let obj = Object.fromEntries(map.entries()); // 通常のオブジェクトを作成します (*) */!* // 完了! +======= +let obj = Object.fromEntries(map.entries()); // make a plain object (*) +*/!* + +// done! +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 // obj = { banana: 1, orange: 2, meat: 4 } alert(obj.orange); // 2 ``` +<<<<<<< HEAD `map.entries()` への呼び出しはキー/値ペアの配列を返し、それはまさに `Object.fromEntries` の正しい形式です。 また、行 `(*)` をより短くすることもできます: +======= +A call to `map.entries()` returns an iterable of key/value pairs, exactly in the right format for `Object.fromEntries`. + +We could also make line `(*)` shorter: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let obj = Object.fromEntries(map); // omit .entries() ``` +<<<<<<< HEAD これは同じことです。なぜなら、`Object.fromEntries` は引数に反復可能なオブジェクトを期待するからです。つまり配列である必要はありません。そして、`map` の標準のイテレーションは `map.entries()` と同じキー/値を返します。したがって、`map` と同じキー/値を持つプレーンなオブジェクトが取得できます。 ## Set @@ -239,6 +412,28 @@ let obj = Object.fromEntries(map); // omit .entries() 例えば、訪問者全員を覚えておきたいです。が、繰り返し訪問しても重複しないようにしたいです。訪問者は一度だけ "カウント" される必要があります。 `Set` はそれに相応しいものです: +======= +That's the same, because `Object.fromEntries` expects an iterable object as the argument. Not necessarily an array. And the standard iteration for `map` returns same key/value pairs as `map.entries()`. So we get a plain object with same key/values as the `map`. + +## Set + +A `Set` is a special type collection - "set of values" (without keys), where each value may occur only once. + +Its main methods are: + +- `new Set(iterable)` -- creates the set, and if an `iterable` object is provided (usually an array), copies values from it into the set. +- `set.add(value)` -- adds a value, returns the set itself. +- `set.delete(value)` -- removes the value, returns `true` if `value` existed at the moment of the call, otherwise `false`. +- `set.has(value)` -- returns `true` if the value exists in the set, otherwise `false`. +- `set.clear()` -- removes everything from the set. +- `set.size` -- is the elements count. + +The main feature is that repeated calls of `set.add(value)` with the same value don't do anything. That's the reason why each value appears in a `Set` only once. + +For example, we have visitors coming, and we'd like to remember everyone. But repeated visits should not lead to duplicates. A visitor must be "counted" only once. + +`Set` is just the right thing for that: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let set = new Set(); @@ -247,13 +442,18 @@ let john = { name: "John" }; let pete = { name: "Pete" }; let mary = { name: "Mary" }; +<<<<<<< HEAD // 訪問、何度も来るユーザもいます +======= +// visits, some users come multiple times +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 set.add(john); set.add(pete); set.add(mary); set.add(john); set.add(mary); +<<<<<<< HEAD // set はユニークな値のみをキープします alert( set.size ); // 3 @@ -267,18 +467,38 @@ for (let user of set) { ## Set での繰り返し `for..of` または `forEach` を使うことで set をループすることができます: +======= +// set keeps only unique values +alert( set.size ); // 3 + +for (let user of set) { + alert(user.name); // John (then Pete and Mary) +} +``` + +The alternative to `Set` could be an array of users, and the code to check for duplicates on every insertion using [arr.find](mdn:js/Array/find). But the performance would be much worse, because this method walks through the whole array checking every element. `Set` is much better optimized internally for uniqueness checks. + +## Iteration over Set + +We can loop over a set either with `for..of` or using `forEach`: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let set = new Set(["oranges", "apples", "bananas"]); for (let value of set) alert(value); +<<<<<<< HEAD // forEach と同じ: +======= +// the same with forEach: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 set.forEach((value, valueAgain, set) => { alert(value); }); ``` +<<<<<<< HEAD 面白い点に注意してください。`Set` の中の `forEach` 関数は3つの引数を持っています: 値(value), 次に *再び値(valueAgain)*, 次にターゲットのオブジェクトです。実際、引数には同じ値が2回出現します。 これは `forEach` が3つの引数をもつ `Map` との互換性のために作られています。 @@ -318,3 +538,46 @@ set.forEach((value, valueAgain, set) => { - `set.size` -- set の要素数です。 `Map` と `Set` のイテレーションは常に挿入順で行われます。そのため、これらのコレクションが順序付けられていないとは言えませんが、要素を並べ替えたり、その番号で要素を直接取得することはできません。 +======= +Note the funny thing. The callback function passed in `forEach` has 3 arguments: a `value`, then *the same value* `valueAgain`, and then the target object. Indeed, the same value appears in the arguments twice. + +That's for compatibility with `Map` where the callback passed `forEach` has three arguments. Looks a bit strange, for sure. But may help to replace `Map` with `Set` in certain cases with ease, and vice versa. + +The same methods `Map` has for iterators are also supported: + +- `set.keys()` -- returns an iterable object for values, +- `set.values()` -- same as `set.keys()`, for compatibility with `Map`, +- `set.entries()` -- returns an iterable object for entries `[value, value]`, exists for compatibility with `Map`. + +## Summary + +`Map` -- is a collection of keyed values. + +Methods and properties: + +- `new Map([iterable])` -- creates the map, with optional `iterable` (e.g. array) of `[key,value]` pairs for initialization. +- `map.set(key, value)` -- stores the value by the key. +- `map.get(key)` -- returns the value by the key, `undefined` if `key` doesn't exist in map. +- `map.has(key)` -- returns `true` if the `key` exists, `false` otherwise. +- `map.delete(key)` -- removes the value by the key. +- `map.clear()` -- removes everything from the map. +- `map.size` -- returns the current element count. + +The differences from a regular `Object`: + +- Any keys, objects can be keys. +- Additional convenient methods, the `size` property. + +`Set` -- is a collection of unique values. + +Methods and properties: + +- `new Set([iterable])` -- creates the set, with optional `iterable` (e.g. array) of values for initialization. +- `set.add(value)` -- adds a value (does nothing if `value` exists), returns the set itself. +- `set.delete(value)` -- removes the value, returns `true` if `value` existed at the moment of the call, otherwise `false`. +- `set.has(value)` -- returns `true` if the value exists in the set, otherwise `false`. +- `set.clear()` -- removes everything from the set. +- `set.size` -- is the elements count. + +Iteration over `Map` and `Set` is always in the insertion order, so we can't say that these collections are unordered, but we can't reorder elements or directly get an element by its number. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/solution.md b/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/solution.md index cf4ef28dce..6a4c20baf7 100644 --- a/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/solution.md +++ b/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/solution.md @@ -1,41 +1,43 @@ -ここでの良い選択肢は `WeakSet` です: +Let's store read messages in `WeakSet`: -```js +```js run let messages = [ - {text: "Hello", from: "John"}, - {text: "How goes?", from: "John"}, - {text: "See you soon", from: "Alice"} + {text: "Hello", from: "John"}, + {text: "How goes?", from: "John"}, + {text: "See you soon", from: "Alice"} ]; let readMessages = new WeakSet(); -// 2つのメッセージは読まれました +// two messages have been read readMessages.add(messages[0]); readMessages.add(messages[1]); -// readMessages は2つの要素を持っています +// readMessages has 2 elements -// ...再び最初のメッセージを読みましょう! +// ...let's read the first message again! readMessages.add(messages[0]); -// readMessages は依然として2つのユニークな要素をもっています +// readMessages still has 2 unique elements -// 答え: message[0] は読んだ? +// answer: was the message[0] read? alert("Read message 0: " + readMessages.has(messages[0])); // true messages.shift(); -// これで readMessages の要素は1つです(技術的にはメモリは後ほどクリーンされるかもしれません) +// now readMessages has 1 element (technically memory may be cleaned later) ``` -`WeakSet` でメッセージのセットを格納し、その中でメッセージの存在を簡単に確認することができます。 +The `WeakSet` allows to store a set of messages and easily check for the existance of a message in it. -それは自動的に自身をクリーンアップします。トレードオフはそれをイテレートすることができないことです。私たちは直接 "すべての既読メッセージ" を取得することができません。しかし、すべての messages をイテレートし、set 中のものをフィルタリングすることでそれを実現できます。 +It cleans up itself automatically. The tradeoff is that we can't iterate over it, can't get "all read messages" from it directly. But we can do it by iterating over all messages and filtering those that are in the set. -P.S メッセージが誰か他の人のコードで管理されている場合、各メッセージに同時のプロパティを追加することは危険です。が、衝突を回避するためにシンボルでそれをすることができます。 +Another, different solution could be to add a property like `message.isRead=true` to a message after it's read. As messages objects are managed by another code, that's generally discouraged, but we can use a symbolic property to avoid conflicts. -このようになります: +Like this: ```js -// シンボリックプロパティは我々のコードだけが知っています +// the symbolic property is only known to our code let isRead = Symbol("isRead"); messages[0][isRead] = true; ``` -これで、たとえ他のコードがメッセージプロパティのために `for..in` ループを使っても、隠しフラグは表示されません。 +Now third-party code probably won't see our extra property. + +Although symbols allow to lower the probability of problems, using `WeakSet` is better from the architectural point of view. diff --git a/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/task.md b/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/task.md index 66fbe2dd01..ddccc7312f 100644 --- a/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/task.md +++ b/1-js/05-data-types/08-weakmap-weakset/01-recipients-read/task.md @@ -2,6 +2,7 @@ importance: 5 --- +<<<<<<< HEAD # "未既読" フラグを格納する メッセージの配列があります: @@ -21,3 +22,24 @@ let messages = [ P.S メッセージが `messages` から削除されたとき、あなたの構造からも同様に消える必要があります。 P.P.S. 私たちはメッセージオブジェクトを直接変更すべきではありません。ほかの誰かのコードによって管理されている場合、余分なプロパティの追加は悪い結果になる可能性があります。 +======= +# Store "unread" flags + +There's an array of messages: + +```js +let messages = [ + {text: "Hello", from: "John"}, + {text: "How goes?", from: "John"}, + {text: "See you soon", from: "Alice"} +]; +``` + +Your code can access it, but the messages are managed by someone else's code. New messages are added, old ones are removed regularly by that code, and you don't know the exact moments when it happens. + +Now, which data structure could you use to store information about whether the message "has been read"? The structure must be well-suited to give the answer "was it read?" for the given message object. + +P.S. When a message is removed from `messages`, it should disappear from your structure as well. + +P.P.S. We shouldn't modify message objects, add our properties to them. As they are managed by someone else's code, that may lead to bad consequences. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/05-data-types/08-weakmap-weakset/02-recipients-when-read/solution.md b/1-js/05-data-types/08-weakmap-weakset/02-recipients-when-read/solution.md index bf207ad8cb..0a93de7af2 100644 --- a/1-js/05-data-types/08-weakmap-weakset/02-recipients-when-read/solution.md +++ b/1-js/05-data-types/08-weakmap-weakset/02-recipients-when-read/solution.md @@ -3,9 +3,9 @@ ```js let messages = [ - {text: "Hello", from: "John"}, - {text: "How goes?", from: "John"}, - {text: "See you soon", from: "Alice"} + {text: "Hello", from: "John"}, + {text: "How goes?", from: "John"}, + {text: "See you soon", from: "Alice"} ]; let readMap = new WeakMap(); diff --git a/1-js/05-data-types/08-weakmap-weakset/02-recipients-when-read/task.md b/1-js/05-data-types/08-weakmap-weakset/02-recipients-when-read/task.md index 93a481699b..8e341c1841 100644 --- a/1-js/05-data-types/08-weakmap-weakset/02-recipients-when-read/task.md +++ b/1-js/05-data-types/08-weakmap-weakset/02-recipients-when-read/task.md @@ -2,18 +2,20 @@ importance: 5 --- -# 読んだ日付を格納する +# Store read dates -[前のタスク](info:task/recipients-read)のメッセージ配列があります。状況は似ています。 +There's an array of messages as in the [previous task](info:task/recipients-read). The situation is similar. ```js let messages = [ - {text: "Hello", from: "John"}, - {text: "How goes?", from: "John"}, - {text: "See you soon", from: "Alice"} + {text: "Hello", from: "John"}, + {text: "How goes?", from: "John"}, + {text: "See you soon", from: "Alice"} ]; ``` -この問題: "いつメッセージが読まれたか" という情報を格納するのにあなたが提案するのはどのようなデータ構造ですか? +The question now is: which data structure you'd suggest to store the information: "when the message was read?". -前のタスクでは、"既読/未読" の事実の保持だけが必要でした。今度は日付を保存する必要があります。なお、前と同じようにメッセージが削除されたら現れないでください。 +In the previous task we only needed to store the "yes/no" fact. Now we need to store the date, and it should only remain in memory until the message is garbage collected. + +P.S. Dates can be stored as objects of built-in `Date` class, that we'll cover later. 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 a6ac4a8945..7f8a0d49a7 100644 --- a/1-js/05-data-types/08-weakmap-weakset/article.md +++ b/1-js/05-data-types/08-weakmap-weakset/article.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD # WeakMap と WeakSet チャプター で学んだ通り、JavaScriptエンジンは、それが到達可能な(そして潜在的に利用される可能性がある)間、メモリ上に値を保持しています。 @@ -21,12 +22,38 @@ john = null; 例えば、あるオブジェクトを配列に入れた場合、その配列が生きている間は、他の参照がなくてもそのオブジェクトは生きていることになります。 例: +======= +# WeakMap and WeakSet + +As we know from the chapter , JavaScript engine stores a value in memory while it is reachable (and can potentially be used). + +For instance: +```js +let john = { name: "John" }; + +// the object can be accessed, john is the reference to it + +// overwrite the reference +john = null; + +*!* +// the object will be removed from memory +*/!* +``` + +Usually, properties of an object or elements of an array or another data structure are considered reachable and kept in memory while that data structure is in memory. + +For instance, if we put an object into an array, then while the array is alive, the object will be alive as well, even if there are no other references to it. + +Like this: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let john = { name: "John" }; let array = [ john ]; +<<<<<<< HEAD john = null; // 参照を上書きします *!* @@ -38,12 +65,27 @@ john = null; // 参照を上書きします また、通常の Map のキーとしてオブジェクトを使うと、Map が存在している間はそのオブジェクトも存在します。これはメモリを占め、ガベージコレクションされないかもしれません。 例: +======= +john = null; // overwrite the reference + +*!* +// john is stored inside the array, so it won't be garbage-collected +// we can get it as array[0] +*/!* +``` + +Similar to that, if we use an object as the key in a regular `Map`, then while the `Map` exists, that object exists as well. It occupies memory and may not be garbage collected. + +For instance: + +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let john = { name: "John" }; let map = new Map(); map.set(john, "..."); +<<<<<<< HEAD john = null; // 参照を上書きします *!* @@ -59,12 +101,30 @@ john = null; // 参照を上書きします ## WeakMap `Map` との最初の違いは、WeakMap のキーはプリミティブな値ではなくオブジェクトでなければならないことです: +======= +john = null; // overwrite the reference + +*!* +// john is stored inside the map, +// we can get it by using map.keys() +*/!* +``` + +`WeakMap` is fundamentally different in this aspect. It doesn't prevent garbage-collection of key objects. + +Let's see what it means on examples. + +## WeakMap + +The first difference from `Map` is that `WeakMap` keys must be objects, not primitive values: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let weakMap = new WeakMap(); let obj = {}; +<<<<<<< HEAD weakMap.set(obj, "ok"); // 正常に動作します (オブジェクトのキー) *!* @@ -73,6 +133,17 @@ weakMap.set("test", "Whoops"); // エラー, "test" はプリミティブだか ``` いま、オブジェクトをキーとして使用し、そのオブジェクトへの参照が他にない場合、自動的にメモリ(と map)から削除されます。 +======= +weakMap.set(obj, "ok"); // works fine (object key) + +*!* +// can't use a string as the key +weakMap.set("test", "Whoops"); // Error, because "test" is not an object +*/!* +``` + +Now, if we use an object as the key in it, and there are no other references to that object -- it will be removed from memory (and from the map) automatically. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let john = { name: "John" }; @@ -80,6 +151,7 @@ let john = { name: "John" }; let weakMap = new WeakMap(); weakMap.set(john, "..."); +<<<<<<< HEAD john = null; // 参照を上書きします // john はメモリから削除されます! @@ -103,6 +175,31 @@ john = null; // 参照を上書きします さて、どこでこのようなものが必要なのでしょう? ## ユースケース: additional data +======= +john = null; // overwrite the reference + +// john is removed from memory! +``` + +Compare it with the regular `Map` example above. Now if `john` only exists as the key of `WeakMap` -- it will be automatically deleted from the map (and memory). + +`WeakMap` does not support iteration and methods `keys()`, `values()`, `entries()`, so there's no way to get all keys or values from it. + +`WeakMap` has only the following methods: + +- `weakMap.get(key)` +- `weakMap.set(key, value)` +- `weakMap.delete(key)` +- `weakMap.has(key)` + +Why such a limitation? That's for technical reasons. If an object has lost all other references (like `john` in the code above), then it is to be garbage-collected automatically. But technically it's not exactly specified *when the cleanup happens*. + +The JavaScript engine decides that. It may choose to perform the memory cleanup immediately or to wait and do the cleaning later when more deletions happen. So, technically the current element count of a `WeakMap` is not known. The engine may have cleaned it up or not, or did it partially. For that reason, methods that access all keys/values are not supported. + +Now where do we need such data structure? + +## Use case: additional data +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 The main area of application for `WeakMap` is an *additional data storage*. @@ -111,8 +208,13 @@ If we're working with an object that "belongs" to another code, maybe even a thi We put the data to a `WeakMap`, using the object as the key, and when the object is garbage collected, that data will automatically disappear as well. ```js +<<<<<<< HEAD weakMap.put(john, "secret documents"); // もし john がなくなった場合、秘密のドキュメントは破壊されるでしょう +======= +weakMap.set(john, "secret documents"); +// if john dies, secret documents will be destroyed automatically +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` Let's look at an example. @@ -139,7 +241,10 @@ And here's another part of the code, maybe another file using it: let john = { name: "John" }; countUser(john); // count his visits +<<<<<<< HEAD countUser(john); +======= +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 // later john leaves us john = null; diff --git a/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/solution.md b/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/solution.md index e69de29bb2..27a7b418ab 100644 --- a/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/solution.md +++ b/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/solution.md @@ -0,0 +1,29 @@ +```js run demo +function sumSalaries(salaries) { + + let sum = 0; + for (let salary of Object.values(salaries)) { + sum += salary; + } + + return sum; // 650 +} + +let salaries = { + "John": 100, + "Pete": 300, + "Mary": 250 +}; + +alert( sumSalaries(salaries) ); // 650 +``` +Or, optionally, we could also get the sum using `Object.values` and `reduce`: + +```js +// reduce loops over array of salaries, +// adding them up +// and returns the result +function sumSalaries(salaries) { + return Object.values(salaries).reduce((a, b) => a + b, 0) // 650 +} +``` diff --git a/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/task.md b/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/task.md index fe936a085a..211357d03a 100644 --- a/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/task.md +++ b/1-js/05-data-types/09-keys-values-entries/01-sum-salaries/task.md @@ -2,15 +2,15 @@ importance: 5 --- -# プロパティを合計する +# Sum the properties -任意の数の給与を持つ `salaries` オブジェクトがあります。 +There is a `salaries` object with arbitrary number of salaries. -`Object.values` と `for..of` ループを使ってすべての給与の合計を返す関数 `sumSalaries(salaries)` を書いてください。 +Write the function `sumSalaries(salaries)` that returns the sum of all salaries using `Object.values` and the `for..of` loop. -もし `salaries` が空の場合、結果は `0` になります。 +If `salaries` is empty, then the result must be `0`. -例: +For instance: ```js let salaries = { @@ -21,3 +21,4 @@ let salaries = { alert( sumSalaries(salaries) ); // 650 ``` + diff --git a/1-js/05-data-types/09-keys-values-entries/02-count-properties/task.md b/1-js/05-data-types/09-keys-values-entries/02-count-properties/task.md index e495098a91..d7aebb1faa 100644 --- a/1-js/05-data-types/09-keys-values-entries/02-count-properties/task.md +++ b/1-js/05-data-types/09-keys-values-entries/02-count-properties/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# プロパティをカウントする +# Count properties -オブジェクトの中のプロパティの数を返す関数 `count(obj)` を書いてください。 +Write a function `count(obj)` that returns the number of properties in the object: ```js let user = { @@ -15,6 +15,7 @@ let user = { alert( count(user) ); // 2 ``` -できるだけ短いコードを作ってください。 +Try to make the code as short as possible. + +P.S. Ignore symbolic properties, count only "regular" ones. -P.S. シンボリックプロパティは無視し、"通常" のものだけをカウントしてください。 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 e331453b36..4af1925150 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 @@ -1,42 +1,42 @@ # Object.keys, values, entries -ここでは、個々のデータ構造から離れて、それらの繰り返し処理について話しましょう。 +Let's step away from the individual data structures and talk about the iterations over them. -前のチャプターで、`map.keys()`, `map.values()`, `map.entries()` と言うメソッドを見ました。 +In the previous chapter we saw methods `map.keys()`, `map.values()`, `map.entries()`. -これらのメソッドは一般的なものであり、データ構造に対して利用することは共通認識です。そのため、もし独自のデータ構造を作成するときには、それらも実装しておく方がよいです。 +These methods are generic, there is a common agreement to use them for data structures. If we ever create a data structure of our own, we should implement them too. -これらは以下でサポートされています: +They are supported for: - `Map` - `Set` -- `Array` (`arr.values()` を除く) +- `Array` -通常のオブジェクトも同様のメソッドをサポートしますが、構文は少し異なります。 +Plain objects also support similar methods, but the syntax is a bit different. ## Object.keys, values, entries -通常のオブジェクトでは、次のメソッドが使えます。: +For plain objects, the following methods are available: -- [Object.keys(obj)](mdn:js/Object/keys) -- キーの配列を返します。 -- [Object.values(obj)](mdn:js/Object/values) -- 値の配列を返します。 -- [Object.entries(obj)](mdn:js/Object/entries) -- `[key, value]` ペアの配列を返します。 +- [Object.keys(obj)](mdn:js/Object/keys) -- returns an array of keys. +- [Object.values(obj)](mdn:js/Object/values) -- returns an array of values. +- [Object.entries(obj)](mdn:js/Object/entries) -- returns an array of `[key, value]` pairs. -しかし、それらの違いに注意してください(例として map との比較です。): +Please note the distinctions (compared to map for example): | | Map | Object | |-------------|------------------|--------------| -| 構文 | `map.keys()` | `Object.keys(obj)`. `obj.keys()` ではありません。 | -| 戻り値 | iterable | "本当の" Array | +| Call syntax | `map.keys()` | `Object.keys(obj)`, but not `obj.keys()` | +| Returns | iterable | "real" Array | -最初の違いは、`obj.keys()` ではなく、`Object.keys(obj)` と呼ぶ必要がある点です。 +The first difference is that we have to call `Object.keys(obj)`, and not `obj.keys()`. -なぜそうなっているのでしょう?主な理由は柔軟性です。JavaScript ではオブジェクトはすべての複雑な構造のベースであることを忘れないでください。そのため、独自の `order.values()` メソッドを実装する `order` という独自のオブジェクトがあるかもしれません。それでも `Object.values(order)` を呼ぶことができます。 +Why so? The main reason is flexibility. Remember, objects are a base of all complex structures in JavaScript. So we may have an object of our own like `data` that implements its own `data.values()` method. And we still can call `Object.values(data)` on it. -2つ目の違いは、`Object.*` メソッドが単なる iterable ではなく "本当の" 配列オブジェクトを返すことです。これは主に歴史的な理由です。 +The second difference is that `Object.*` methods return "real" array objects, not just an iterable. That's mainly for historical reasons. -例: +For instance: ```js let user = { @@ -45,11 +45,11 @@ let user = { }; ``` -- `Object.keys(user) = [name, age]` +- `Object.keys(user) = ["name", "age"]` - `Object.values(user) = ["John", 30]` - `Object.entries(user) = [ ["name","John"], ["age",30] ]` -ここの例では、`Object.values` を使って、プロパティの値をループします: +Here's an example of using `Object.values` to loop over property values: ```js run let user = { @@ -57,14 +57,46 @@ let user = { age: 30 }; -// 値のループ +// loop over values for (let value of Object.values(user)) { - alert(value); // John, そして 30 + alert(value); // John, then 30 } ``` -## Object.keys/values/entries は Symbol を使っているプロパティを無視します +```warn header="Object.keys/values/entries ignore symbolic properties" +Just like a `for..in` loop, these methods ignore properties that use `Symbol(...)` as keys. -`for..in` ループのように、これらのメソッドはキーとして `Symbol(...)` を使っているプロパティを無視します。 +Usually that's convenient. But if we want symbolic keys too, then there's a separate method [Object.getOwnPropertySymbols](mdn:js/Object/getOwnPropertySymbols) that returns an array of only symbolic keys. Also, there exist a method [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) that returns *all* keys. +``` + + +## Transforming objects + +Objects lack many methods that exist for arrays, e.g. `map`, `filter` and others. + +If we'd like to apply them, then we can use `Object.entries` followed `Object.fromEntries`: + +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`. +3. Use `Object.fromEntries(array)` on the resulting array to turn it back into an object. + +For example, we have an object with prices, and would like to double them: + +```js run +let prices = { + banana: 1, + orange: 2, + meat: 4, +}; + +*!* +let doublePrices = Object.fromEntries( + // convert to array, map, and then fromEntries gives back the object + Object.entries(prices).map(([key, value]) => [key, value * 2]) +); +*/!* + +alert(doublePrices.meat); // 8 +``` -通常それは便利です。しかし、もしもこのようなキーも同様に扱いたい場合は、別のメソッド [Object.getOwnPropertySymbols](mdn:js/Object/getOwnPropertySymbols) があります。これは Symbol を使っているキーのみの配列を返します。また、メソッド [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) は *すべての* キーを返します。 +It may look difficult from the first sight, but becomes easy to understand after you use it once or twice. We can make powerful chains of transforms this way. diff --git a/1-js/05-data-types/10-destructuring-assignment/1-destruct-user/task.md b/1-js/05-data-types/10-destructuring-assignment/1-destruct-user/task.md index 30c7d04b6c..b68db5c593 100644 --- a/1-js/05-data-types/10-destructuring-assignment/1-destruct-user/task.md +++ b/1-js/05-data-types/10-destructuring-assignment/1-destruct-user/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# 分割代入 +# Destructuring assignment -次のオブジェクトがあります: +We have an object: ```js let user = { @@ -13,13 +13,13 @@ let user = { }; ``` -以下のような分割代入を書いてください: +Write the destructuring assignment that reads: -- `name` プロパティを変数 `name` に、 -- `years` プロパティを変数 `age` に、 -- `isAdmin` プロパティを変数 `isAdmin` (存在しない場合は false )にしてください。 +- `name` property into the variable `name`. +- `years` property into the variable `age`. +- `isAdmin` property into the variable `isAdmin` (false, if no such property) -代入後の値は次のようになる必要があります: +Here's an example of the values after your assignment: ```js let user = { name: "John", years: 30 }; diff --git a/1-js/05-data-types/10-destructuring-assignment/6-max-salary/_js.view/solution.js b/1-js/05-data-types/10-destructuring-assignment/6-max-salary/_js.view/solution.js index d95cf1b1e5..f4bd5c761c 100644 --- a/1-js/05-data-types/10-destructuring-assignment/6-max-salary/_js.view/solution.js +++ b/1-js/05-data-types/10-destructuring-assignment/6-max-salary/_js.view/solution.js @@ -3,7 +3,7 @@ function topSalary(salaries) { let max = 0; let maxName = null; - for(let [name, salary] of Object.entries(salaries)) { + for(const [name, salary] of Object.entries(salaries)) { if (max < salary) { max = salary; maxName = name; diff --git a/1-js/05-data-types/10-destructuring-assignment/6-max-salary/task.md b/1-js/05-data-types/10-destructuring-assignment/6-max-salary/task.md index 9945c255c2..9f33de0897 100644 --- a/1-js/05-data-types/10-destructuring-assignment/6-max-salary/task.md +++ b/1-js/05-data-types/10-destructuring-assignment/6-max-salary/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# 最大の給与 +# The maximal salary -`salaries` オブジェクトがあります: +There is a `salaries` object: ```js let salaries = { @@ -14,9 +14,9 @@ let salaries = { }; ``` -支払い額がトップの名前を返す関数 `topSalary(salaries)` を作ってください。 +Create the function `topSalary(salaries)` that returns the name of the top-paid person. -- `salaries` がからの場合、`null` を返します。 -- トップの人が複数いる場合、それらのいずれかを返します。 +- If `salaries` is empty, it should return `null`. +- If there are multiple top-paid persons, return any of them. -P.S. キー/値ベアを反復するために `Object.entries` と分割代入を使ってください。 +P.S. Use `Object.entries` and destructuring to iterate over key/value pairs. 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 3524124cd6..626fd1fdb3 100644 --- a/1-js/05-data-types/10-destructuring-assignment/article.md +++ b/1-js/05-data-types/10-destructuring-assignment/article.md @@ -1,23 +1,25 @@ -# 分割代入 +# Destructuring assignment -JavaScriptで最も使われる2つのデータ構造は `Object` と `Array` です。 +The two most used data structures in JavaScript are `Object` and `Array`. -オブジェクトは多くの情報を1つのエンティティにまとめることができ、配列は順序付けされたコレクションを格納することができます。従って、私たちはオブジェクトまたは配列を作り、それを1つのエンティティとして扱うことができます。また、それを関数呼び出しの際に渡すこともできます。 +Objects allow us to create a single entity that stores data items by key, and arrays allow us to gather data items into an ordered collection. -*分割代入(Destructuring assignment)* は、配列またはオブジェクトの中身を複数の変数に代入できる特別な構文です。デストラクタリング(非構造化/構造の分解)は、多くのパラメータとデフォルト値を持つ複雑な関数でもうまく機能します。このチャプターでは、すぐにこれらがどのように処理されているかわかるでしょう。 +But when we pass those to a function, it may need not an object/array as a whole, but rather individual pieces. -[cut] +*Destructuring assignment* is a special syntax that allows us to "unpack" arrays or objects into a bunch of variables, as sometimes that's more convenient. Destructuring also works great with complex functions that have a lot of parameters, default values, and so on. -## Array の非構造化 +## Array destructuring -配列を変数に分割する方法の例です: +An example of how the array is destructured into variables: ```js -// 姓名の配列があります +// we have an array with the name and surname let arr = ["Ilya", "Kantor"] *!* -// 分割代入 +// destructuring assignment +// sets firstName = arr[0] +// and surname = arr[1] let [firstName, surname] = arr; */!* @@ -25,18 +27,18 @@ alert(firstName); // Ilya alert(surname); // Kantor ``` -これで、配列要素の代わりに変数を扱うことができます。 +Now we can work with variables instead of array members. -`split` やその他配列を返すメソッドと組み合わせると便利です: +It looks great when combined with `split` or other array-returning methods: ```js let [firstName, surname] = "Ilya Kantor".split(' '); ``` -````smart header="\"分割\" は \"破壊的\" を意味しません" -これは、項目を変数にコピーすることによって "非構造化(destructurizes)" するため、"分割代入(destructuring assignment)" と呼ばれています。 配列自体は変更されません。 +````smart header="\"Destructuring\" does not mean \"destructive\"." +It's called "destructuring assignment," because it "destructurizes" by copying items into variables. But the array itself is not modified. -これは、より短い書き方になります: +It's just a shorter way to write: ```js // let [firstName, surname] = arr; let firstName = arr[0]; @@ -44,24 +46,24 @@ let surname = arr[1]; ``` ```` -````smart header="最初の要素を無視する" -配列の不要な要素は、余分なカンマをつけることで捨てることができます: +````smart header="Ignore elements using commas" +Unwanted elements of the array can also be thrown away via an extra comma: ```js run *!* -// 1番目、2番目の要素が不要の場合 -let [, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"]; +// second element is not needed +let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"]; */!* alert( title ); // Consul ``` -上のコードでは、最初の2つの要素がスキップされ、3つ目は `title` に代入され、残りもスキップされています。 +In the code above, the second element of the array is skipped, the third one is assigned to `title`, and the rest of the array items is also skipped (as there are no variables for them). ```` -````smart header="右辺は任意の反復可能(iterable)に対して動作します" +````smart header="Works with any iterable on the right-side" -実際には配列だけでなく、任意の反復可能(iterable)に対して使うことができます: +...Actually, we can use it with any iterable, not only arrays: ```js let [a, b, c] = "abc"; // ["a", "b", "c"] @@ -71,11 +73,11 @@ let [one, two, three] = new Set([1, 2, 3]); ```` -````smart header="左辺では任意のものに代入することが可能です" +````smart header="Assign to anything at the left-side" -左辺には任意の "割り当て可能なもの" を指定することができます。 +We can use any "assignables" at the left side. -例えば、オブジェクトのプロパティも指定できます: +For instance, an object property: ```js run let user = {}; [user.name, user.surname] = "Ilya Kantor".split(' '); @@ -85,11 +87,11 @@ alert(user.name); // Ilya ```` -````smart header=".entries() を使ったループ" +````smart header="Looping with .entries()" -以前のチャプターで、[Object.entries(obj)](mdn:js/Object/entries) メソッドを見ました。 +In the previous chapter we saw the [Object.entries(obj)](mdn:js/Object/entries) method. -オブジェクトの key-value をループするのに、分割代入を一緒に使うこともできます: +We can use it with destructuring to loop over keys-and-values of an object: ```js run let user = { @@ -97,7 +99,7 @@ let user = { age: 30 }; -// key-value のループ +// loop over keys-and-values *!* for (let [key, value] of Object.entries(user)) { */!* @@ -105,7 +107,7 @@ for (let [key, value] of Object.entries(user)) { } ``` -map も同様です: +...And the same for a map: ```js run let user = new Map(); @@ -113,17 +115,34 @@ user.set("name", "John"); user.set("age", "30"); *!* -for (let [key, value] of user.entries()) { +for (let [key, value] of user) { */!* alert(`${key}:${value}`); // name:John, then age:30 } ``` ```` -### 残り '...' +```smart header="Swap variables trick" +A well-known trick for swapping values of two variables: -最初の値を取得するだけでなく、それに続くすべての値も集めたい場合、"残りの部分" の取得を意味する 3つのドッド `"..."` をパラメータに追加することで実現できます: +```js run +let guest = "Jane"; +let admin = "Pete"; + +// Swap values: make guest=Pete, admin=Jane +[guest, admin] = [admin, guest]; + +alert(`${guest} ${admin}`); // Pete Jane (successfully swapped!) +``` + +Here we create a temporary array of two variables and immediately destructure it in swapped order. + +We can swap more than two variables this way. +``` + +### The rest '...' +If we want not just to get first values, but also to gather all that follows -- we can add one more parameter that gets "the rest" using three dots `"..."`: ```js run let [name1, name2, *!*...rest*/!*] = ["Julius", "Caesar", *!*"Consul", "of the Roman Republic"*/!*]; @@ -132,17 +151,18 @@ alert(name1); // Julius alert(name2); // Caesar *!* +// Note that type of `rest` is Array. alert(rest[0]); // Consul alert(rest[1]); // of the Roman Republic alert(rest.length); // 2 */!* ``` -`rest` は残りの値が要素として格納されている配列です。 `rest` の代わりに他の変数名を使うこともできます。変数名の前には3つのドットがあり、利用時には分割代入の最後にくるようにしてください。 +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. -### デフォルト値 +### Default values -代入する変数の数よりも配列の要素数のほうが少ない場合、エラーにはなりません。不足している値は undefined とみなされます: +If there are fewer values in the array than variables in the assignment, there will be no error. Absent values are considered undefined: ```js run *!* @@ -150,46 +170,48 @@ let [firstName, surname] = []; */!* alert(firstName); // undefined +alert(surname); // undefined ``` -値がなかった場合に "デフォルト" 値を使いたければ、`=` を使ってデフォルト値を指定することができます: +If we want a "default" value to replace the missing one, we can provide it using `=`: ```js run *!* -// デフォルト値 +// default values let [name = "Guest", surname = "Anonymous"] = ["Julius"]; */!* -alert(name); // Julius (配列から) -alert(surname); // Anonymous (デフォルトが使用されました) +alert(name); // Julius (from array) +alert(surname); // Anonymous (default used) ``` -デフォルト値はより複雑な式や関数呼び出しにすることもできます。それらは値が提供されなかったときのみ評価されます。 +Default values can be more complex expressions or even function calls. They are evaluated only if the value is not provided. -例えば、ここでは2つのデフォルトに対して `prompt` 関数を使っていますが、値がなかった場合のみ実行されます: +For instance, here we use the `prompt` function for two defaults. But it will run only for the missing one: ```js run -// 姓のプロンプトのみを実行する +// runs only prompt for surname let [name = prompt('name?'), surname = prompt('surname?')] = ["Julius"]; -alert(name); // Julius (配列から) -alert(surname); // プロンプトが得たもの +alert(name); // Julius (from array) +alert(surname); // whatever prompt gets ``` -## オブジェクトの非構造化 -分割代入はオブジェクトでも動作します。 +## Object destructuring -基本の構文は次の通りです: +The destructuring assignment also works with objects. + +The basic syntax is: ```js -let {var1, var2} = {var1:…, var2…} +let {var1, var2} = {var1:…, var2:…} ``` -右辺には、変数に分割したい既存のオブジェクトがあります。左辺には該当するプロパティの "パターン" を指定します。単純なケースでは、それは `{...}` に変数名を並べたものです。 +We have an existing object at the right side, that we want to split into variables. The left side contains a "pattern" for corresponding properties. In the simple case, that's a list of variable names in `{...}`. -例: +For instance: ```js run let options = { @@ -207,16 +229,16 @@ alert(width); // 100 alert(height); // 200 ``` -プロパティ `options.title`, `options.width` と `options.height` は、該当する変数に代入されます。順序は関係ありません。これも動作します。: +Properties `options.title`, `options.width` and `options.height` are assigned to the corresponding variables. The order does not matter. This works too: ```js -// let {...} 内のプロパティ順を変えた場合 +// changed the order in let {...} let {height, width, title} = { title: "Menu", height: 200, width: 100 } ``` -左辺のパターンはより複雑で、プロパティと変数の間のマッピングを指定することができます。 +The pattern on the left side may be more complex and specify the mapping between properties and variables. -プロパティを別の名前の変数に代入したい場合、例えば、`options.width` を変数名 `w` にしたい場合、コロンを使うことでセットすることができます: +If we want to assign a property to a variable with another name, for instance, `options.width` to go into the variable named `w`, then we can set it using a colon: ```js run let options = { @@ -226,7 +248,7 @@ let options = { }; *!* -// { 元のプロパティ: ターゲットとなる変数 } +// { sourceProperty: targetVariable } let {width: w, height: h, title} = options; */!* @@ -239,9 +261,9 @@ alert(w); // 100 alert(h); // 200 ``` -コロンは "何を: どこに" を示します。上の例では、プロパティ `width` は `w`に、プロパティ `height` は `h`, `title` は同じ名前に代入されます。 +The colon shows "what : goes where". In the example above the property `width` goes to `w`, property `height` goes to `h`, and `title` is assigned to the same name. -値がない可能性のあるプロパティについては、次のように `"="` を使ってデフォルト値を設定できます: +For potentially missing properties we can set default values using `"="`, like this: ```js run let options = { @@ -257,9 +279,9 @@ alert(width); // 100 alert(height); // 200 ``` -配列や関数パラメータのように、デフォルト値は任意の式または関数呼び出しにすることができます。それらは値がない場合に評価されます。 +Just like with arrays or function parameters, default values can be any expressions or even function calls. They will be evaluated if the value is not provided. -下のコードは、 width はプロンプトで尋ねられますが、 title は聞かれません。 +In the code below `prompt` asks for `width`, but not for `title`: ```js run let options = { @@ -271,10 +293,10 @@ let {width = prompt("width?"), title = prompt("title?")} = options; */!* alert(title); // Menu -alert(width); // (プロンプトの結果) +alert(width); // (whatever the result of prompt is) ``` -コロンと等号の両方を組み合わせることもできます。: +We also can combine both the colon and equality: ```js run let options = { @@ -290,13 +312,28 @@ alert(w); // 100 alert(h); // 200 ``` -### 残りの演算子(Rest operator) +If we have a complex object with many properties, we can extract only what we need: + +```js run +let options = { + title: "Menu", + width: 100, + height: 200 +}; + +// only extract title as a variable +let { title } = options; + +alert(title); // Menu +``` + +### The rest pattern "..." -仮に、指定した変数よりも多くのプロパティをオブジェクトがもっていたらどうなるでしょうか。いくつか設定した後、"残り" をどこかにまとめて代入することはできるでしょうか? +What if the object has more properties than we have variables? Can we take some and then assign the "rest" somewhere? -ここで、残りの演算子(3つのドット)を使用するという仕様はほぼ標準ですが、ほとんどのブラウザではまだサポートされていません。 +We can use the rest pattern, just like we did with arrays. It's not supported by some older browsers (IE, use Babel to polyfill it), but works in modern ones. -このようになります: +It looks like this: ```js run let options = { @@ -306,6 +343,8 @@ let options = { }; *!* +// title = property named title +// rest = object with the rest of properties let {title, ...rest} = options; */!* @@ -314,20 +353,18 @@ alert(rest.height); // 200 alert(rest.width); // 100 ``` +````smart header="Gotcha if there's no `let`" +In the examples above variables were declared right in the assignment: `let {…} = {…}`. Of course, we could use existing variables too, without `let`. But there's a catch. - -````smart header="Gotcha without `let`" -上の例で、変数は代入の直前に宣言されています: `let {…} = {…}`。もちろん既存の変数を使うこともできますが、罠もあります。 - -これは動作しません: +This won't work: ```js run let title, width, height; -// この行はエラーです +// error in this line {title, width, height} = {title: "Menu", width: 200, height: 100}; ``` -問題は、JavaScriptがメインコードフローの `{...}' をコードブロックとして扱うことです。このようなコードブロックは、次のように文をグループ化するために使われます。 +The problem is that JavaScript treats `{...}` in the main code flow (not inside another expression) as a code block. Such code blocks can be used to group statements, like this: ```js run { @@ -338,24 +375,25 @@ let title, width, height; } ``` -コードブロックではないと JavaScript に示すためには、代入全体を括弧 `(...)` で囲む必要があります: +So here JavaScript assumes that we have a code block, that's why there's an error. We want destructuring instead. + +To show JavaScript that it's not a code block, we can wrap the expression in parentheses `(...)`: ```js run let title, width, height; -// これでOKです +// okay now *!*(*/!*{title, width, height} = {title: "Menu", width: 200, height: 100}*!*)*/!*; alert( title ); // Menu ``` - ```` -## 入れ子構造の非構造化 +## Nested destructuring -オブジェクトまたは配列に他のオブジェクトや配列が含まれている場合、より複雑な左辺のパターンを使用して、より深い部分を抽出することもできます。 +If an object or an array contain other nested objects and arrays, we can use more complex left-side patterns to extract deeper portions. -下のコードでは、`options` はプロパティ `size` の中に別のオブジェクトを持っており、プロパティ `items` に配列を持っています。ここで、代入する左辺のパターンは同じ構造を持っています。: +In the code below `options` has another object in the property `size` and an array in the property `items`. The pattern at the left side of the assignment has the same structure to extract values from them: ```js run let options = { @@ -364,17 +402,17 @@ let options = { height: 200 }, items: ["Cake", "Donut"], - extra: true // 分割されない何か追加のデータ + extra: true }; -// わかりやすくするために、複数の行での分割代入 +// destructuring assignment split in multiple lines for clarity let { - size: { // ここにサイズを格納 + size: { // put size here width, height }, - items: [item1, item2], // ここに items を割り当てる - title = "Menu" // オブジェクトには存在しない (デフォルト値が使われます) + items: [item1, item2], // assign items here + title = "Menu" // not present in the object (default value is used) } = options; alert(title); // Menu @@ -384,25 +422,19 @@ alert(item1); // Cake alert(item2); // Donut ``` -左辺で言及されていなかった `extra` を除いた `options` オブジェクト全体が該当する変数に代入されます。 +All properties of `options` object except `extra` that is absent in the left part, are assigned to corresponding variables: ![](destructuring-complex.svg) -最終的には、`width`, `height`, `item1`, `item2` と、デフォルト値から `title` を得ます。 - -これは分割代入ではよく起こります。私たちは、多くのプロパティを持つ複雑なオブジェクトを持っており、必要なものだけを抽出したいからです。 +Finally, we have `width`, `height`, `item1`, `item2` and `title` from the default value. -このようなことも頻繁にあります。: -```js -// 変数全体から size を取り、残りは無視します -let { size } = options; -``` +Note that there are no variables for `size` and `items`, as we take their content instead. -## スマートな関数パラメータ +## Smart function parameters -ある関数が多くのパラメータを持っており、ほどんどがオプションであることがあります。特にユーザインタフェースのときに当てはまります。メニューを作る関数を想像してみてください。幅と高さ、タイトル、アイテムのリストなどを持っています。 +There are times when a function has many parameters, most of which are optional. That's especially true for user interfaces. Imagine a function that creates a menu. It may have a width, a height, a title, items list and so on. -ここに、良くない関数の書き方があります: +Here's a bad way to write such function: ```js function showMenu(title = "Untitled", width = 200, height = 100, items = []) { @@ -410,31 +442,32 @@ function showMenu(title = "Untitled", width = 200, height = 100, items = []) { } ``` -現実の問題の1つは、どうやって引数の順番を覚えるか、です。コードがしっかりドキュメント化されていれば、通常は IDE が助けてくれます。しかし、他にも問題があります。ほとんどのパタメータがデフォルトでOKの場合の関数の呼び方です。 +In real-life, the problem is how to remember the order of arguments. Usually IDEs try to help us, especially if the code is well-documented, but still... Another problem is how to call a function when most parameters are ok by default. -こうなりますか? +Like this? ```js +// undefined where default values are fine showMenu("My Menu", undefined, undefined, ["Item1", "Item2"]) ``` -これは見にくく、より多くのパラメータを扱う場合、非常に読みにくいです。 +That's ugly. And becomes unreadable when we deal with more parameters. -このようなケースで非構造化が役に立ちます! +Destructuring comes to the rescue! -オブエジェクトとしてパラメータを渡し、関数はそれらを変数に分解します: +We can pass parameters as an object, and the function immediately destructurizes them into variables: ```js run -// オブジェクトを関数に渡す +// we pass object to function let options = { title: "My menu", items: ["Item1", "Item2"] }; -// ...そしてすぐに変数に展開します +// ...and it immediately expands it to variables function showMenu(*!*{title = "Untitled", width = 200, height = 100, items = []}*/!*) { - // title, items – options から取得, - // width, height – デフォルト値を利用 + // title, items – taken from options, + // width, height – defaults used alert( `${title} ${width} ${height}` ); // My Menu 200 100 alert( items ); // Item1, Item2 } @@ -442,7 +475,7 @@ function showMenu(*!*{title = "Untitled", width = 200, height = 100, items = []} showMenu(options); ``` -また、入れ子のオブジェクトやコロンのマッピング使った複雑な非構造化を使うこともできます: +We can also use more complex destructuring with nested objects and colon mappings: ```js run let options = { @@ -453,9 +486,9 @@ let options = { *!* function showMenu({ title = "Untitled", - width: w = 100, // width は w に - height: h = 200, // height は h に - items: [item1, item2] // items の最初の要素は item1 へ、次は item2 へ + width: w = 100, // width goes to w + height: h = 200, // height goes to h + items: [item1, item2] // items first element goes to item1, second to item2 }) { */!* alert( `${title} ${w} ${h}` ); // My Menu 100 200 @@ -466,54 +499,54 @@ function showMenu({ showMenu(options); ``` -構文は分割代入と同じです: +The full syntax is the same as for a destructuring assignment: ```js function({ - // 渡されるプロパティ: 内部で利用するパラメータ名 = デフォルト値 - incomingProperty: parameterName = defaultValue + incomingProperty: varName = defaultValue ... }) ``` -なお、このような分割代入は `showMenu()` に引数があることを前提にしている点に注意してください。もしすべての値をデフォルトにしたい場合には、空のオブジェクトを指定する必要があります: +Then, for an object of parameters, there will be a variable `varName` for property `incomingProperty`, with `defaultValue` by default. + +Please note that such destructuring assumes that `showMenu()` does have an argument. If we want all values by default, then we should specify an empty object: ```js -showMenu({}); +showMenu({}); // ok, all values are default -// これはエラーになります -showMenu(); +showMenu(); // this would give an error ``` -これについては、非構造化対象全体のデフォルト値に `{}` を指定することで対応することができます: - +We can fix this by making `{}` the default value for the whole object of parameters: ```js run -// 明快にするためのちょっとしたパラメータの簡略化 -function showMenu(*!*{ title = "Menu", width = 100, height = 200 } = {}*/!*) { +function showMenu({ title = "Menu", width = 100, height = 200 }*!* = {}*/!*) { alert( `${title} ${width} ${height}` ); } showMenu(); // Menu 100 200 ``` -上のコードでは、全体の引数オブジェクトがデフォルトで `{}` なので常に分解する何かがあります。 +In the code above, the whole arguments object is `{}` by default, so there's always something to destructurize. -## サマリ +## Summary -- 分割代入はオブジェクトや配列を多数の変数に即座にマッピングすることができます。 -- オブジェクト構文: +- Destructuring assignment allows for instantly mapping an object or array onto many variables. +- The full object syntax: ```js - let {prop : varName = default, ...} = object + let {prop : varName = default, ...rest} = object ``` - これはプロパティ `prop` が変数 `varName` に代入され、もしこのようなプロパティが存在しない場合には `default` が使われることを意味します。 + This means that property `prop` should go into the variable `varName` and, if no such property exists, then the `default` value should be used. + + Object properties that have no mapping are copied to the `rest` object. -- 配列構文: +- The full array syntax: ```js let [item1 = default, item2, ...rest] = array ``` - 最初のアイテムは `item1` に行き、2つ目は `item2` に行きます。残りのすべてのアイテムは配列 `rest` になります。 + The first item goes to `item1`; the second goes into `item2`, all the rest makes the array `rest`. -- より複雑なケースでは、左辺は右辺と同じ構造を指定します。 +- It's possible to extract data from nested arrays/objects, for that the left side must have the same structure as the right one. 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 c1767dcb23..4fc4f11540 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 @@ -1,6 +1,12 @@ +<<<<<<< HEAD `new Date` コンストラクタはデフォルトでローカルのタイムゾーンを使います。なので、覚えておくべき重要なことは 月 はゼロからスタートすることだけです。 2月は数値で 1 になります。 +======= +The `new Date` constructor uses the local time zone. So the only important thing to remember is that months start from zero. + +So February has number 1. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let d = new Date(2012, 1, 20, 3, 12); diff --git a/1-js/05-data-types/11-date/1-new-date/task.md b/1-js/05-data-types/11-date/1-new-date/task.md index eca0680909..1b40d5ac04 100644 --- a/1-js/05-data-types/11-date/1-new-date/task.md +++ b/1-js/05-data-types/11-date/1-new-date/task.md @@ -2,8 +2,8 @@ importance: 5 --- -# 日付の作成 +# Create a date -日付 "Feb 20, 2012, 3:12am" の `Date` オブジェクトを作成してください。タイムゾーンはローカルです。 +Create a `Date` object for the date: Feb 20, 2012, 3:12am. The time zone is local. -`alert` を使って表示してください。 +Show it using `alert`. diff --git a/1-js/05-data-types/11-date/2-get-week-day/solution.md b/1-js/05-data-types/11-date/2-get-week-day/solution.md index 229456c131..1eb57f2549 100644 --- a/1-js/05-data-types/11-date/2-get-week-day/solution.md +++ b/1-js/05-data-types/11-date/2-get-week-day/solution.md @@ -2,7 +2,7 @@ その数値から適切な日の名前が取得できるよう、平日の配列を作りましょう。 -```js run +```js run demo function getWeekDay(date) { let days = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA']; diff --git a/1-js/05-data-types/11-date/2-get-week-day/task.md b/1-js/05-data-types/11-date/2-get-week-day/task.md index e040e34a4b..5cf31565da 100644 --- a/1-js/05-data-types/11-date/2-get-week-day/task.md +++ b/1-js/05-data-types/11-date/2-get-week-day/task.md @@ -2,13 +2,13 @@ importance: 5 --- -# 平日を表示する +# Show a weekday -ショートフォーマット: 'MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU' で平日を表示する関数 `getWeekDay(date)` を書いてください。 +Write a function `getWeekDay(date)` to show the weekday in short format: 'MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU'. -例: +For instance: ```js no-beautify let date = new Date(2012, 0, 3); // 3 Jan 2012 -alert( getWeekDay(date) ); // "TU" と表示される +alert( getWeekDay(date) ); // should output "TU" ``` diff --git a/1-js/05-data-types/11-date/3-weekday/task.md b/1-js/05-data-types/11-date/3-weekday/task.md index f59fe70c5f..d1adc371af 100644 --- a/1-js/05-data-types/11-date/3-weekday/task.md +++ b/1-js/05-data-types/11-date/3-weekday/task.md @@ -2,9 +2,15 @@ importance: 5 --- +<<<<<<< HEAD # ヨーロッパの平日 ヨーロッパ諸国では、月曜日(1) から始まり、次に火曜日(2)、日曜日(7)までの曜日があります。 `date` について "ヨーロッパ " の曜日を返す関数` getLocalDay(date)` を書いてください。 +======= +# European weekday + +European countries have days of week starting with Monday (number 1), then Tuesday (number 2) and till Sunday (number 7). Write a function `getLocalDay(date)` that returns the "European" day of week for `date`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js no-beautify let date = new Date(2012, 0, 3); // 3 Jan 2012 diff --git a/1-js/05-data-types/11-date/4-get-date-ago/solution.md b/1-js/05-data-types/11-date/4-get-date-ago/solution.md index 2cf2ecc233..e9bfc524f2 100644 --- a/1-js/05-data-types/11-date/4-get-date-ago/solution.md +++ b/1-js/05-data-types/11-date/4-get-date-ago/solution.md @@ -11,7 +11,7 @@ function getDateAgo(date, days) { それを実装するために、次のように日付をクローンしましょう: -```js run +```js run demo function getDateAgo(date, days) { let dateCopy = new Date(date); diff --git a/1-js/05-data-types/11-date/4-get-date-ago/task.md b/1-js/05-data-types/11-date/4-get-date-ago/task.md index 6e27d85547..058d39c7ea 100644 --- a/1-js/05-data-types/11-date/4-get-date-ago/task.md +++ b/1-js/05-data-types/11-date/4-get-date-ago/task.md @@ -2,13 +2,13 @@ importance: 4 --- -# n 日前の日付はなんでしょう? +# Which day of month was many days ago? -`date` から` days` 前の日付を返す関数 `getDateAgo(date, days)` を作成してください。 +Create a function `getDateAgo(date, days)` to return the day of month `days` ago from the `date`. -例えば、今日が 20日の場合、`getDateAgo(new Date(), 1)` は 19で、`getDateAgo(new Date(), 2)` は 18になります。 +For instance, if today is 20th, then `getDateAgo(new Date(), 1)` should be 19th and `getDateAgo(new Date(), 2)` should be 18th. -数ヶ月/年に対しても、信頼性をもって動作しなければなりません: +Should work reliably for `days=365` or more: ```js let date = new Date(2015, 0, 2); @@ -18,4 +18,4 @@ alert( getDateAgo(date, 2) ); // 31, (31 Dec 2014) alert( getDateAgo(date, 365) ); // 2, (2 Jan 2014) ``` -P.S. 関数は与えられた `date` を変更すべきではありません。 +P.S. The function should not modify the given `date`. diff --git a/1-js/05-data-types/11-date/5-last-day-of-month/solution.md b/1-js/05-data-types/11-date/5-last-day-of-month/solution.md index f2eece361c..4f642536e1 100644 --- a/1-js/05-data-types/11-date/5-last-day-of-month/solution.md +++ b/1-js/05-data-types/11-date/5-last-day-of-month/solution.md @@ -1,5 +1,5 @@ -次の月を使って日付を作りますが、その日としてゼロを渡します: -```js run +Let's create a date using the next month, but pass zero as the day: +```js run demo function getLastDayOfMonth(year, month) { let date = new Date(year, month + 1, 0); return date.getDate(); @@ -10,4 +10,4 @@ alert( getLastDayOfMonth(2012, 1) ); // 29 alert( getLastDayOfMonth(2013, 1) ); // 28 ``` -通常、日は 1から始まりますが、技術的には任意の数値を渡すことが可能で、日付は自身を自動調整します。なので、 0 を渡したとき、それは "その月の1日より、1日前" を意味します。: つまり、"前の月の最終日" になります。 +Normally, dates start from 1, but technically we can pass any number, the date will autoadjust itself. So when we pass 0, then it means "one day before 1st day of the month", in other words: "the last day of the previous month". diff --git a/1-js/05-data-types/11-date/5-last-day-of-month/task.md b/1-js/05-data-types/11-date/5-last-day-of-month/task.md index 36d90d2d88..10dfb7a7a2 100644 --- a/1-js/05-data-types/11-date/5-last-day-of-month/task.md +++ b/1-js/05-data-types/11-date/5-last-day-of-month/task.md @@ -2,13 +2,13 @@ importance: 5 --- -# 月の最後日は? +# Last day of month? -月の最後の日を返す関数 `getLastDayOfMonth(year, month)` を書いてください。それは 30, 31, または2月であれば 28/29 です。 +Write a function `getLastDayOfMonth(year, month)` that returns the last day of month. Sometimes it is 30th, 31st or even 28/29th for Feb. -パラメータ: +Parameters: -- `year` -- 4桁の年、例えば 2012 -- `month` -- 月、0 から 11 +- `year` -- four-digits year, for instance 2012. +- `month` -- month, from 0 to 11. -例えば、`getLastDayOfMonth(2012, 1) = 29` (うるう年、2月) +For instance, `getLastDayOfMonth(2012, 1) = 29` (leap year, Feb). diff --git a/1-js/05-data-types/11-date/6-get-seconds-today/solution.md b/1-js/05-data-types/11-date/6-get-seconds-today/solution.md index 3d00851921..8f8e52b68d 100644 --- a/1-js/05-data-types/11-date/6-get-seconds-today/solution.md +++ b/1-js/05-data-types/11-date/6-get-seconds-today/solution.md @@ -1,26 +1,28 @@ -秒数を取得するために、現在の日で、時間が 00:00:00 の日付を生成し、"今" からそれを減算します。 +To get the number of seconds, we can generate a date using the current day and time 00:00:00, then substract it from "now". -差異はその日の開始からのミリ秒であり、秒を取得するために1000で割る必要があります。: +The difference is the number of milliseconds from the beginning of the day, that we should divide by 1000 to get seconds: ```js run function getSecondsToday() { let now = new Date(); - // 現在の 日/月/年を使ってオブジェクトを作成 + // create an object using the current day/month/year let today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); let diff = now - today; // ms difference - return Math.round(diff / 1000); // 秒を作る + return Math.round(diff / 1000); // make seconds } alert( getSecondsToday() ); ``` -代わりの解答として、時間/分/秒 を取得してそれらを秒に変換する、という方法もあります。: +An alternative solution would be to get hours/minutes/seconds and convert them to seconds: ```js run function getSecondsToday() { let d = new Date(); return d.getHours() * 3600 + d.getMinutes() * 60 + d.getSeconds(); -}; +} + +alert( getSecondsToday() ); ``` diff --git a/1-js/05-data-types/11-date/6-get-seconds-today/task.md b/1-js/05-data-types/11-date/6-get-seconds-today/task.md index 7e7ba4ab6c..4567909286 100644 --- a/1-js/05-data-types/11-date/6-get-seconds-today/task.md +++ b/1-js/05-data-types/11-date/6-get-seconds-today/task.md @@ -2,14 +2,14 @@ importance: 5 --- -# 今日何秒経過しましたか? +# How many seconds have passed today? -今日の開始から秒数を返す関数 `getSecondsToday()` を書いてください。 +Write a function `getSecondsToday()` that returns the number of seconds from the beginning of today. -例えば、今 `10:00 am` で夏時間のシフトがない場合: +For instance, if now were `10:00 am`, and there was no daylight savings shift, then: ```js getSecondsToday() == 36000 // (3600 * 10) ``` -関数は任意の日で動作する必要があります。つまり、"今日" のハードコードを持つべきではありません。 +The function should work in any day. That is, it should not have a hard-coded value of "today". diff --git a/1-js/05-data-types/11-date/7-get-seconds-to-tomorrow/task.md b/1-js/05-data-types/11-date/7-get-seconds-to-tomorrow/task.md index cd5953bf03..e059030268 100644 --- a/1-js/05-data-types/11-date/7-get-seconds-to-tomorrow/task.md +++ b/1-js/05-data-types/11-date/7-get-seconds-to-tomorrow/task.md @@ -2,14 +2,14 @@ importance: 5 --- -# 明日までの秒数は? +# How many seconds till tomorrow? -明日までの秒数を返す関数 `getSecondsToTomorrow()` を作成してください。 +Create a function `getSecondsToTomorrow()` that returns the number of seconds till tomorrow. -例えば、今が `23:00` とすると: +For instance, if now is `23:00`, then: ```js getSecondsToTomorrow() == 3600 ``` -P.S. 関数は任意の日付で動作する必要があり、"今日" はハードコードではありません。 +P.S. The function should work at any day, the "today" is not hardcoded. diff --git a/1-js/05-data-types/11-date/8-format-date-relative/solution.md b/1-js/05-data-types/11-date/8-format-date-relative/solution.md index c65fc73367..93f12ffa03 100644 --- a/1-js/05-data-types/11-date/8-format-date-relative/solution.md +++ b/1-js/05-data-types/11-date/8-format-date-relative/solution.md @@ -1,6 +1,6 @@ `date` から "今" までの 時間を取得するために -- 日付を減算しましょう。 -```js run +```js run demo function formatDate(date) { let diff = new Date() - date; // ミリ秒での差 @@ -40,6 +40,39 @@ alert( formatDate(new Date(new Date - 30 * 1000)) ); // "30 sec. ago" alert( formatDate(new Date(new Date - 5 * 60 * 1000)) ); // "5 min. ago" -// yesterday's date like 31.12.2016, 20:00 +// yesterday's date like 31.12.2016 20:00 alert( formatDate(new Date(new Date - 86400 * 1000)) ); ``` + +Alternative solution: + +```js run +function formatDate(date) { + let dayOfMonth = date.getDate(); + let month = date.getMonth() + 1; + let year = date.getFullYear(); + let hour = date.getHours(); + let minutes = date.getMinutes(); + let diffMs = new Date() - date; + let diffSec = Math.round(diffMs / 1000); + let diffMin = diffSec / 60; + let diffHour = diffMin / 60; + + // formatting + year = year.toString().slice(-2); + month = month < 10 ? '0' + month : month; + dayOfMonth = dayOfMonth < 10 ? '0' + dayOfMonth : dayOfMonth; + hour = hour < 10 ? '0' + hour : hour; + minutes = minutes < 10 ? '0' + minutes : minutes; + + if (diffSec < 1) { + return 'right now'; + } else if (diffMin < 1) { + return `${diffSec} sec. ago` + } else if (diffHour < 1) { + return `${diffMin} min. ago` + } else { + return `${dayOfMonth}.${month}.${year} ${hour}:${minutes}` + } +} +``` diff --git a/1-js/05-data-types/11-date/8-format-date-relative/task.md b/1-js/05-data-types/11-date/8-format-date-relative/task.md index 750fd7198d..9651b305f5 100644 --- a/1-js/05-data-types/11-date/8-format-date-relative/task.md +++ b/1-js/05-data-types/11-date/8-format-date-relative/task.md @@ -2,16 +2,16 @@ importance: 4 --- -# 相対日付をフォーマットする +# Format the relative date -次のように `date` をフォーマットする関数 `formatDate(date)` を書いてください。: +Write a function `formatDate(date)` that should format `date` as follows: -- もし `date` が1秒未満で渡された場合、`"right now"` です。 -- そうではなく、`date` が1分未満で渡された場合、`"n sec. ago"` です。 -- そうではなく、1時間未満の場合は `"m min. ago"` です。 -- そ例外の場合はフォーマット `"DD.MM.YY HH:mm"` の完全な日付です。つまり: `"day.month.year hours:minutes"`, すべて2桁の形式です。e.g. `31.12.16 10:00` +- If since `date` passed less than 1 second, then `"right now"`. +- Otherwise, if since `date` passed less than 1 minute, then `"n sec. ago"`. +- Otherwise, if less than an hour, then `"m min. ago"`. +- Otherwise, the full date in the format `"DD.MM.YY HH:mm"`. That is: `"day.month.year hours:minutes"`, all in 2-digit format, e.g. `31.12.16 10:00`. -例: +For instance: ```js alert( formatDate(new Date(new Date - 1)) ); // "right now" @@ -20,6 +20,6 @@ alert( formatDate(new Date(new Date - 30 * 1000)) ); // "30 sec. ago" alert( formatDate(new Date(new Date - 5 * 60 * 1000)) ); // "5 min. ago" -// yesterday's date like 31.12.2016, 20:00 +// yesterday's date like 31.12.16 20:00 alert( formatDate(new Date(new Date - 86400 * 1000)) ); ``` diff --git a/1-js/05-data-types/11-date/article.md b/1-js/05-data-types/11-date/article.md index f4c89a8512..a2de63ae40 100644 --- a/1-js/05-data-types/11-date/article.md +++ b/1-js/05-data-types/11-date/article.md @@ -1,172 +1,181 @@ -# 日付 と 時刻 +# Date and time -新しい組み込みオブジェクトを見ていきましょう: [Date](mdn:js/Date)。日付や時刻を保存し、管理するためのメソッドを提供します。 +Let's meet a new built-in object: [Date](mdn:js/Date). It stores the date, time and provides methods for date/time management. -例えば、作成/修正時刻を保存したり、時間を測定したり、単に現在の時刻を表示するために使うことができます。 +For instance, we can use it to store creation/modification times, to measure time, or just to print out the current date. -[cut] +## Creation -## 作成 - -新しい `Date` オブジェクトを作るには、 次のいずれかの引数で `new Date()` を呼びます: +To create a new `Date` object call `new Date()` with one of the following arguments: `new Date()` -: 引数なし -- 現在の日付と時刻で `Date` オブジェクトを作ります: +: Without arguments -- create a `Date` object for the current date and time: ```js run let now = new Date(); - alert( now ); // 現在の日時を表示します + alert( now ); // shows current date/time ``` `new Date(milliseconds)` -: Jan 1st of 1970 UTC+0 (1970年 1月1日 UTC+0) からの経過したミリ秒(秒の1/1000)に等しい時間をもつ `Date` オブジェクトを作ります。 +: Create a `Date` object with the time equal to number of milliseconds (1/1000 of a second) passed after the Jan 1st of 1970 UTC+0. ```js run - // 0 は 01.01.1970 UTC+0 を意味します + // 0 means 01.01.1970 UTC+0 let Jan01_1970 = new Date(0); alert( Jan01_1970 ); - // 今 24 時間を追加しました, 02.01.1970 UTC+0 になります + // now add 24 hours, get 02.01.1970 UTC+0 let Jan02_1970 = new Date(24 * 3600 * 1000); alert( Jan02_1970 ); ``` - 1970年初めから経過したミリ秒の数値は *タイムスタンプ* と呼ばれます。 + An integer number representing the number of milliseconds that has passed since the beginning of 1970 is called a *timestamp*. + + It's a lightweight numeric representation of a date. We can always create a date from a timestamp using `new Date(timestamp)` and convert the existing `Date` object to a timestamp using the `date.getTime()` method (see below). - これは日付の軽量な数値表現です。常に `new Date(timestamp)` を使ってタイムスタンプから日付を作成し、存在する `Date` オブジェクトを `date.getTime()` メソッド(後述) を使ってタイムスタンプに変換します。 + Dates before 01.01.1970 have negative timestamps, e.g.: + ```js run + // 31 Dec 1969 + let Dec31_1969 = new Date(-24 * 3600 * 1000); + alert( Dec31_1969 ); + ``` `new Date(datestring)` -: 1つの引数でそれが文字列の場合、`Date.parse` アルゴリズム(後述)でパースされます。 +: If there is a single argument, and it's a string, then it is parsed automatically. The algorithm is the same as `Date.parse` uses, we'll cover it later. ```js run let date = new Date("2017-01-26"); - alert(date); // Thu Jan 26 2017 ... + alert(date); + // The time is not set, so it's assumed to be midnight GMT and + // is adjusted according to the timezone the code is run in + // So the result could be + // Thu Jan 26 2017 11:00:00 GMT+1100 (Australian Eastern Daylight Time) + // or + // Wed Jan 25 2017 16:00:00 GMT-0800 (Pacific Standard Time) ``` `new Date(year, month, date, hours, minutes, seconds, ms)` -: ローカルタイムゾーンで、与えられた要素で日付を作成します。最初の2つの引数は必須です。 - - 補足: +: Create the date with the given components in the local time zone. Only the first two arguments are obligatory. - - `year` は4桁でなければいけません。`2013` はOKですが、`98` はダメです。 - - `month` `0` (1月) から数え、`11` (12月)までです。 - - `date` パラメータは実際の月の日です。もし指定がなければ `1` になります。 - - もし `hours/minutes/seconds/ms` がなければ、これらは `0` とみなされます。 + - The `year` must have 4 digits: `2013` is okay, `98` is not. + - 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`. - 例: + For instance: ```js - new Date(2011, 0, 1, 0, 0, 0, 0); // // 1 Jan 2011, 00:00:00 - new Date(2011, 0, 1); // 同じです。時などはデフォルトで 0 です + new Date(2011, 0, 1, 0, 0, 0, 0); // 1 Jan 2011, 00:00:00 + new Date(2011, 0, 1); // the same, hours etc are 0 by default ``` - 最小の精度は 1ms (1/1000秒)です: + The minimal precision is 1 ms (1/1000 sec): ```js run let date = new Date(2011, 0, 1, 2, 3, 4, 567); alert( date ); // 1.01.2011, 02:03:04.567 ``` -## date コンポーネントへのアクセス +## Access date components -`Date` オブジェクトから 年、月などへアクセスする多くのメソッドがあります。しかし、カテゴライズすることで簡単に覚えることができます。 +There are methods to access the year, month and so on from the `Date` object: [getFullYear()](mdn:js/Date/getFullYear) -: 年を取得します(4桁) +: Get the year (4 digits) [getMonth()](mdn:js/Date/getMonth) -: 月を取得します, **0から11**。 +: Get the month, **from 0 to 11**. [getDate()](mdn:js/Date/getDate) -: 月の日を取得し、値は 1 から 31 です。メソッドの名前には少し違和感がありますが。 +: Get the day of month, from 1 to 31, the name of the method does look a little bit strange. [getHours()](mdn:js/Date/getHours), [getMinutes()](mdn:js/Date/getMinutes), [getSeconds()](mdn:js/Date/getSeconds), [getMilliseconds()](mdn:js/Date/getMilliseconds) -: 対応する時刻の構成要素を取得します。 +: Get the corresponding time components. -```warn header="`getYear()` ではなく `getFullYear()` です" -多くのJavaScriptエンジンは 標準ではないメソッド `getYear()` を実装しています。このメソッドは非推奨です。これは2桁の年を返す時があるので、決して使わないでください。年の取得には `getFullYear()` があります。 +```warn header="Not `getYear()`, but `getFullYear()`" +Many JavaScript engines implement a non-standard method `getYear()`. This method is deprecated. It returns 2-digit year sometimes. Please never use it. There is `getFullYear()` for the year. ``` -加えて、週の曜日を取得することもできます: +Additionally, we can get a day of week: [getDay()](mdn:js/Date/getDay) -: 週の曜日を取得し、値は `0` (日曜) から `6` (土曜) です。最初の日は常に日曜です。いくつかの国ではそうではありませんが、変えることはできません。 +: Get the day of week, from `0` (Sunday) to `6` (Saturday). The first day is always Sunday, in some countries that's not so, but can't be changed. -**上のすべてのメソッドはローカルタイムゾーンを基準に構成要素を返します。** +**All the methods above return the components relative to the local time zone.** -タイムゾーン UTC+0 の日、月、年などを返す、UTCカウンターパートもあります:[getUTCFullYear()](mdn:js/Date/getUTCFullYear), [getUTCMonth()](mdn:js/Date/getUTCMonth), [getUTCDay()](mdn:js/Date/getUTCDay). 単に `"get"` の直後に `"UTC"` を挿入するだけです。. +There are also their UTC-counterparts, that return day, month, year and so on for the time zone UTC+0: [getUTCFullYear()](mdn:js/Date/getUTCFullYear), [getUTCMonth()](mdn:js/Date/getUTCMonth), [getUTCDay()](mdn:js/Date/getUTCDay). Just insert the `"UTC"` right after `"get"`. -あなたのタイムゾーンが UTC から相対的にシフトしている場合、下のコードの結果は異なる時間を表示します: +If your local time zone is shifted relative to UTC, then the code below shows different hours: ```js run -// 現在の date +// current date let date = new Date(); -// あなたの現在のタイムゾーンでの時間 +// the hour in your current time zone alert( date.getHours() ); -// UTC+0 のタイムゾーンでの時間 (サマータイムのないロンドン時間) +// the hour in UTC+0 time zone (London time without daylight savings) alert( date.getUTCHours() ); ``` -なお、UTCのパターンを持たない、2つの特別なメソッドがあります: +Besides the given methods, there are two special ones that do not have a UTC-variant: [getTime()](mdn:js/Date/getTime) -: 日付のタイムスタンプを返します -- それは、1970年 UTC+0 の 1月1日からの経過ミリ秒です。 +: Returns the timestamp for the date -- a number of milliseconds passed from the January 1st of 1970 UTC+0. [getTimezoneOffset()](mdn:js/Date/getTimezoneOffset) -: ローカルタイムゾーンとUTCの差を、分で返します: +: Returns the difference between UTC and the local time zone, in minutes: ```js run - // タイムゾーン UTC-1 にいる場合、60 を出力 - // タイムゾーン UTC+3 にいる場合、-180 を出力 + // if you are in timezone UTC-1, outputs 60 + // if you are in timezone UTC+3, outputs -180 alert( new Date().getTimezoneOffset() ); ``` -## 日付の構成要素を設定する +## Setting date components -次のメソッドで、日付/時刻の構成要素をセットすることができます: +The following methods allow to set date/time components: -- [`setFullYear(year [, month, date])`](mdn:js/Date/setFullYear) -- [`setMonth(month [, date])`](mdn:js/Date/setMonth) +- [`setFullYear(year, [month], [date])`](mdn:js/Date/setFullYear) +- [`setMonth(month, [date])`](mdn:js/Date/setMonth) - [`setDate(date)`](mdn:js/Date/setDate) -- [`setHours(hour [, min, sec, ms])`](mdn:js/Date/setHours) -- [`setMinutes(min [, sec, ms])`](mdn:js/Date/setMinutes) -- [`setSeconds(sec [, ms])`](mdn:js/Date/setSeconds) +- [`setHours(hour, [min], [sec], [ms])`](mdn:js/Date/setHours) +- [`setMinutes(min, [sec], [ms])`](mdn:js/Date/setMinutes) +- [`setSeconds(sec, [ms])`](mdn:js/Date/setSeconds) - [`setMilliseconds(ms)`](mdn:js/Date/setMilliseconds) -- [`setTime(milliseconds)`](mdn:js/Date/setTime) (1970年1月1日UTC+0からの経過日をミリ秒で設定します) +- [`setTime(milliseconds)`](mdn:js/Date/setTime) (sets the whole date by milliseconds since 01.01.1970 UTC) -`setTime()` を除くすべてのものは UTCのパターンもあります。例えば `setUTCHours()` です。 +Every one of them except `setTime()` has a UTC-variant, for instance: `setUTCHours()`. -これまで見たように、いくつかのメソッドは一度に複数の構成要素をセットすることができます。例えば、`setHours` です。設定するときに言及されていない構成要素は変更されません。 +As we can see, some methods can set multiple components at once, for example `setHours`. The components that are not mentioned are not modified. -例: +For instance: ```js run let today = new Date(); today.setHours(0); -alert(today); // 今日のままですが、時は 0 に変更されます +alert(today); // still today, but the hour is changed to 0 today.setHours(0, 0, 0, 0); -alert(today); // 今日のままで, 今は 00:00:00 です +alert(today); // still today, now 00:00:00 sharp. ``` -## 自動補正 +## Autocorrection -*自動補正* は `Date` オブジェクトのとても便利な機能です。私たちが範囲外の値を指定した場合、それは自動的に調節されます。 +The *autocorrection* is a very handy feature of `Date` objects. We can set out-of-range values, and it will auto-adjust itself. -例: +For instance: ```js run let date = new Date(2013, 0, *!*32*/!*); // 32 Jan 2013 ?!? -alert(date); // ...iは 2013/2/1 です! +alert(date); // ...is 1st Feb 2013! ``` -範囲外の数値が指定された構成要素は自動的に補正されます。 +Out-of-range date components are distributed automatically. -"2016年2月28日" の日付を2日増やす必要があるとしましょう。"3月2日"、うるう年の場合には "3月1日" になりますが、考える必要はありません。 2日を追加するだけです。 `Date` オブジェクトが残りを行います: +Let's say we need to increase the date "28 Feb 2016" by 2 days. It may be "2 Mar" or "1 Mar" in case of a leap-year. We don't need to think about it. Just add 2 days. The `Date` object will do the rest: ```js run let date = new Date(2016, 1, 28); @@ -177,90 +186,92 @@ date.setDate(date.getDate() + 2); alert( date ); // 1 Mar 2016 ``` -この機能は、指定した期間後の日付を取得したいときによく利用されます。 例えば、"70秒後" の日付を取得しましょう。: +That feature is often used to get the date after the given period of time. For instance, let's get the date for "70 seconds after now": ```js run let date = new Date(); date.setSeconds(date.getSeconds() + 70); -alert( date ); // 正しい日時を表示します +alert( date ); // shows the correct date ``` -また、ゼロや負値をセットすることもできます。例えば: +We can also set zero or even negative values. For example: ```js run let date = new Date(2016, 0, 2); // 2 Jan 2016 -date.setDate(1); // 月の1日を設定します +date.setDate(1); // set day 1 of month alert( date ); -date.setDate(0); // 最小日は1なので、先月の最後の日になります +date.setDate(0); // min day is 1, so the last day of the previous month is assumed alert( date ); // 31 Dec 2015 ``` -## 日付から数値へ、日付の差分 +## Date to number, date diff -`Date` オブジェクトが数値へ変換されるとき、`date.getTime()` と同じようにタイムスタンプになります: +When a `Date` object is converted to number, it becomes the timestamp same as `date.getTime()`: ```js run let date = new Date(); -alert(+date); // ミリ秒の数値です, date.getTime() と同じです +alert(+date); // the number of milliseconds, same as date.getTime() ``` -重要な副作用は、日付は減算することができますが、結果はミリ秒単位での差分になることです。 +The important side effect: dates can be subtracted, the result is their difference in ms. -これは時間の計測で使うことができます: +That can be used for time measurements: ```js run -let start = new Date(); // 計測開始 +let start = new Date(); // start measuring time -// なにかする +// do the job for (let i = 0; i < 100000; i++) { let doSomething = i * i * i; } -let end = new Date(); // 終了 +let end = new Date(); // end measuring time alert( `The loop took ${end - start} ms` ); ``` -## Date.now() +## Date.now() -もし差分だけ測定したい場合、`Date` オブジェクトを使う必要はありません。 +If we only want to measure time, we don't need the `Date` object. -現在のタイムスタンプを返す特別なメソッド `Date.now()` があります。 +There's a special method `Date.now()` that returns the current timestamp. -これは、意味的には `new Date().getTime()` と同じですが、中間の `Date` オブジェクトを作らないため、より速く、ガベージコレクションに負荷をかけません。 +It is semantically equivalent to `new Date().getTime()`, but it doesn't create an intermediate `Date` object. So it's faster and doesn't put pressure on garbage collection. -これは主に利便性であったり、JavaScriptでのゲームやその他特別なアプリケーションなどパフォーマンスが重要な場合に使われます。 +It is used mostly for convenience or when performance matters, like in games in JavaScript or other specialized applications. -なので、これはおそらくベターです: +So this is probably better: ```js run *!* -let start = Date.now(); // 1 Jan 1970 からのミリ秒 +let start = Date.now(); // milliseconds count from 1 Jan 1970 */!* -// なにかする +// do the job for (let i = 0; i < 100000; i++) { let doSomething = i * i * i; } *!* -let end = Date.now(); // 終了 +let end = Date.now(); // done */!* -alert( `The loop took ${end - start} ms` ); // 日付ではなく、数値を減算する +alert( `The loop took ${end - start} ms` ); // subtract numbers, not dates ``` -## ベンチマーク +## Benchmarking + +If we want a reliable benchmark of CPU-hungry function, we should be careful. -CPUを必要とする機能について、信頼できるベンチマークが必要な場合は注意が必要です。 +For instance, let's measure two functions that calculate the difference between two dates: which one is faster? -例えば、2つの日付の差を計算する2つの関数を測定してみましょう。どちらがより速いでしょうか? +Such performance measurements are often called "benchmarks". ```js -// date1 と date2 を持っており、これらの差をmsで返すのはどちらの関数が速いでしょう? +// we have date1 and date2, which function faster returns their difference in ms? function diffSubtract(date1, date2) { return date2 - date1; } @@ -271,13 +282,13 @@ function diffGetTime(date1, date2) { } ``` -これら2つは正確に同じことをしますが、片方は日付のミリ秒を取得するために明示的な `date.getTime()` を使います。また、もう一方は日付の数値変換を当てにしています。これらの結果は常に同じです。 +These two do exactly the same thing, but one of them uses an explicit `date.getTime()` to get the date in ms, and the other one relies on a date-to-number transform. Their result is always the same. -さて、どちらがより速いでしょうか? +So, which one is faster? -最初に思いつくアイデアは、それらを何度も連続で実行し、その時間の差を測ることです。我々のケースでは、関数はとてもシンプルなので、約10万回程度行う必要があります。 +The first idea may be to run them many times in a row and measure the time difference. For our case, functions are very simple, so we have to do it at least 100000 times. -測定してみましょう。: +Let's measure: ```js run function diffSubtract(date1, date2) { @@ -301,19 +312,19 @@ alert( 'Time of diffSubtract: ' + bench(diffSubtract) + 'ms' ); alert( 'Time of diffGetTime: ' + bench(diffGetTime) + 'ms' ); ``` -なんということでしょう! `getTime()` を使う方が遥かに速いです! なぜかと言うと、この場合は型変換がなく、エンジンが最適化をするのがとても簡単なためです。 +Wow! Using `getTime()` is so much faster! That's because there's no type conversion, it is much easier for engines to optimize. -さて、私たちは測定結果を得ましたが、これはまだ良いベンチマークではありません。 +Okay, we have something. But that's not a good benchmark yet. -`bench(diffSubtract)` を実行しているときにCPUは並列で何かをしていてリソースを消費しており、`bench(diffGetTime)` の実行時までにはその作業が完了していたと想像してください。 +Imagine that at the time of running `bench(diffSubtract)` CPU was doing something in parallel, and it was taking resources. And by the time of running `bench(diffGetTime)` that work has finished. -これは、現代のマルチプロセスOSでのよくある実際のシナリオです。 +A pretty real scenario for a modern multi-process OS. -上の場合、結果として最初のベンチマークは2回目よりも利用できるCPUリソースが少なくなります。これは誤った結果を導きます。 +As a result, the first benchmark will have less CPU resources than the second. That may lead to wrong results. -**より信頼性の高いベンチマークを行うには、ベンチマーク全体を複数回再実行する必要があります。** +**For more reliable benchmarking, the whole pack of benchmarks should be rerun multiple times.** -ここではそのコードのサンプルです: +For example, like this: ```js run function diffSubtract(date1, date2) { @@ -337,7 +348,7 @@ let time1 = 0; let time2 = 0; *!* -// bench(upperSlice) と bench(upperLoop) を交互に10回実行する +// run bench(upperSlice) and bench(upperLoop) each 10 times alternating for (let i = 0; i < 10; i++) { time1 += bench(diffSubtract); time2 += bench(diffGetTime); @@ -348,10 +359,10 @@ alert( 'Total time for diffSubtract: ' + time1 ); alert( 'Total time for diffGetTime: ' + time2 ); ``` -現代のJavaScriptエンジンは、何度も実行される「ホットコード」に対してのみ高度な最適化を適用し始めます(ほとんど実行されないものを最適化する必要はないためです)。したがって、上記の例では、最初の実行は最適化されていません。 ヒートアップ(メインの実行の前の助走)を追加することもできます: +Modern JavaScript engines start applying advanced optimizations only to "hot code" that executes many times (no need to optimize rarely executed things). So, in the example above, first executions are not well-optimized. We may want to add a heat-up run: ```js -// メインループの前の "ヒートアップ" のために追加 +// added for "heating up" prior to the main loop bench(diffSubtract); bench(diffGetTime); @@ -362,28 +373,28 @@ for (let i = 0; i < 10; i++) { } ``` -```warn header="マイクロベンチマークをするのは気をつけてください" -現代のJavaScriptエンジンは多くの最適化を行います。それらは "人工的なテスト" の結果を "通常の使用" と比較して調整するかもしれません。 非常に小さいものをベンチマークするときは特にそうです。従って、真面目にパフォーマンスを理解したいのであれば、JavaScriptエンジンの仕組みを学んでください。そして、マイクロベンチマークは全く必要ないでしょう。 +```warn header="Be careful doing microbenchmarking" +Modern JavaScript engines perform many optimizations. They may tweak results of "artificial tests" compared to "normal usage", especially when we benchmark something very small, such as how an operator works, or a built-in function. So if you seriously want to understand performance, then please study how the JavaScript engine works. And then you probably won't need microbenchmarks at all. -V8 についての素晴らしい記事は にあります。 +The great pack of articles about V8 can be found at . ``` -## 文字列からの Date.parse +## Date.parse from a string -メソッド [Date.parse(str)](mdn:js/Date/parse) は文字列から日付を読むことができます。 +The method [Date.parse(str)](mdn:js/Date/parse) can read a date from a string. -文字列のフォーマットは `YYYY-MM-DDTHH:mm:ss.sssZ` でなければなりません。: +The string format should be: `YYYY-MM-DDTHH:mm:ss.sssZ`, where: -- `YYYY-MM-DD` は日付です。年-月-日 -- `"T"` の文字はデリミタとして使用されます。 -- `HH:mm:ss.sss` は時間です(時、分、秒とミリ秒)。 -- オプションの `'Z'` の部分は、フォーマット `+-hh:mm` のタイムゾーンを示します。UTC+0 を意味する単一の文字 `Z` です。 +- `YYYY-MM-DD` -- is the date: year-month-day. +- The character `"T"` is used as the delimiter. +- `HH:mm:ss.sss` -- is the time: hours, minutes, seconds and milliseconds. +- The optional `'Z'` part denotes the time zone in the format `+-hh:mm`. A single letter `Z` that would mean UTC+0. -より短い表記も可能です。`YYYY-MM-DD` や `YYYY-MM` 、または `YYYY` です。 +Shorter variants are also possible, like `YYYY-MM-DD` or `YYYY-MM` or even `YYYY`. -`Date.parse(str)` の呼び出しでは、文字列を与えられたフォーマットにパースし、タイムスタンプを返します(1970年 1月1日 UTC+0からのミリ秒)。もしフォーマットが正しくない場合には `NaN` を返します。 +The call to `Date.parse(str)` parses the string in the given format and returns the timestamp (number of milliseconds from 1 Jan 1970 UTC+0). If the format is invalid, returns `NaN`. -例: +For instance: ```js run let ms = Date.parse('2012-01-26T13:51:50.417-07:00'); @@ -391,7 +402,7 @@ let ms = Date.parse('2012-01-26T13:51:50.417-07:00'); alert(ms); // 1327611110417 (timestamp) ``` -タイムスタンプから、即座に `new Date` オブジェクトを作ることができます。 +We can instantly create a `new Date` object from the timestamp: ```js run let date = new Date( Date.parse('2012-01-26T13:51:50.417-07:00') ); @@ -399,24 +410,24 @@ let date = new Date( Date.parse('2012-01-26T13:51:50.417-07:00') ); alert(date); ``` -## サマリ +## Summary -- JavaScript での日付と時刻は[Date](mdn:js/Date) オブジェクトで表現されます。"日付だけ"、"時刻だけ" を作ることはできません。`Date` オブジェクトは常に両方を持ちます。 -- 月はゼロからカウントされます(なので、1月は ゼロです)。 -- `getDay()` の週の曜日もゼロからカウントされます(ゼロは日曜です) -- 範囲外の構成要素がセットされたとき、`Date` は自身を自動補正します。日/月/時の加減算の場合には便利です。 -- 日付はミリ秒で与えられた差分で引き算することができます。これは、数値に変換されるとき、`Date` はタイムスタンプになるためです。 -- 素早く現在のタイムスタンプを取得するには `Date.now()` を使いましょう。 +- Date and time in JavaScript are represented with the [Date](mdn:js/Date) object. We can't create "only date" or "only time": `Date` objects always carry both. +- Months are counted from zero (yes, January is a zero month). +- Days of week in `getDay()` are also counted from zero (that's Sunday). +- `Date` auto-corrects itself when out-of-range components are set. Good for adding/subtracting days/months/hours. +- Dates can be subtracted, giving their difference in milliseconds. That's because a `Date` becomes the timestamp when converted to a number. +- Use `Date.now()` to get the current timestamp fast. -多くの他のシステムとは異なり、JavaScriptでのタイムスタンプは秒ではなく、ミリ秒です。 +Note that unlike many other systems, timestamps in JavaScript are in milliseconds, not in seconds. -また、私たちはより高精度の時間計測が必要な場合があります。JavaScript自身はマイクロ秒(100万分の1秒)での時間を計測する方法を持っていませんが、ほとんどの環境はそれを提供しています。例えば、ブラウザはマイクロ秒の精度(少数第3桁)で、ページ読み込み開始からのミリ秒を返す [performance.now()](mdn:api/Performance/now) を持っています。: +Sometimes we need more precise time measurements. JavaScript itself does not have a way to measure time in microseconds (1 millionth of a second), but most environments provide it. For instance, browser has [performance.now()](mdn:api/Performance/now) that gives the number of milliseconds from the start of page loading with microsecond precision (3 digits after the point): ```js run alert(`Loading started ${performance.now()}ms ago`); -// このようになります: "Loading started 34731.26000000001ms ago" -// .26 はマイクロ秒 (260 マイクロ秒) -// 少数点3桁以上は精度エラーで、最初の3桁だけが正しいです +// Something like: "Loading started 34731.26000000001ms ago" +// .26 is microseconds (260 microseconds) +// more than 3 digits after the decimal point are precision errors, but only the first 3 are correct ``` -Node.JS は `microtime` モジュールや他の方法を持っています。技術的には、どのデバイスや環境でも精度をあげることができます。単に `Date` にはないだけです。 +Node.js has `microtime` module and other ways. Technically, almost any device and environment allows to get more precision, it's just not in `Date`. diff --git a/1-js/05-data-types/12-json/1-serialize-object/task.md b/1-js/05-data-types/12-json/1-serialize-object/task.md index 0101953503..53343e4c3e 100644 --- a/1-js/05-data-types/12-json/1-serialize-object/task.md +++ b/1-js/05-data-types/12-json/1-serialize-object/task.md @@ -2,9 +2,9 @@ importance: 5 --- -# オブジェクトを JSON に変換して戻す +# Turn the object into JSON and back -`user` を JSON に変換し、別の変数に読み戻します。 +Turn the `user` into JSON and then read it back into another variable. ```js let user = { diff --git a/1-js/05-data-types/12-json/2-serialize-event-circular/task.md b/1-js/05-data-types/12-json/2-serialize-event-circular/task.md index 45f5afd711..3755a24aa2 100644 --- a/1-js/05-data-types/12-json/2-serialize-event-circular/task.md +++ b/1-js/05-data-types/12-json/2-serialize-event-circular/task.md @@ -2,13 +2,13 @@ importance: 5 --- -# 後方参照を除外する +# Exclude backreferences -循環参照のシンプルなケースでは、問題のあるプロパティをその名前でシリアライズから除外することができます。 +In simple cases of circular references, we can exclude an offending property from serialization by its name. -しかし、ときには多くの後方参照があります。また、名前は循環参照と通常のプロパティの両方で使用される可能性があります。 +But sometimes we can't just use the name, as it may be used both in circular references and normal properties. So we can check the property by its value. -すべてを文字列化しますが、`meetup` を参照するプロパティを削除する `replacer` 関数を書いてください。: +Write `replacer` function to stringify everything, but remove properties that reference `meetup`: ```js run let room = { @@ -22,7 +22,7 @@ let meetup = { }; *!* -// 循環参照 +// circular references room.occupiedBy = meetup; meetup.self = meetup; */!* @@ -31,7 +31,7 @@ alert( JSON.stringify(meetup, function replacer(key, value) { /* your code */ })); -/* 結果は次のようになるはずです: +/* result should be: { "title":"Conference", "occupiedBy":[{"name":"John"},{"name":"Alice"}], diff --git a/1-js/05-data-types/12-json/article.md b/1-js/05-data-types/12-json/article.md index 13ca5b9064..a5f2974af0 100644 --- a/1-js/05-data-types/12-json/article.md +++ b/1-js/05-data-types/12-json/article.md @@ -1,10 +1,10 @@ -# JSON メソッド, toJSON +# JSON methods, toJSON -複雑なオブジェクトを持っており、それをネットワーク経由で送ったり、単にログ出力するために文字列に変換したいとします。 +Let's say we have a complex object, and we'd like to convert it into a string, to send it over a network, or just to output it for logging purposes. -もちろん、変換された文字列にはすべての重要なプロパティを含んでいる必要があります。 +Naturally, such a string should include all important properties. -私たちは、次のように変換処理を実装することができます: +We could implement the conversion like this: ```js run let user = { @@ -21,22 +21,20 @@ let user = { alert(user); // {name: "John", age: 30} ``` -...しかし、開発の過程では、新しいプロパティが追加されたり、古いプロパティがリネーム/削除されます。このような状況で `toString` を毎回更新するのは面倒です。オブジェクト中のプロパティをループすることはできますが、オブジェクトが複雑で、プロパティにネストされたオブジェクトがある場合はどうなるでしょうか? それらの変換処理も実装する必要があります。 また、ネットワーク経由でオブジェクトを送信する場合には、受信側でそれらを「読み取る」ためのコードも提供する必要があります。 +...But in the process of development, new properties are added, old properties are renamed and removed. Updating such `toString` every time can become a pain. We could try to loop over properties in it, but what if the object is complex and has nested objects in properties? We'd need to implement their conversion as well. -幸いにも、これらの処理を行うためにコードを書く必要はありません。この課題は既に解決されています。 - -[cut] +Luckily, there's no need to write the code to handle all this. The task has been solved already. ## JSON.stringify -[JSON](http://en.wikipedia.org/wiki/JSON) (JavaScript Object Notation) は値とオブジェクトを表現する一般的な形式です。[RFC 4627](http://tools.ietf.org/html/rfc4627) で標準として記述されています。当初はJavaScriptのために作られたものでしたが、多くの他の言語も同様に JSON を処理するライブラリを持っています。従って、クライアントが JavaScript を使い、サーバが Ruby/PHP/Java/その他 で書かれている場合に、データ交換としてJSONを使うのは簡単です。 +The [JSON](http://en.wikipedia.org/wiki/JSON) (JavaScript Object Notation) is a general format to represent values and objects. It is described as in [RFC 4627](http://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. -JavaScriptは次のメソッドを提供しています: +JavaScript provides methods: -- `JSON.stringify` : オブジェクトをJSONに変換します。 -- `JSON.parse` : JSONをオブジェクトに変換します。 +- `JSON.stringify` to convert objects into JSON. +- `JSON.parse` to convert JSON back into an object. -例えば、ここで student を `JSON.stringify` します: +For instance, here we `JSON.stringify` a student: ```js run let student = { name: 'John', @@ -50,7 +48,7 @@ let student = { let json = JSON.stringify(student); */!* -alert(typeof json); // string です! +alert(typeof json); // we've got a string! alert(json); *!* @@ -66,35 +64,35 @@ alert(json); */!* ``` -メソッド `JSON.stringify(student)` はオブジェクトを受け取り、それを文字列に変換します。 +The method `JSON.stringify(student)` takes the object and converts it into a string. + +The resulting `json` string is called a *JSON-encoded* or *serialized* or *stringified* or *marshalled* object. We are ready to send it over the wire or put into a plain data store. -結果の `json` 文字列は *JSONエンコードされた*, *シリアライズされた(serialized)*, *文字列化された(stringified)* または *整列化された(marshalled)* オブジェクトと呼ばれます。 -これでネットワーク経由で送信したり、シンプルなデータストアに格納する準備ができました。 -JSONエンコードされたオブジェクトは、オブジェクトリテラルと比べ、何点か重要な違いがあることに注意してください: +Please note that a JSON-encoded object has several important differences from the object literal: -- 文字列にはダブルクォートを使います。JSONにはシングルクォートやバッククォートはありません。従って `'John'` は `"John"` になります。 -- オブジェクトのプロパティ名もまたダブルクォートであり、必須です。従って `age:30` は `"age":30` になります。 +- Strings use double quotes. No single quotes or backticks in JSON. So `'John'` becomes `"John"`. +- Object property names are double-quoted also. That's obligatory. So `age:30` becomes `"age":30`. -`JSON.stringify` はプリミティブに対しても同様に適用できます。 +`JSON.stringify` can be applied to primitives as well. -ネイティブにサポートされるJSONタイプは次のとおりです。: +JSON supports following data types: -- オブジェクト(Object) `{ ... }` -- 配列(Array) `[ ... ]` -- プリミティブ(Primitives): - - 文字列(strings), - - 数値(numbers), - - 真偽値(boolean values) `true/false`, +- Objects `{ ... }` +- Arrays `[ ... ]` +- Primitives: + - strings, + - numbers, + - boolean values `true/false`, - `null`. -例: +For instance: ```js run -// JSON 内の数値はまさに数値です +// a number in JSON is just a number alert( JSON.stringify(1) ) // 1 -// JSON 内の文字列は文字列のままですが、ダブルクォートです +// a string in JSON is still a string, but double-quoted alert( JSON.stringify('test') ) // "test" alert( JSON.stringify(true) ); // true @@ -102,45 +100,45 @@ alert( JSON.stringify(true) ); // true alert( JSON.stringify([1, 2, 3]) ); // [1,2,3] ``` -JSONはデータのみのマルチ言語仕様なので、JavaScript固有のオブジェクトプロパティの一部は `JSON.stringify` ではスキップされます。 +JSON is data-only language-independent specification, so some JavaScript-specific object properties are skipped by `JSON.stringify`. -つまり、次のようなプロパティは無視されます: +Namely: -- 関数プロパティ(メソッド) -- シンボルプロパティ -- `undefined` を格納しているプロパティ +- Function properties (methods). +- Symbolic properties. +- Properties that store `undefined`. ```js run let user = { - sayHi() { // 無視される + sayHi() { // ignored alert("Hello"); }, - [Symbol("id")]: 123, // 無視される - something: undefined // 無視される + [Symbol("id")]: 123, // ignored + something: undefined // ignored }; -alert( JSON.stringify(user) ); // {} (空オブジェクト) +alert( JSON.stringify(user) ); // {} (empty object) ``` -通常これは問題ありませんが、もしそうしたくない場合、その処理をカスタマイズすることができます(方法は後ほど説明します)。 +Usually that's fine. If that's not what we want, then soon we'll see how to customize the process. -このメソッドの素晴らしい点は、入れ子のオブジェクトもサポートされており自動的に変換されることです。 +The great thing is that nested objects are supported and converted automatically. -例: +For instance: ```js run let meetup = { title: "Conference", *!* room: { - number: 123, + number: 23, participants: ["john", "ann"] } */!* }; alert( JSON.stringify(meetup) ); -/* 構造全体が文字列化されました: +/* The whole structure is stringified: { "title":"Conference", "room":{"number":23,"participants":["john","ann"]}, @@ -148,9 +146,9 @@ alert( JSON.stringify(meetup) ); */ ``` -重要な制限: 循環参照があってはいけません。 +The important limitation: there must be no circular references. -例: +For instance: ```js run let room = { @@ -162,41 +160,41 @@ let meetup = { participants: ["john", "ann"] }; -meetup.place = room; // meetup は room を参照 -room.occupiedBy = meetup; // room は meetup を参照 +meetup.place = room; // meetup references room +room.occupiedBy = meetup; // room references meetup *!* JSON.stringify(meetup); // Error: Converting circular structure to JSON */!* ``` -ここでは、循環参照(`room.occupiedBy` が `meetup` を参照し、`meetup.place` が `room` を参照している)のため変換が失敗します。: +Here, the conversion fails, because of circular reference: `room.occupiedBy` references `meetup`, and `meetup.place` references `room`: ![](json-meetup.svg) -## 除外(Excluding)と変形(transforming): replacer +## Excluding and transforming: replacer -`JSON.stringify` の完全な構文は次の通りです: +The full syntax of `JSON.stringify` is: ```js let json = JSON.stringify(value[, replacer, space]) ``` value -: エンコードする値です。 +: A value to encode. replacer -: エンコードするプロパティの配列、またはマッピング関数 `function(key, value)` です。 +: Array of properties to encode or a mapping function `function(key, value)`. space -: フォーマットで使うスペースの数です。 +: Amount of space to use for formatting -ほとんどのケースで `JSON.stringify` は最初の引数だけで使用されます。しかし、循環参照をフィルタリングするような置換処理を微調整する必要がある場合は、`JSON.stringify` の第2引数を使用できます。 +Most of the time, `JSON.stringify` is used with the first argument only. But if we need to fine-tune the replacement process, like to filter out circular references, we can use the second argument of `JSON.stringify`. -もしも第2引数にプロパティの配列を渡した場合、それらのプロパティだけがエンコードされます。 +If we pass an array of properties to it, only these properties will be encoded. -例: +For instance: ```js run let room = { @@ -206,18 +204,18 @@ let room = { let meetup = { title: "Conference", participants: [{name: "John"}, {name: "Alice"}], - place: room // meetup は room を参照 + place: room // meetup references room }; -room.occupiedBy = meetup; // room は meetup を参照 +room.occupiedBy = meetup; // room references meetup alert( JSON.stringify(meetup, *!*['title', 'participants']*/!*) ); // {"title":"Conference","participants":[{},{}]} ``` -これでは厳しすぎるかもしれません。プロパティリストは、オブジェクト構造全体に適用されるため、`name` はリストに無く、`participants` は空になります。 +Here we are probably too strict. The property list is applied to the whole object structure. So the objects in `participants` are empty, because `name` is not in the list. -循環参照を引き起こす `room.occupiedBy` を除いた各プロパティを含めましょう: +Let's include in the list every property except `room.occupiedBy` that would cause the circular reference: ```js run let room = { @@ -227,10 +225,10 @@ let room = { let meetup = { title: "Conference", participants: [{name: "John"}, {name: "Alice"}], - place: room // meetup は room を参照 + place: room // meetup references room }; -room.occupiedBy = meetup; // room は meetup を参照 +room.occupiedBy = meetup; // room references meetup alert( JSON.stringify(meetup, *!*['title', 'participants', 'place', 'name', 'number']*/!*) ); /* @@ -242,13 +240,13 @@ alert( JSON.stringify(meetup, *!*['title', 'participants', 'place', 'name', 'num */ ``` -これで、`occupiedBy` を除くすべてがシリアライズされました。しかし、プロパティのリストは非常に長いです。 +Now everything except `occupiedBy` is serialized. But the list of properties is quite long. -幸いなことに、そのような場合は配列の代わりに `replacer` 関数を使うことができます。 +Fortunately, we can use a function instead of an array as the `replacer`. -関数はすべての `(key,value)` ペアで呼ばれ、"置換された" 値を返す必要があります。そしてそれはオリジナルのものの代わりに使われます。 +The function will be called for every `(key, value)` pair and should return the "replaced" value, which will be used instead of the original one. Or `undefined` if the value is to be skipped. -私たちのケースでは、`occupiedBy` 以外のすべてが "そのままの" `value` を返せばOKです。`occupiedBy` を無視するため、下のコードでは `undefied` を返しています: +In our case, we can return `value` "as is" for everything except `occupiedBy`. To ignore `occupiedBy`, the code below returns `undefined`: ```js run let room = { @@ -258,17 +256,17 @@ let room = { let meetup = { title: "Conference", participants: [{name: "John"}, {name: "Alice"}], - place: room // meetup が room を参照する + place: room // meetup references room }; -room.occupiedBy = meetup; // room が meetup を参照する +room.occupiedBy = meetup; // room references meetup alert( JSON.stringify(meetup, function replacer(key, value) { - alert(`${key}: ${value}`); // replacer が取得しているものを見るために + alert(`${key}: ${value}`); return (key == 'occupiedBy') ? undefined : value; })); -/* replacer に来た key:value ペア: +/* key:value pairs that come to replacer: : [object Object] title: Conference participants: [object Object],[object Object] @@ -281,20 +279,20 @@ number: 23 */ ``` -`replacer` 関数はネストされたオブジェクトや配列のアイテムを含むすべての key/value ペアを取得することに留意してください。再帰的に適用されます。`replacer` の内側での `this` の値は現在のプロパティを含むオブジェクトです。 +Please note that `replacer` function gets every key/value pair including nested objects and array items. It is applied recursively. The value of `this` inside `replacer` is the object that contains the current property. -最初の呼び出しだけ特別です。これは特別な "ラッパーオブジェクト" (`{"": meetup}`) を使って作られます。 言い換えると、最初の `(key,value)` ペアは空のキーを持ち、値はターゲットのオブジェクト全体です。そういう訳で、上の例の最初の行は `":[object Object]"` となっています。 +The first call is special. It is made using a special "wrapper object": `{"": meetup}`. In other words, the first `(key, value)` pair has an empty key, and the value is the target object as a whole. That's why the first line is `":[object Object]"` in the example above. -このアイデアは、できるだけ多くの力を `replace` を提供することです。必要に応じてオブジェクト全体を分析したり、置換/スキップすることができます。 +The idea is to provide as much power for `replacer` as possible: it has a chance to analyze and replace/skip even the whole object if necessary. -## 書式設定: spacer +## Formatting: space -`JSON.stringify(value, replacer, spaces)` の第3引数は、整形されたフォーマットで使うスペースの数です。 +The third argument of `JSON.stringify(value, replacer, space)` is the number of spaces to use for pretty formatting. -以前は、すべての文字列化(stringified)されたオブジェクトはインデントや余分なスペースを持っていませんでした。それはネットワーク経由でオブジェクトを送りたいときには正しいです。`spaces` 引数は見やすい出力をしたいときに使われます。 +Previously, all stringified objects had no indents and extra spaces. That's fine if we want to send an object over a network. The `space` argument is used exclusively for a nice output. -この例では、`spaces = 2` はJavaScriptがネストされたオブジェクトを複数行で表示するように指示し、オブジェクトの内側は2つスペースでインデントします: +Here `space = 2` tells JavaScript to show nested objects on multiple lines, with indentation of 2 spaces inside an object: ```js run let user = { @@ -307,7 +305,7 @@ let user = { }; alert(JSON.stringify(user, null, 2)); -/* 2つのスペースインデント: +/* two-space indents: { "name": "John", "age": 25, @@ -318,7 +316,7 @@ alert(JSON.stringify(user, null, 2)); } */ -/* JSON.stringify(user, null, 4) の場合、結果はよりインデントされたものです: +/* for JSON.stringify(user, null, 4) the result would be more indented: { "name": "John", "age": 25, @@ -330,13 +328,13 @@ alert(JSON.stringify(user, null, 2)); */ ``` -`spaces` パラメータは単にロギングや見やすい出力のためだけに使われます。 +The `space` parameter is used solely for logging and nice-output purposes. -## カスタムの "toJSON" +## Custom "toJSON" -文字列変換用の `toString` のように、オブジェクトはJSONへの変換用メソッド `toJSON` を提供しています。`JSON.stringify` は利用可能であればそれを自動で呼び出します。 +Like `toString` for string conversion, an object may provide method `toJSON` for to-JSON conversion. `JSON.stringify` automatically calls it if available. -例: +For instance: ```js run let room = { @@ -361,9 +359,9 @@ alert( JSON.stringify(meetup) ); */ ``` -ここで、`date` `(1)` が文字列になっているのが分かります。これは、すべての date にこのような種類の文字列を返す組み込みの `toJSON` メソッドがあるからです。 +Here we can see that `date` `(1)` became a string. That's because all dates have a built-in `toJSON` method which returns such kind of string. -さて、オブジェクト `room` にカスタムの `toJSON` を足してみましょう: +Now let's add a custom `toJSON` for our object `room` `(2)`: ```js run let room = { @@ -395,27 +393,28 @@ alert( JSON.stringify(meetup) ); */ ``` -上の通り、`toJSON` は `JSON.stringify(room)` の直接呼び出しとネストされたオブジェクト両方で使われます。 +As we can see, `toJSON` is used both for the direct call `JSON.stringify(room)` and when `room` is nested in another encoded object. + ## JSON.parse -JSON文字列をデコードするには、[JSON.parse](mdn:js/JSON/parse) と言うメソッドが必要です。 +To decode a JSON-string, we need another method named [JSON.parse](mdn:js/JSON/parse). -構文: +The syntax: ```js -let value = JSON.parse(str[, reviver]); +let value = JSON.parse(str, [reviver]); ``` str -: パースする JSON文字列です。 +: JSON-string to parse. reviver -: 各 `(key,value)` ペアで呼ばれ、値を変形することができるオプションの関数(function(key,value))です。 +: Optional function(key,value) that will be called for each `(key, value)` pair and can transform the value. -例: +For instance: ```js run -// 文字列化された配列 +// stringified array let numbers = "[0, 1, 2, 3]"; numbers = JSON.parse(numbers); @@ -423,50 +422,50 @@ numbers = JSON.parse(numbers); alert( numbers[1] ); // 1 ``` -次はネストされたオブジェクトの場合です: +Or for nested objects: ```js run -let user = '{ "name": "John", "age": 35, "isAdmin": false, "friends": [0,1,2,3] }'; +let userData = '{ "name": "John", "age": 35, "isAdmin": false, "friends": [0,1,2,3] }'; -user = JSON.parse(user); +let user = JSON.parse(userData); alert( user.friends[1] ); // 1 ``` -JSONは必要に応じて複雑になることがあります。オブジェクトと配列には他のオブジェクトや配列を含むことができます。しかし、それらは形式に従う必要があります。 +The JSON may be as complex as necessary, objects and arrays can include other objects and arrays. But they must obey the same JSON format. -ここに手書きのJSONでの典型的な間違いを示します(デバッグ目的で書かなければならないことがあります)。: +Here are typical mistakes in hand-written JSON (sometimes we have to write it for debugging purposes): ```js let json = `{ - *!*name*/!*: "John", // 誤り: クォートなしのプロパティ名 - "surname": *!*'Smith'*/!*, // 誤り: 値がシングルクォート (ダブルクォート必須) - *!*'isAdmin'*/!*: false // 誤り: キーがシングルクォート (ダブルクォート必須) - "birthday": *!*new Date(2000, 2, 3)*/!*, // 誤り: "new" は許可されていません, 裸の値のみです。 - "friends": [0,1,2,3] // ここはOKです + *!*name*/!*: "John", // mistake: property name without quotes + "surname": *!*'Smith'*/!*, // mistake: single quotes in value (must be double) + *!*'isAdmin'*/!*: false // mistake: single quotes in key (must be double) + "birthday": *!*new Date(2000, 2, 3)*/!*, // mistake: no "new" is allowed, only bare values + "friends": [0,1,2,3] // here all fine }`; ``` -加えて、JSONはコメントをサポートしていません。JSONへコメントを追加すると無効になります。 +Besides, JSON does not support comments. Adding a comment to JSON makes it invalid. -[JSON5](http://json5.org/) と呼ばれる別のフォーマットもあり、それは引用符のないキーや、コメントなどが許可されています。しかし、これはスタンドアローンのライブラリで、言語仕様ではありません。 +There's another format named [JSON5](http://json5.org/), which allows unquoted keys, comments etc. But this is a standalone library, not in the specification of the language. -正規のJSONは、その開発者が怠惰なのではなく、簡単で信頼性があり、かつ非常に高速なパースアルゴリズムの実装を可能にするために厳格です。 +The regular JSON is that strict not because its developers are lazy, but to allow easy, reliable and very fast implementations of the parsing algorithm. -## リバイバー(reviver)を利用する +## Using reviver -私たちはサーバから JSONエンコードされた `meetup` オブジェクトを取得したとイメージしてください。 +Imagine, we got a stringified `meetup` object from the server. -それはこのように見えます: +It looks like this: ```js // title: (meetup title), date: (meetup date) let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}'; ``` -...そして今、JavaScriptオブジェクトに戻すため、それを *デシリアライズ* する必要があります。 +...And now we need to *deserialize* it, to turn back into JavaScript object. -`JSON.parse` を呼び出してそれをしましょう: +Let's do it by calling `JSON.parse`: ```js run let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}'; @@ -478,11 +477,11 @@ alert( meetup.date.getDate() ); // Error! */!* ``` -おっと!エラーです! +Whoops! An error! -`meetup.date` の値は文字列であり、`Date` オブジェクトではありません。どうやれば `JSON.parse` はその文字列を `Date` に変換すべきだと知ることができるでしょうか? +The value of `meetup.date` is a string, not a `Date` object. How could `JSON.parse` know that it should transform that string into a `Date`? -すべての値を "そのまま" で返しますが、`date` は `Date` になるような復帰関数を `JSON.parse` に渡しましょう。: +Let's pass to `JSON.parse` the reviving function as the second argument, that returns all values "as is", but `date` will become a `Date`: ```js run let str = '{"title":"Conference","date":"2017-11-30T12:00:00.000Z"}'; @@ -494,10 +493,10 @@ let meetup = JSON.parse(str, function(key, value) { }); */!* -alert( meetup.date.getDate() ); // 動作します! +alert( meetup.date.getDate() ); // now works! ``` -ところで、これはネストされたオブジェクトでも同様に動作します: +By the way, that works for nested objects as well: ```js run let schedule = `{ @@ -513,15 +512,16 @@ schedule = JSON.parse(schedule, function(key, value) { }); *!* -alert( schedule.meetups[1].date.getDate() ); // これも動作します! +alert( schedule.meetups[1].date.getDate() ); // works! */!* ``` -## サマリ -- JSON はほとんどのプログラミング言語に対して、自身の独立した標準とライブラリを持つデータ形式です。 -- JSON はプレーンなオブジェクト、配列、文字列、数値、真偽値、`null` をサポートします。 -- JavaScript は JSON にシリアライズするためのメソッド [JSON.stringify](mdn:js/JSON/stringify) と、 JSONから読み込みをする [JSON.parse](mdn:js/JSON/parse) を提供します。 -- 両メソッドとも、スマートな読み書きのための変換関数をサポートしています。 -- もしもオブジェクトが `toJSON` を持っていたら、`JSON.stringify` がそれを呼び出します。 +## Summary + +- JSON is a data format that has its own independent standard and libraries for most programming languages. +- JSON supports plain objects, arrays, strings, numbers, booleans, and `null`. +- JavaScript provides methods [JSON.stringify](mdn:js/JSON/stringify) to serialize into JSON and [JSON.parse](mdn:js/JSON/parse) to read from JSON. +- Both methods support transformer functions for smart reading/writing. +- If an object has `toJSON`, then it is called by `JSON.stringify`. 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 e9df18b8fb..140ac897fd 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 @@ P.S. 当然のことながら、この式は最速の解法です。任意の数 ループのバリアントは速度の点では2番目です。再帰とループのバリアント共に同じ数を合計していますが、再帰にはネストされた呼び出しと実行スタック管理が含まれます。それもまたリソースを取るため、より遅くなります。 +<<<<<<< HEAD P.P.S この規格は、「テールコール(末尾呼び出し)」最適化について説明しています。もし再帰呼び出しが関数の中の最後のものである場合(上の `sumTo` のように)、外部の関数は実行を再開する必要はなく、その実行コンテキストを覚えておく必要はありません。その場合であれば、`sumTo(100000)` はカウント可能です。しかし、もしあなたのJavaScriptエンジンがそれをサポートしていない場合は最大スタックサイズを超えたというエラーが発生します。これは、通常、スタックサイズの合計に制限があるためです。 +======= +P.P.S. Some engines support the "tail call" optimization: if a recursive call is the very last one in the function (like in `sumTo` above), 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, so counting `sumTo(100000)` becomes possible. 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. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/06-advanced-functions/01-recursion/04-output-single-linked-list/solution.md b/1-js/06-advanced-functions/01-recursion/04-output-single-linked-list/solution.md index ec145a002d..f096656fb0 100644 --- a/1-js/06-advanced-functions/01-recursion/04-output-single-linked-list/solution.md +++ b/1-js/06-advanced-functions/01-recursion/04-output-single-linked-list/solution.md @@ -43,7 +43,11 @@ function printList(list) { } ``` +<<<<<<< HEAD ...しかし、それは賢くありません。将来、リストに何かをするよう、関数を拡張する必要があるかもしれません。もし `list` を変えると、このような能力を失います。 +======= +...But that would be unwise. In the future we may need to extend a function, do something else with the list. If we change `list`, then we lose such ability. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 良い変数名について言うと、`list` はここではリスト自身です。その最初の要素です。そして、それはそのままでいるべきです。それは明らかで信頼できるものです。 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 d8b24a9e16..9ab41a0fd5 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 @@ -37,7 +37,11 @@ printReverseList(list); 我々の `list` で最後の値を取得する方法はありません。また、 "戻る" こともできません。 +<<<<<<< HEAD 従って、できることは直接の並びでアイテムを調べて、それらを配列に覚えます。そして逆順で覚えていることを出力していきます。: +======= +So what we can do is to first go through the items in the direct order and remember them in an array, and then output what we remembered in the reverse order: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let list = { diff --git a/1-js/06-advanced-functions/01-recursion/article.md b/1-js/06-advanced-functions/01-recursion/article.md index 3106b0c16d..1e77029ce8 100644 --- a/1-js/06-advanced-functions/01-recursion/article.md +++ b/1-js/06-advanced-functions/01-recursion/article.md @@ -10,9 +10,13 @@ 関数がタスクを解決するとき、処理の過程で多くの他の関数を呼ぶことができます。この部分的なケースとして、関数が *自分自身* を呼ぶときです。それは *再帰* と呼ばれます。 +<<<<<<< HEAD [cut] ## 2つの考え方 +======= +## Two ways of thinking +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 初めのシンプルな例として、`x` の `n` 乗をする関数 `pow(x, n)` を書いてみましょう。つまり、`x` 自身を `n` 回乗算します。 @@ -88,7 +92,11 @@ pow(x, n) = ````smart header="通常、再帰はより短く書けます" 再帰的な解決策は、通常、反復する方法よりも短いです。 +<<<<<<< HEAD ここで、`pow(x, n)` をより簡潔にし、かつ読みやすくするために `if` の代わりに3項演算子 `?` を使って書き直すことができます。: +======= +Here we can rewrite the same using the conditional operator `?` instead of `if` to make `pow(x, n)` more terse and still very readable: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run function pow(x, n) { @@ -99,15 +107,27 @@ function pow(x, n) { 入れ子呼び出しの最大数(最初の1回を含む)は *再帰の深さ* と呼ばれます。我々のケースでは、それは `n` になります。 +<<<<<<< HEAD 最大の再帰の深さは JavaScript エンジンによって制限されています。10,000 は確実で、エンジンによってはより多くの値が可能ですが、100,000 は恐らく大多数の制限を超えます。これを緩和する自動最適もあります("末尾再帰")が、どこでもサポートされているわけではなく、単純なケースでのみ機能します。 +======= +The maximal recursion depth is limited by JavaScript engine. We can rely on it being 10000, some engines allow more, but 100000 is probably out of limit for the majority of them. There are automatic optimizations that help alleviate this ("tail calls optimizations"), but they are not yet supported everywhere and work only in simple cases. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 それは再帰の使用を制限しますが、依然として非常に広範囲に使われています。再帰的な考え方でコードがシンプルになり、保守が容易になるタスクはたくさんあります。 +<<<<<<< HEAD ## 実行スタック +======= +## The execution context and stack +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 さて、どのように再帰呼び出しが動作するか検証してみましょう。そのためには関数の内部を見ていきます。 +<<<<<<< HEAD 関数の実行に関する情報は、その *実行コンテキスト* に格納されています。 +======= +The information about the process of execution of a running function is stored in its *execution context*. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 [実行コンテキスト(execution context)](https://tc39.github.io/ecma262/#sec-execution-contexts) は関数の実行に関する詳細を含む内部のデータ構造です。: 今はどの制御フローであるか、現在の変数、`this` の値(ここでは使いませんが)や、その他いくつかの内部データを持ちます。 @@ -187,7 +207,17 @@ alert( pow(2, 3) ); 新しい現在の実行コンテキストが上(で太字のもの)で、以前に記憶されたコンテキストが下にあります。 +<<<<<<< HEAD サブコールが終わったとき、以前のコンテキストを再開するのは簡単です。なぜなら、変数と停止したコードの正確な位置を両方とも維持しているためです。この絵の中では、"行(line)" という言葉を使いましたが、もちろん実際それはより精密です。 +======= +When we finish the subcall -- it is easy to resume the previous context, because it keeps both variables and the exact place of the code where it stopped. + +```smart +Here in the picture we use the word "line", as our example there's only one subcall in line, but generally a single line of code may contain multiple subcalls, like `pow(…) + pow(…) + somethingElse(…)`. + +So it would be more precise to say that the execution resumes "immediately after the subcall". +``` +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ### pow(2, 1) @@ -298,7 +328,7 @@ let company = { salary: 1000 }, { name: 'Alice', - salary: 600 + salary: 1600 }], development: { @@ -318,7 +348,15 @@ let company = { }; ``` +<<<<<<< HEAD 言い換えると、会社は部署を持っています。 +======= +In other words, a company has departments. + +- A department may have an array of staff. For instance, `sales` department has 2 employees: John and Alice. +- Or a department may split into subdepartments, like `development` has two branches: `sites` and `internals`. Each of them has their own staff. +- It is also possible that when a subdepartment grows, it divides into subsubdepartments (or teams). +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 - 部署はスタッフの配列を持っているかもしれません。例えば、`sales` 部門は2人の従業員がいます。John と Alice です。 - もしくは、`development` は2つの枝(`sites` と `internals`)を持っているように、部署はサブの部署に分割されるかもしれません。それらは各々のスタッフを持ちます。 @@ -326,26 +364,44 @@ let company = { 例えば、将来 `sites` 部門が `siteA` と `siteB` のチームに分割されるかもしれません。そしてそれらは潜在的にさらに分割することができます。 +<<<<<<< HEAD では、全員の給料の合計を取得する関数が欲しいとしましょう。どのようにすればよいでしょう? +======= +An iterative approach is not easy, because the structure is not simple. The first idea may be to make a `for` loop over `company` with nested subloop over 1st level departments. But then we need more nested subloops to iterate over the staff in 2nd level departments like `sites`... And then another subloop inside those for 3rd level departments that might appear in the future? If we put 3-4 nested subloops in the code to traverse a single object, it becomes rather ugly. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 反復的なアプローチは簡単ではありません。なぜなら構造はシンプルではないためです。最初のアイデアは、第1レベルの所属のネストされたサブループをもつ `company` に `for` をループを作ることです。しかし、次に `sites` のような 第2レベルの部門のスタッフを反復するためには、より多くのネストされたサブループが必要になります。...そして、将来現れるかもしれない第3レベルの部門のための別のサブループも必要ですか?またレベル3で停止するか、レベル4のループも作成する必要がありますか? 1つのオブジェクトを探索するために3〜4個のネストされたサブループをコード内に置くと、それはかなり醜いものになります。 再帰でトライしてみましょう。 +<<<<<<< HEAD 上から分かるように、関数が合計するための部署を取得するとき、2つのケースがあります: 1. *人の配列* を持つ "シンプルな" 部署の場合です。この場合は単純なループで給料を合計することができます。 2. もしくは *`N` 個のサブ部門を持つオブジェクト* の場合です。この場合は、`N` 回の再帰呼び出しを行ってサブ部門の各合計を取得し、結果を結合します。 (1) は再帰の基底で、自明なケースです。 +======= +1. Either it's a "simple" department with an *array* of people -- then we can sum the salaries in a simple loop. +2. Or it's *an object* with `N` subdepartments -- then we can make `N` recursive calls to get the sum for each of the subdeps and combine the results. + +The 1st case is the base of recursion, the trivial case, when we get an array. + +The 2nd case when we get an object is the recursive step. A complex task is split into subtasks for smaller departments. They may in turn split again, but sooner or later the split will finish at (1). +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 (2) は再帰ステップです。複雑なタスクはより小さい部門のためのサブタスクに分割されます。それらは次々に繰り返し分割するかもしれませんが、遅かれ早かれ分割は (1) で終わります。 このアルゴリズムは恐らくコードからさらに読みやすくなるでしょう: ```js run +<<<<<<< HEAD let company = { // 同じオブジェクトです。簡略のため圧縮しています sales: [{name: 'John', salary: 1000}, {name: 'Alice', salary: 600 }], +======= +let company = { // the same object, compressed for brevity + sales: [{name: 'John', salary: 1000}, {name: 'Alice', salary: 1600 }], +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 development: { sites: [{name: 'Peter', salary: 2000}, {name: 'Alex', salary: 1800 }], internals: [{name: 'Jack', salary: 1300}] @@ -367,7 +423,7 @@ function sumSalaries(department) { } */!* -alert(sumSalaries(company)); // 6700 +alert(sumSalaries(company)); // 7700 ``` コードは(望んだように?)短く理解しやすくなりました。これが再帰の力です。また、これは任意のレベルのサブ部門のネスティングでも正しく動作します。 @@ -418,7 +474,11 @@ let arr = [obj1, obj2, obj3]; ...しかし、配列を使う場合には問題があります。 "要素の削除" と "要素の挿入" 操作はコストが高いです。例えば `arr.unshift(obj)` 操作は新しい `obj` のための場所を作るために、全ての要素の番号を振り直す必要があります。また、もし配列が大きい場合、それは時間がかかります。`arr.shift()` も同じです。 +<<<<<<< HEAD 大量の番号の再割当てを必要としない唯一の構造変更は配列の末尾への操作です: `arr.push/pop`。従って、配列は大きなキューに対しては非常に遅くなる可能性があります。 +======= +The only structural modifications that do not require mass-renumbering are those that operate with the end of array: `arr.push/pop`. So an array can be quite slow for big queues, when we have to work with the beginning. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 あるいは、もしも本当に速い挿入/削除が必要であれば、[連結リスト(linked list)](https://en.wikipedia.org/wiki/Linked_list) と呼ばれる別のデータ構造を選択することもできます。 @@ -455,9 +515,14 @@ let list = { value: 1 }; list.next = { value: 2 }; list.next.next = { value: 3 }; list.next.next.next = { value: 4 }; +list.next.next.next.next = null; ``` +<<<<<<< HEAD ここでは複数のオブジェクトがあり、それぞれが `value` と隣を指し示す `next` を持っていることがはっきり見えます。`list` 変数はチェーンの最初なので、`next` ポインタの後にはどの要素にも到達することができます。 +======= +Here we can even more clearly see that there are multiple objects, each one has the `value` and `next` pointing to the neighbour. The `list` variable is the first object in the chain, so following `next` pointers from it we can reach any element. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 リストは簡単に複数の部分に分割したり、後で戻したりできます: @@ -508,14 +573,28 @@ list.next = list.next.next; 主な欠点は、番号では簡単に要素にアクセスできないことです。配列では簡単です( `arr[n]` で直接参照します)が、リストではアイテムの最初から始めてN個目の要素を取得するために、`N` 回 `next` を行う必要があります。 +<<<<<<< HEAD ...でも、常にこのような操作が必要とは限りません。例えば、キュー(queue)や [デック(deque)](https://en.wikipedia.org/wiki/Double-ended_queue) が必要なときです。これらは両端から要素を非常に高速に追加/削除できる順序付けられた構造です。 時には、リストの最後の要素を追跡するために `tail` という名前の別の変数を追加する価値があります(そして要素を最後に追加または削除するときにそれを更新します)。要素の集合が大きいと、配列と速度の違いが大きくなります。 +======= +...But we don't always need such operations. For instance, when we need a queue or even a [deque](https://en.wikipedia.org/wiki/Double-ended_queue) -- the ordered structure that must allow very fast adding/removing elements from both ends, but access to its middle is not needed. + +Lists can be enhanced: +- We can add property `prev` in addition to `next` to reference the previous element, to move back easily. +- We can also add a variable named `tail` referencing the last element of the list (and update it when adding/removing elements from the end). +- ...The data structure may vary according to our needs. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## サマリ +<<<<<<< HEAD 用語: - *再帰* は "自己呼び出し" 関数を意味するプログラミングの用語です。このような関数を使用して、特定のタスクを簡潔で美しい方法で解決することができます。 +======= +Terms: +- *Recursion* is a programming term that means calling a function from itself. Recursive functions can be used to solve tasks in elegant ways. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 関数が自身を呼び出すとき、それは *再帰ステップ* と呼ばれます。 再帰の *基底* は、関数がそれ以上の呼び出しを行わないようにタスクを単純化する関数の引数です。 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 805d924e98..1f139d7a4a 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 @@ -1,22 +1,20 @@ -# 残りのパラメータ(Rest parameters)とスプレッド演算子(Spread operator) +# Rest parameters and spread syntax -JavaScript の主な組み込み関数は、任意の数の引数をサポートしています。 +Many JavaScript built-in functions support an arbitrary number of arguments. -例: +For instance: -- `Math.max(arg1, arg2, ..., argN)` -- 引数の中で最大のものを返します。 -- `Object.assign(dest, src1, ..., srcN)` -- `src1..N` のプロパティを `dest` にコピーします。 -- など. +- `Math.max(arg1, arg2, ..., argN)` -- returns the greatest of the arguments. +- `Object.assign(dest, src1, ..., srcN)` -- copies properties from `src1..N` into `dest`. +- ...and so on. -このチャプターでは、その方法を説明します。そして、より重要なことは、そのような関数や配列を快適に扱う方法です。 +In this chapter we'll learn how to do the same. And also, how to pass arrays to such functions as parameters. -[cut] +## Rest parameters `...` -## 残りのパラメータ '...' +A function can be called with any number of arguments, no matter how it is defined. -関数は、どのように定義されたかに関係なく、任意の数の引数で呼ぶことができます。 - -このような感じです: +Like here: ```js run function sum(a, b) { return a + b; @@ -25,14 +23,14 @@ function sum(a, b) { alert( sum(1, 2, 3, 4, 5) ); ``` -"必要以上の" 引数でもエラーにはなりません。 しかし、結果はもちろん最初の2つだけが使われます。 +There will be no error because of "excessive" arguments. But of course in the result only the first two will be counted. -残りのパラメータは、3つのドット `...` を持つ関数定義で記述できます。これは文字通り、"残りのパラメータを配列にまとめる" という意味です。 +The rest of the parameters can be included in the function definition by using three dots `...` followed by the name of the array that will contain them. The dots literally mean "gather the remaining parameters into an array". -例えば、すべての引数を配列 `args` に集める場合は次のようになります: +For instance, to gather all arguments into array `args`: ```js run -function sumAll(...args) { // args は配列の名前です +function sumAll(...args) { // args is the name for the array let sum = 0; for (let arg of args) sum += arg; @@ -45,15 +43,15 @@ alert( sumAll(1, 2) ); // 3 alert( sumAll(1, 2, 3) ); // 6 ``` -最初のパラメータを変数として取得するようにし、残りだけを集めることもできます。 +We can choose to get the first parameters as variables, and gather only the rest. -ここでは、最初の2つの引数が変数に入り、残りは `titles` 配列に格納されます: +Here the first two arguments go into variables and the rest go into `titles` array: ```js run function showName(firstName, lastName, ...titles) { alert( firstName + ' ' + lastName ); // Julius Caesar - // 残りは titles 配列に入ります + // the rest go into titles array // i.e. titles = ["Consul", "Imperator"] alert( titles[0] ); // Consul alert( titles[1] ); // Imperator @@ -63,8 +61,8 @@ function showName(firstName, lastName, ...titles) { showName("Julius", "Caesar", "Consul", "Imperator"); ``` -````warn header="残りのパラメータは最後である必要があります" -残りのパラメータはすべての残っている引数をまとめるため、下記は意味をなさず、エラーとなります。: +````warn header="The rest parameters must be at the end" +The rest parameters gather all remaining arguments, so the following does not make sense and causes an error: ```js function f(arg1, ...rest, arg2) { // arg2 after ...rest ?! @@ -72,14 +70,14 @@ function f(arg1, ...rest, arg2) { // arg2 after ...rest ?! } ``` -`...rest` は常に最後です。 +The `...rest` must always be last. ```` -## "arguments" 変数 +## The "arguments" variable -インデックスによってすべての引数を含む `arguments` と言う特別な配列ライクなオブジェクトもあります。 +There is also a special array-like object named `arguments` that contains all arguments by their index. -例: +For instance: ```js run function showName() { @@ -87,31 +85,29 @@ function showName() { alert( arguments[0] ); alert( arguments[1] ); - // 反復可能(iterable) です。 + // it's iterable // for(let arg of arguments) alert(arg); } -// 表示: 2, Julius, Caesar +// shows: 2, Julius, Caesar showName("Julius", "Caesar"); -// 表示: 1, Ilya, undefined (2つ目の引数がないので) +// shows: 1, Ilya, undefined (no second argument) showName("Ilya"); ``` -以前は、残りのパラメータは言語仕様に存在しませんでした。そして、`arguments` は引数の数に関係なく、関数に指定されたすべての引数を取得するための唯一の方法でした。 - -そして、これは今でも動作するので使うことができます。 +In old times, rest parameters did not exist in the language, and using `arguments` was the only way to get all arguments of the function. And it still works, we can find it in the old code. -が、デメリットは `arguments` は配列ではなく、配列ライクで反復可能という点です。従って、配列メソッドをサポートしないので、 `arguments.map(...)` 呼び出しをすることはできません。 +But the downside is that although `arguments` is both array-like and iterable, it's not an array. It does not support array methods, so we can't call `arguments.map(...)` for example. -また、すべての引数が常に含まれているため、残りのパラメータのように部分的に取り込むことはできません。 +Also, it always contains all arguments. We can't capture them partially, like we did with rest parameters. -したがって、これらの機能が必要な場合には "残りのパラメータ" が好ましいです。 +So when we need these features, then rest parameters are preferred. -````smart header="アロー関数は `\"arguments\"` を持ちません" -もしもアロー関数から `arguments` オブジェクトにアクセスすると、外部の "通常の" 関数からそれらを取得します。 +````smart header="Arrow functions do not have `\"arguments\"`" +If we access the `arguments` object from an arrow function, it takes them from the outer "normal" function. -ここではその例です: +Here's an example: ```js run function f() { @@ -122,24 +118,25 @@ function f() { f(1); // 1 ``` -以前学んだように、アロー関数は自身の `this` を持ちません。そして、特別な `arguments` オブジェクトも持っていないことが分かります。 +As we remember, arrow functions don't have their own `this`. Now we know they don't have the special `arguments` object either. ```` -## スプレッド 演算子 -先ほど、パラメータのリストから配列を取得する方法をみました。 +## Spread syntax [#spread-syntax] + +We've just seen how to get an array from the list of parameters. -一方、我々はその逆を正確に行う必要がある場合があります。 +But sometimes we need to do exactly the reverse. -例えば、リストから最大値を返す組み込み関数 [Math.max](mdn:js/Math/max) です。 +For instance, there's a built-in function [Math.max](mdn:js/Math/max) that returns the greatest number from a list: ```js run alert( Math.max(3, 5, 1) ); // 5 ``` -今、配列 `[3 ,5, 1]` を持っているとします。それを使って `Math.max` を呼び出すにはどうやるでしょう? +Now let's say we have an array `[3, 5, 1]`. How do we call `Math.max` with it? -それを "そのまま" 渡すと上手く動きません。なぜなら `Math.max` は数値の引数のリストを期待しており、単一の配列がくることは期待していません。: +Passing it "as is" won't work, because `Math.max` expects a list of numeric arguments, not a single array: ```js run let arr = [3, 5, 1]; @@ -149,22 +146,21 @@ alert( Math.max(arr) ); // NaN */!* ``` -...そして、おそらくコードの中で手動で項目をリストする(`Math.max(arg[0], arg[1], arg[2])`)こともできません。なぜなら , -それがどれだけあるか分からないからです。スクリプトが動くとき、もっと多いかもしれないし、全くないかもしれません。また、その書き方は格好悪いです。 +And surely we can't manually list items in the code `Math.max(arr[0], arr[1], arr[2])`, because we may be unsure how many there are. As our script executes, there could be a lot, or there could be none. And that would get ugly. -*スプレッド演算子 (Spread operator)* はその場合に役立ちます。残りのパラメータと似ており、`...` を使いますが、全く反対のことをします。 +*Spread syntax* to the rescue! It looks similar to rest parameters, also using `...`, but does quite the opposite. -関数呼び出しで `...arr` が使われると、反復可能なオブジェクト `arr` を引数のリストに展開します。 +When `...arr` is used in the function call, it "expands" an iterable object `arr` into the list of arguments. -`Math.max` の場合: +For `Math.max`: ```js run let arr = [3, 5, 1]; -alert( Math.max(...arr) ); // 5 (配列を引数のリストに変換する) +alert( Math.max(...arr) ); // 5 (spread turns array into a list of arguments) ``` -また、この方法で複数の iterables を渡すこともできます: +We also can pass multiple iterables this way: ```js run let arr1 = [1, -2, 3, 4]; @@ -173,7 +169,8 @@ let arr2 = [8, 3, -8, 1]; alert( Math.max(...arr1, ...arr2) ); // 8 ``` -...そして、通常の値とスプレッド演算子を組み合わせることもできます。: +We can even combine the spread syntax with normal values: + ```js run let arr1 = [1, -2, 3, 4]; @@ -182,7 +179,7 @@ let arr2 = [8, 3, -8, 1]; alert( Math.max(1, ...arr1, 2, ...arr2, 25) ); // 25 ``` -さらにスプレッド演算子は配列をマージするために使うこともできます: +Also, the spread syntax can be used to merge arrays: ```js run let arr = [3, 5, 1]; @@ -195,9 +192,9 @@ let merged = [0, ...arr, 2, ...arr2]; alert(merged); // 0,3,5,1,2,8,9,15 (0, then arr, then 2, then arr2) ``` -上の例では、スプレッド演算子のデモをするために配列を使いましたが、任意の iterable で動作します。 +In the examples above we used an array to demonstrate the spread syntax, but any iterable will do. -例えば、ここではスプレッド演算子を使って、文字列を文字の配列にします: +For instance, here we use the spread syntax to turn the string into array of characters: ```js run let str = "Hello"; @@ -205,43 +202,88 @@ let str = "Hello"; alert( [...str] ); // H,e,l,l,o ``` -スプレッド演算子は内部的にはイテレータを使用して要素を集めます。これは `for..of` と同じ方法です。 +The spread syntax internally uses iterators to gather elements, the same way as `for..of` does. -従って、文字列の場合、 `for..of` は文字を返すので `...str` は `"H","e","l","l","o"` になります。文字のリストは配列初期化子 `[...str]` に渡されます。 +So, for a string, `for..of` returns characters and `...str` becomes `"H","e","l","l","o"`. The list of characters is passed to array initializer `[...str]`. -この特定のタスクでは、`Array.from` を使うこともできます。それは iterable(文字列など) を配列に変換するからです: +For this particular task we could also use `Array.from`, because it converts an iterable (like a string) into an array: ```js run let str = "Hello"; -// Array.from は iterable を配列に変換します +// Array.from converts an iterable into an array alert( Array.from(str) ); // H,e,l,l,o ``` -結果は `[...str]` と同じです。 +The result is the same as `[...str]`. + +But there's a subtle difference between `Array.from(obj)` and `[...obj]`: + +- `Array.from` operates on both array-likes and iterables. +- The spread syntax works only with iterables. + +So, for the task of turning something into an array, `Array.from` tends to be more universal. + + +## Get a new copy of an array/object + +Remember when we talked about `Object.assign()` [in the past](info:object-copy#cloning-and-merging-object-assign)? + +It is possible to do the same thing with the spread syntax. + +```js run +let arr = [1, 2, 3]; +let arrCopy = [...arr]; // spread the array into a list of parameters + // then put the result into a new array + +// do the arrays have the same contents? +alert(JSON.stringify(arr) === JSON.stringify(arrCopy)); // true + +// are the arrays equal? +alert(arr === arrCopy); // false (not same reference) + +// modifying our initial array does not modify the copy: +arr.push(4); +alert(arr); // 1, 2, 3, 4 +alert(arrCopy); // 1, 2, 3 +``` + +Note that it is possible to do the same thing to make a copy of an object: + +```js run +let obj = { a: 1, b: 2, c: 3 }; +let objCopy = { ...obj }; // spread the object into a list of parameters + // then return the result in a new object -しかし `Array.from(obj)` と `[...obj]` には微妙な違いがあります: +// do the objects have the same contents? +alert(JSON.stringify(obj) === JSON.stringify(objCopy)); // true -- `Array.from`は配列ライクと iterables の両方で動作します。 -- スプレッド演算子は iterables でのみ動作します。 +// are the objects equal? +alert(obj === objCopy); // false (not same reference) + +// modifying our initial object does not modify the copy: +obj.d = 4; +alert(JSON.stringify(obj)); // {"a":1,"b":2,"c":3,"d":4} +alert(JSON.stringify(objCopy)); // {"a":1,"b":2,"c":3} +``` -従って、何かを配列に変換するタスクにおいては、`Array.from` がより適しています。 +This way of copying an object is much shorter than `let objCopy = Object.assign({}, obj);` or for an array `let arrCopy = Object.assign([], arr);` so we prefer to use it whenever we can. -## サマリ +## Summary -コード上に `"..."` がある場合、それは残りのパラメータかスプレッド演算子です。 +When we see `"..."` in the code, it is either rest parameters or the spread syntax. -それらを区別する簡単な方法があります: +There's an easy way to distinguish between them: -- `...` が関数パラメータの最後にある場合、それは "残りのパラメータ" で、リストの残りを配列に集めます。 -- 関数呼び出しなどで `...` があると、それは "スプレッド演算子" と呼ばれ、配列をリストに展開します。 +- When `...` is at the end of function parameters, it's "rest parameters" and gathers the rest of the list of arguments into an array. +- When `...` occurs in a function call or alike, it's called a "spread syntax" and expands an array into a list. -利用パターン: +Use patterns: -- 残りのパラメータは、任意の数の引数を受け入れる関数を作成する際に使用されます。 -- スプレッド演算子は、通常、多くの引数のリストを必要とする関数に配列を渡す際に使用されます。 +- Rest parameters are used to create functions that accept any number of arguments. +- The spread syntax is used to pass an array to functions that normally require a list of many arguments. -共にそれらはリストとパラメータの配列を簡単にやり取りするのに役立ちます。 +Together they help to travel between a list and an array of parameters with ease. -関数呼び出しのすべての引数は "昔のスタイル" `arguments`(配列ライクな反復可能オブジェクト) も利用可能です。 +All arguments of a function call are also available in "old-style" `arguments`: array-like iterable object. diff --git a/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/solution.md b/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/solution.md index 68d5d69844..4c7d735298 100644 --- a/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/solution.md +++ b/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/solution.md @@ -1,5 +1,13 @@ +<<<<<<< HEAD 答えは: **Pete** です。 関数は "今" の外部変数を取得し、最新の値を利用します。 古い変数の値はどこにも保存されません。関数が変数を必要とするとき、自身、あるいは外部のレキシカル環境から現在の値を取得します。 +======= +The answer is: **Pete**. + +A function gets outer variables as they are now, it uses the most recent values. + +Old variable values are not saved anywhere. When a function wants a variable, it takes the current value from its own Lexical Environment or the outer one. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/task.md b/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/task.md index 25c390f3aa..35ba091ebd 100644 --- a/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/task.md +++ b/1-js/06-advanced-functions/03-closure/1-closure-latest-changes/task.md @@ -2,9 +2,15 @@ importance: 5 --- +<<<<<<< HEAD # 関数は最新の変更を取得しますか? 関数 sayHi は外部の変数を使用しています。関数実行時、どの値が利用されるでしょう? +======= +# Does a function pickup latest changes? + +The function sayHi uses an external variable name. When the function runs, which value is it going to use? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let name = "John"; @@ -15,6 +21,7 @@ function sayHi() { name = "Pete"; +<<<<<<< HEAD sayHi(); // 何が表示される?: "John" or "Pete"? ``` @@ -22,3 +29,11 @@ sayHi(); // 何が表示される?: "John" or "Pete"? したがって、問題は: 最新の変更を取得しますか? +======= +sayHi(); // what will it show: "John" or "Pete"? +``` + +Such situations are common both in browser and server-side development. A function may be scheduled to execute later than it is created, for instance after a user action or a network request. + +So, the question is: does it pick up the latest changes? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/06-advanced-functions/03-closure/10-make-army/solution.md b/1-js/06-advanced-functions/03-closure/10-make-army/solution.md index 3e163b4838..0fb0b4a49a 100644 --- a/1-js/06-advanced-functions/03-closure/10-make-army/solution.md +++ b/1-js/06-advanced-functions/03-closure/10-make-army/solution.md @@ -1,14 +1,14 @@ -`makeArmy` の中で行われていることを検査してみましょう、それで解決策が明白になるでしょう。 +Let's examine what's done inside `makeArmy`, and the solution will become obvious. -1. 空の配列 `shooters` を作ります: +1. It creates an empty array `shooters`: ```js let shooters = []; ``` -2. ループで、`shooters.push(function...)` を通してそれを埋めます。 +2. Fills it in the loop via `shooters.push(function...)`. - すべての要素は関数なので、結果の配列はこのように見えます: + Every element is a function, so the resulting array looks like this: ```js no-beautify shooters = [ @@ -25,17 +25,17 @@ ]; ``` -3. 配列が関数から返却されます。 +3. The array is returned from the function. -次に、`army[5]()` の呼び出しは、その配列から `army[5]` の要素を取得(それは関数になります)し、呼び出します。 +Then, later, the call to `army[5]()` will get the element `army[5]` from the array (it will be a function) and call it. -さて、なぜすべての関数は同じものを表示するのでしょう? +Now why all such functions show the same? -それは、`shooter` 関数の内側にローカル変数 `i` がないからです。このような関数が呼ばれるとき、`i` はその外部のレキシカル環境から取られます。 +That's because there's no local variable `i` inside `shooter` functions. When such a function is called, it takes `i` from its outer lexical environment. -`i` の値は何になるでしょう? +What will be the value of `i`? -ソースを見ると: +If we look at the source: ```js function makeArmy() { @@ -51,13 +51,13 @@ function makeArmy() { } ``` -...`i` は現在の `makeArmy()` の実行に関連付けられたレキシカル環境で生きているのがわかります。しかし、`army[5]()` が呼ばれたとき、`makeArmy` はすでにその処理を終えているので、`i` は最後の値である `10` (`while` の最後) です。 +...We can see that it lives in the lexical environment associated with the current `makeArmy()` run. But when `army[5]()` is called, `makeArmy` has already finished its job, and `i` has the last value: `10` (the end of `while`). -結果として、すべての `shooter` 関数は外部のレキシカル環境から同じ最後の値 `i=10` を取ります。 +As a result, all `shooter` functions get from the outer lexical envrironment the same, last value `i=10`. -修正はとてもシンプルです。: +We can fix it by moving the variable definition into the loop: -```js run +```js run demo function makeArmy() { let shooters = []; @@ -80,16 +80,15 @@ army[0](); // 0 army[5](); // 5 ``` -これで、正しく動きます。なぜなら、`for (..) {...}` で毎回コードブロックが実行され、`i` の値に対応する新しいレキシカル環境が作られるからです。 +Now it works correctly, because every time the code block in `for (let i=0...) {...}` is executed, a new Lexical Environment is created for it, with the corresponding variable `i`. -従って、`i` の値は今は少し近くにあります。`makeArmy` レキシカル環境ではなく、現在のループイテレーションに対応するレキシカル環境の中です。`shooter` は作られたレキシカル環境から値を取り出します。 +So, the value of `i` now lives a little bit closer. Not in `makeArmy()` Lexical Environment, but in the Lexical Environment that corresponds the current loop iteration. That's why now it works. ![](lexenv-makearmy.svg) -これは、`while` を `for` で書き直しました。 - -別のトリックでも可能です。この話題をより理解するために次のコードを見てみましょう。: +Here we rewrote `while` into `for`. +Another trick could be possible, let's see it for better understanding of the subject: ```js run function makeArmy() { @@ -116,6 +115,6 @@ army[0](); // 0 army[5](); // 5 ``` -ちょうど `for` と同じように `while` ループは各実行に対するレキシカル環境を作ります。従って、`shooter` の正しい値を取得することが確認できます。 +The `while` loop, just like `for`, makes a new Lexical Environment for each run. So here we make sure that it gets the right value for a `shooter`. -私たちは `let j = i` のコピーをしています。これはループ本体のローカル `j` を作り、`i` の値をコピーします。プリミティブは "値によって" コピーされるので、現在のループイテレーションに属する実際に完全に独立した `i` のコピーになります。 +We copy `let j = i`. This makes a loop body local `j` and copies the value of `i` to it. Primitives are copied "by value", so we actually get a complete independent copy of `i`, belonging to the current loop iteration. diff --git a/1-js/06-advanced-functions/03-closure/10-make-army/task.md b/1-js/06-advanced-functions/03-closure/10-make-army/task.md index 63461a8e0a..93e64f2d02 100644 --- a/1-js/06-advanced-functions/03-closure/10-make-army/task.md +++ b/1-js/06-advanced-functions/03-closure/10-make-army/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# 関数の軍隊 +# Army of functions -次のコードは `shooters` の配列を作ります。 +The following code creates an array of `shooters`. -すべての関数は、その番号を出力するためのものです。しかし、どこか間違っています... +Every function is meant to output its number. But something is wrong... ```js run function makeArmy() { @@ -14,8 +14,8 @@ function makeArmy() { let i = 0; while (i < 10) { - let shooter = function() { // 射手(shooter) 関数 - alert( i ); // その番号を表示するべき + let shooter = function() { // shooter function + alert( i ); // should show its number }; shooters.push(shooter); i++; @@ -26,9 +26,10 @@ function makeArmy() { let army = makeArmy(); -army[0](); // 射手 番号 0 表示 10 -army[5](); // また 番号 5 ですが表示は 10... -// ... すべての射手は 0, 1, 2, 3... の代わりに 10 が表示されます +army[0](); // the shooter number 0 shows 10 +army[5](); // and number 5 also outputs 10... +// ... all shooters show 10 instead of their 0, 1, 2, 3... ``` -なぜすべての射手(shooters)は同じものが表示されるのでしょう?期待通りに動作するようコードを直してください。 +Why do all of the shooters show the same value? Fix the code so that they work as intended. + diff --git a/1-js/06-advanced-functions/03-closure/2-closure-variable-access/solution.md b/1-js/06-advanced-functions/03-closure/2-closure-variable-access/solution.md index 2348f92d49..b5420fb633 100644 --- a/1-js/06-advanced-functions/03-closure/2-closure-variable-access/solution.md +++ b/1-js/06-advanced-functions/03-closure/2-closure-variable-access/solution.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD 答えは: **Pete** です。 以下のコードの `work()` 関数は、外部のレキシカル環境参照を介して、元の場所から `name` を取得します。: @@ -7,3 +8,14 @@ したがって、結果は `"Pete"` になります。 しかし、`makeWorker()` に `let name` が無かった場合は、検索は外部に向かい、上のチェーンの通りグローバル変数を取ります。この場合、結果は `"John"` になります。 +======= +The answer is: **Pete**. + +The `work()` function in the code below gets `name` from the place of its origin through the outer lexical environment reference: + +![](lexenv-nested-work.svg) + +So, the result is `"Pete"` here. + +But if there were no `let name` in `makeWorker()`, then the search would go outside and take the global variable as we can see from the chain above. In that case the result would be `"John"`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/06-advanced-functions/03-closure/2-closure-variable-access/task.md b/1-js/06-advanced-functions/03-closure/2-closure-variable-access/task.md index 8fa8816e32..dd10da346c 100644 --- a/1-js/06-advanced-functions/03-closure/2-closure-variable-access/task.md +++ b/1-js/06-advanced-functions/03-closure/2-closure-variable-access/task.md @@ -2,11 +2,19 @@ importance: 5 --- +<<<<<<< HEAD # どちらの変数が利用可能でしょう? 以下の関数 `makeWorker` は別の関数を作りそれを返します。その新しい関数はどこからでも呼ぶことが可能です。 これは作成された場所から外部の変数へアクセスするでしょうか?それとも実行された場所から?あるいはその両方? +======= +# Which variables are available? + +The function `makeWorker` below makes another function and returns it. That new function can be called from somewhere else. + +Will it have access to the outer variables from its creation place, or the invocation place, or both? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js function makeWorker() { @@ -19,6 +27,7 @@ function makeWorker() { let name = "John"; +<<<<<<< HEAD // 関数を作成 let work = makeWorker(); @@ -27,3 +36,13 @@ work(); // 何が表示されるでしょう? ``` "Pete" or "John" どちらの値が表示されるでしょう? +======= +// create a function +let work = makeWorker(); + +// call it +work(); // what will it show? +``` + +Which value it will show? "Pete" or "John"? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/06-advanced-functions/03-closure/3-counter-independent/solution.md b/1-js/06-advanced-functions/03-closure/3-counter-independent/solution.md index fa46091eb3..25ecbea4cc 100644 --- a/1-js/06-advanced-functions/03-closure/3-counter-independent/solution.md +++ b/1-js/06-advanced-functions/03-closure/3-counter-independent/solution.md @@ -1,5 +1,5 @@ -答え: **0,1.** +The answer: **0,1.** -関数 `counter` と `counter2` は異なる `makeCounter` の呼び出しで作られています。 +Functions `counter` and `counter2` are created by different invocations of `makeCounter`. -そのため、それらは独立した外部のレキシカル環境を持っており、それぞれ独自の `count` を持ちます。 +So they have independent outer Lexical Environments, each one has its own `count`. diff --git a/1-js/06-advanced-functions/03-closure/3-counter-independent/task.md b/1-js/06-advanced-functions/03-closure/3-counter-independent/task.md index b37d1a3b62..e8c17dd31c 100644 --- a/1-js/06-advanced-functions/03-closure/3-counter-independent/task.md +++ b/1-js/06-advanced-functions/03-closure/3-counter-independent/task.md @@ -2,11 +2,11 @@ importance: 5 --- -# カウンタは独立していますか? +# Are counters independent? -ここで2つのカウンタを作ります: 同じ `makeCounter` 関数を使って `counter` と `counter2` を作ります。 +Here we make two counters: `counter` and `counter2` using the same `makeCounter` function. -それらは独立していますか?2つ目のカウンタは何が表示されるでしょうか? `0,1` or `2,3` or その他? +Are they independent? What is the second counter going to show? `0,1` or `2,3` or something else? ```js function makeCounter() { @@ -28,3 +28,4 @@ alert( counter2() ); // ? alert( counter2() ); // ? */!* ``` + diff --git a/1-js/06-advanced-functions/03-closure/5-function-in-if/solution.md b/1-js/06-advanced-functions/03-closure/5-function-in-if/solution.md index 5fe4e8b9ac..e2e7a91b33 100644 --- a/1-js/06-advanced-functions/03-closure/5-function-in-if/solution.md +++ b/1-js/06-advanced-functions/03-closure/5-function-in-if/solution.md @@ -1,3 +1,3 @@ -結果は **エラー** です。 +The result is **an error**. -関数 `sayHi` は `if` の内側で宣言されているので、その中でのみ生きています。外部に `sayHi` はありません。 +The function `sayHi` is declared inside the `if`, so it only lives inside it. There is no `sayHi` outside. \ No newline at end of file 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 86125cb5e6..b28f1b9e89 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,7 +1,11 @@ # if の中の関数 +<<<<<<< HEAD:1-js/06-advanced-functions/03-closure/5-function-in-if/task.md このコードを見てください。最後の行の呼び出しの結果は何でしょうか? +======= +Look at the code. What will be the result of the call at the last line? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/06-advanced-functions/03-closure/5-function-in-if/task.md ```js run let phrase = "Hello"; diff --git a/1-js/06-advanced-functions/03-closure/6-closure-sum/solution.md b/1-js/06-advanced-functions/03-closure/6-closure-sum/solution.md index 560dbe838f..a6679cd209 100644 --- a/1-js/06-advanced-functions/03-closure/6-closure-sum/solution.md +++ b/1-js/06-advanced-functions/03-closure/6-closure-sum/solution.md @@ -1,12 +1,12 @@ -2つ目の括弧が動作するために、1つ目は関数を返さなければなりません。 +For the second parentheses to work, the first ones must return a function. -このようになります: +Like this: ```js run function sum(a) { return function(b) { - return a + b; // 外部のレキシカル環境から "a" を取る + return a + b; // takes "a" from the outer lexical environment }; } @@ -14,3 +14,4 @@ function sum(a) { alert( sum(1)(2) ); // 3 alert( sum(5)(-1) ); // 4 ``` + diff --git a/1-js/06-advanced-functions/03-closure/6-closure-sum/task.md b/1-js/06-advanced-functions/03-closure/6-closure-sum/task.md index a9ba4e4adc..b45758562e 100644 --- a/1-js/06-advanced-functions/03-closure/6-closure-sum/task.md +++ b/1-js/06-advanced-functions/03-closure/6-closure-sum/task.md @@ -2,15 +2,16 @@ importance: 4 --- -# クロージャで合計する +# Sum with closures -`sum(a)(b) = a+b` のように動作する関数 `sum` を書いてください。 +Write function `sum` that works like this: `sum(a)(b) = a+b`. -正確にこの通り2つの括弧で指定します(タイプミスではありません)。 +Yes, exactly this way, using double parentheses (not a mistype). -例: +For instance: ```js sum(1)(2) = 3 sum(5)(-1) = 4 ``` + diff --git a/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md b/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md index 026eebcd53..577d2febdb 100644 --- a/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md +++ b/1-js/06-advanced-functions/03-closure/7-let-scope/solution.md @@ -1,6 +1,12 @@ +<<<<<<< HEAD 結果は: **エラー** です。 実行してみましょう: +======= +The result is: **error**. + +Try running it: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run let x = 1; @@ -15,6 +21,7 @@ function func() { func(); ``` +<<<<<<< HEAD この例では、"存在しない" 変数と "初期化されていない" 変数の変わった違いを見ることができます。 記事 [](info:closure) でご覧になったかもしれませんが、変数は実行がコードブロック(または関数)に入った時点から、"初期化されていない" 状態 で始まります。そして対応する `let` 文まで初期化されません。 @@ -22,19 +29,41 @@ func(); つまり、変数は技術的には存在しますが、`let` 以前では利用できません。 上のコードを説明します。 +======= +In this example we can observe the peculiar difference between a "non-existing" and "unitialized" variable. + +As you may have read in the article [](info:closure), a variable starts in the "uninitialized" state from the moment when the execution enters a code block (or a function). And it stays uninitalized until the corresponding `let` statement. + +In other words, a variable technically exists, but can't be used before `let`. + +The code above demonstrates it. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js function func() { *!* +<<<<<<< HEAD // エンジンは関数の最初の時点でローカル変数 x を知っています。 // が、let までは "初期化されていません" (利用できません) // なのでエラーです */!* console.log(x); // ReferenceError: Cannot access 'vx before initialization +======= + // the local variable x is known to the engine from the beginning of the function, + // but "unitialized" (unusable) until let ("dead zone") + // hence the error +*/!* + + console.log(x); // ReferenceError: Cannot access 'x' before initialization +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 let x = 2; } ``` +<<<<<<< HEAD 変数が一時的に利用できないゾーン(コードブロックの先頭から `let` まで)は "デッドゾーン" と呼ばれることがあります。 +======= +This zone of temporary unusability of a variable (from the beginning of the code block till `let`) is sometimes called the "dead zone". +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/06-advanced-functions/03-closure/7-let-scope/task.md b/1-js/06-advanced-functions/03-closure/7-let-scope/task.md index 01dd15eda4..fa0d7a9693 100644 --- a/1-js/06-advanced-functions/03-closure/7-let-scope/task.md +++ b/1-js/06-advanced-functions/03-closure/7-let-scope/task.md @@ -2,9 +2,15 @@ importance: 4 --- +<<<<<<< HEAD # 変数は参照できますか? このコードの結果はどうなるでしょう? +======= +# Is variable visible? + +What will be the result of this code? +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let x = 1; @@ -18,4 +24,8 @@ function func() { func(); ``` +<<<<<<< HEAD P.S. このタスクには落とし穴があります。 +======= +P.S. There's a pitfall in this task. The solution is not obvious. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/06-advanced-functions/03-closure/8-filter-through-function/solution.md b/1-js/06-advanced-functions/03-closure/8-filter-through-function/solution.md index 5bbc33b025..46c5514a8d 100644 --- a/1-js/06-advanced-functions/03-closure/8-filter-through-function/solution.md +++ b/1-js/06-advanced-functions/03-closure/8-filter-through-function/solution.md @@ -14,7 +14,7 @@ alert( arr.filter(inBetween(3, 6)) ); // 3,4,5,6 # Filter inArray -```js run +```js run demo function inArray(arr) { return function(x) { return arr.includes(x); diff --git a/1-js/06-advanced-functions/03-closure/8-filter-through-function/task.md b/1-js/06-advanced-functions/03-closure/8-filter-through-function/task.md index 5efe9e2353..d1c39f949c 100644 --- a/1-js/06-advanced-functions/03-closure/8-filter-through-function/task.md +++ b/1-js/06-advanced-functions/03-closure/8-filter-through-function/task.md @@ -2,21 +2,21 @@ importance: 5 --- -# 関数を通してフィルタする +# Filter through function -私たちは、配列に対する組み込みのメソッド `arr.filter(f)` を持っています。それはすべての要素を関数 `f` を通してフィルタします。もし `true` を帰す場合、その要素は結果の配列に入れられます。 +We have a built-in method `arr.filter(f)` for arrays. It filters all elements through the function `f`. If it returns `true`, then that element is returned in the resulting array. -"すぐに使える" フィルタを作りましょう: +Make a set of "ready to use" filters: -- `inBetween(a, b)` -- `a` と `b` の間、またはそれらと等しい(包括的) -- `inArray([...])` -- 与えられた配列に存在する +- `inBetween(a, b)` -- between `a` and `b` or equal to them (inclusively). +- `inArray([...])` -- in the given array. -使用方法はこのようになります: +The usage must be like this: -- `arr.filter(inBetween(3,6))` -- 3 から 6 までの値だけを選び出します -- `arr.filter(inArray([1,2,3]))` -- `[1,2,3]` のメンバの1つにマッチする要素だけを選び出します +- `arr.filter(inBetween(3,6))` -- selects only values between 3 and 6. +- `arr.filter(inArray([1,2,3]))` -- selects only elements matching with one of the members of `[1,2,3]`. -例: +For instance: ```js /* .. your code for inBetween and inArray */ @@ -26,3 +26,4 @@ alert( arr.filter(inBetween(3, 6)) ); // 3,4,5,6 alert( arr.filter(inArray([1, 2, 10])) ); // 1,2 ``` + diff --git a/1-js/06-advanced-functions/03-closure/article.md b/1-js/06-advanced-functions/03-closure/article.md index 33039d56b3..6aa4992ec1 100644 --- a/1-js/06-advanced-functions/03-closure/article.md +++ b/1-js/06-advanced-functions/03-closure/article.md @@ -1,4 +1,5 @@ +<<<<<<< HEAD # クロージャ JavaScript は非常に関数指向な言語です。それは我々に多くの自由を与えます。ある時点で作成した関数は、別の変数にコピーしたり別の関数に引数として渡し、後でまったく別の場所から呼ぶことができます。 @@ -109,24 +110,50 @@ JavaScript では、すべての実行中の関数やコードブロック、ス 下のコードはレキシカル環境は最初から空ではないことを示しています。関数宣言なので `say` を持っています。その後 `let` で宣言された `phrase` を取得します: ![lexical environment](lexical-environment-global-3.svg) +======= +# Variable scope +JavaScript is a very function-oriented language. It gives us a lot of freedom. A function can be created dynamically, passed as an argument to another function and called from a totally different place of code later. +We already know that a function can access variables outside of it. + +Now let's expand our knowledge to include more complex scenarios. + +```smart header="We'll talk about `let/const` variables here" +In JavaScript, there are 3 ways to declare a variable: `let`, `const` (the modern ones), and `var` (the remnant of the past). + +- In this article we'll use `let` variables in examples. +- Variables, declared with `const`, behave the same, so this article is about `const` too. +- The old `var` has some notable differences, they will be covered in the article . +``` + +## Code blocks +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 + +If a variable is declared inside a code block `{...}`, it's only visible inside that block. + +<<<<<<< HEAD ### 内外のレキシカル環境 呼び出しの中で、`say()` は外部変数を使います。何が起きているか見てみましょう。 まず、関数を実行するとき、新しい関数のレキシカル環境が自動的に作られます。それはすべての関数での一般的なルールです。そのレキシカル環境はローカル変数や呼び出しパラメータを格納するために使われます。 +======= +For example: - これは、実行が `say("John")` の内部にあるときで、矢印のついた行にあるレキシカル環境の図です。: @@ -158,21 +185,54 @@ say("John"); // Hello, John これは、説明されたメカニズムによるものです。 古い変数の値はどこにも保存されません。 関数がそれらを必要とするとき、自身または外部のレキシカル環境から現在の値を取ります。 従って、最初の質問の答えは `Pete` です: +======= + +We can use this to isolate a piece of code that does its own task, with variables that only belong to it: ```js run -let name = "John"; +{ + // show message + let message = "Hello"; + alert(message); +} -function sayHi() { - alert("Hi, " + name); +{ + // show another message + let message = "Goodbye"; + alert(message); } +``` -name = "Pete"; // (*) +````smart header="There'd be an error without blocks" +Please note, without separate blocks there would be an error, if we use `let` with the existing variable name: +```js run +// show message +let message = "Hello"; +alert(message); + +// show another message *!* -sayHi(); // Pete +let message = "Goodbye"; // Error: variable already declared */!* +alert(message); +``` +```` + +For `if`, `for`, `while` and so on, variables declared in `{...}` are also only visible inside: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 + +```js run +if (true) { + let phrase = "Hello!"; + + alert(phrase); // Hello! +} + +alert(phrase); // Error, no such variable! ``` +<<<<<<< HEAD 上のコードの実行フローは次の通りです: 1. グローバルレキシカル環境は `name` を持っています: `"John"`. @@ -187,16 +247,38 @@ sayHi(); // Pete ```smart header="レキシカル環境は仕様上のオブジェクトです" "レキシカル環境" は仕様上のオブジェクトです。コードからそのオブジェクトを取得したり、直接操作することはできません。JavaScriptエンジンはメモリを節約するために使っていない変数を破棄したり、他の内部トリックを行うと言った最適化をする場合がありますが、見える振る舞いは上で説明した通りである必要があります。 +======= +Here, after `if` finishes, the `alert` below won't see the `phrase`, hence the error. + +That's great, as it allows us to create block-local variables, specific to an `if` branch. + +The similar thing holds true for `for` and `while` loops: + +```js run +for (let i = 0; i < 3; i++) { + // the variable i is only visible inside this for + alert(i); // 0, then 1, then 2 +} + +alert(i); // Error, no such variable +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` +Visually, `let i` is outside of `{...}`. But the `for` construct is special here: the variable, declared inside it, is considered a part of the block. ## ネストされた関数 関数は、別の関数の内部で作成されたとき、"ネストされた" と呼ばれます。 +<<<<<<< HEAD 技術的には、それは簡単に可能です。 私たちは、コードを整理するのに利用します: +======= +It is easily possible to do this with JavaScript. + +We can use it to organize our code, like this: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js function sayHiBye(firstName, lastName) { @@ -212,6 +294,7 @@ function sayHiBye(firstName, lastName) { } ``` +<<<<<<< HEAD ここでの *ネストされた* 関数 `getFullName()` は利便性のために作られています。それは外部変数にアクセスすることができるので、フルネームを返すことができます。 さらに興味深い点は、新しいオブジェクトのプロパティ(外部関数がメソッドを持つオブジェクトを作成する場合)またはその自身の結果として、ネストされた関数を返すことができることです: それは他の場所で使うことができます。どこにいても、同じ外部変数には依然としてアクセスできます。 @@ -233,13 +316,24 @@ user.sayHi(); // このメソッドは外部の "name" へアクセスできま ``` 関数を返す例です: +======= +Here the *nested* function `getFullName()` is made for convenience. It can access the outer variables and so can return the full name. Nested functions are quite common in JavaScript. + +What's much more interesting, a nested function can be returned: either as a property of a new object or as a result by itself. It can then be used somewhere else. No matter where, it still has access to the same outer variables. + +Below, `makeCounter` creates the "counter" function that returns the next number on each invocation: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run function makeCounter() { let count = 0; return function() { +<<<<<<< HEAD return count++; // 外の counter へアクセスできます +======= + return count++; +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 }; } @@ -250,6 +344,7 @@ alert( counter() ); // 1 alert( counter() ); // 2 ``` +<<<<<<< HEAD `makeCounter` の例を続けましょう。それは各呼び出しで次の数値を返す "counter" 関数を作ります。シンプルであるにも関わらず、そのコードからわずかに変更されたバリアントは実践で使われています。例えば、[擬似乱数生成器(pseudorandom number generator)](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) などです。なので、この例はあまり不自然ではありません。 counter は内部でどのように動作しているのでしょう? @@ -290,10 +385,20 @@ function makeCounter() { let counter1 = makeCounter(); let counter2 = makeCounter(); +======= +Despite being simple, slightly modified variants of that code have practical uses, for instance, as a [random number generator](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) to generate random values for automated tests. -alert( counter1() ); // 0 -alert( counter1() ); // 1 +How does this work? If we create multiple counters, will they be independent? What's going on with the variables here? +Undestanding such things is great for the overall knowledge of JavaScript and beneficial for more complex scenarios. So let's go a bit in-depth. + +## Lexical Environment +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 + +```warn header="Here be dragons!" +The in-depth technical explanation lies ahead. + +<<<<<<< HEAD alert( counter2() ); // 0 (独立)) ``` @@ -390,33 +495,152 @@ alert( counter2() ); // 0 (独立)) 上の例では関数に焦点を当てていました。しかしレキシカル環境はコードブロック `{...}` にも存在します。 コードブロックが実行され、ブロック内のローカル変数を含むときそれらが作られます。ここではいくつかの例を示します。 +======= +As far as I'd like to avoid low-level language details, any understanding without them would be lacking and incomplete, so get ready. +``` -## If +For clarity, the explanation is split into multiple steps. -下の例では、実行が `if` ブロックに来たとき、新しい "ifだけの" レキシカル環境が作られます。: +### Step 1. Variables + +In JavaScript, every running function, code block `{...}`, and the script as a whole have an internal (hidden) associated object known as the *Lexical Environment*. + +The Lexical Environment object consists of two parts: + +1. *Environment Record* -- an object that stores all local variables as its properties (and some other information like the value of `this`). +2. A reference to the *outer lexical environment*, the one associated with the outer code. + +**A "variable" is just a property of the special internal object, `Environment Record`. "To get or change a variable" means "to get or change a property of that object".** + +In this simple code without functions, there is only one Lexical Environment: + +![lexical environment](lexical-environment-global.svg) + +This is the so-called *global* Lexical Environment, associated with the whole script. + +On the picture above, the rectangle means Environment Record (variable store) and the arrow means the outer reference. The global Lexical Environment has no outer reference, that's why the arrow points to `null`. + +As the code starts executing and goes on, the Lexical Environment changes. + +Here's a little bit longer code: + +![lexical environment](closure-variable-phrase.svg) + +Rectangles on the right-hand side demonstrate how the global Lexical Environment changes during the execution: + +1. When the script starts, the Lexical Environment is pre-populated with all declared variables. + - Initially, they are in the "Uninitialized" state. That's a special internal state, it means that the engine knows about the variable, but it cannot be referenced until it has been declared with `let`. It's almost the same as if the variable didn't exist. +2. Then `let phrase` definition appears. There's no assignment yet, so its value is `undefined`. We can use the variable since this moment. +3. `phrase` is assigned a value. +4. `phrase` changes the value. + +Everything looks simple for now, right? + +- A variable is a property of a special internal object, associated with the currently executing block/function/script. +- Working with variables is actually working with the properties of that object. + +```smart header="Lexical Environment is a specification object" +"Lexical Environment" is a specification object: it only exists "theoretically" in the [language specification](https://tc39.es/ecma262/#sec-lexical-environments) to describe how things work. We can't get this object in our code and manipulate it directly. + +JavaScript engines also may optimize it, discard variables that are unused to save memory and perform other internal tricks, as long as the visible behavior remains as described. +``` + +### Step 2. Function Declarations + +A function is also a value, like a variable. + +**The difference is that a Function Declaration is instantly fully initialized.** + +When a Lexical Environment is created, a Function Declaration immediately becomes a ready-to-use function (unlike `let`, that is unusable till the declaration). + +That's why we can use a function, declared as Function Declaration, even before the declaration itself. + +For example, here's the initial state of the global Lexical Environment when we add a function: + +![](closure-function-declaration.svg) + +Naturally, this behavior only applies to Function Declarations, not Function Expressions where we assign a function to a variable, such as `let say = function(name)...`. + +### Step 3. Inner and outer Lexical Environment + +When a function runs, at the beginning of the call, a new Lexical Environment is created automatically to store local variables and parameters of the call. + +For instance, for `say("John")`, it looks like this (the execution is at the line, labelled with an arrow): + +![](lexical-environment-simple.svg) + +During the function call we have two Lexical Environments: the inner one (for the function call) and the outer one (global): + +- The inner Lexical Environment corresponds to the current execution of `say`. It has a single property: `name`, the function argument. We called `say("John")`, so the value of the `name` is `"John"`. +- The outer Lexical Environment is the global Lexical Environment. It has the `phrase` variable and the function itself. + +The inner Lexical Environment has a reference to the `outer` one. + +**When the code wants to access a variable -- the inner Lexical Environment is searched first, then the outer one, then the more outer one and so on until the global one.** + +If a variable is not found anywhere, that's an error in strict mode (without `use strict`, an assignment to a non-existing variable creates a new global variable, for compatibility with old code). + +In this example the search proceeds as follows: + +- For the `name` variable, the `alert` inside `say` finds it immediately in the inner Lexical Environment. +- When it wants to access `phrase`, then there is no `phrase` locally, so it follows the reference to the outer Lexical Environment and finds it there. + +![lexical environment lookup](lexical-environment-simple-lookup.svg) +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 + + +<<<<<<< HEAD +下の例では、実行が `if` ブロックに来たとき、新しい "ifだけの" レキシカル環境が作られます。: +======= +### Step 4. Returning a function +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 + +Let's return to the `makeCounter` example. + +```js +function makeCounter() { + let count = 0; - alert(`${phrase}, ${user}`); // Hello, John + return function() { + return count++; + }; } +<<<<<<< HEAD alert(user); // Error, このような変数は見えません! +======= +let counter = makeCounter(); +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ``` ---> +<<<<<<< HEAD ![](lexenv-if.svg) 新しいレキシカル環境はその外部への参照をもつため `phrase` を見つけることができます。しかし、`if` の中で宣言されたすべての変数と関数式はレキシカル環境の中にあり、外部からは見えません。 例えば、`if` が終わった後にある `alert` は、 `user`が見えないため、エラーになります。 +======= +At the beginning of each `makeCounter()` call, a new Lexical Environment object is created, to store variables for this `makeCounter` run. -## For, while +So we have two nested Lexical Environments, just like in the example above: +![](closure-makecounter.svg) +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 + +What's different is that, during the execution of `makeCounter()`, a tiny nested function is created of only one line: `return count++`. We don't run it yet, only create. + +<<<<<<< HEAD ループでは、すべての実行が別々のレキシカル環境を持っています。もし変数が `for` で宣言されると、そのレキシカル環境のローカル変数になります: ```js run @@ -445,12 +669,36 @@ alert(i); // Error, このような変数はありません ```js run { // 外には見せるべきでないローカル変数で必要な処理をする +======= +All functions remember the Lexical Environment in which they were made. Technically, there's no magic here: all functions have the hidden property named `[[Environment]]`, that keeps the reference to the Lexical Environment where the function was created: - let message = "Hello"; +![](closure-makecounter-environment.svg) - alert(message); // Hello -} +So, `counter.[[Environment]]` has the reference to `{count: 0}` Lexical Environment. That's how the function remembers where it was created, no matter where it's called. The `[[Environment]]` reference is set once and forever at function creation time. + +Later, when `counter()` is called, a new Lexical Environment is created for the call, and its outer Lexical Environment reference is taken from `counter.[[Environment]]`: + +![](closure-makecounter-nested-call.svg) + +Now when the code inside `counter()` looks for `count` variable, it first searches its own Lexical Environment (empty, as there are no local variables there), then the Lexical Environment of the outer `makeCounter()` call, where finds it and changes. + +**A variable is updated in the Lexical Environment where it lives.** + +Here's the state after the execution: + +![](closure-makecounter-nested-call-2.svg) + +If we call `counter()` multiple times, the `count` variable will be increased to `2`, `3` and so on, at the same place. + +```smart header="Closure" +There is a general programming term "closure", that developers generally should know. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 + +A [closure](https://en.wikipedia.org/wiki/Closure_(computer_programming)) is a function that remembers its outer variables and can access them. In some languages, that's not possible, or a function should be written in a special way to make it happen. But as explained above, in JavaScript, all functions are naturally closures (there is only one exception, to be covered in ). +That is: they automatically remember where they were created using a hidden `[[Environment]]` property, and then their code can access outer variables. + +<<<<<<< HEAD alert(message); // Error: message は未定義 ``` @@ -461,17 +709,35 @@ alert(message); // Error: message は未定義 古いスクリプトでは、いわゆる "即時実行関数(immediately-invoked function expressions)" (IIFEと略します) がこの目的に使われます。 このようなものです。: +======= +When on an interview, a frontend developer gets a question about "what's a closure?", a valid answer would be a definition of the closure and an explanation that all functions in JavaScript are closures, and maybe a few more words about technical details: the `[[Environment]]` property and how Lexical Environments work. +``` -```js run -(function() { +## Garbage collection - let message = "Hello"; +Usually, a Lexical Environment is removed from memory with all the variables after the function call finishes. That's because there are no references to it. As any JavaScript object, it's only kept in memory while it's reachable. - alert(message); // Hello +...But if there's a nested function that is still reachable after the end of a function, then it has `[[Environment]]` property that references the lexical environment. + +In that case the Lexical Environment is still reachable even after the completion of the function, so it stays alive. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 + +For example: -})(); +```js +function f() { + let value = 123; + + return function() { + alert(value); + } +} + +let g = f(); // g.[[Environment]] stores a reference to the Lexical Environment +// of the corresponding f() call ``` +<<<<<<< HEAD 関数式が作られすぐに呼ばれます。従って、コードはすぐに実行され自身のプライベート変数を持ちます。 関数式は括弧 `(function {...})` で囲まれています。なぜなら、JavaScriptはメインコードフローの中で `"function"` を見つけると、関数宣言の開始と理解します。しかし、関数宣言は名前が必須なので、エラーになります。 @@ -589,23 +855,68 @@ JavaScriptには、関数式を意味する他の方法があります: ``` ### 現実の最適化(Real-life optimizations) +======= +Please note that if `f()` is called many times, and resulting functions are saved, then all corresponding Lexical Environment objects will also be retained in memory. All 3 of them in the code below: + +```js +function f() { + let value = Math.random(); + + return function() { alert(value); }; +} + +// 3 functions in array, every one of them links to Lexical Environment +// from the corresponding f() run +let arr = [f(), f(), f()]; +``` + +A Lexical Environment object dies when it becomes unreachable (just like any other object). In other words, it exists only while there's at least one nested function referencing it. + +In the code below, after the nested function is removed, its enclosing Lexical Environment (and hence the `value`) is cleaned from memory: + +```js +function f() { + let value = 123; + + return function() { + alert(value); + } +} + +let g = f(); // while g function exists, the value stays in memory + +g = null; // ...and now the memory is cleaned up +``` + +### Real-life optimizations +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 これまで見てきたように、理論的には関数が生きている間、すべての外部変数も保持されます。 +<<<<<<< HEAD しかし、実際にはJavaScriptエンジンはそれを最適化しようとします。変数の使用状況を分析し、外部変数が使用されていないことがわかりやすい場合は削除されます。 +======= +But in practice, JavaScript engines try to optimize that. They analyze variable usage and if it's obvious from the code that an outer variable is not used -- it is removed. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 **V8(Chrome, Opera)の重要な副作用はこのような変数はデバッグでは利用できなくなることです。** +<<<<<<< HEAD Chromeで Developer Tools を開いて下の例を実行してみてください。 一時停止したとき、console で `alert(value)` をタイプしてください。 +======= +Try running the example below in Chrome with the Developer Tools open. + +When it pauses, in the console type `alert(value)`. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run function f() { let value = Math.random(); function g() { - debugger; // in console: type alert( value ); No such variable! + debugger; // in console: type alert(value); No such variable! } return g; @@ -626,7 +937,7 @@ function f() { let value = "the closest value"; function g() { - debugger; // in console: type alert( value ); Surprise! + debugger; // in console: type alert(value); Surprise! } return g; @@ -636,9 +947,15 @@ let g = f(); g(); ``` +<<<<<<< HEAD ```warn header="See ya!" V8 のこの機能は知っておくと良いです。もしも Chrome/Opera でデバッグしている場合、遅かれ早かれこれに遭遇するでしょう。 これはデバッガのバグではなく、V8の特別な機能です。時々変わるかもしれません。 このページの例を実行することで、いつでもチェックすることができます。 ``` +======= +This feature of V8 is good to know. If you are debugging with Chrome/Opera, sooner or later you will meet it. + +That is not a bug in the debugger, but rather a special feature of V8. Perhaps it will be changed sometime. You always can check for it by running the examples on this page. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/1-js/06-advanced-functions/03-closure/closure-function-declaration.svg b/1-js/06-advanced-functions/03-closure/closure-function-declaration.svg new file mode 100644 index 0000000000..97f76e5691 --- /dev/null +++ b/1-js/06-advanced-functions/03-closure/closure-function-declaration.svg @@ -0,0 +1 @@ +outernullexecution startphrase: <uninitialized> say: function... \ No newline at end of file diff --git a/1-js/06-advanced-functions/03-closure/closure-makecounter-environment.svg b/1-js/06-advanced-functions/03-closure/closure-makecounter-environment.svg new file mode 100644 index 0000000000..b9060bc8a2 --- /dev/null +++ b/1-js/06-advanced-functions/03-closure/closure-makecounter-environment.svg @@ -0,0 +1 @@ +null[[Environment]]makeCounter: function counter: undefinedcount: 0outerouter \ No newline at end of file diff --git a/1-js/06-advanced-functions/03-closure/closure-makecounter-nested-call-2.svg b/1-js/06-advanced-functions/03-closure/closure-makecounter-nested-call-2.svg new file mode 100644 index 0000000000..3e4206ca6d --- /dev/null +++ b/1-js/06-advanced-functions/03-closure/closure-makecounter-nested-call-2.svg @@ -0,0 +1 @@ +count: 1<empty>nullouterouteroutermakeCounter: function counter: functionmodified here \ No newline at end of file diff --git a/1-js/06-advanced-functions/03-closure/closure-makecounter-nested-call.svg b/1-js/06-advanced-functions/03-closure/closure-makecounter-nested-call.svg new file mode 100644 index 0000000000..e1bb8cc8f9 --- /dev/null +++ b/1-js/06-advanced-functions/03-closure/closure-makecounter-nested-call.svg @@ -0,0 +1 @@ +count: 0<empty>nullouterouteroutermakeCounter: function counter: function \ No newline at end of file diff --git a/1-js/06-advanced-functions/03-closure/closure-makecounter.svg b/1-js/06-advanced-functions/03-closure/closure-makecounter.svg new file mode 100644 index 0000000000..2a1c4a7296 --- /dev/null +++ b/1-js/06-advanced-functions/03-closure/closure-makecounter.svg @@ -0,0 +1 @@ +makeCounter: function counter: undefinedcount: 0nullglobal LexicalEnvironmentLexicalEnvironment of makeCounter() callouterouter \ No newline at end of file diff --git a/1-js/06-advanced-functions/03-closure/closure-variable-phrase.svg b/1-js/06-advanced-functions/03-closure/closure-variable-phrase.svg new file mode 100644 index 0000000000..741c054487 --- /dev/null +++ b/1-js/06-advanced-functions/03-closure/closure-variable-phrase.svg @@ -0,0 +1 @@ +phrase: "Bye"phrase: "Hello"phrase: undefinedphrase: <uninitialized>outernullexecution start \ No newline at end of file diff --git a/1-js/06-advanced-functions/03-closure/variable-scope-lookup.svg b/1-js/06-advanced-functions/03-closure/variable-scope-lookup.svg new file mode 100644 index 0000000000..674437196a --- /dev/null +++ b/1-js/06-advanced-functions/03-closure/variable-scope-lookup.svg @@ -0,0 +1 @@ +functionUser(name){this.sayHi=function(){alert(name);};}letuser=newUser("John");user.sayHi(); \ No newline at end of file diff --git a/1-js/06-advanced-functions/04-var/article.md b/1-js/06-advanced-functions/04-var/article.md index 88ca984a03..2711c7cdb2 100644 --- a/1-js/06-advanced-functions/04-var/article.md +++ b/1-js/06-advanced-functions/04-var/article.md @@ -1,12 +1,23 @@ # 古い "var" +<<<<<<< HEAD [変数](info:variables) の最初の章では、変数を宣言する3つの方法について述べました: +======= +```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 a new code. +``` + +In the very first chapter about [variables](info:variables), we mentioned three ways of variable declaration: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 1. `let` 2. `const` 3. `var` +<<<<<<< HEAD `let` と `const` は、レキシカル環境に関してまったく同じように振る舞います。 しかし、`var` はそれらとは大きく異なり、そしてそれは非常に古くからのものです。一般的には、 `var` は現在のスクリプトでは使われませんが、古いスクリプトにはまだ潜んでいます。 @@ -23,21 +34,39 @@ function sayHi() { alert(phrase); // Hello } +======= +The `var` declaration is similar to `let`. Most of the time we can replace `let` by `var` or vice-versa and expect things to work: -sayHi(); +```js run +var message = "Hi"; +alert(message); // Hi +``` +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 +But internally `var` is a very different beast, that originates from very old times. It's generally not used in modern scripts, but still lurks in the old ones. + +<<<<<<< HEAD alert(phrase); // Error, phrase は未定義です ``` ...しかし、ここには違いがあります。 +======= +If you don't plan on meeting such scripts you may even skip this chapter or postpone it. + +On the other hand, it's important to understand differences when migrating old scripts from `var` to `let`, to avoid odd errors. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ## "var" はブロックスコープを持ちません +<<<<<<< HEAD `var` 変数はのスコープは "関数全体" か "グローバル" のいずれかであり、ブロックを通って見ることができます。 +======= +Variables, declared with `var`, are either function-wide or global. They are visible through blocks. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 例: -```js +```js run if (true) { var test = true; // "let" の代わりに "var" を使う } @@ -47,7 +76,23 @@ alert(test); // true, if の後も変数は生きています */!* ``` +<<<<<<< HEAD もし2行目で `let test` を使った場合、`alert` では見えません。しかし `var` はコードブロックを無視するので、グローバルの `test` を取得します。 +======= +As `var` ignores code blocks, we've got a global variable `test`. + +If we used `let test` instead of `var test`, then the variable would only be visible inside `if`: + +```js run +if (true) { + let test = true; // use "let" +} + +*!* +alert(test); // Error: test is not defined +*/!* +``` +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ループでも同様です: `var` はブロック、またはループのローカルにはなれません: @@ -63,7 +108,7 @@ alert(i); // 10, "i" ループ後も見え、それはグローバル変数で コードブロックが関数の内側にある場合、`var` は関数レベルの変数になります: -```js +```js run function sayHi() { if (true) { var phrase = "Hello"; @@ -73,12 +118,41 @@ function sayHi() { } sayHi(); +<<<<<<< HEAD alert(phrase); // Error: phrase は未定義 ``` 上の通り、`var` は `if`, `for` もしくは他のコードブロックを貫通します。それは、JavaScriptは長い間ブロックがレキシカル環境を持っていなかったためです。そして、 `var` はそれを想起させます。 ## "var" は関数の開始で処理されます +======= +alert(phrase); // Error: phrase is not defined (Check the Developer Console) +``` + +As we can see, `var` pierces through `if`, `for` or other code blocks. That's because a long time ago in JavaScript blocks had no Lexical Environments. And `var` is a remnant of that. + +## "var" tolerates redeclarations + +If we declare the same variable with `let` twice in the same scope, that's an error: + +```js run +let user; +let user; // SyntaxError: 'user' has already been declared +``` + +With `var`, we can redeclare a variable any number of times. If we use `var` with an already-declared variable, it's just ignored: + +```js run +var user = "Pete"; + +var user = "John"; // this "var" does nothing (already declared) +// ...it doesn't trigger an error + +alert(user); // John +``` + +## "var" variables can be declared below their use +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 `var` 宣言は、関数の開始時(またはグローバルのスクリプト開始時)に処理されます。 @@ -86,7 +160,7 @@ alert(phrase); // Error: phrase は未定義 従って、このようなコード: -```js +```js run function sayHi() { phrase = "Hello"; @@ -96,11 +170,12 @@ function sayHi() { var phrase; */!* } +sayHi(); ``` ...は技術的にはこれと同じです(`var phrase` を上に移動させています): -```js +```js run function sayHi() { *!* var phrase; @@ -110,11 +185,12 @@ function sayHi() { alert(phrase); } +sayHi(); ``` ...もしくはこれです(コードブロックが無視されることを忘れないでください): -```js +```js run function sayHi() { phrase = "Hello"; // (*) @@ -126,6 +202,7 @@ function sayHi() { alert(phrase); } +sayHi(); ``` また、すべての `var` が関数の先頭に "持ち上げられ" ているので、人々はそのような振る舞いを "巻き上げ" とも呼びます。 @@ -134,7 +211,11 @@ function sayHi() { **宣言は巻き上げられますが、代入はされません。** +<<<<<<< HEAD 次のコードはその例です: +======= +That's best demonstrated with an example: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js run function sayHi() { @@ -175,6 +256,7 @@ sayHi(); 上の両方の例では、 `alert` はエラーなく動作します。なぜなら変数 `phrase` が存在するからです。しかし、その値は代入されていないので、 `undefied` を表示します。 +<<<<<<< HEAD ## サマリ `var` の大きな違いが2つあります: @@ -185,3 +267,83 @@ sayHi(); グローバルオブジェクトに関連する小さな違いがもう少しあります。それは次のチャプターで説明します。 これらの違いは、実際にはほとんどの場合で悪いことです。 まず、ブロックローカル変数を作成することができません。また、巻き上げはエラーを引き起こす余地を増やします。 したがって、新しいスクリプトでは、 `var` はほとんど使用されません。 +======= +### IIFE + +As in the past there was only `var`, and it has no block-level visibility, programmers invented a way to emulate it. What they did was called "immediately-invoked function expressions" (abbreviated as IIFE). + +That's not something we should use nowadays, but you can find them in old scripts. + +An IIFE looks like this: + +```js run +(function() { + + let message = "Hello"; + + alert(message); // Hello + +})(); +``` + +Here a Function Expression is created and immediately called. So the code executes right away and has its own private variables. + +The Function Expression is wrapped with parenthesis `(function {...})`, because when JavaScript meets `"function"` in the main code flow, it understands it as the start of a Function Declaration. But a Function Declaration must have a name, so this kind of code will give an error: + +```js run +// Try to declare and immediately call a function +function() { // <-- Error: Function statements require a function name + + let message = "Hello"; + + alert(message); // Hello + +}(); +``` + +Even if we say: "okay, let's add a name", that won't work, as JavaScript does not allow Function Declarations to be called immediately: + +```js run +// syntax error because of parentheses below +function go() { + +}(); // <-- can't call Function Declaration immediately +``` + +So, the parentheses around the function is a trick to show JavaScript that the function is created in the context of another expression, and hence it's a Function Expression: it needs no name and can be called immediately. + +There exist other ways besides parentheses to tell JavaScript that we mean a Function Expression: + +```js run +// Ways to create IIFE + +(function() { + alert("Parentheses around the function"); +}*!*)*/!*(); + +(function() { + alert("Parentheses around the whole thing"); +}()*!*)*/!*; + +*!*!*/!*function() { + alert("Bitwise NOT operator starts the expression"); +}(); + +*!*+*/!*function() { + alert("Unary plus starts the expression"); +}(); +``` + +In all the above cases we declare a Function Expression and run it immediately. Let's note again: nowadays there's no reason to write such code. + +## Summary + +There are two main differences of `var` compared to `let/const`: + +1. `var` variables have no block scope, they are visible minimum at the function level. +2. `var` declarations are processed at function start (script start for globals). + +There's one more very minor difference related to the global object, that we'll cover in the next chapter. + +These differences make `var` worse than `let` most of the time. Block-level variables is such a great thing. That's why `let` was introduced in the standard long ago, and is now a major way (along with `const`) to declare a variable. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 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 8a0e47739a..2758f53893 100644 --- a/1-js/06-advanced-functions/05-global-object/article.md +++ b/1-js/06-advanced-functions/05-global-object/article.md @@ -1,4 +1,5 @@ +<<<<<<< HEAD # グローバルオブジェクト @@ -24,15 +25,19 @@ JavaScript が作られたとき、すべてのグローバル変数と関数を 他の組み込みに対しても同様です。E.g. `Array` の代わりに、`window.Array` と書くことができます。 2. グローバルな関数宣言と `var` 変数へのアクセスを提供します。私たちはそのプロパティを使って、それらの読み書きをすることが出来ます。例えば: +======= +# Global object - - ```js untrusted run no-strict refresh - var phrase = "Hello"; +The global object provides variables and functions that are available anywhere. By default, those that are built into the language or the environment. - function sayHi() { - alert(phrase); - } +In a browser it is named `window`, for Node.js it is `global`, for other environments it may have another name. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 + +Recently, `globalThis` was added to the language, as a standardized name for a global object, that should be supported across all environments. In some browsers, namely non-Chromium Edge, `globalThis` is not yet supported, but can be easily polyfilled. +We'll use `window` here, assuming that our environment is a browser. If your script may run in other environments, it's better to use `globalThis` instead. + +<<<<<<< HEAD // windows から読める alert( window.phrase ); // Hello (グローバル var) alert( window.sayHi ); // function (グローバル関数宣言) @@ -114,8 +119,35 @@ Node.JSのようなサーバサイド環境では、`global` オブジェクト ``` これは `window` を使っていませんが、(理論的には)信頼性が低いです。なぜなら、 `typeof` はローカルの XMLHttpRequest を使う可能性があるためです。 +======= +All properties of the global object can be accessed directly: + +```js run +alert("Hello"); +// is the same as +window.alert("Hello"); +``` + +In a browser, global functions and variables declared with `var` (not `let/const`!) become the property of the global object: + +```js run untrusted refresh +var gVar = 5; + +alert(window.gVar); // 5 (became a property of the global object) +``` + +Please don't rely on that! This behavior exists for compatibility reasons. Modern scripts use [JavaScript modules](info:modules) where such thing doesn't happen. + +If we used `let` instead, such thing wouldn't happen: + +```js run untrusted refresh +let gLet = 5; +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 +alert(window.gLet); // undefined (doesn't become a property of the global object) +``` +<<<<<<< HEAD 3. 正当な window から変数を取得する場合です。恐らくこれが最も有効なユースケースです。 ブラウザは複数のウィンドウやタブを開いている場合があります。また ` ``` -上のコードは、以下を除く操作に対してエラーを表示します。: - -- 内部のウィンドウ `iframe.contentWindow` への参照を取得する -- その `location` を変更する - -```smart header="`iframe.onload` vs `iframe.contentWindow.onload`" -`iframe.onload` イベントは実際には `iframe.contentWindow.onload` と同じです。これは埋め込みウィンドウがすべてのリソース含め完全に読み込まれた時にトリガーされます。 +The code above shows errors for any operations except: -...しかし、`iframe.onload` は常に利用可能な一方、`iframe.contentWindow.onload` は同一オリジンである必要があります。 -``` +- Getting the reference to the inner window `iframe.contentWindow` - that's allowed. +- Writing to `location`. -そして、これは同一オリジンの例です。埋め込みウィンドウでなんでもできます。: +Contrary to that, if the ` ``` -### iframe がロードされるまで待ってください +```smart header="`iframe.onload` vs `iframe.contentWindow.onload`" +The `iframe.onload` event (on the ` @@ -127,18 +135,20 @@ iframe が作成されると、すぐにドキュメントを持ちます。し iframe.onload = function() { let newDoc = iframe.contentDocument; *!* - // ロードされたドキュメントは初期のものとは同じではありません! + // the loaded document is not the same as initial! alert(oldDoc == newDoc); // false */!* }; ``` -これは実際に、開発者の間でよく知られた落とし穴です。それは *間違ったドキュメント* なので、すぐにドキュメントを使った処理をするべきではありません。もしそこに任意のイベントハンドラを設定しても無視されます。 +We shouldn't work with the document of a not-yet-loaded iframe, because that's the *wrong document*. If we set any event handlers on it, they will be ignored. + +How to detect the moment when the document is there? -...しかし、`onload` イベントはすべてのリソースを含む iframe 全体がロードされたときにトリガーされます。仮により早く、埋め込みドキュメントの `DOMContentLoaded` でなにかしたい場合どうすればよいでしょうか? +The right document is definitely at place when `iframe.onload` triggers. But it only triggers when the whole iframe with all resources is loaded. -iframe が別のオリジンから来ている場合は不可能です。しかし、同一オリジンの場合は、次のように新しいドキュメントが現れる瞬間を捉えて、必要なハンドラの設定を試みることができます。: +We can try to catch the moment earlier using checks in `setInterval`: ```html run @@ -146,30 +156,26 @@ iframe が別のオリジンから来ている場合は不可能です。しか ``` -より良い方法を知っていたらコメントで教えてください。 - -## window.frames +## Collection: window.frames -` @@ -180,21 +186,21 @@ iframe が別のオリジンから来ている場合は不可能です。しか ``` -iframe は内側に別の iframe を持つ場合があります。対応する `window` オブジェクトを階層を形成します。 +An iframe may have other iframes inside. The corresponding `window` objects form a hierarchy. -ナビゲーションリンクは次のようになります: +Navigation links are: -- `window.frames` -- "子" のウィンドウのコレクション(ネストされたフレーム用) -- `window.parent` -- "親" (外部の)ウィンドウへの参照 -- `window.top` -- 一番上のウィンドウへの参照 +- `window.frames` -- the collection of "children" windows (for nested frames). +- `window.parent` -- the reference to the "parent" (outer) window. +- `window.top` -- the reference to the topmost parent window. -例: +For instance: ```js run window.frames[0].parent === window; // true ``` -現在のドキュメントがフレームの中で開かれているかどうかを確認するのに、`top` プロパティが使えます。: +We can use the `top` property to check if the current document is open inside a frame or not: ```js run if (window == top) { // current window == window.top? @@ -204,69 +210,69 @@ if (window == top) { // current window == window.top? } ``` -## The sandbox attribute +## The "sandbox" iframe attribute -`sandbox` 属性は、信頼できないコードが実行されるのを防ぐため、` @@ -45,6 +80,7 @@ iframe { /* 被害サイト からの iframe */
...And you're cool (I'm a cool hacker actually)!
``` +<<<<<<< HEAD 攻撃の完全がデモがこちらです: [codetabs src="clickjacking-visible" height=160] @@ -74,6 +110,37 @@ iframe { /* 被害サイト からの iframe */ 最も古い防御策は、フレーム内でページを開くことを禁止する JavaScript です(いわゆる "フレームバスティング(framebusting)")。 このようになります: +======= +The full demo of the attack: + +[codetabs src="clickjacking-visible" height=160] + +Here we have a half-transparent ` ``` +<<<<<<< HEAD この単純な防御を回避する方法は他にもあります。 ## X-Frame-Options @@ -141,11 +243,38 @@ window.onbeforeunload = function() { ````online 動作確認: +======= +There are other ways to work around that simple protection too. + +## X-Frame-Options + +The server-side header `X-Frame-Options` can permit or forbid displaying the page inside a frame. + +It must be sent exactly as HTTP-header: the browser will ignore it if found in HTML `` tag. So, `` won't do anything. + +The header may have 3 values: + + +`DENY` +: Never ever show the page inside a frame. + +`SAMEORIGIN` +: Allow inside a frame if the parent document comes from the same origin. + +`ALLOW-FROM domain` +: Allow inside a frame if the parent document is from the given domain. + +For instance, Twitter uses `X-Frame-Options: SAMEORIGIN`. + +````online +Here's the result: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```html ``` +<<<<<<< HEAD 利用しているブラウザによって、上の `iframe` は空、またはブラウザがそのページをこの方法では移動することを許可しないことを警告するものになります。 @@ -158,6 +287,21 @@ window.onbeforeunload = function() { そのため、他の解決策もあります。例えば、すべてのクリックを遮断するよう、`height: 100%; width: 100%;` を持つ `
` でページを "覆う" ことができます。`window == top` または、保護の必要がないと判断した場合には、 `
` は消えるようにします。 このようなものです: +======= + + + +Depending on your browser, the `iframe` above is either empty or alerting you that the browser won't permit that page to be navigating in this way. +```` + +## Showing with disabled functionality + +The `X-Frame-Options` header has a side-effect. Other sites won't be able to show our page in a frame, even if they have good reasons to do so. + +So there are other solutions... For instance, we can "cover" the page with a `
` with styles `height: 100%; width: 100%;`, so that it will intercept all clicks. That `
` is to be removed if `window == top` or if we figure out that we don't need the protection. + +Something like this: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```html ``` -`@keyframes` や [詳細な仕様](https://drafts.csswg.org/css-animations/) について多くの記事があります。 +There are many articles about `@keyframes` and a [detailed specification](https://drafts.csswg.org/css-animations/). -ただし、あなたのサイト上で常に動いているものがない限り、恐らく `@keyframes` を頻繁に必要とはしないでしょう。 +Probably you won't need `@keyframes` often, unless everything is in the constant move on your sites. -## サマリ +## Summary -CSS アニメーションは、1つ以上の CSS プロパティの変更をなめらかにアニメーション化できます。 +CSS animations allow to smoothly (or not) animate changes of one or multiple CSS properties. -これはほとんどのアニメーションのタスクに適しています。なお、アニメーションに JavaScript を使うこともできます。次のチャプターではそれを見ていきます。 +They are good for most animation tasks. We're also able to use JavaScript for animations, the next chapter is devoted to that. -JavaScript アニメーションと比較した場合の CSS アニメーションの制限は次の通りです: +Limitations of CSS animations compared to JavaScript animations: ```compare plus="CSS animations" minus="JavaScript animations" -+ 簡単なことは簡単にできます。 -+ CPU に対し高速であり軽量です。 -- JavaScript アニメーションは柔軟です。 要素の "爆発" のような任意のアニメーションロジックを実装することができます。 -- 単なるプロパティの変更ではありません。JavaScript ではアニメーション目的で新しい要素を作成すると言ったことが可能です。 ++ Simple things done simply. ++ Fast and lightweight for CPU. +- JavaScript animations are flexible. They can implement any animation logic, like an "explosion" of an element. +- Not just property changes. We can create new elements in JavaScript for purposes of animation. ``` -大部分のアニメーションはこのチャプターで説明した CSS を使用して実装することができます。そして `transitionend` イベントはアニメーションの後に JavaScript を実行することができるので、コードともうまく統合できます。 +The majority of animations can be implemented using CSS as described in this chapter. And `transitionend` event allows to run JavaScript after the animation, so it integrates fine with the code. -しかし、次のチャプターではより複雑なケースを取り扱うため、 JavaScript アニメーションをいくつか見ていきます。 +But in the next chapter we'll do some JavaScript animations to cover more complex cases. diff --git a/7-animation/2-css-animations/step-list.view/index.html b/7-animation/2-css-animations/step-list.view/index.html new file mode 100644 index 0000000000..d7931f5e28 --- /dev/null +++ b/7-animation/2-css-animations/step-list.view/index.html @@ -0,0 +1,14 @@ + + + + + + + + + + +
0123456789
+ + + diff --git a/7-animation/2-css-animations/step-list.view/style.css b/7-animation/2-css-animations/step-list.view/style.css new file mode 100644 index 0000000000..a934e83406 --- /dev/null +++ b/7-animation/2-css-animations/step-list.view/style.css @@ -0,0 +1,9 @@ +#digit { + border: 1px solid red; + width: 1.2em; +} + +#stripe { + display: inline-block; + font: 32px monospace; +} diff --git a/7-animation/3-js-animation/1-animate-ball/solution.md b/7-animation/3-js-animation/1-animate-ball/solution.md index 4e2dfd8279..db0eb17310 100644 --- a/7-animation/3-js-animation/1-animate-ball/solution.md +++ b/7-animation/3-js-animation/1-animate-ball/solution.md @@ -1,3 +1,4 @@ +<<<<<<< HEAD バウンドさせるには、`position:relative` をもつフィールド内のボールに対して、CSS プロパティ `top` と `position:absolute` を使うことで実現できます。 フィールドの下部の座標は `field.clientHeight` です。しかし、`top` プロパティはボール上部の座標のため、下端の位置は `field.clientHeight - ball.clientHeight` になります。 @@ -7,6 +8,15 @@ あとは、"バウンド" 効果を行うためにタイミング関数 `bounce` を `easeOut` モードで使います。 これがアニメーションの最終的なコードです: +======= +To bounce we can use CSS property `top` and `position:absolute` for the ball inside the field with `position:relative`. + +The bottom coordinate of the field is `field.clientHeight`. The CSS `top` property refers to the upper edge of the ball. So it should go from `0` till `field.clientHeight - ball.clientHeight`, that's the final lowest position of the upper edge of the ball. + +To to get the "bouncing" effect we can use the timing function `bounce` in `easeOut` mode. + +Here's the final code for the animation: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```js let to = field.clientHeight - ball.clientHeight; diff --git a/7-animation/3-js-animation/1-animate-ball/task.md b/7-animation/3-js-animation/1-animate-ball/task.md index bb98a8063e..903e823843 100644 --- a/7-animation/3-js-animation/1-animate-ball/task.md +++ b/7-animation/3-js-animation/1-animate-ball/task.md @@ -2,8 +2,8 @@ importance: 5 --- -# バウンドするボールのアニメーション +# Animate the bouncing ball -バウンドするボールを作ってください。ボールをクリックすると動きを確認できます。: +Make a bouncing ball. Click to see how it should look: [iframe height=250 src="solution"] diff --git a/7-animation/3-js-animation/2-animate-ball-hops/solution.md b/7-animation/3-js-animation/2-animate-ball-hops/solution.md index eeb255b53f..d47387e30a 100644 --- a/7-animation/3-js-animation/2-animate-ball-hops/solution.md +++ b/7-animation/3-js-animation/2-animate-ball-hops/solution.md @@ -1,12 +1,12 @@ -タスク では、アニメーションするプロパティは1つだけでした。ここではもう1つ必要です。:`elem.style.left`. +In the task we had only one property to animate. Now we need one more: `elem.style.left`. -水平座標は別の法則("バウンド" ではなく、徐々にボールを右にシフトする)で変化します。 +The horizontal coordinate changes by another law: it does not "bounce", but gradually increases shifting the ball to the right. -そのため、もう一つの `animate` を記述します。 +We can write one more `animate` for it. -時間関数として `linear` も使えますが、`makeEaseOut(quad)` などの方がはるかによく見えます。 +As the time function we could use `linear`, but something like `makeEaseOut(quad)` looks much better. -コード: +The code: ```js let height = field.clientHeight - ball.clientHeight; diff --git a/7-animation/3-js-animation/2-animate-ball-hops/task.md b/7-animation/3-js-animation/2-animate-ball-hops/task.md index 8436e9889b..216f3dcda1 100644 --- a/7-animation/3-js-animation/2-animate-ball-hops/task.md +++ b/7-animation/3-js-animation/2-animate-ball-hops/task.md @@ -2,6 +2,7 @@ importance: 5 --- +<<<<<<< HEAD # 右にバウンドするボールのアニメーション 次のように、ボールを右にバウンドさせます。: @@ -11,3 +12,14 @@ importance: 5 アニメーションコードを記述してください。右への距離は `100px` です。 前のタスク の答えをソースとして使ってください。 +======= +# Animate the ball bouncing to the right + +Make the ball bounce to the right. Like this: + +[iframe height=250 src="solution"] + +Write the animation code. The distance to the left is `100px`. + +Take the solution of the previous task as the source. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/7-animation/3-js-animation/article.md b/7-animation/3-js-animation/article.md index 9f67c05c0a..0049543401 100644 --- a/7-animation/3-js-animation/article.md +++ b/7-animation/3-js-animation/article.md @@ -1,68 +1,63 @@ -# JavaScript アニメーション +# JavaScript animations -JavaScript アニメーションは CSS ではできないことを扱うことができます。 +JavaScript animations can handle things that CSS can't. -例えば、ベジェ曲線とは異なるタイミング関数を用いて複雑な経路に沿って移動したり、canvas 上でのアニメーションなどです。 +For instance, moving along a complex path, with a timing function different from Bezier curves, or an animation on a canvas. -[cut] +## Using setInterval -## setInterval +An animation can be implemented as a sequence of frames -- usually small changes to HTML/CSS properties. -HTML/CSS の観点からは、アニメーションはスタイルプロパティの段階的な変更です。例えば、`style.left` を `0px` から `100px` に変更すると、要素が移動します。 +For instance, changing `style.left` from `0px` to `100px` moves the element. And if we increase it in `setInterval`, changing by `2px` with a tiny delay, like 50 times per second, then it looks smooth. That's the same principle as in the cinema: 24 frames per second is enough to make it look smooth. -そして、もしそれを `setInterval` の中で増加させるとき、毎秒 50 回の小さな変更を加えることによって、その変化はなめらかに見えます。これは映画館と同じ原理です。: 毎秒 24 以上のフレームがあれば十分に滑らかに見えます。 - -疑似コードは次のようになります: +The pseudo-code can look like this: ```js -let delay = 1000 / 50; // 1 秒で 50 フレーム let timer = setInterval(function() { if (animation complete) clearInterval(timer); - else increase style.left -}, delay) + else increase style.left by 2px +}, 20); // change by 2px every 20ms, about 50 frames per second ``` -より複雑なアニメーションの例: +More complete example of the animation: ```js -let start = Date.now(); // 開始時間を覚える +let start = Date.now(); // remember start time let timer = setInterval(function() { - // 開始からの経過時間は? + // how much time passed from the start? let timePassed = Date.now() - start; if (timePassed >= 2000) { - clearInterval(timer); // 2秒後にアニメーションが終了 + clearInterval(timer); // finish the animation after 2 seconds return; } - // timePassed 時点のアニメーションを描画 + // draw the animation at the moment timePassed draw(timePassed); }, 20); -// timePassed は 0 から 2000 まで進む -// なので、left は 0px から 400px になります +// as timePassed goes from 0 to 2000 +// left gets values from 0px to 400px function draw(timePassed) { train.style.left = timePassed / 5 + 'px'; } ``` -デモです。電車をクリックしてみてください: +Click for the demo: [codetabs height=200 src="move"] -## requestAnimationFrame - -複数のアニメーションが同時に実行されているとしましょう。 +## Using requestAnimationFrame -もしそれらを別々に実行し、それぞれが個別に `setInterval(..., 20)` を持っていると、ブラウザは `20ms` 間隔よりもっと頻繁に再描画をする必要があります。 +Let's imagine we have several animations running simultaneously. -各 `setInterval` は `20ms` 毎に一回トリガしますが、独立しているので `20ms` の中に複数の独立した実行があることになります。 +If we run them separately, then even though each one has `setInterval(..., 20)`, then the browser would have to repaint much more often than every `20ms`. -これらの複数の独立した再描画は、ブラウザの再描画を簡単にし、CPUの負荷を減らしてよりなめらかに見せるためにグループ化すべきです。 +That's because they have different starting time, so "every 20ms" differs between different animations. The intervals are not aligned. So we'll have several independent runs within `20ms`. -言い換えると、次のコード: +In other words, this: ```js setInterval(function() { @@ -72,39 +67,40 @@ setInterval(function() { }, 20) ``` -...は以下のコードよりも軽量です: +...Is lighter than three independent calls: ```js -setInterval(animate1, 20); -setInterval(animate2, 20); +setInterval(animate1, 20); // independent animations +setInterval(animate2, 20); // in different places of the script setInterval(animate3, 20); ``` -心に留めておくべきことがもう一つあります。CPUが過負荷になっている場合や、その他再描画をあまりしなくて良い場合があります(ブラウザタブが非表示になっているようなとき)。そのため、本当は20ms毎に実行すべきではありません。 +These several independent redraws should be grouped together, to make the redraw easier for the browser and hence load less CPU load and look smoother. + +There's one more thing to keep in mind. Sometimes when 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`. -しかし、それを JavaScript ではどうやってしるのでしょう? 関数 `requestAnimationFrame` を提供する標準の [アニメーションタイミング](http://www.w3.org/TR/animation-timing/) があります。この関数は、これらすべての問題及び、その他多くのことに対応しています。 +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. -構文: +The syntax: ```js let requestId = requestAnimationFrame(callback) ``` -これは、ブラウザがアニメーションをしたい最も近い時間に `callback` 関数を実行するようスケジューリングします。 +That schedules the `callback` function to run in the closest time when the browser wants to do animation. -もし `callback` の中で要素を変更すると、他の `requestAnimationFrame` コールバックや CSS アニメーションと一緒にグループ化されます。これにより、配置の再計算と再描画がそれぞれではなく1回でまとめて行われます。 +If we do changes in elements in `callback` then they will be grouped together with other `requestAnimationFrame` callbacks and with CSS animations. So there will be one geometry recalculation and repaint instead of many. -返却値 `requestId` は呼び出しをキャンセルするのに使うことができます: +The returned value `requestId` can be used to cancel the call: ```js -// スケジューリングされたコールバックの実行をキャンセルする +// cancel the scheduled execution of callback cancelAnimationFrame(requestId); ``` -`callback` は1つの引数を取ります -- ページロードの開始からの経過時間のマイクロ秒です。 -この時間は [performance.now()](mdn:api/Performance/now) を呼び出すことでも得ることができます。 +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). -通常 `callback` は CPU が過負荷状態になったり、ノートPCのバッテリーがほとんどなかったり、その他別の理由がある場合を除きすぐに実行されます。 +Usually `callback` runs very soon, unless the CPU is overloaded or the laptop battery is almost discharged, or there's another reason. -下のコードは `requestAnimationFrame` での最初の10回の実行時間を表示します。通常は 10-20ms です。 +The code below shows the time between first 10 runs for `requestAnimationFrame`. Usually it's 10-20ms: ```html run height=40 refresh ``` +<<<<<<< HEAD 1. レンダリングロジックは `render` ヘルパーメソッドに移動しました。 2. 要素がページに挿入されたときに1回だけ呼び出します。 3. `observedAttributes()` にリストされた属性の変更に対し、`attributeChangedCallback` がトリガーされます。 @@ -220,6 +340,21 @@ HTML パーサーが DOM を構築するとき、要素は次々に処理され これはカスタム要素に対して重要な結果をもたらします。 例えば、カスタム要素が `connectedCallback` の中で `innerHTML` にアクセスしようとしても、何も得られません。: +======= +1. The rendering logic is moved to `render()` helper method. +2. We call it once when the element is inserted into page. +3. For a change of an attribute, listed in `observedAttributes()`, `attributeChangedCallback` triggers. +4. ...and re-renders the element. +5. At the end, we can easily make a live timer. + +## Rendering order + +When HTML parser builds the DOM, elements are processed one after another, parents before children. E.g. if we have ``, then `` element is created and connected to DOM first, and then ``. + +That leads to important consequences for custom elements. + +For example, if a custom element tries to access `innerHTML` in `connectedCallback`, it gets nothing: +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 ```html run height=40 ``` +<<<<<<< HEAD 1. ドキュメントのスタイルは shadow tree には影響しません。 2. ...ですが、内部のスタイルは機能します。 3. shadow tree 内で要素を取得するには、ツリーの内側からクエリーを行う必要があります。 @@ -155,4 +253,30 @@ Shadow DOM 要素: - メインのドキュメントからの JavaScript セレクタ(e.g. `querySelector`)には見えません - shadow tree 内のスタイルのみを使用し、メインドキュメントのスタイルは適用されません -Shadow DOM が存在する場合、いわゆる "light DOM" (通常の子)の代わりに、ブラウザによってレンダリングされます。チャプター でこれらを構成する方法を見ていきます。 \ No newline at end of file +Shadow DOM が存在する場合、いわゆる "light DOM" (通常の子)の代わりに、ブラウザによってレンダリングされます。チャプター でこれらを構成する方法を見ていきます。 +======= +1. The style from the document does not affect the shadow tree. +2. ...But the style from the inside works. +3. To get elements in shadow tree, we must query from inside the tree. + +## References + +- DOM: +- Compatibility: +- Shadow DOM is mentioned in many other specifications, e.g. [DOM Parsing](https://w3c.github.io/DOM-Parsing/#the-innerhtml-mixin) specifies that shadow root has `innerHTML`. + + +## Summary + +Shadow DOM is a way to create a component-local DOM. + +1. `shadowRoot = elem.attachShadow({mode: open|closed})` -- creates shadow DOM for `elem`. If `mode="open"`, then it's accessible as `elem.shadowRoot` property. +2. We can populate `shadowRoot` using `innerHTML` or other DOM methods. + +Shadow DOM elements: +- Have their own ids space, +- Invisible to JavaScript selectors from the main document, such as `querySelector`, +- Use styles only from the shadow tree, not from the main document. + +Shadow DOM, if exists, is rendered by the browser instead of so-called "light DOM" (regular children). In the chapter we'll see how to compose them. +>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8 diff --git a/8-web-components/4-template-element/article.md b/8-web-components/4-template-element/article.md index d1a5d08468..495ca81740 100644 --- a/8-web-components/4-template-element/article.md +++ b/8-web-components/4-template-element/article.md @@ -1,4 +1,5 @@ +<<<<<<< HEAD # Template 要素 組み込みの `