diff --git a/README.md b/README.md index e8c773e8..e69de29b 100644 --- a/README.md +++ b/README.md @@ -1,1675 +0,0 @@ -2日でできる JavaScriptTraining -============================== - -JavaScript 初心者が JS の未来を見据えつつ、 -基礎をひととおり身に付けるための資料です。 - - - -この README は `npm run presentation` で -再生することができます。 - - - -トレーニングの目標 ------------------- - - - -このトレーニングの目標は、 -**モジュールを読み書きできるようになり、** -自分の好きなモジュールを -つくれるようになることです。 - - - -トレーニングの前に、セットアップを -終わらせてしまいましょう。 - - - -セットアップ ------------- - - - -### 1. 環境をセットアップ - -この研修では [Google Chrome](https://www.google.co.jp/chrome/browser/desktop/index.html) を利用します。 -上のリンクから Chrome をインストールしてください。 - -[Node.js](http://nodejs.jp/nodejs.org_ja/) も利用しています。 -こちらも上のリンクからインストールしてください。 - - - -### 2. JavaScriptTraining を fork - -JavaScriptTraining の学習履歴を残すために、 -JavaScriptTraining リポジトリを fork します。 - -画面右上にある fork ボタンを押してください。 - -[](http://mixi-inc.github.io/JavaScriptTraining/images/fork-button.png) - - - -### 3. 必要なものをダウンロード - -ここからはターミナル上での操作になります。 -リポジトリの URL をコピーし、下のコマンドを -ターミナルで実行してください。 - - git clone コピーしたURL - - - -### 4. セットアップ - -下のコマンドをターミナルで実行してください。 - - cd JavaScriptTraining - npm install - - - -### 5. webサーバーを立ち上げる - -下のコマンドをターミナルで実行してください。 - -なお、トレーニング中はこのコマンドを -終了しないでください。 - - npm run serve - - - -### 6. トップページにアクセスする - -ブラウザから [http://localhost:8000](http://localhost:8000) へ -アクセスしてください。 - -トレーニングの一覧が表示されていれば完了です。 - - - -トレーニング前レクチャー ------------------------- - - - -### JavaScript とは - -> JavaScript はウェブの言語です。 -> -> ウェブページにある特定の要素を -> 操作する手段として始まりましたが、 -> 途方もなく成長しました。 -> -> (JavaScript パターン, O'Reilly) - - - -### JavaScript のすごいところ - -> クラスというものがなく、 -> 第一級オブジェクトである関数が -> 多くの仕事に使われます。 -> -> (JavaScript パターン, O'Reilly) - - - -> Java や PHP が追加しはじめた -> クロージャーや無名関数といった -> 機能は、JavaScript 開発者が -> 楽しんできた機能であり、 -> あるのが当然だと思われていました。 -> -> (JavaScript パターン, O'Reilly) - - - -### 楽しんできた機能??? - -```javascript -['Foo', 'Bar', 'Buz'].forEach(function(name) { - console.log('hello ' + name); -}); -``` - -(クロージャーはトレーニングで扱います) - - - -### JavaScript はどこで動くのか - -- Web ブラウザ -- Node.js, io.js - -JavaScript の特色のひとつは、ブラウザ上で -動作するということです。ブラウザ上で動作できる -言語はいくつかありますが、一般的に -JavaScript がよく使われます。 - - - -### いつ JavaScript を使うのか - -- Web ページに独自の動きをつけたいとき - - (一部は CSS でできます) - -- ページ遷移なしにサーバーと通信したいとき -- パフォーマンスチューニング -- フロントエンドエコシステム使いたいとき - - (タスクランナーとかパッケージマネージャ) - - - -### JavaScript を使うと… - -- アニメーションの例: [Si digital](http://sidigital.co/) -- インタラクションの例: [Vim.js](http://coolwanglu.github.io/vim.js/emterpreter/vim.html) -- Web API の例: [Google Map](https://www.google.co.jp/maps) - - - -JavaScript に会いにいこう -------------------------- - - - -### 1. 開発ツールを開く - -Chrome で [http://localhost:8000](http://localhost:8000) を開きます。 - -Web ページの適当な場所で -右クリック > 要素の検証 - -または - -- Mac の人: ⌘ + ⌥ + i -- Windows の人:Ctrl + Shift + i - - - -### 2. Console を開く - -開発ツールを選択し、Esc キーを -数回おしてみてください。 - -すると、下に Console が出てきます。 -この Console から、JavaScript を -実行することができます。 - -[](http://mixi-inc.github.io/JavaScriptTraining/images/console.png) - - - -### 3. 何か実行してみる - -試しに `alert('Foo');` と実行してみてください。 - -アラートポップアップが表示されます。 - - - -### 4. 計算させてみる - -`1 + 1` や `'Foo' + 'Bar'` なども実行できますね。 - - - -### 5. 変数代入・参照してみる - -変数代入・参照もできますね。 - -```javascript -var foo = 'bar'; -foo; -``` - - - -### 6. ブラウザオブジェクトをいじる - -ブラウザオブジェクトもいじってみましょう。 - -```javascript -document.title = 'あなたとjava 今すぐダウンロード'; -``` - -Chrome のタブ名が書き変わりました。 - - - -### 7. ページを再読み込みすると戻る - -ページを再読み込みしてみてください。 - -これまでの変更はすべてリセットされます。 -(つまり、この方法で本番リリースは -できないということですね!) - - - -### 8. JavaScript とここで会える - -- スクリプト読み込みパターン(推奨) - - <script src="foo.js"></script> - -- インラインパターン - - <script>alert('inline!');</script> - -- インラインイベントハンドラーパターン - - <img src="buz.png" onerror="alert('onerror!')"> - -- ブックマークレットパターン - - <a href="javascript: alert('bookmarklet!')"></a> - - - -開発環境道場 ------------- - -(あるいはポエム) - - - -JavaScript を効率的に書けるようにするために -最低限の開発環境を整えます。 - - - -JavaScript に精通していない人に -「どんなツールを使ったらいいですか?」と -聞かれることがよくあります。 - -私は「構文ハイライトと lint を使うといいですよ」、 -と答えることにしています。 - -[](http://mixi-inc.github.io/JavaScriptTraining/images/syntax-error.png) - - - -ひとつエピソードを紹介します。 - - - -JavaScript には静的型検査がないことや、 -記号が多い構文や、まずい仕様がいくつもあるので、 -ミスを犯しやすい言語の一つです。 - - - -たとえば、JavaScript には `"use strict"` という -宣言があります。この宣言は JavaScript の -まずい仕様の一部をエラーにすることで修正を -促す効果があり、よく記述を推奨される宣言です。 - - - -あるプロジェクトで気を利かした -プログラマーが `"use strict"` を -新しいスクリプトで使い始めました。 - -```javascript -"use strict"; - -// Do something... -``` - -これは、開発時のミスを早期発見できるように -するよい方法です! - - - -しかし、リリース後、新しいスクリプトとは -関係ないはずの JavaScript による -メニューが動作しなくなっていました。 - -なぜでしょうか? - - - -これは、パフォーマンスチューニングの一環で -複数の JavaScript ファイルを結合していたこと、 -ファイルに対する `"use strict"` を利用していた -ことの2つが原因となって起きた不具合です。 - -`"use strict"` が結合された -すべてのファイル全体に効くように -なり、`"use strict"` に対応していない -古いファイルがエラーを出すように -なってしまっていたのでした。 - - - -このエピソードは、いわゆる**初見殺し**です。 - -「何それどうしてそんな仕様なの😱」 -と言いたくなりますね。 - - - -悲しいことに、このような落とし穴は -JavaScript の仕様・文化に数多く -潜んでいます。 - -これらのミスをどのようにしたら -防げるのでしょうか? - - - -[ESLint](http://eslint.org/) や [JSHint](http://jshint.com/)、 [JSLint](http://www.jslint.com/) のような lint を -使いましょう。 - -たとえば、ESLint を実行すると -下のような警告が出されます。これによって、 -潜在的な不具合をだいぶ減らせるようになるのです。 - - Use the function form of "use strict". - (関数形式の "use strict" を使ってね) - - - -ミスを防ぐためには、「頑張る」とか -「注意する」のような精神論ではなく、 - lint によって防止することが必要です。 -あなたが JavaScript にまだ精通していないので -あれば、真っ先にいれるべきは lint なのです。 - - - -1. lint をかけてみる - - ターミナルで下のコマンドを実行してください。 - ESLint が実行されます。 - - gulp lint-stage1 - -2. 構文ハイライトを効かせる - - ほとんどのエディタは構文ハイライトを - サポートしています。Vim のように - 構文ハイライトが選べるのであれば、 - よりミスのわかりやすい構文ハイライトを - 利用します。 - - - -トレーニング ------------- - - - -### ステージ1 - -DOM 要素を取得するトレーニング - - - -#### DOM とは - -Web ページは HTML のタグによって -構成されています。 - -[](http://mixi-inc.github.io/JavaScriptTraining/images/github.png) -[](http://mixi-inc.github.io/JavaScriptTraining/images/github-elements.png) - -この 3D ビューを見ると、複数の HTML タグから -Web ページが構成されていることがよくわかります。 - - - -この HTML タグは下のような木構造をとっています。 - -[](http://mixi-inc.github.io/JavaScriptTraining/images/github-elements.png) -[](http://mixi-inc.github.io/JavaScriptTraining/images/github-tree.png) - -実際に、[mixi-inc/JavaScriptTraining](https://github.com/mixi-inc/JavaScriptTraining) を開き、 -開発コンソールのElement タブに表示されている -構造を確認してみてください。 - - - -DOM (Document Object Model) は、この HTML のタグを -JavaScript の世界で操作することができる API です。 - -HTML タグは、JavaScript の世界で -DOM 要素というオブジェクトとして扱われます。 - - - -[](http://mixi-inc.github.io/JavaScriptTraining/images/github-tree.png) - -HTML のタグを JavaScript 側で操作するためには -HTML のタグを HTML 文書から取り出し、 -JavaScript の世界へと取ってこなければなりません。 - -このステージでは、HTML から DOM 要素を -取得するという操作について学びます。 - - - -HTML タグには、目印となるいくつかの情報が -付属しています。たとえば、下の div タグには -ID 属性が付属しています。 - -```html -
foo
-``` - -JavaScript はこの目印を DOM API に渡すことで、 -DOM 要素を取得することができます。 - -```javascript -var div = document.getElementById('foo'); -``` - - - -他にも CSS クラスやタグ名、その他の属性から、 -DOM 要素を取得することができます。 - -```html -
foo
-``` - - - -#### CSS セレクタについて - -また、目印の指定の仕方のひとつに、 -CSS セレクタがあります。 - -たとえば、`foo` という ID のついたタグであれば、 - -```html -
foo
-``` - -```javascript -var div = document.querySelector('#foo'); -``` - -というように、ID の先頭に `#` をつけた -IDセレクタ `#foo` で、取得したい DOM 要素を指示します。 - - - -この方法の利点は、複雑な位置にある DOM 要素を -取得することができるということでしょう。 - -下の HTML の bar を包む `div` タグにあたる -DOM 要素を取得する場合、 - -```html -
-
foo
-
bar
-
-``` - -```javascript -var div = document.querySelector('.foo div:last-child'); -``` - -というように、CSS クラスセレクタ `.foo` に -該当する要素の子要素を子孫セレクタ (スペース) で -取得し、このうち `div` タグから CSS 疑似セレクタ -`:last-child` にマッチするものを取得する -という操作になります。 - - - -図にすると、このようになります。 - -[](http://mixi-inc.github.io/JavaScriptTraining/images/css-selector-example.png) - -CSS セレクタについては、[MDN のCSS リファレンス](https://developer.mozilla.org/ja/docs/Web/CSS/Reference#Selectors) が -参考になります。 - -仕様を見ないと我慢ならぬ!という立派な方は、 -[セレクタ Level 3 仕様](http://standards.mitsue.co.jp/resources/w3c/TR/css3-selectors/) を見るとよいでしょう。 - - - -#### 実習 - -下のテストが green になるように、 -`public/stage1/tests.js` を -修正してください。 - -[http://localhost:8000/stage1/](http://localhost:8000/stage1/) - - - -#### クリアできたら - -Lint をかけてみましょう。 - - gulp lint-stage1 - -警告があれば、修正してみてください。 - - - -### ステージ2 - -DOM 要素の属性・テキストを変更する -トレーニング - - - -このステージでは、スタイルの変更や -表示文字列を変更するやり方を学びます。 - - - -#### DOM 要素の属性・テキスト - -DOM 要素には、 - -- 先ほど DOM API に渡した ID 属性 -- CSS クラス属性などの目印となる属性 -- 見た目を操作するスタイル属性 - -などが付属しています。 - -(DOM の属性の一覧は [MDN DOM リファレンス](https://developer.mozilla.org/ja/docs/DOM/DOM_Reference) を -参照してください) - - - -このうち、スタイル属性を編集すると、DOM 要素の -見た目を変化させることができます。 - -たとえば、Github のヘッダの octocat の -style.color 属性を変更してみました。 - -[](http://mixi-inc.github.io/JavaScriptTraining/images/octocats.png) - - - -このスタイル属性は CSS の仕様と対応するように -定められています。 - -ただ、アニメーションを含め、見た目の変更は -CSS クラス名の追加/編集/削除によっておこなう -ことが推奨されてきています。 - -([レンダリングエンジンによる最適化が効くのです!](https://developer.mozilla.org/ja/docs/Web/Guide/CSS/Using_CSS_animations)) - -JavaScript は見た目の変更のきっかけを -与えるだけにとどめるのが、上手な -HTML/JavaScript/CSS 分業の基本です。 - - - -残念なお知らせですが、 -今回のトレーニングは CSS を -書けるようになることが目的ではないので、 -レガシーな element.style を編集するやり方を -学びます。 - - - -レガシー… 😱 - - - -まあ、肩を落とさないでください。 - -レガシーとはいえ、レガシーブラウザーを -相手にするライブラリを読み書きするときには、 -どうしても必要になります。 - -ちなみに、「レガシー?帰らせていただきます」は -フロントエンドエンジニアとして大切な感覚ですので -大事にしてください。 - - - -#### 実習 - -下のテストが green になるように、 -`public/stage2/tests.js` を -修正してください。 - -[http://localhost:8000/stage2/](http://localhost:8000/stage2/) - - - -#### クリアできたら - -Lint をかけてみましょう。 - - gulp lint-stage2 - -警告があれば、修正してみてください。 - - - -### ステージ3 - -DOM の構造を変更するトレーニング - - - -#### DOM の構造 - -このステージでは、DOM の属性ではなく、 -構造を変更するトレーニングをおこないます。 - -たとえば、書籍を検索する Web API を使って、 -書籍検索サービスを開発することを例に、 -DOM の構造を変更する必要性を考えてみます。 - - - -書籍検索サービスの API は、検索結果を -下のように返したとしましょう。 - -```javascript -[ - { - "title": "紅", - "score": 5 - }, - { - "title": "円環少女", - "score": 5 - }, - { - "title": "SHI-NO -シノ- 黒き魂の少女", - "score": 5 - }, - ... -] -``` - - - -このとき、画面に表示するために下のような HTML を -追加することになります。 - -```html - -``` - - - -サーバー側で上のような HTML を -生成してもよいのですが、 -JavaScript による DOM 構造の操作に -よって実現させることができれば、 -軽快な書籍検索サービスをつくることができます。 - -(ページのリロードが必要ないからですね!) - - - -このように、Web サービスの使いやすさを -追求するためには、JavaScript による -DOM 構造の操作が重要なのです。 - - - -#### 実習 - -下のテストが green になるように、 -`public/stage3/tests.js` を -修正してください。 - -[http://localhost:8000/stage3/](http://localhost:8000/stage3/) - - - -#### クリアできたら - -Lint をかけてみましょう。 - - gulp lint-stage3 - -警告があれば、修正してみてください。 - - - -### ステージ4 - -DOM イベントを利用するトレーニング - - - -### DOM イベント解説編 - -ユーザーがボタンを押したり、 -検索欄に入力したとき、JavaScript は -DOM イベントをうけとることができます。 - -たとえば、下のボタンは click イベントを -引きがねとして、DOM 構造を書き換えます。 - -
- - - -click イベント以外にも多様なイベントがあります: - -- dblclick: 要素上でダブルクリックされたとき -- mousemove: 要素上でポインタが移動しているとき -- scroll: 画面がスクロールされたとき -- unload: 次のページに遷移する直前 -- keydown: キーボードが押されたとき -- animationstart: CSS アニメーションが開始したとき -- offline: ブラウザがオフラインになったとき - -ここに載っていないイベントの一覧は -[MDN DOM イベントリファレンス](https://developer.mozilla.org/ja/docs/Web2/Reference/Events) を -参照するとよいでしょう。 - - - -試しに、このページを制御する JavaScript が -監視しているイベントを見てみましょう。 - -開発ツールを開き、Elements タブの中段にある -Event Listeners タブを開いてみてください。 - - - -[](http://mixi-inc.github.io/JavaScriptTraining/images/chrome-dev-tool-event-debugging.png) - -たくさんのイベントが登録されていますね。 - -では、これらのイベントの使い方を解説していきます。 - - - -#### DOM イベント実装編 - -DOM のイベントを JavaScript 側で監視するには、 -いくつかの方法があります。 - -- addEventListener スタイル - - ```javascript - var button = document.getElementById('button'); - button.addEventListener('click', function(event) { - console.log(event); - }); - ``` - -- インラインイベントハンドラースタイル - - ```html - - ``` - -- イベント属性スタイル(レガシー) - - ```javascript - var button = document.getElementById('button'); - button.onclick = function(event) { - console.log(event); - }; - ``` - - - -このうち、 `addEventListener` スタイルが -お行儀のよい方法だといわれ、 -推奨されてきました。 - -```javascript -// お行儀のよさ -button.addEventListener('click', function(event) { - console.log(event); -}); -``` - - - -しかし、[AngularJS](https://angularjs.org/) という最近の -フレームワークでイベント属性スタイルを -積極的に採用する動きもあります。 - -```html - - - - - -``` - -このような場合は、無理に `addEventListener` を -使わずに、そのフレームワークのしきたりに -従うとよいでしょう。 - - - -### DOM イベント伝搬の仕組み - -次に、DOM のイベント伝搬(propagation) -について解説します。 - - - -下のようなボタンを例に、伝搬の必要性を -考えていきます。このボタンは、アイコンつきで -表示されることを意図しています。 - -```html - -``` - -この button 要素の `click` イベントを -監視することを考えます。 - -button 要素に `addEventListener` すればよいように -見えますが、アイコン画像をクリックされた場合 -どうなるのでしょうか? - - - -実は、子要素で発生した DOM イベントは -親要素からも監視することができます。 - -この仕組みが DOM イベントの伝搬です。 - - - -[](http://www.w3.org/TR/DOM-Level-3-Events/#event-flow) - - - -`addEventListener` の引数で -1-2-4 か 1-3-4 のどちらかを選べます。 - -1. capturing フェーズ - - ルート要素からイベントの対象要素まで降りていく - -2. target フェーズ - - イベントの対象要素に到着 - -3. bubbling フェーズ - - イベントの対象要素からルート要素まで昇っていく - -4. ブラウザ既定の処理がおこなわれるフェーズ - - リンクなどによる画面遷移がおこなわれる - - - -先ほどのボタンの例では、img 要素の -click イベントは bubbling によって -button 要素まで通知されるのです。 - -```html - -``` - -```javascript -// button への addEventListener で OK -button.addEventListener('click', function(event) { - // Do something -}); -``` - - - -#### 実習 - -下のテストが green になるように、 -`public/stage4/tests.js` を -修正してください。 - -[http://localhost:8000/stage4/](http://localhost:8000/stage4/) - - - -#### クリアできたら - -Lint をかけてみましょう。 - - gulp lint-stage4 - -警告があれば、修正してみてください。 - - - -### ステージ5 - -非同期処理のトレーニング - - - -JavaScript の美しい機能のひとつに -非同期処理があります。 - -下のコードは 1 秒まったあとに -`console.log(1)` を実行するコードです。 - -```javascript -setTimeout(function() { - console.log(1); -}, 0); - -console.log(2); -``` - -このコードを実行すると、`1` と `2` の -どちらか先に表示されるでしょうか。 - - - -答えは、`2` です。`setTimeout` に登録された -関数はいま実行途中のすべての関数が終了してから -呼び出されます([JavaScriptのsetTimeoutを理解する](http://blog.mouten.info/2014/09/20/article/))。 - -ここでは、関数を実行するタイミングを -後回しにすることによって、待っている間に -別のことができる、ということを覚えてください。 - -この待ち時間の間に別の処理を実行する -やり方を非同期処理と呼びます。 - - - -#### サーバーとの通信 - -非同期処理の代表例といえばサーバーとの通信です。 - -サーバーとの通信はネットワークを通過するため、 -かなりの時間がかかります。そこで、レスポンスが -返ってくるまでの間に、別の処理をおこなうことに -よって、時間を有効活用することが重要になります。 - - - -JavaScript にはサーバーと非同期に通信するための -API が用意されています。 - -- [Fetch API](http://www.hcn.zaq.ne.jp/___/WEB/Fetch-ja.html) - - 現在策定中の新しい標準仕様 - -- [XMLHttpRequest](https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest) - - jQuery.ajax のようなショートハンドが使われる - ことが多く、実際手で書くことはほとんどない - - - -今回は、JavaScript の将来を見据えて、 -Fetch API によるサーバーとの通信を -トレーニングします。 - - - -#### Fetch API - -Fetch API は下のように書きます。 -このコードは、`/users.json` を -取得します。 - -```javascript -fetch('/users.json') - .then(function(response) { - return response.json() - }) - .then(function(json) { - console.log('parsed json', json) - }) - .catch(function(error) { - console.error('parsing failed', error) - }); -``` - -`.then`、`.catch` という不思議なメソッドで -つながっています。 - - - -#### Promise を使った非同期処理 - -さきほどの `.then`、`.catch` は、非同期処理の -結果を、引数に渡した関数で受け取るために -用意されています。 - -たとえば、`.then` を使うと、正常にレスポンスが -受け取れた場合に関数を実行できます。 - -```javascript -fetch('/users.json') - .then(function(response) { - - // /users.json を正常に取得できたときに、 - // response をログに出力する - console.log(response); - }); -``` - -エラーがあった場合は、ログ出力は実行されません。 - - - -また、`.catch` を使うと、エラーが発生した場合に -関数を実行できます。 - -```javascript -fetch('/users.json') - .catch(function(errror) { - - // /users.json の取得時にエラーがでたときに、 - // error をログに出力する - console.error(error); - }); -``` - -こちらは、正常にレスポンスを受け取れた場合は、 -ログ出力は実行されません。 - -なお、先ほどの例のように `.then` と `.catch` を -同時につけることもできます。 - - - -サーバーと通信するだけなのに、 -なんか複雑すぎるような…? - - - -実はこの Promise という複雑な仕組みを使う理由は、 - -- 並行非同期処理 -- 直列非同期処理 - -を書きやすくする、ということなのです。 - - - -#### Promise による平行非同期処理 - -`Promise.all` を使います。 - -```javascript -// 2つの Web API からレスポンスが欲しい! - -Promise.all([ - fetch('/api/foo'), - fetch('/api/bar') -]) -.then(function(responses) { - var responseFoo = responses[0]; - var responseBar = responses[1]; - doSomething(responseFoo, responseBar); -}); -``` - - - -#### Promise による直列非同期処理 - -`.then` で次々に処理を連結できます。 - -```javascript -// Web API の結果を利用して別の API を実行したい! - -fetch('/api/foo') - .then(doSomething) - .then(function() { return fetch('/api/bar'); }) - .then(doSomething) - .then(function() { return fetch('/api/buz'); }) - .then(doSomething); -``` - - - -#### 実習 - -下のテストが green になるように、 -`public/stage5/tests.js` を -修正してください。 - -[http://localhost:8000/stage5/](http://localhost:8000/stage5/) - - - -#### 参考になる資料 - -- [Promise に関する参考情報](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise) -- [Promise 参考情報(重量級)](http://azu.github.io/promises-book/) -- [Fetch API に関する参考情報](https://github.com/github/fetch) -- [Github API に関する参考情報](https://developer.github.com/v3/) - - - -#### クリアできたら - -Lint をかけてみましょう。 - - gulp lint-stage5 - -警告があれば、修正してみてください。 - - - -### ステージ6 - -モジュールを実装するトレーニング - - - -JavaScript は言語機能としてモジュールの -仕組みをもっていません。 - -言語機能としてのモジュールシステムを利用するには -[ECMAScript 6](https://developer.mozilla.org/ja/docs/Web/JavaScript/ECMAScript_6_support_in_Mozilla) を待たなければなりません。 - - - -とはいっても、みんなモジュールを使いたかったので、 -さまざまなモジュールシステムとそれに付随する -エコシステムが開発されてきました。 - - - -- bower -- component -- jam -- volo -- npm with browserify -- spm -- jspm -- duo - -(source: [wilmoore/frontend-packagers](https://github.com/wilmoore/frontend-packagers)) - - - -あ…めっちゃ多い…😵 - - - -今回は、利用方法がシンプルな「[bower](http://bower.io)」を使います。 - - - -#### bower - -bower は、JavaScript、HTML、CSSなどを -共有して使えるようにするフロントエンドの -エコシステムです。 - -他の人が作ったモジュールを利用することや、 -自分が作ったモジュールを公開することも -できます。 - - - -ただ、bower はモジュール読み込みの -仕組みを提供していません。 - -この部分は RequireJS など、別の -モジュールシステムに頼ることになります。 - -どのモジュールシステムに対応するかという選択は、 -bower によって読み込まれるパッケージ側に -裁量(責務)があります。 - - - -この方針を[公式ドキュメント](http://bower.io/#getting-started)は端的に -言い表しています。 - -> How you use packages is up to you. -> -> (どのようにしてパッケージを使うのかはあなた次第です) - - - -#### 実習 - -まず、bower を実行することを体験してみます。 -bower の設定ファイル bower.json を対話的に -作成します。 - - cd public/stage6/sample - bower init - - - -あとは説明に従って選択していくと、bower の -パッケージ設定ファイル `bower.json` が作成されます。 - - - -##### 1. name - -このパッケージの名前を指定します。 - -パッケージとして公開する場合には、既に同じ -パッケージ名が存在していないか確かめる必要が -あります。 - -この研修では、公開/非公開を問わないので、 -お好きな名前をつけてください。 - - - -##### 2. version - -このパッケージのバージョンを指定します。 - -バージョンの形式は [Semantic Versioning](http://semver.org/lang/ja/) に -準拠しています。 - -この形式は、一般的に `X.Y.Z` と記述されます。 - -- `X` は major version(後方互換性がなくなる変更) -- `Y` は minor version(前方互換性がなくなる変更) -- `Z` は patch version(バグ修正など) - -今回は開発版なので、0.0.0 にしておきましょう -(major versionの 0 は開発版であることを示します)。 - - - -##### 3. description - -パッケージの簡単な概要を記述します。 - -有名どころの説明をみてみます。 - -- bootstrap: The most popular HTML, CSS, and JavaScript framework for developing responsive, mobile first projects on the web. -- angular-latest: HTML enhanced for web apps -- less.js: Leaner CSS - - - -##### 4. main file - -このパッケージが外部のパッケージに公開したい -ファイルを指定します。文字列と配列が指定できます。 -今回は空で問題ありません。 - - - -##### 5. what types of module does this package expose? - -このパッケージが外部にエンドポイントを公開する -方法を明示します。 - -- amd: [Asynchronouse Module Definition](https://github.com/amdjs/amdjs-api/wiki/AMD) ([参考資料](http://www.matzmtok.com/blog/?p=845)) -- es6: [EcmaScript 6](http://wiki.ecmascript.org/lib/exe/fetch.php?id=harmony%3Aspecification_drafts&cache=cache&media=harmony:ecma-262_edition_6_03-17-15-releasecandidate3.pdf) ([参考資料](https://www.xenophy.com/javascript/8447#run-time-renaissance)) -- globals: グローバル変数経由でエンドポイント公開 -- node: [Node.js](https://nodejs.org/api/modules.html) -- yui: [YUI](http://yuilibrary.com/yui/docs/yui/create.html) (メンテ停止したのでもうやめましょう) - -今回は何も選択しないで問題ありません。 - - - -##### 6. keywords - -このパッケージを検索でヒットさせるための -キーワードを指定します。 - - - -##### 7. authors - -このパッケージの作者を指定します。 - - - -##### 8. license - -好きなライセンスを選ぶとよいです。 - -デフォルトは [MIT ライセンス](http://sourceforge.jp/projects/opensource/wiki/licenses%2FMIT_license)です。 - - - -##### 9. homepage - -このパッケージの情報が見られる URL を記述します。 - - - -##### 10. set currenttly installed components as dependencies? - -既に `bower_components` に含まれている -コンポーネントをパッケージ設定に -含まれるようにするかどうかを指定します。 - -n で構いません。 - - - -##### 11. add commonly ignored files to ignore list? - -`.gitignore` などのファイルから、 -パッケージに含めないファイルの指定を -読み込むかどうか指定します。 - -y で読み込ませます。 - - - -##### 12. would you like to mark this package as private which prevents it from being accidentaly published to the registry? - -bower のレジストリへ登録できないようにするか -どうか指定します。 - -y でレジストリへの公開ができないように設定します。 - - - -##### 13. Looks good? - -この設定で問題なければ y を入力します。 - - - -##### bower install - -いよいよ、パッケージを追加していきます。 - -パッケージは [Search Bower packages](http://bower.io/search/) で -検索することができます。 - - - -では、試しに [Buttons](https://github.com/alexwolfe/Buttons) パッケージを -追加してみましょう。 - -下のコマンドによって、Buttons パッケージが、 -`bower_components` 以下に配置されます。 - - bower install --save Buttons - - - -`--save` はパッケージ設定に依存ファイルを -追記する効果があります(`bower.json` の -内容が変化しているので、見てみてください)。 - -ここで設定に追記されたパッケージは、 -次回から `bower install` でまとめて -取得することができるようになります。 - - - -今回は、簡単のために script タグで直接 -`bower_components` 以下の JavaScript/CSS を -読み込みます。 - - - -今回の実習はテスト駆動形式ではありません。 - -満足のいく Web アプリケーションが書けたら、 -`qualityOfYourAppliation` に `true` を -代入してください。 - -[http://localhost:8000/stage6/](http://localhost:8000/stage6/) - - - -#### クリアできたら - -Lint をかけてみましょう。 - - gulp lint-stage6 - -警告があれば、修正してみてください。 - - - -### ステージ7 - -よくあるイディオムを読むトレーニング - - - -このステージでは、よくある JavaScript の -不思議な書き方を学びます。 - -なお、今回はヒントがありません! -ぜひ自分で調べて、結果を確かめてみてください! - - - -なお、興味のある方は、ステージ「闇」に -挑戦してみてくださいね! - -`.skip` を削除すれば挑戦できるようにに -なります。 - - - -#### 実習 - -下のテストが green になるように、 -`public/stage7/tests.js` を -修正してください。 - -[http://localhost:8000/stage7/](http://localhost:8000/stage7/) - - - -#### クリアできたら - -Lint をかけてみましょう。 - - gulp lint-stage7 - -警告があれば、修正してみてください。 - - - -付録 ----- - - - -### 解答・解説について - -解答は [2015-example-solution](https://github.com/mixi-inc/JavaScriptTraining/compare/2015...2015-example-solution) で見られます! - - - -### Promise について - - - -#### Promise による平行非同期処理 - -Promise による平行非同期処理を通常のやりかたと、 -Promise らしいやり方とでやってみました。 - -コードを比較してみてください。 - - - -```javascript -// 2つの Web API からレスポンスが欲しい! - -var done = { foo: false, bar: false }; -var responses = { foo: null, bar: false }; -fetch('/api/foo').then(function(responseFoo) { - if (!done.bar) { - done.foo = true; - responses.foo = responseFoo; - return; - } - doSomething(responseFoo, responses.bar); -}); -fetch('/api/bar').then(function(responseBar) { - if (!done.foo) { - done.bar = true; - responses.bar = responseFoo; - return; - } - doSomething(responses.foo, responseBar); -}); -``` - -レスポンス取得の待ち合わせ処理があり、 -状態を複数もつ厄介なコードにしあがっていますね。 - - - -```javascript -// 2つの Web API からレスポンスが欲しい! - -Promise.all([ - fetch('/api/foo'), - fetch('/api/bar') -]) -.then(function(responses) { - var responseFoo = responses[0]; - var responseBar = responses[1]; - doSomething(responseFoo, responseBar); -}); -``` - -`Promise.all` を使うと、待ち合わせ処理が -なくスッキリ! - - - -#### Promise による直列非同期処理 - -直列非同期処理についても、通常のやり方と、 -Promise らしいやり方でやってみました。 - -コードを比較してみてください。 - - - -```javascript -// Web API の結果を利用して別の API を実行したい! - -fetch('/api/foo').then(function(responseFoo) { - doSomething(responseFoo); - fetch('/api/bar').then(function(responseBar) { - doSomething(responseBar); - fetch('/api/buz').then(function(responseBuz) { - doSomething(responseBuz); - }); - }); -}); -``` - -コードがネストしているので、後ろの方の -関数のスコープが深くなってしまっています。 -変数を追跡するのに手間がかかりそうです。 - - - -ネストの外に出すだけならば、終了コールバックを -呼び出す[継続渡しスタイル](http://ja.wikipedia.org/wiki/%E7%B6%99%E7%B6%9A%E6%B8%A1%E3%81%97%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB) で -書くことができます。 - -```javascript -// Web API の結果を利用して別の API を実行したい! - -fetch('/api/foo').then(callbackFoo); - -function callbackFoo(responseFoo) { - doSomething(responseFoo); - fetchBar(callbackBar); -} - -function fetchBar(callback) { - fetch('/api/bar').then(callback); -} - -function callbackBar(responseBar) { - doSomething(responseBar); - fetchBuz(callbackBuz); -} - -function fetchBuz(callback) { - fetch('/api/buz').then(callback); -} - -function callbackBuz(responseBuz) { - doSomething(responseBuz); -} -``` - -流れが追いづらい! - - - -クロージャー + 継続渡しスタイルを使うと… - -```javascript -// Web API の結果を利用して別の API を実行したい! - -fetch('/api/foo').then(fetchBar(fetchBuz(doSomething))); - -function fetchBar(callback) { - return function(responseFoo) { - doSomething(responseFoo); - fetchBar(callback); - }; -} - -function fetchBuz(callback) { - return function(responseBar) { - doSomething(responseBar); - fetchBuz(callback); - }; -} -``` - - - -これはこれで美しい…😌 - -(JS に慣れるまではちょっと読みづらいと思います) - - - -Promise らしいやり方をとると `.then` で -次々に処理を連結できます。 - -```javascript -// Web API の結果を利用して別の API を実行したい! - -fetch('/api/foo') - .then(doSomething) - .then(function() { return fetch('/api/bar'); }) - .then(doSomething) - .then(function() { return fetch('/api/buz'); }) - .then(doSomething); -``` diff --git a/public/stage1/tests.js b/public/stage1/tests.js index 46f1ed45..6489c7ef 100644 --- a/public/stage1/tests.js +++ b/public/stage1/tests.js @@ -12,7 +12,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // 'change me!' を document.getElementById(elementId) に // 書き換え、ブラウザをリロードしてみてください。 var elementId = 'firebrick'; - var element = 'change me!'; + var element = document.getElementById(elementId); expect(element).to.be.instanceof(HTMLElement); expect(element).to.have.property('id', elementId); @@ -27,7 +27,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // 'change me!' を書き換えてください。 var elementId = 'chocolate'; - var element = 'change me!'; + var element = document.getElementById(elementId); expect(element).to.be.instanceof(HTMLElement); expect(element).to.have.property('id', elementId); @@ -41,7 +41,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // 'change me!' を書き換えてください。 var elementClassName = 'mediumseagreen'; - var elements = 'change me!'; + var elements = document.getElementsByClassName(elementClassName); expect(elements).to.have.length(1); expect(elements[0]).to.have.property('className', elementClassName); @@ -55,7 +55,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // 'change me!' を書き換えてください。 var elementClassName = 'turquoise'; - var elements = 'change me!'; + var elements = document.getElementsByClassName(elementClassName); expect(elements).to.have.length(2); expect(elements[0]).to.have.property('className', elementClassName); @@ -70,7 +70,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // 'change me!' を書き換えてください。 var elementTagName = 'blockquote'; - var elements = 'change me!'; + var elements = document.getElementsByTagName(elementTagName); expect(elements).to.have.length(1); expect(elements[0]).to.have.property('tagName', elementTagName.toUpperCase()); @@ -93,7 +93,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // すると、開発ツール上で
  • ... が選択されます。 // このことから、7 番の赤色の要素の ID は brown だということがわかります。 // では、'change me!' を document.getElementById('brown') に書き換えてみましょう。 - var element = 'change me!'; + var element = document.getElementById('brown'); expect(element).to.have.property(secret('vq'), secret('oebja')); }); @@ -102,7 +102,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('8 番の橙色の要素が1つ取得できる', function() { // 'change me!' を書き換えてください。 - var element = 'change me!'; + var element = document.getElementById('darkorange'); expect(element).to.have.property(secret('vq'), secret('qnexbenatr')); }); @@ -111,7 +111,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('9 番の緑色の要素が1つ取得できる', function() { // 'change me!' を書き換えてください。 - var elements = 'change me!'; + var elements = document.getElementsByClassName('limegreen'); expect(elements).to.have.length(1); expect(elements[0]).to.have.property(secret('pynffAnzr'), secret('yvzrterra')); @@ -121,7 +121,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('10 番の水色の要素が2つ取得できる', function() { // 'change me!' を書き換えてください。 - var elements = 'change me!'; + var elements = document.getElementsByClassName('mediumturquoise'); expect(elements).to.have.length(2); expect(elements[0]).to.have.property(secret('pynffAnzr'), secret('zrqvhzghedhbvfr')); @@ -135,7 +135,8 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // // なお、11 番の青色の要素は li 要素ではありません! // よくみると、色がついているのはさらに内側の要素のようです。 - var elements = 'change me!'; + var elements = document.getElementsByTagName('p'); + console.log(elements); expect(elements).to.have.length(1); expect(elements[0]).to.have.property(secret('gntAnzr'), secret('C')); @@ -152,7 +153,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // // 'change me!' を document.querySelector('#firebrick') に // 書き換えてください。 - var element = 'change me!'; + var element = document.querySelector('#firebrick'); expect(element).to.have.property(secret('vq'), secret('sveroevpx')); @@ -164,7 +165,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('2 番の橙色の要素を querySelector を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var element = 'change me!'; + var element = document.querySelector('#chocolate'); expect(element).to.have.property(secret('vq'), secret('pubpbyngr')); @@ -176,7 +177,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('3 番の緑色の要素を querySelector を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var element = 'change me!'; + var element = document.querySelector('.mediumseagreen'); expect(element).to.have.property(secret('pynffAnzr'), secret('zrqvhzfrnterra')); }); @@ -185,7 +186,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('4 番の水色の要素を querySelectorAll を使って2つ取得できる', function() { // 'change me!' を書き換えてください。 - var elements = 'change me!'; + var elements = document.querySelectorAll('.turquoise'); expect(elements).to.have.length(2); expect(elements[0]).to.have.property(secret('pynffAnzr'), secret('ghedhbvfr')); @@ -196,7 +197,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('5 番の青色の要素を querySelector を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var element = 'change me!'; + var element = document.querySelector('.js-training li blockquote'); expect(element).to.have.property(secret('gntAnzr'), secret('OYBPXDHBGR')); }); @@ -205,7 +206,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('6 番の紫色の要素を querySelector を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var element = 'change me!'; + var element = document.querySelector('[data-js-training="blueviolet"]'); expect(element).to.have.deep.property(secret('qngnfrg.wfGenvavat'), secret('oyhrivbyrg')); @@ -220,7 +221,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // // 'change me!' を '.js-training:nth-child(2) li' // に書き換えてください。 - var selector = 'change me!'; + var selector = '.js-training:nth-child(2) li'; var element = document.querySelector(selector); expect(selector).to.not.have.string('#'); @@ -231,7 +232,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('8 番の橙色の要素を ID セレクタを使わずに1つ取得できる', function() { // 'change me!' を書き換えてください。 - var selector = 'change me!'; + var selector = '.js-training:nth-child(2) li+li'; var element = document.querySelector(selector); expect(selector).to.not.have.string('#'); @@ -245,7 +246,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('12 番の紫色の要素を、属性セレクタと :nth-child(N) セレクタを使わずに1つ取得できる', function() { // 'change me!' を書き換えてください。 - var selector = 'change me!'; + var selector = '.js-training [data-js-training="darkorchid"]'; var element = document.querySelector(selector); expect(selector).to.not.match(/\[\s*name\s*[~\|\^\$\*]?=/); @@ -265,7 +266,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな // 基本的な使い方は document.querySelectorAll と同じです。 // // 'change me!' を $('#brown') に書き換えてください。 - var $element = 'change me!'; + var $element = $('#brown'); expect($element).to.be.instanceof(jQuery); expect($element).to.have.id(secret('oebja')); @@ -275,7 +276,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('8 番の橙色の要素を jQuery を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var $element = 'change me!'; + var $element = $('#darkorange'); expect($element).to.be.instanceof(jQuery); expect($element).to.have.id(secret('qnexbenatr')); @@ -288,7 +289,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('9 番の緑色の要素を jQuery を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var $element = 'change me!'; + var $element = $('.limegreen'); expect($element).to.be.instanceof(jQuery); expect($element).to.have.class(secret('yvzrterra')); @@ -298,7 +299,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('10 番の水色の要素を jQuery を使って2つ取得できる', function() { // 'change me!' を書き換えてください。 - var $element = 'change me!'; + var $element = $('.mediumturquoise'); expect($element).to.be.instanceof(jQuery); expect($element).to.have.length(2); @@ -309,7 +310,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('11 番の青色の要素を jQuery を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var $element = 'change me!'; + var $element = $('p'); expect($element).to.be.instanceof(jQuery); expect($element).to.have.length(1); @@ -320,7 +321,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('12 番の紫色の要素を jQuery を使って1つ取得できる', function() { // 'change me!' を書き換えてください。 - var $element = 'change me!'; + var $element = $('[data-js-training="darkorchid"]'); expect($element).to.be.instanceof(jQuery); expect($element).to.have.length(1); @@ -334,8 +335,7 @@ describe('ステージ1(意図した DOM 要素を取得できるようにな it('動いている寿司要素を取得する', function() { // 'change me!' を書き換えてください。 - var element = 'change me!'; - + var element = document.querySelector('body > div:nth-child(11) > div'); expect(element).to.have.deep.property( secret('grkgPbagrag'), '\uD83C\uDF63'); }); diff --git a/public/stage2/tests.js b/public/stage2/tests.js index b430dfdc..4a0952ae 100644 --- a/public/stage2/tests.js +++ b/public/stage2/tests.js @@ -9,9 +9,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // // ここに以下のコードを記述してください。 // - // var element = document.getElementById('firebrick'); - // element.textContent = element.textContent + element.textContent; - var element = 'change me!'; + var element = document.getElementById('firebrick'); + element.textContent = element.textContent + element.textContent; expect(element).to.have.property(secret('vq'), secret('sveroevpx')); @@ -24,7 +23,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は element 変数に代入してください。 - var element = 'change me!'; + var element = document.getElementById('chocolate'); + element.textContent = element.textContent + element.textContent; expect(element).to.have.property(secret('vq'), secret('pubpbyngr')); @@ -40,8 +40,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は element 変数に代入してください。 - var element = 'change me!'; - + var element = document.querySelector('body > div:nth-child(1) > ul > li.mediumseagreen'); + element.style.backgroundColor = 'limegreen'; expect(element).to.have.property( secret('pynffAnzr'), secret('zrqvhzfrnterra')); @@ -58,8 +58,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は element 変数に代入してください。 - var element = 'change me!'; - + var element = document.querySelector('body > div:nth-child(1) > ul > li.turquoise'); + element.style.opacity = '0.5'; expect(element).to.have.property( secret('pynffAnzr'), secret('ghedhbvfr')); @@ -76,7 +76,9 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は element 変数に代入してください。 - var element = 'change me!'; + var element = document.querySelector('body > div:nth-child(1) > ul > li:nth-child(5) > blockquote'); + console.log(element); + element.style.transform = 'rotate(10deg)'; expect(element).to.have.property( @@ -97,7 +99,12 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // // なお、上に 20px 移動させる方法は複数ありますが、今回は top 属性を // 使う方法を使ってください。 - var element = 'change me!'; + var element = document.querySelector('body > div:nth-child(1) > ul > li:nth-child(6)'); + element.style.top = '-20px'; + element.style.position = 'relative'; + console.log(secret('qngnfrg.wfGenvavat')); + console.log(secret('fglyr.gbc')); + console.log(secret('fglyr.cbfvgvba')); expect(element).to.have.deep.property( @@ -125,10 +132,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // // ここに以下のコードを記述してください。 // - // var $element = $('#brown'); - // $element.text($element.text() + $element.text()); - var $element = 'change me!'; - + var $element = $('#brown'); + $element.text($element.text() + $element.text()); expect($element).to.be.instanceof(jQuery); expect($element).to.have.id(secret('oebja')); @@ -140,8 +145,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は $element 変数に代入してください。 - var $element = 'change me!'; - + var $element = $('#darkorange'); + $element.text($element.text() + $element.text()); expect($element).to.be.instanceof(jQuery); expect($element).to.have.id(secret('qnexbenatr')); @@ -156,7 +161,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は $element 変数に代入してください。 - var $element = 'change me!'; + var $element = $('.limegreen'); + $element.css('background-color', 'mediumseagreen'); expect($element).to.be.instanceof(jQuery); @@ -173,7 +179,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は $element 変数に代入してください。 - var $element = 'change me!'; + var $element = $('.mediumturquoise'); + $element.css('opacity', '0.5'); expect($element).to.be.instanceof(jQuery); @@ -186,7 +193,8 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // ここにコードを記述してください。 // 変更した DOM 要素は $element 変数に代入してください。 - var $element = 'change me!'; + var $element = $('body > div:nth-child(2) > ul > li:nth-child(5) > p'); + $element.css('transform', 'rotate(10deg)'); expect($element).to.be.instanceof(jQuery); @@ -205,7 +213,9 @@ describe('ステージ2(意図した通りに DOM 要素の属性・テキス // // なお、上に 20px 移動させる方法は複数ありますが、今回は top 属性を // 使う方法を使ってください。 - var $element = 'change me!'; + var $element = $('body > div:nth-child(2) > ul > li:nth-child(6)'); + $element.css('top', '-20px'); + $element.css('position', 'relative'); expect($element).to.be.instanceof(jQuery); diff --git a/public/stage3/tests.js b/public/stage3/tests.js index fa3cb6f2..df521b77 100644 --- a/public/stage3/tests.js +++ b/public/stage3/tests.js @@ -8,10 +8,9 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で // // ここに以下のコードを記述してください。 // - // var element = document.querySelector('#firebrick'); - // var ghost = document.querySelector('.firebrick-ghost'); - // element.removeChild(ghost); - + var element = document.querySelector('#firebrick'); + var ghost = document.querySelector('.firebrick-ghost'); + element.removeChild(ghost); var firebrick = document.getElementById('firebrick'); expect(firebrick.childNodes.length).to.equal(1); @@ -22,6 +21,9 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で it('2 番の要素からインベーダー要素を除去する', function() { // ここにコードを記述してください。 + var element = document.getElementById('chocolate'); + var invador = document.querySelector('.chocolate-space-invader'); + element.removeChild(invador); var darkorange = document.getElementById('chocolate'); @@ -32,7 +34,10 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で it('3 番の要素の左右の幽霊要素をすべて除去する', function() { - // ここにコードを記述してください。 + var element = document.querySelector('.mediumseagreen'); + var ghost = document.querySelector('.mediumseagreen-ghosts'); + element.removeChild(ghost); + element.removeChild(element.lastChild); var darkorange = document.querySelector('.mediumseagreen'); @@ -45,6 +50,8 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で elementToAdd.textContent = '\uD83D\uDC2C'; // 上の elementToAdd を追加するコードをここに記述してください。 + var element = document.querySelector('.turquoise'); + element.appendChild(elementToAdd); var turquoise = document.querySelector('.turquoise'); @@ -60,7 +67,9 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で // 上の elementToAdd を、5 番の青色の要素の最初に追加するコードを // ここに記述してください。 - + var parent = document.querySelector('blockquote'); + var child = parent.firstChild; + parent.insertBefore(elementToAdd, child); var blockquote = document.querySelector('blockquote'); expect(blockquote.childNodes.length).to.equal(2); @@ -78,7 +87,7 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で // jQuery でも同じことをおこなってみましょう。 // ここに以下のコードを記述してください。 // - // $('.brown-ghost').remove(); + $('.brown-ghost').remove(); var $brown = $('#brown'); @@ -90,7 +99,7 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で it('7 番の要素からインベーダー要素を除去する', function() { // ここにコードを記述してください。 - + $('.darkorange-space-invader').remove(); var $darkorange = $('#darkorange'); expect($darkorange.children()).to.have.length(0); @@ -104,6 +113,7 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で it('8 番の要素の左右の幽霊要素をすべて除去する', function() { // ここにコードを記述してください。 + $('.limegreen-ghosts').remove(); var $limegreen = $('.limegreen'); @@ -115,7 +125,7 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で var $elementToAdd = $('\uD83D\uDC2C'); // 上の $elementToAdd を追加するコードをここに記述してください。 - + $('.mediumturquoise').append($elementToAdd); var $mediumturquoise = $('.mediumturquoise'); expect($mediumturquoise.children()).to.have.length(1); @@ -127,7 +137,7 @@ describe('ステージ3(意図した通りに DOM 要素の構造を変更で var $elementToAdd = $('\uD83D\uDC1F'); // 上の $elementToAdd を追加するコードをここに記述してください。 - + $('p').prepend($elementToAdd); var $p = $('p'); expect($p.children()).to.have.length(1); diff --git a/public/stage4/tests.js b/public/stage4/tests.js index 599536b6..b72bdcdc 100644 --- a/public/stage4/tests.js +++ b/public/stage4/tests.js @@ -10,10 +10,10 @@ describe('ステージ4(意図通りにイベントを利用できる)', fun // // jQuery じゃない版: // - // var element = document.getElementById('firebrick'); - // element.addEventListener('click', function() { - // element.textContent = Number(element.textContent) + 1; - // }); + var element = document.getElementById('firebrick'); + element.addEventListener('click', function() { + element.textContent = Number(element.textContent) + 1; + }); // // jQuery 版: // @@ -40,6 +40,10 @@ describe('ステージ4(意図通りにイベントを利用できる)', fun var chocolate = document.getElementById('chocolate'); + chocolate.addEventListener('click', function(){ + chocolate.textContent = Number(chocolate.textContent) - 1; + + }); chocolate.dispatchEvent(createClickEvent()); expect(chocolate).to.have.property('textContent', '1'); @@ -51,9 +55,12 @@ describe('ステージ4(意図通りにイベントを利用できる)', fun it('3 番の要素の click イベントで要素を 10 度ずつ回転できる', function() { // ここにコードを記述してください。 - - + var nowDeg = 10; var mediumseagreen = document.querySelector('.mediumseagreen'); + mediumseagreen.addEventListener('click', function(){ + mediumseagreen.style.transform = 'rotate(' + nowDeg + 'deg)'; + nowDeg += 10; + }); mediumseagreen.dispatchEvent(createClickEvent()); expect(mediumseagreen).to.have.deep.property( secret('fglyr.genafsbez'), secret('ebgngr(10qrt)')); @@ -71,6 +78,10 @@ describe('ステージ4(意図通りにイベントを利用できる)', fun var turquoise = document.querySelector('.turquoise'); var turquoiseInput = turquoise.querySelector('input'); + turquoise.addEventListener('change', function(){ + var deg = document.querySelector('body > div:nth-child(1) > ul > li.turquoise > input[type="number"]').value; + turquoise.style.transform = 'rotate(' + deg + 'deg)'; + }); simulateChangeEvent(turquoiseInput, 10); expect(turquoise).to.have.deep.property( @@ -93,8 +104,10 @@ describe('ステージ4(意図通りにイベントを利用できる)', fun // なお、expect(steelblue).to.be.null は上記のテストの要件を満たして // いないので、正解ではありません。 - var steelblue = document.querySelector('.steelblue'); - expect(steelblue).to.have.property('textContent', '5 \uD83D\uDC33'); + document.addEventListener('onload', function(){ + var steelblue = document.querySelector('.steelblue'); + expect(steelblue).to.have.property('textContent', '5 \uD83D\uDC33'); + }); done(); }); }); diff --git a/public/stage5/tests.js b/public/stage5/tests.js index 568548d3..e028704e 100644 --- a/public/stage5/tests.js +++ b/public/stage5/tests.js @@ -9,10 +9,10 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', // // ここに下記のコードを記述してください。 // - // promise.then(function(msg) { - // expect(msg).to.equal('resolved!'); - // testDone(); - // }); + promise.then(function(msg) { + expect(msg).to.equal('resolved!'); + testDone(); + }); }); @@ -22,10 +22,10 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', // reject ハンドラーを使って、下の assertion が promise の // エラー値を検証できるように記述してください。 // - // expect(msg).to.equal('rejected!'); - // testDone(); - - // ここにコードを記述してください。 + promise.catch(function(msg){ + expect(msg).to.equal('rejected!'); + testDone(); + }); }); @@ -38,7 +38,12 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', var promise3 = createWaitPromise(messageFragments[2], 30); // 作成した promise を promise 変数に代入してください。 - var promise = 'change me!'; + var promise = Promise.all([ + promise1, + promise2, + promise3 + ]); + return expect(promise).to.eventually.deep.equal(messageFragments); @@ -52,7 +57,11 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', var promise3 = createWaitPromise(messageFragments[2], 30); // 作成した promise を promise 変数に代入してください。 - var promise = 'change me!'; + var promise = Promise.race([ + promise1, + promise2, + promise3 + ]); return expect(promise).to.eventually.equal(messageFragments[1]); @@ -69,9 +78,9 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', // // ここに下記のコードを記述してください。 // - // var promisedFriends = fetch(api + username).then(function(res) { - // return res.json(); - // }); + var promisedFriends = fetch(api + username).then(function(res) { + return res.json(); + }); return expect(promisedFriends).to.eventually.have.length(1) @@ -84,7 +93,9 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', var username = 'Shen'; // 作成した promise を promisedFriends 変数に代入してください。 - var promisedFriends = 'change me!'; + var promisedFriends = fetch(api + username).then(function(res) { + return res.json(); + }); return expect(promisedFriends).to.eventually.have.length(2) @@ -95,9 +106,30 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', it('/api/friends API を使って Shen の友人の友人を取得できる', function() { var api = '/api/friends/'; var username = 'Shen'; + // 答案を見た + // 友人を取得する + function getFriends(usernameTo){ + return fetch(api + usernameTo) + .then(function(res){ + return res.json(); + }); + } + + // array => flatten + function flatMap(array){ + return array.reduce(function(flatArray, a){ + return flatArray.concat(a); + }, []); + } // 作成した promise を promisedFriends 変数に代入してください。 - var promisedFriends = 'change me!'; + var promisedFriends = getFriends(username) + .then(function(friends){ + return Promise.all(friends.map(getFriends)); + }) + .then(function(friendsArray) { + return flatMap(friendsArray); + }); return expect(promisedFriends).to.eventually.have.length(1) @@ -127,7 +159,10 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', it('Github の mixi-inc の organization の情報を取得できる', function() { // 作成した promise を mixiOrg 変数に代入してください。 - var mixiOrg = 'change me!'; + var mixiOrg = fetch('https://api.github.com/orgs/mixi-inc') + .then(function(res){ + return res.json(); + }); return expect(mixiOrg).to.eventually.have.property('id', 1089312); @@ -140,7 +175,10 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', var repository = 'mixi-inc/JavaScriptTraining'; // 作成した promise を mixiRepo 変数に代入してください。 - var mixiRepo = 'change me!'; + var mixiRepo = fetch('https://api.github.com/repos/' + repository) + .then(function(res){ + return res.json(); + }); return expect(mixiRepo).to.eventually.have.property('full_name', repository); @@ -153,7 +191,30 @@ describe('ステージ5(意図通りに非同期処理を利用できる)', it('Github API を使って、VimL、Emacs Lisp でスターが最も多いプロダクト名を' + 'それぞれ 1 つずつ取得できる', function() { var languages = [ 'VimL', '"Emacs Lisp"' ]; - var mostPopularRepos = 'change me!'; + + function makeQuery(queryMap){ + return Object.keys(queryMap) + .map(function(key) { + return encodeURIComponent(key) + '=' + encodeURIComponent(queryMap[key]); + }) + .join('&'); + } + + function searchMostPopularRepoByLang(lang){ + var queryString = makeQuery({ + q: 'language:' + lang, + sort: 'stars' + }); + + return fetch('https://api.github.com/search/repositories?' + queryString) + .then(function(res){ + return res.json(); + }) + .then(function(res){ + return res.items[0].full_name; + }); + } + var mostPopularRepos = Promise.all(languages.map(searchMostPopularRepoByLang)); // 作成した promise を mostPopularRepos 変数に代入してください。 diff --git a/public/stage6/sample/bower.json b/public/stage6/sample/bower.json new file mode 100644 index 00000000..731d1c67 --- /dev/null +++ b/public/stage6/sample/bower.json @@ -0,0 +1,21 @@ +{ + "name": "sample", + "version": "0.0.0", + "homepage": "https://github.com/jajkeqos/JavaScriptTraining", + "authors": [ + "jajkeqos" + ], + "description": "sample test", + "license": "MIT", + "private": true, + "ignore": [ + "**/.*", + "node_modules", + "bower_components", + "test", + "tests" + ], + "dependencies": { + "Buttons": "~2.0.0" + } +} diff --git a/public/stage6/tests.js b/public/stage6/tests.js index 12920d31..70d30140 100644 --- a/public/stage6/tests.js +++ b/public/stage6/tests.js @@ -5,7 +5,7 @@ describe('ステージ6(意図通りにモジュールを書ける)', functi // ボタンはサービスです。 // 自由に使ってください。 - var qualityOfYourAppliation = undefined; + var qualityOfYourAppliation = true; expect(qualityOfYourAppliation).to.be.ok; }); diff --git a/public/stage7/tests.js b/public/stage7/tests.js index 3a72ba58..13ba1885 100644 --- a/public/stage7/tests.js +++ b/public/stage7/tests.js @@ -14,39 +14,39 @@ describe('ステージ7(よくあるJSのイディオムを読める)', func it('1回目の値がわかる', function() { - expect(counter()).to.equal(/* ここに値を書き込んでください */); + expect(counter()).to.equal(0/* ここに値を書き込んでください */); }); it('2回目の値がわかる', function() { - expect(counter()).to.equal(/* ここに値を書き込んでください */); + expect(counter()).to.equal(1/* ここに値を書き込んでください */); }); it('3回目の値がわかる', function() { - expect(counter()).to.equal(/* ここに値を書き込んでください */); + expect(counter()).to.equal(2/* ここに値を書き込んでください */); }); }); describe('ショートサーキット演算', function() { it("true && 'default' の結果がわかる", function() { - expect(true && 'default').to.equal(/* ここに値を書き込んでください */); + expect(true && 'default').to.equal('default'/* ここに値を書き込んでください */); }); it("false || 'default' の結果がわかる", function() { - expect(false || 'default').to.equal(/* ここに値を書き込んでください */); + expect(false || 'default').to.equal('default'/* ここに値を書き込んでください */); }); it("0 || 'default' の結果がわかる", function() { - expect(0 || 'default').to.equal(/* ここに値を書き込んでください */); + expect(0 || 'default').to.equal('default'/* ここに値を書き込んでください */); }); it("{} || 'default' の結果がわかる", function() { - expect({} || 'default').to.deep.equal(/* ここに値を書き込んでください */); + expect({} || 'default').to.deep.equal({}/* ここに値を書き込んでください */); }); @@ -55,7 +55,7 @@ describe('ステージ7(よくあるJSのイディオムを読める)', func return arg || { foo: 'foo' }; }; - expect(func({ foo: 'bar' })).to.deep.equal(/* ここに値を書き込んでください */); + expect(func({ foo: 'bar' })).to.deep.equal({ foo: 'bar' }/* ここに値を書き込んでください */); }); @@ -64,7 +64,7 @@ describe('ステージ7(よくあるJSのイディオムを読める)', func return arg || { foo: 'foo' }; }; - expect(func()).to.deep.equal(/* ここに値を書き込んでください */); + expect(func()).to.deep.equal({ foo: 'foo'}/* ここに値を書き込んでください */); }); }); @@ -76,7 +76,7 @@ describe('ステージ7(よくあるJSのイディオムを読める)', func num = 1; })(); - expect(num).to.equal(/* ここに値を書き込んでください */); + expect(num).to.equal(1/* ここに値を書き込んでください */); }); @@ -87,7 +87,7 @@ describe('ステージ7(よくあるJSのイディオムを読める)', func num = 1; }, 0); - expect(num).to.equal(/* ここに値を書き込んでください */); + expect(num).to.equal(0/* ここに値を書き込んでください */); }); @@ -97,22 +97,22 @@ describe('ステージ7(よくあるJSのイディオムを読める)', func it('!!truthy の結果がわかる', function() { - expect(!!truthy).to.equal(/* ここに値を書き込んでください */); + expect(!!truthy).to.equal(true/* ここに値を書き込んでください */); }); it('!!falsey の結果がわかる', function() { - expect(!!falsey).to.equal(/* ここに値を書き込んでください */); + expect(!!falsey).to.equal(false/* ここに値を書き込んでください */); }); it('Boolean(truthy) の結果がわかる', function() { - expect(Boolean(truthy)).to.equal(/* ここに値を書き込んでください */); + expect(Boolean(truthy)).to.equal(true/* ここに値を書き込んでください */); }); it('Boolean(falsey) の結果がわかる', function() { - expect(Boolean(falsey)).to.equal(/* ここに値を書き込んでください */); + expect(Boolean(falsey)).to.equal(false/* ここに値を書き込んでください */); }); }); @@ -137,71 +137,71 @@ describe('ステージ7(よくあるJSのイディオムを読める)', func it('parent.grandParent の値がわかる', function() { - expect(parent.grandParent).to.equal(/* ここに値を書き込んでください */); + expect(parent.grandParent).to.equal(true/* ここに値を書き込んでください */); }); it('parent.child の値がわかる', function() { - expect(parent.child).to.equal(/* ここに値を書き込んでください */); + expect(parent.child).to.equal(undefined/* ここに値を書き込んでください */); }); it('child.grandParent の値がわかる', function() { - expect(child.grandParent).to.equal(/* ここに値を書き込んでください */); + expect(child.grandParent).to.equal(true/* ここに値を書き込んでください */); }); it('child.parent の値がわかる', function() { - expect(child.parent).to.equal(/* ここに値を書き込んでください */); + expect(child.parent).to.equal(true/* ここに値を書き込んでください */); }); }); }); -describe.skip('あなたの闇のJS力', function() { +describe('あなたの闇のJS力', function() { // .skip を外せば始められます describe('ゆるふわ == 演算子', function() { it("'10' == 10 の振る舞いがわかる", function() { expect('10' == 10) - .to.equal(/* ここに値を書き込んでください */); + .to.equal(true); }); it('null == undefined の振る舞いがわかる', function() { expect(null == undefined) - .to.equal(/* ここに値を書き込んでください */); + .to.equal(true/* ここに値を書き込んでください */); }); it('null == false の振る舞いがわかる', function() { expect(null == false) - .to.equal(/* ここに値を書き込んでください */); + .to.equal(false/* ここに値を書き込んでください */); }); it('true == 1 の振る舞いがわかる', function() { expect(true == 1) - .to.equal(/* ここに値を書き込んでください */); + .to.equal(true/* ここに値を書き込んでください */); }); it('true == 10 の振る舞いがわかる', function() { expect(true == 10) - .to.equal(/* ここに値を書き込んでください */); + .to.equal(false); }); it('[0, 1] == 0 の振る舞いがわかる', function() { expect([0, 1] == 0) - .to.equal(/* ここに値を書き込んでください */); + .to.equal(false/* ここに値を書き込んでください */); }); it('[1] == 1 の振る舞いがわかる', function() { expect([1] == 1) - .to.equal(/* ここに値を書き込んでください */); + .to.equal(true/* ここに値を書き込んでください */); }); }); @@ -209,72 +209,72 @@ describe.skip('あなたの闇のJS力', function() { describe('意図しない truthy/falsey', function() { it('Boolean(false) が truthy/falsey のどちらなのかわかる', function() { expect(Boolean(false) ? true : false) - .to.equal(/* ここに値を書き込んでください */); + .to.equal(false/* ここに値を書き込んでください */); }); it('Boolean(0) が truthy/falsey のどちらなのかわかる', function() { expect(Boolean(0) ? true : false) - .to.equal(/* ここに値を書き込んでください */); + .to.equal(false/* ここに値を書き込んでください */); }); it('new Boolean(0) が truthy/falsey のどちらなのかわかる', function() { expect(new Boolean(0) ? true : false) - .to.equal(/* ここに値を書き込んでください */); + .to.equal(true/* ここに値を書き込んでください */); }); it("'abc' が truthy/falsey のどちらなのかわかる", function() { expect('abc' ? true : false) - .to.equal(/* ここに値を書き込んでください */); + .to.equal(true/* ここに値を書き込んでください */); }); it("'' が truthy/falsey のどちらなのかわかる", function() { expect('' ? true : false) - .to.equal(/* ここに値を書き込んでください */); + .to.equal(false/* ここに値を書き込んでください */); }); it('String(0) が truthy/falsey のどちらなのかわかる', function() { expect(String(0) ? true : false) - .to.equal(/* ここに値を書き込んでください */); + .to.equal(true/* ここに値を書き込んでください */); }); it("String('') が truthy/falsey のどちらなのかわかる", function() { expect(String('') ? true : false) - .to.equal(/* ここに値を書き込んでください */); + .to.equal(false/* ここに値を書き込んでください */); }); it('new String(0) が truthy/falsey のどちらなのかわかる', function() { expect(new String(0) ? true : false) - .to.equal(/* ここに値を書き込んでください */); + .to.equal(true/* ここに値を書き込んでください */); }); it("new String('') が truthy/falsey のどちらなのかわかる", function() { expect(new String('') ? true : false) - .to.equal(/* ここに値を書き込んでください */); + .to.equal(true/* ここに値を書き込んでください */); }); }); describe('読めないキャスト万歳!', function() { it("10 + '' の値がわかる", function() { - expect(10 + '').to.equal(/* ここに値を書き込んでください */); + expect(10 + '').to.equal('10'/* ここに値を書き込んでください */); }); it("+'10' の値がわかる", function() { - expect(+'10').to.equal(/* ここに値を書き込んでください */); + expect(+'10').to.equal(10/* ここに値を書き込んでください */); }); it("'10.1'|0 の値がわかる", function() { - expect('10.1'|0).to.equal(/* ここに値を書き込んでください */); + expect('10.1'|0).to.equal(10/* ここに値を書き込んでください */); }); @@ -282,51 +282,53 @@ describe.skip('あなたの闇のJS力', function() { var obj = { length: 2, 0: 'foo', 1: 'bar' }; expect(Array.prototype.slice.call(obj)) - .to.deep.equal(/* ここに値を書き込んでください */); + .to.deep.equal(['foo', 'bar']/* ここに値を書き込んでください */); }); it('+(new Date()) の型がわかる', function() { expect(typeof +(new Date())) - .to.equal(/* ここに値を書き込んでください */); + .to.equal('number'/* ここに値を書き込んでください */); }); it('(new Date()) + 0 の型がわかる', function() { expect(typeof ((new Date()) + 0)) - .to.equal(/* ここに値を書き込んでください */); + .to.equal('string'/* ここに値を書き込んでください */); }); }); describe('ダブルスタンダード Array コンストラクタ', function() { it('Array(3) が作成する配列の長さがわかる', function() { - expect(Array(3)).to.have.length(/* ここに値を書き込んでください */); + expect(Array(3)).to.have.length(3/* ここに値を書き込んでください */); }); it('Array(3) が作成する配列の0番目の要素がわかる', function() { - expect(Array(3)[0]).to.equal(/* ここに値を書き込んでください */); + expect(Array(3)[0]).to.equal(undefined/* ここに値を書き込んでください */); }); it('Array(3) が作成する配列がわかる', function() { - expect(Array(3)).to.deep.equal(/* ここに値を書き込んでください */); + var array = []; + array.length = 3; + expect(Array(3)).to.deep.equal(array/* ここに値を書き込んでください */); }); it('Array(1, 2, 3) が作成する配列の長さがわかる', function() { - expect(Array(1, 2, 3)).to.have.length(/* ここに値を書き込んでください */); + expect(Array(1, 2, 3)).to.have.length(3/* ここに値を書き込んでください */); }); it('Array(1, 2, 3) が作成する配列の0番目の要素がわかる', function() { - expect(Array(1, 2, 3)[0]).to.equal(/* ここに値を書き込んでください */); + expect(Array(1, 2, 3)[0]).to.equal(1/* ここに値を書き込んでください */); }); it('Array(1, 2, 3) が作成する配列がわかる', function() { - expect(Array(1, 2, 3)).to.deep.equal(/* ここに値を書き込んでください */); + expect(Array(1, 2, 3)).to.deep.equal([1, 2, 3]/* ここに値を書き込んでください */); }); }); @@ -336,7 +338,7 @@ describe.skip('あなたの闇のJS力', function() { var obj = { foo: 'bar' }; with (obj) { - expect(foo).to.equal(/* ここに値を書き込んでください */); + expect(foo).to.equal('bar'/* ここに値を書き込んでください */); } }); @@ -345,7 +347,7 @@ describe.skip('あなたの闇のJS力', function() { var obj = { 'foo': 'bar', 'undefined': 'bar' }; with (obj) { - expect(foo === undefined).to.equal(/* ここに値を書き込んでください */); + expect(foo === undefined).to.equal(true/* ここに値を書き込んでください */); } }); @@ -354,7 +356,7 @@ describe.skip('あなたの闇のJS力', function() { var obj = { 'foo': 'bar', 'null': 'bar' }; with (obj) { - expect(foo === null).to.equal(/* ここに値を書き込んでください */); + expect(foo === null).to.equal(false/* ここに値を書き込んでください */); } }); }); @@ -362,35 +364,35 @@ describe.skip('あなたの闇のJS力', function() { describe('JavaScript のゆるふわ型判定', function() { it('typeof 0 の結果がわかる', function() { - expect(typeof 0).to.equal(/* ここに値を書き込んでください */); + expect(typeof 0).to.equal('number'/* ここに値を書き込んでください */); }); it('typeof true の結果がわかる', function() { - expect(typeof true).to.equal(/* ここに値を書き込んでください */); + expect(typeof true).to.equal('boolean'/* ここに値を書き込んでください */); }); it("typeof 'string' の結果がわかる", function() { - expect(typeof 'string').to.equal(/* ここに値を書き込んでください */); + expect(typeof 'string').to.equal('string'/* ここに値を書き込んでください */); }); it('typeof function() {} の結果がわかる', function() { - expect(typeof function() {}).to.equal(/* ここに値を書き込んでください */); + expect(typeof function() {}).to.equal('function'/* ここに値を書き込んでください */); }); it('typeof {} の結果がわかる', function() { - expect(typeof {}).to.equal(/* ここに値を書き込んでください */); + expect(typeof {}).to.equal('object'/* ここに値を書き込んでください */); }); it('typeof [] の結果がわかる', function() { - expect(typeof []).to.equal(/* ここに値を書き込んでください */); + expect(typeof []).to.equal('object'/* ここに値を書き込んでください */); }); it('typeof undefined の結果がわかる', function() { - expect(typeof undefined).to.equal(/* ここに値を書き込んでください */); + expect(typeof undefined).to.equal('undefined'/* ここに値を書き込んでください */); }); it('typeof null の結果がわかる', function() { - expect(typeof null).to.equal(/* ここに値を書き込んでください */); + expect(typeof null).to.equal('object'/* ここに値を書き込んでください */); }); }); });