├── solutions ├── this │ └── index.js ├── function-return-values │ └── index.js ├── introduction │ └── index.js ├── numbers │ └── index.js ├── variables │ └── index.js ├── number-to-string │ └── index.js ├── strings │ └── index.js ├── string-length │ └── index.js ├── accessing-array-values │ └── index.js ├── object-properties │ └── index.js ├── arrays │ └── index.js ├── arrow-functions │ └── index.js ├── rounding-numbers │ └── index.js ├── function-arguments │ └── index.js ├── functions │ └── index.js ├── looping-through-arrays │ └── index.js ├── revising-strings │ └── index.js ├── for-loop │ └── index.js ├── objects │ └── index.js ├── object-keys │ └── index.js ├── array-filtering │ └── index.js ├── callback │ └── index.js ├── object-spreading │ └── index.js ├── if-statement │ └── index.js ├── destructuring │ └── index.js ├── fizzbuzz │ └── index.js ├── arrays-more │ └── index.js ├── fetch │ └── index.mjs ├── use-regex-luke │ └── index.js ├── booleans │ └── index.js ├── closure │ └── index.js ├── scope │ └── index.js ├── null-undefined │ └── index.js ├── promise │ └── index.js ├── async-await │ └── index.js ├── promise-all │ └── index.js └── pagination │ └── index.js ├── .prettierignore ├── problems ├── this │ ├── problem_ja.md │ └── solution_ja.md ├── function-return-values │ ├── problem_ja.md │ └── solution_ja.md ├── closure │ ├── solution_ja.md │ └── problem_ja.md ├── fetch │ ├── solution_ja.md │ └── problem_ja.md ├── scope │ ├── solution_ja.md │ └── problem_ja.md ├── function-arguments │ ├── solution_ja.md │ └── problem_ja.md ├── string-length │ ├── solution_ja.md │ └── problem_ja.md ├── arrays-more │ ├── solution_ja.md │ └── problem_ja.md ├── strings │ ├── solution_ja.md │ └── problem_ja.md ├── array-filtering │ ├── solution_ja.md │ └── problem_ja.md ├── arrays │ ├── solution_ja.md │ └── problem_ja.md ├── booleans │ ├── solution_ja.md │ └── problem_ja.md ├── variables │ ├── solution_ja.md │ └── problem_ja.md ├── functions │ ├── solution_ja.md │ └── problem_ja.md ├── objects │ ├── solution_ja.md │ └── problem_ja.md ├── promise │ ├── solution_ja.md │ └── problem_ja.md ├── pagination │ ├── solution_ja.md │ └── problem_ja.md ├── use-regex-luke │ ├── solution_ja.md │ └── problem_ja.md ├── arrow-functions │ ├── solution_ja.md │ └── problem_ja.md ├── numbers │ ├── solution_ja.md │ └── problem_ja.md ├── object-properties │ ├── solution_ja.md │ └── problem_ja.md ├── rounding-numbers │ ├── solution_ja.md │ └── problem_ja.md ├── async-await │ ├── solution_ja.md │ └── problem_ja.md ├── if-statement │ ├── solution_ja.md │ └── problem_ja.md ├── number-to-string │ ├── solution_ja.md │ └── problem_ja.md ├── accessing-array-values │ ├── solution_ja.md │ └── problem_ja.md ├── null-undefined │ ├── solution_ja.md │ └── problem_ja.md ├── promise-all │ ├── solution_ja.md │ └── problem_ja.md ├── callback │ ├── solution_ja.md │ └── problem_ja.md ├── revising-strings │ ├── solution_ja.md │ └── problem_ja.md ├── looping-through-arrays │ ├── solution_ja.md │ └── problem_ja.md ├── for-loop │ ├── solution_ja.md │ └── problem_ja.md ├── object-keys │ ├── solution_ja.md │ └── problem_ja.md ├── fizzbuzz │ ├── solution_ja.md │ └── problem_ja.md ├── object-spreading │ ├── solution_ja.md │ └── problem_ja.md ├── introduction │ ├── solution_ja.md │ └── problem_ja.md └── destructuring │ ├── solution_ja.md │ └── problem_ja.md ├── .gitignore ├── bin └── javascripting ├── i18n ├── footer │ └── ja.md ├── troubleshooting_ja.md └── ja.json ├── lib ├── footer.js ├── get-file.js ├── compare-solution.js ├── run-solution.js └── problem.js ├── README.md ├── TROUBLESHOOTING.md ├── package.json ├── menu.json ├── index.js ├── LICENSE.md └── CONTRIBUTING.md /solutions/this/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /solutions/function-return-values/index.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /problems/strings/problem_ja.md 2 | -------------------------------------------------------------------------------- /problems/this/problem_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | --- 4 | -------------------------------------------------------------------------------- /problems/this/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | --- 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | .settings 4 | -------------------------------------------------------------------------------- /solutions/introduction/index.js: -------------------------------------------------------------------------------- 1 | console.log("hello"); 2 | -------------------------------------------------------------------------------- /problems/function-return-values/problem_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | --- 4 | -------------------------------------------------------------------------------- /problems/function-return-values/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 3 | --- 4 | -------------------------------------------------------------------------------- /solutions/numbers/index.js: -------------------------------------------------------------------------------- 1 | const example = 123456789; 2 | console.log(example); 3 | -------------------------------------------------------------------------------- /solutions/variables/index.js: -------------------------------------------------------------------------------- 1 | const example = "some string"; 2 | console.log(example); 3 | -------------------------------------------------------------------------------- /solutions/number-to-string/index.js: -------------------------------------------------------------------------------- 1 | const number = 128; 2 | console.log(number.toString()); 3 | -------------------------------------------------------------------------------- /solutions/strings/index.js: -------------------------------------------------------------------------------- 1 | const someString = "this is a string"; 2 | console.log(someString); 3 | -------------------------------------------------------------------------------- /bin/javascripting: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require("../index").execute(process.argv.slice(2)); 4 | -------------------------------------------------------------------------------- /solutions/string-length/index.js: -------------------------------------------------------------------------------- 1 | const example = "example string"; 2 | console.log(example.length); 3 | -------------------------------------------------------------------------------- /i18n/footer/ja.md: -------------------------------------------------------------------------------- 1 | **ヘルプが必要ですか??** このワークショップのREADMEを読んでください。: https://github.com/ledsun/javascripting 2 | -------------------------------------------------------------------------------- /solutions/accessing-array-values/index.js: -------------------------------------------------------------------------------- 1 | const food = ["apple", "pizza", "pear"]; 2 | 3 | console.log(food[1]); 4 | -------------------------------------------------------------------------------- /solutions/object-properties/index.js: -------------------------------------------------------------------------------- 1 | const food = { 2 | types: "only pizza", 3 | }; 4 | 5 | console.log(food.types); 6 | -------------------------------------------------------------------------------- /solutions/arrays/index.js: -------------------------------------------------------------------------------- 1 | const pizzaToppings = ["tomato sauce", "cheese", "pepperoni"]; 2 | console.log(pizzaToppings); 3 | -------------------------------------------------------------------------------- /solutions/arrow-functions/index.js: -------------------------------------------------------------------------------- 1 | const eat = (food) => food + " tasted really good."; 2 | 3 | console.log(eat("apples")); 4 | -------------------------------------------------------------------------------- /solutions/rounding-numbers/index.js: -------------------------------------------------------------------------------- 1 | const roundUp = 1.5; 2 | const rounded = Math.round(roundUp); 3 | console.log(rounded); 4 | -------------------------------------------------------------------------------- /solutions/function-arguments/index.js: -------------------------------------------------------------------------------- 1 | function math(a, b, c) { 2 | return b * c + a; 3 | } 4 | 5 | console.log(math(53, 61, 67)); 6 | -------------------------------------------------------------------------------- /problems/closure/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 検証成功です! 3 | 4 | カウンターが動作しました。 5 | 6 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 7 | --- 8 | -------------------------------------------------------------------------------- /solutions/functions/index.js: -------------------------------------------------------------------------------- 1 | function eat(food) { 2 | return food + " tasted really good."; 3 | } 4 | 5 | console.log(eat("bananas")); 6 | -------------------------------------------------------------------------------- /solutions/looping-through-arrays/index.js: -------------------------------------------------------------------------------- 1 | const pets = ["cat", "dog", "rat"]; 2 | 3 | for (const pet of pets) { 4 | console.log(pet + "s"); 5 | } 6 | -------------------------------------------------------------------------------- /problems/fetch/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # fetchを使ってデータを取得できましたね! 3 | 4 | これでこの演習は終わりです。 5 | 6 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 7 | --- 8 | -------------------------------------------------------------------------------- /problems/scope/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 素晴らしい! 3 | 4 | やるね! 二番目の関数が、求めていたスコープを持っています。 5 | 6 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 7 | --- 8 | -------------------------------------------------------------------------------- /problems/function-arguments/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # もう引数を自在に使えますね 3 | 4 | これでこの演習は終わりです。 5 | 6 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 7 | --- 8 | -------------------------------------------------------------------------------- /solutions/revising-strings/index.js: -------------------------------------------------------------------------------- 1 | const pizza = "pizza is alright"; 2 | const replaced = pizza.replace("alright", "wonderful"); 3 | console.log(replaced); 4 | -------------------------------------------------------------------------------- /solutions/for-loop/index.js: -------------------------------------------------------------------------------- 1 | let total = 0; 2 | const limit = 10; 3 | 4 | for (let i = 0; i < limit; i++) { 5 | total += i; 6 | } 7 | 8 | console.log(total); 9 | -------------------------------------------------------------------------------- /problems/string-length/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 14文字が取れました 3 | 4 | やりました! 文字列 `example string` は14文字です。 5 | 6 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 7 | --- 8 | -------------------------------------------------------------------------------- /solutions/objects/index.js: -------------------------------------------------------------------------------- 1 | const pizza = { 2 | toppings: ["cheese", "sauce", "pepperoni"], 3 | crust: "deep dish", 4 | serves: 2, 5 | }; 6 | 7 | console.log(pizza); 8 | -------------------------------------------------------------------------------- /problems/arrays-more/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 君は配列操作の魔術師 3 | 4 | 配列の操作ができましたね! 5 | 6 | これでこの演習は終わりです。 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /problems/strings/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # パチパチ! 3 | 4 | 文字列の使い方に慣れてきました。 5 | 6 | 次の課題では文字列の長さを扱います。 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /solutions/object-keys/index.js: -------------------------------------------------------------------------------- 1 | const car = { 2 | make: "Honda", 3 | model: "Accord", 4 | year: 2020, 5 | }; 6 | const keys = Object.keys(car); 7 | 8 | console.log(keys); 9 | -------------------------------------------------------------------------------- /problems/array-filtering/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # フィルターされました! 3 | 4 | いいですね。フィルターができましたよ。 5 | 6 | 次の課題に挑戦しましょう。 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /problems/arrays/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # ヘイ、ピザお待ちぃ! 3 | 4 | 配列の作成ができました! 5 | 6 | 次の課題では、配列の値にアクセスする例に取り組みます。 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /problems/booleans/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 白黒ついた! 3 | 4 | 真偽値の挙動はあらかた把握できましたね! 5 | 6 | 次は **if 文** です。準備はいいですか? 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /problems/variables/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 変数を作れました! 3 | 4 | 素晴らしい仕事です。 5 | 6 | 次の課題では **文字列** をもっと詳しく見てみましょう。 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /solutions/array-filtering/index.js: -------------------------------------------------------------------------------- 1 | const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 2 | 3 | const filtered = numbers.filter((number) => number % 2 === 0); 4 | 5 | console.log(filtered); 6 | -------------------------------------------------------------------------------- /solutions/callback/index.js: -------------------------------------------------------------------------------- 1 | // console.time("setTimeout"); 2 | 3 | setTimeout(() => { 4 | console.log("callback function is executed!"); 5 | // console.timeEnd("setTimeout"); 6 | }, 1000); 7 | -------------------------------------------------------------------------------- /problems/functions/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # バナナウマー 3 | 4 | やったね! 5 | 入力を取り、それを処理し、結果を返す関数が作れました。 6 | 7 | 次の課題は、関数の引数です。 8 | 9 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 10 | --- 11 | -------------------------------------------------------------------------------- /problems/objects/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # ピザオブジェクト準備完了 3 | 4 | オブジェクトを生成できました! 5 | 6 | 次の課題では、オブジェクトのプロパティへのアクセスを見てみましょう。 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /problems/promise/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 信じるか信じないかはあなた次第です 3 | 4 | `Promise` をうまく取り扱うことができましたね! 5 | 6 | これでこの演習は終わりです。 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /problems/pagination/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # You are Pagination Master! 3 | 4 | ページネーションの実装をすることができましたね! 5 | 6 | これでこの演習は終わりです。 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /problems/use-regex-luke/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 8888888 3 | 4 | 正規表現を乱用するのはよくありませんが、有効に使えると非常に強力です。 5 | 6 | これでこの演習は終わりです。 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /problems/arrow-functions/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 膝に矢を受けてしまってな... 3 | 4 | やったね! 5 | 関数をより簡素に記述することができました。 6 | 7 | これでこの演習は終わりです。 8 | 9 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 10 | --- 11 | -------------------------------------------------------------------------------- /problems/numbers/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # イエーイ!めっちゃナンバー! 3 | 4 | イェィイェィ!変数を数値 `123456789` として定義できました。 5 | 6 | 次の課題では、数値の変更を扱います。 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /problems/object-properties/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 出前はピザ、それが俺のジャスティス。 3 | 4 | よくぞプロパティにアクセスしました。 5 | 6 | 次の課題では、 **関数** のすべてを説明します。 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /problems/rounding-numbers/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 丸く収まりました 3 | 4 | 良い仕事ですね。`1.5` が `2` に見事に丸まっています。 5 | 6 | 次の課題では、数値を文字列に変換します。 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /problems/async-await/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # あなたは「あしんく」派? 「えいしんく」派? 3 | 4 | `async` / `await` を使った非同期処理が書けましたね! 5 | 6 | これでこの演習は終わりです。 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /problems/if-statement/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 達人の条件クリア! 3 | 4 | やったね! `orange` の文字数は 5 を超えています。 5 | 6 | 次は **for loop** です。準備はいいですか? 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /problems/number-to-string/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 見て見て、数値が文字列になったわ! 3 | 4 | よくできました。数値を文字列に変換する良い動きです。 5 | 6 | 次の課題では、 **真偽値** を見てみましょう。 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /solutions/object-spreading/index.js: -------------------------------------------------------------------------------- 1 | const obj1 = { 2 | key1: "A", 3 | key2: "A", 4 | }; 5 | 6 | const obj2 = { 7 | key2: "B", 8 | key3: "C", 9 | }; 10 | 11 | console.log({ ...obj1, ...obj2 }); 12 | -------------------------------------------------------------------------------- /problems/accessing-array-values/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 配列の2番目の要素が出力されました! 3 | 4 | いいですね。配列の要素にアクセスできました。 5 | 6 | 次の課題では、配列のループの例に取り組みます。 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /problems/null-undefined/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # Great, you've got "none"! 3 | 4 | `null` と `undefined` の性質は理解できましたか? 5 | 6 | これでこの演習は終わりです。 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /problems/promise-all/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 複数の `Promise` を操る 3 | 4 | `Promise.all` と `Promise.any` をうまく取り扱うことができましたね! 5 | 6 | これでこの演習は終わりです。 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 9 | --- 10 | -------------------------------------------------------------------------------- /problems/callback/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 1 秒後に呼ばれる関数 3 | 4 | 1 秒後に関数が呼ばれることを確認できましたか? 5 | (実際には 1000ms 以上経った後に呼ばれているはずです。) 6 | 7 | これでこの演習は終わりです。 8 | 9 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 10 | --- 11 | -------------------------------------------------------------------------------- /problems/revising-strings/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # pizza is wonderful です! 4 | 5 | `.replace()` メソッドがいい感じです。 6 | 7 | つづいて **数値** の探検をしましょう。 8 | 9 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 10 | 11 | --- 12 | -------------------------------------------------------------------------------- /solutions/if-statement/index.js: -------------------------------------------------------------------------------- 1 | const fruit = "orange"; 2 | if (fruit.length > 5) { 3 | console.log("The fruit name has more than five characters."); 4 | } else { 5 | console.log("The fruit name has five characters or less."); 6 | } 7 | -------------------------------------------------------------------------------- /problems/looping-through-arrays/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # パチパチパチ! ペット盛り沢山! 4 | 5 | `pets` 配列内のそれぞれの要素を順に処理することができました! 6 | 7 | 次の課題では、配列を離れ **オブジェクト** へ行きましょう。 8 | 9 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 10 | 11 | --- 12 | -------------------------------------------------------------------------------- /problems/for-loop/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 1から9まで足したら45 3 | 4 | for ループの基本的な使い方がわかりました。 for ループはいろいろな場面で便利です。 5 | 特に文字列や配列のようなデータ型と組み合わせるのが最高です。 6 | 7 | 次の課題では **配列** に取り組みましょう。 8 | 9 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 10 | --- 11 | -------------------------------------------------------------------------------- /problems/object-keys/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # よろしい。 3 | 4 | `Object.keys()` を使用することで、キーをうまく表示させることができました。オブジェクトのキーを列挙する必要があるときは、この方法を思い出してください。 5 | 6 | 次の課題はオブジェクトのスプレッド構文についてです。 7 | 8 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう. 9 | --- 10 | -------------------------------------------------------------------------------- /solutions/destructuring/index.js: -------------------------------------------------------------------------------- 1 | const pizza = { 2 | toppings: ["cheese", "sauce", "pepperoni"], 3 | crust: "deep dish", 4 | serves: 2, 5 | }; 6 | 7 | const { toppings } = pizza; 8 | const [first, second] = toppings; 9 | console.log(second, first); 10 | -------------------------------------------------------------------------------- /lib/footer.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | module.exports = [ 3 | { text: "---", type: "md" }, 4 | { file: path.join(__dirname, "..", "i18n", "footer", "{lang}.md") }, 5 | { text: "", type: "md" }, 6 | require("workshopper-adventure/default/footer"), 7 | ]; 8 | -------------------------------------------------------------------------------- /problems/fizzbuzz/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 1, 2, Fizz... 3 | 4 | FizzBuzz が実装できましたね! 5 | 6 | もしも余裕がある人はGolfとしてどこまで短く書けるかに挑戦してみてください。ちなみにこの問題の作者である僕は 65 文字でした。もっと短くできるかもしれません。 7 | 8 | これでこの演習は終わりです。 9 | 10 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 11 | --- 12 | -------------------------------------------------------------------------------- /lib/get-file.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | 3 | module.exports = function (filepath) { 4 | return fs 5 | .readFileSync(filepath, "utf8") 6 | .replace(/'/g, "'") 7 | .replace(/"/g, '"') 8 | .replace(/</g, "<") 9 | .replace(/>/g, ">"); 10 | }; 11 | -------------------------------------------------------------------------------- /solutions/fizzbuzz/index.js: -------------------------------------------------------------------------------- 1 | for (let i = 1; i <= 100; i++) { 2 | if (i % 15 === 0) { 3 | console.log("FizzBuzz"); 4 | } else if (i % 3 === 0) { 5 | console.log("Fizz"); 6 | } else if (i % 5 === 0) { 7 | console.log("Buzz"); 8 | } else { 9 | console.log(i); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /problems/object-spreading/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 領域展開! 3 | 4 | 結果は以下のようになるでしょう。 5 | 6 | ```js 7 | { 8 | key1: "A", 9 | key2: "B", 10 | key3: "C", 11 | } 12 | ``` 13 | 14 | より後ろにあるものの方が優先されるようですね。 15 | 16 | 次の課題では関数について学びましょう。 17 | 18 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 19 | --- 20 | -------------------------------------------------------------------------------- /problems/introduction/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # やったね! 4 | 5 | `console.log()` のカッコの間に指定したものを、ターミナルに表示します。 6 | 7 | たとえば... 8 | 9 | ```js 10 | console.log("hello"); 11 | ``` 12 | 13 | ターミナルに `hello` を表示します。 14 | 15 | **文字列** `hello` をターミナルに表示できるようになりました。 16 | 17 | 次の課題では**変数**を学びます。 18 | 19 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 20 | -------------------------------------------------------------------------------- /problems/numbers/problem_ja.md: -------------------------------------------------------------------------------- 1 | JavaScriptの数値は `2` 、`14` 、`4353` のような整数と 2 | 3 | `3.14` 、 `1.5` 、 `100.7893423` のような小数のどちらともを表すことができます。 4 | 5 | ## やってみよう 6 | 7 | `numbers.js` ファイルを作りましょう。 8 | 9 | ファイルの中で、整数の `123456789` を表す、変数 `example` を定義しましょう。 10 | 11 | `console.log` を使い、数値をターミナルに表示しましょう。 12 | 13 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 14 | 15 | `javascripting verify numbers.js` 16 | -------------------------------------------------------------------------------- /solutions/arrays-more/index.js: -------------------------------------------------------------------------------- 1 | const numbers = [...Array(100).keys()]; 2 | 3 | const isPrime = (num) => { 4 | if (num < 2) return false; 5 | 6 | for (let i = 2; i < num; i++) { 7 | if (num % i === 0) return false; 8 | } 9 | 10 | return true; 11 | }; 12 | 13 | const primes = numbers.filter(isPrime).map((num) => Number(num).toString(16)); 14 | 15 | console.log(primes); 16 | -------------------------------------------------------------------------------- /problems/destructuring/solution_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 使いたいやつだけ持ってこよう 3 | 4 | 分割代入は頻繁に使われる構文です。 5 | 一方で、書き方を見てもどう調べればドキュメントに当たるのかが分かりづらい構文でもあります。 6 | なので分割代入 (Destructuring Assignment) という言葉を覚えておくと良いでしょう。 7 | 8 | また、ここでは教えませんでしたが分割代入にはデフォルト値の設定やオブジェクトのキー名とは違う変数の使用など、さまざまな機能があります。 9 | 気になる方は自分で調べてみてください! 10 | 11 | これでこの演習は終わりです。 12 | 13 | コンソールで `javascripting` コマンドを実行します。次の課題を選択しましょう。 14 | --- 15 | -------------------------------------------------------------------------------- /solutions/fetch/index.mjs: -------------------------------------------------------------------------------- 1 | // Top-level await 2 | const todo = await fetchTodo(); 3 | console.log(todo); 4 | 5 | async function fetchTodo() { 6 | const response = await fetch("https://dummyjson.com/todos/1"); 7 | // 200 – 299 の範囲外のステータスの時 8 | if (!response.ok) { 9 | throw new Error(`Error! Status: ${response.status}`); 10 | } 11 | const data = await response.json(); 12 | return data.todo; 13 | } 14 | -------------------------------------------------------------------------------- /solutions/use-regex-luke/index.js: -------------------------------------------------------------------------------- 1 | const zipcodes = ` 2 | correct zipcode 1234567 3 | correct zipcode 111-2222 4 | incorrect zipcode 12345678 5 | incorrect zipcode 1111-222 6 | incorrect zipcode 123-4567-890 7 | incorrect zipcode 123-4567890 8 | `; 9 | 10 | const regex = /[^\d-]\d{7}[^\d-]|[^\d-]\d{3}-\d{4}[^\d-]/g; 11 | 12 | const results = zipcodes.match(regex).map((code) => code.trim()); 13 | console.log(results); 14 | -------------------------------------------------------------------------------- /solutions/booleans/index.js: -------------------------------------------------------------------------------- 1 | console.log((0 == 1) === false); 2 | console.log((0 === 1) === false); 3 | 4 | console.log((10 == "10") === true); 5 | console.log((10 === "10") === false); 6 | 7 | console.log((0 && "") === 0); 8 | console.log((1 && "") === ""); 9 | console.log((0 && 10) === 0); 10 | console.log((1 && 10) === 10); 11 | 12 | console.log((0 || "") === ""); 13 | console.log((1 || "") === 1); 14 | console.log((0 || 10) === 10); 15 | console.log((1 || 10) === 1); 16 | -------------------------------------------------------------------------------- /problems/fizzbuzz/problem_ja.md: -------------------------------------------------------------------------------- 1 | これから for 文や if 文、また教わった知識を使って FizzBuzz ゲームを解いてもらいます。 2 | 3 | # FizzBuzz とは 4 | 5 | > 1 から 100 までの数をプリントするプログラムを書け。 6 | > ただし 3 の倍数のときは数の代わりに `"Fizz"` をプリント、 7 | > 5 の倍数のときは `"Buzz"` とプリント、 8 | > 3 と 5 両方の倍数の場合には `"FizzBuzz"` とプリントすること。 9 | 10 | という問題です。 11 | 12 | # 問題 13 | 14 | `fizzbuzz.js` ファイルを作りましょう。 15 | 16 | FizzBuzz 問題を JavaScript で解いてみてください。 17 | 18 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 19 | 20 | `javascripting verify fizzbuzz.js` 21 | -------------------------------------------------------------------------------- /solutions/closure/index.js: -------------------------------------------------------------------------------- 1 | const makeCounter = () => { 2 | let count = 0; 3 | 4 | const increment = () => { 5 | count++; 6 | return count; 7 | }; 8 | 9 | const decrement = () => { 10 | count--; 11 | return count; 12 | }; 13 | 14 | return [increment, decrement]; 15 | }; 16 | 17 | // 以下は変更しない 18 | const [increment, decrement] = makeCounter(); 19 | console.log(increment()); // 1 20 | console.log(increment()); // 2 21 | console.log(decrement()); // 1 22 | console.log(decrement()); // 0 23 | console.log(increment()); // 1 24 | -------------------------------------------------------------------------------- /problems/number-to-string/problem_ja.md: -------------------------------------------------------------------------------- 1 | 数値を文字列に変換したいことがあります。 2 | 3 | そういう時は `toString()` メソッドを使います。たとえば... 4 | 5 | ```js 6 | const number = 256; 7 | const numString = number.toString(); 8 | ``` 9 | 10 | ## やってみよう 11 | 12 | `number-to-string.js` ファイルを作りましょう。 13 | 14 | ファイルの中で、数値 `128` を表す変数 `number` を定義しましょう。 15 | 16 | 変数 `number` の `toString()` メソッドを呼びましょう。 17 | 18 | `console.log()` を使い、`toString()` メソッドの結果をターミナルに表示しましょう。 19 | 20 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 21 | 22 | ```bash 23 | javascripting verify number-to-string.js 24 | ``` 25 | -------------------------------------------------------------------------------- /solutions/scope/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | 3 | const a = 1; 4 | const b = 2; 5 | const c = 3; 6 | 7 | (function firstFunction() { 8 | const b = 5; 9 | const c = 6; 10 | 11 | (function secondFunction() { 12 | const b = 8; 13 | console.log("a: " + a + ", b: " + b + ", c: " + c); 14 | (function thirdFunction() { 15 | const a = 7; 16 | const c = 9; 17 | 18 | (function fourthFunction() { 19 | const a = 1; 20 | const c = 8; 21 | })(); 22 | })(); 23 | })(); 24 | })(); 25 | -------------------------------------------------------------------------------- /problems/arrays/problem_ja.md: -------------------------------------------------------------------------------- 1 | 配列は、値のリストです。たとえば、こう... 2 | 3 | ```js 4 | const pets = ["cat", "dog", "rat"]; 5 | ``` 6 | 7 | 異なる型の値を含めたり、ネストさせることもできます。 8 | 9 | ```js 10 | ["string", 10, ["nested array"]]; 11 | ``` 12 | 13 | ## やってみよう 14 | 15 | `arrays.js` ファイルを作りましょう。 16 | 17 | ファイルの中で、配列を表す変数 `pizzaToppings` を定義してください。配列は次の3つの文字列変数を順番通りに含みます... 18 | 19 | `tomato sauce, cheese, pepperoni` 20 | 21 | `console.log()` を使って、配列 `pizzaToppings` をターミナルに表示しましょう 22 | 。 23 | 24 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 25 | 26 | ```bash 27 | javascripting verify arrays.js 28 | ``` 29 | -------------------------------------------------------------------------------- /problems/objects/problem_ja.md: -------------------------------------------------------------------------------- 1 | オブジェクトは、配列に似た値のリストです。配列と違い、各要素を整数ではなくキーで識別します。 2 | 3 | たとえば... 4 | 5 | ```js 6 | const foodPreferences = { 7 | pizza: "yum", 8 | salad: "gross", 9 | }; 10 | ``` 11 | 12 | ## やってみよう 13 | 14 | `objects.js` ファイルを作りましょう。 15 | 16 | ファイルの中で、変数 `pizza` を次のようにして定義してください... 17 | 18 | ```js 19 | const pizza = { 20 | toppings: ["cheese", "sauce", "pepperoni"], 21 | crust: "deep dish", 22 | serves: 2, 23 | }; 24 | ``` 25 | 26 | `console.log()` を使って、 `pizza` オブジェクトをターミナルに表示しましょう。 27 | 28 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう... 29 | 30 | ```bash 31 | javascripting verify objects.js 32 | ``` 33 | -------------------------------------------------------------------------------- /problems/introduction/problem_ja.md: -------------------------------------------------------------------------------- 1 | このワークショップで使うディレクトリを作りましょう。 2 | 3 | 次のコマンドを実行して、 `javascripting` ディレクトリを作ります。 4 | 5 | ```bash 6 | mkdir javascripting 7 | ``` 8 | 9 | `javascripting` ディレクトリに移動しましょう。 10 | 11 | ```bash 12 | cd javascripting 13 | ``` 14 | 15 | 次のコマンドで `introduction.js` ファイルを作成します。 16 | 17 | ```bash 18 | touch introduction.js 19 | ``` 20 | 21 | (Windowsを使っているのであれば `type NUL > introduction.js`) 22 | 23 | お好みのエディタでファイルを開きます。次の文を書き足しましょう。 24 | 25 | ```js 26 | console.log("hello"); 27 | ``` 28 | 29 | ファイルを保存します。次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 30 | 31 | ```bash 32 | javascripting verify introduction.js 33 | ``` 34 | -------------------------------------------------------------------------------- /problems/revising-strings/problem_ja.md: -------------------------------------------------------------------------------- 1 | 文字列の中身を書き換えたいことがあります。 2 | 3 | 文字列には用意された機能があります。文字列の中身を調べたり、書き換えたりできます。 4 | 5 | たとえば `.replace()` メソッドは次のように使います... 6 | 7 | ```js 8 | const example = "this example exists"; 9 | const replaced = example.replace("exists", "is awesome"); 10 | console.log(replaced); 11 | ``` 12 | 13 | ## やってみよう 14 | 15 | `revising-strings.js` ファイルを作りましょう。 16 | 17 | ファイルの中で、文字列は `"pizza is alright"` を表す、変数 `pizza` を定義します。 18 | 19 | `.replace()` メソッドを使って `alright` を `wonderful` に変更しましょう。 20 | そしてその結果を `console.log()` を使ってコンソールに表示します。 21 | 22 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 23 | 24 | `javascripting verify revising-strings.js` 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # `@recruit-tech/javascripting` 2 | 3 | Forked from: https://github.com/workshopper/javascripting 4 | 5 | ## Install Node.js 6 | 7 | Make sure Node.js is installed on your computer. 8 | 9 | Install it from [nodejs.org](https://nodejs.org/) 10 | 11 | ### Install `javascripting` with `npm` 12 | 13 | Open your terminal and run this command: 14 | 15 | ``` 16 | npm install -g @recruit-tech/javascripting 17 | ``` 18 | 19 | The `-g` option installs this module globally so that you can run it as a command in your terminal. 20 | 21 | ## Run the workshop 22 | 23 | Open your terminal and run the following command: 24 | 25 | ``` 26 | javascripting 27 | ``` 28 | -------------------------------------------------------------------------------- /problems/string-length/problem_ja.md: -------------------------------------------------------------------------------- 1 | ある文字列の文字数を知りたいことがあります。 2 | 3 | そういう時は `.length` プロパティを使います。たとえば... 4 | 5 | ```js 6 | const example = "example string"; 7 | example.length; 8 | ``` 9 | 10 | `example` と `length` の間にピリオドが必要です。気をつけましょう。 11 | 12 | 上のコードは文字列に含まれる文字の **数** を返します。 13 | 14 | ⚠️: 正確には `.length` が返すのは UTF-16 コード単位の数であり、一部の文字では文字数とは異なる値が返ります。 (e.g.: 👀) 15 | 16 | ## やってみよう 17 | 18 | `string-length.js` ファイルを作りましょう。 19 | 20 | ファイルの中で、変数 `example` を作りましょう。 21 | 22 | 変数 `example` に文字列 `"example string"` を代入しましょう。 23 | 24 | `console.log` を使い、文字列の **length** をターミナルに表示しましょう。 25 | 26 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 27 | 28 | `javascripting verify string-length.js` 29 | -------------------------------------------------------------------------------- /solutions/null-undefined/index.js: -------------------------------------------------------------------------------- 1 | const obj = {}; 2 | console.log(obj.a === undefined); 3 | 4 | const arr = []; 5 | console.log(arr[0] === undefined); 6 | 7 | const id = (x) => x; 8 | console.log(id() === undefined); 9 | 10 | const noop = () => {}; 11 | console.log(noop() === undefined); 12 | 13 | console.log(typeof null === "object"); 14 | console.log(typeof undefined === "undefined"); 15 | 16 | console.log((obj || "default") === obj); 17 | console.log((obj ?? "default") === obj); 18 | 19 | console.log((undefined || "default") === "default"); 20 | console.log((undefined ?? "default") === "default"); 21 | 22 | console.log((false || "default") === "default"); 23 | console.log((false ?? "default") === false); 24 | -------------------------------------------------------------------------------- /solutions/promise/index.js: -------------------------------------------------------------------------------- 1 | const fetchData = (key) => { 2 | return new Promise((resolve, reject) => { 3 | if (key !== "greeting") { 4 | reject(new Error(`unknown key: ${key}`)); 5 | return; 6 | } 7 | 8 | setTimeout(() => { 9 | resolve("Hello"); 10 | }, 1000); 11 | }); 12 | }; 13 | 14 | const processData = (data) => `data: ${data}`; 15 | 16 | const fetchAndDisplayData = (key) => { 17 | return fetchData(key) 18 | .then((data) => processData(data)) 19 | .then((data) => { 20 | console.log(data); 21 | }) 22 | .catch((e) => { 23 | console.error(e); 24 | }); 25 | }; 26 | 27 | fetchAndDisplayData("greeting"); 28 | fetchAndDisplayData("credential"); 29 | -------------------------------------------------------------------------------- /problems/rounding-numbers/problem_ja.md: -------------------------------------------------------------------------------- 1 | 基本的な数値処理には、`+`、 `-`、 `*`、 `/`、 `%` といった、おなじみの演算子を使います。 2 | 3 | より複雑な数値処理をするときは、 `Math` オブジェクトを使います。 4 | 5 | この課題では、 `Math` を使って数値を丸め(四捨五入し)ます。 6 | 7 | ## やってみよう 8 | 9 | rounding-numbers.jsファイルを作りましょう。 10 | 11 | ファイルの中で、小数 `1.5` を表す、変数 `roundUp` を定義しましょう。 12 | 13 | `Math.round()` メソッドを使って数値を切り上げましょう。 このメソッドは引数の数値を四捨五入して、最も近いの整数を返します。 14 | 15 | `Math.round()` メソッドの使用例です... 16 | 17 | ```js 18 | Math.round(0.5); 19 | ``` 20 | 21 | 第二の変数 `rounded` を定義します。この変数は `Math.round()` メソッドの結果を表します。引数には `roundUp` 変数を指定します。 22 | 23 | `console.log` を使い、数値をターミナルに表示しましょう。 24 | 25 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 26 | 27 | ```bash 28 | javascripting verify rounding-numbers.js 29 | ``` 30 | -------------------------------------------------------------------------------- /i18n/troubleshooting_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | # 残念ながら、何かがうまく動いていません。 3 | # でも、あわててはいけません。 4 | --- 5 | 6 | ## あなたの解答を確認してみましょう... 7 | 8 | 期待する解答 =================== 9 | 10 | ``` 11 | %solution% 12 | ``` 13 | 14 | あなたが試した結果 =================== 15 | 16 | ``` 17 | %attempt% 18 | ``` 19 | 20 | その違い =================== 21 | 22 | ``` 23 | %diff% 24 | ``` 25 | 26 | (「期待する解答」や「あなたが試した結果」、「その違い」などは改行などが別の文字に置き換えられて表示されている可能性があります。) 27 | 28 | ## その他の解決方法... 29 | 30 | - ファイル名をタイプミスしていませんか? ls `%filename%` を実行すれば確認できます。もし ls: cannot access `%filename%`: No such file or directory と表示されたら、新しいファイルを作るか、すでにあるファイルの名前を変えるか、ファイルがあるディレクトリを変更する必要があるかもしれません。 31 | - カッコを省略していませんか?省略するとコンパイラはJavaScriptファイル正しく読むことができません。 32 | - ファイルの中身にタイプミスはありませんか? 33 | -------------------------------------------------------------------------------- /TROUBLESHOOTING.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | ### `EACCESS` error 4 | 5 | If you get an `EACCESS` error, the simplest way to fix this is to rerun the command, in either of the following ways: 6 | 7 | - On unix shells, prefix the command with sudo 8 | 9 | > `sudo npm install --global javascripting` 10 | 11 | - On Windows and if using either PowerShell or CMD, ensure you open the shell with administrator privilege. 12 | 13 | You can also fix the permissions so that you don't have to use `sudo`. Take a look at this npm documentation: 14 | https://docs.npmjs.com/getting-started/fixing-npm-permissions 15 | 16 | ### `EEXIST` error 17 | 18 | Make sure you are using an active version of Node.js. Active versions can be found [here](https://nodejs.org/en/about/releases/). 19 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@recruit-tech/javascripting", 3 | "description": "Learn JavaScript by adventuring around in the terminal.", 4 | "version": "3.0.4", 5 | "repository": { 6 | "url": "https://github.com/recruit-tech/javascripting.git" 7 | }, 8 | "author": "yosuke-furukawa", 9 | "bin": { 10 | "javascripting": "./bin/javascripting" 11 | }, 12 | "dependencies": { 13 | "colors": "1.4.0", 14 | "diff": "5.2.0", 15 | "workshopper-adventure": "7.0.0" 16 | }, 17 | "devDependencies": { 18 | "prettier": "3.2.5" 19 | }, 20 | "engines": { 21 | "node": ">=16.20.1" 22 | }, 23 | "license": "MIT", 24 | "main": "./index.js", 25 | "preferGlobal": true, 26 | "scripts": { 27 | "format": "prettier -w ." 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /problems/array-filtering/problem_ja.md: -------------------------------------------------------------------------------- 1 | 配列にはいろいろな操作方法があります。 2 | 3 | よくやる処理に、配列にフィルターをかけて特定の値を取り出すというものがあります。 4 | 5 | フィルターをかけるには、 `.filter()` メソッドを使います。 6 | 7 | たとえば... 8 | 9 | ```js 10 | const pets = ["cat", "dog", "elephant"]; 11 | 12 | const filtered = pets.filter((pet) => pet !== "elephant"); 13 | ``` 14 | 15 | `フィルターした` 配列の中には `cat` と `dog` だけが残ります。 16 | 17 | ## やってみよう 18 | 19 | `array-filtering.js` ファイルを作りましょう。 20 | 21 | ファイルの中で、 次の配列を表す、変数 `numbers` を定義しましょう。 22 | 23 | ```js 24 | [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 25 | ``` 26 | 27 | 次に変数 `numbers` から偶数のみを抜き出した変数 `filtered` を定義しましょう。 28 | 29 | 最後に `console.log()` を使って、 `フィルターした` 配列をターミナルに表示しましょう。 30 | 31 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 32 | 33 | ```bash 34 | javascripting verify array-filtering.js 35 | ``` 36 | -------------------------------------------------------------------------------- /problems/callback/problem_ja.md: -------------------------------------------------------------------------------- 1 | HTTP リクエストなどの処理を同期的に実行すると、上から順に実行されるために非常に時間が掛かります。 2 | この問題への対策として、処理を非同期に実行することが可能です。 3 | 4 | 非同期処理を記述する方法はいくつかありますが、中でも理解しやすいものとしてコールバック関数という方法があります。 5 | 6 | たとえば `setTimeout(callback, ms)` という関数では、指定の時間が経過した後に実行されるようなコールバック関数を設定することができます。 7 | 第一引数にコールバック関数、第二引数にはコールバック関数が実行されるまでに待機する時間をミリ秒単位で指定します。 8 | 9 | ## やってみよう 10 | 11 | `timeout.js` ファイルを作りましょう。 12 | 13 | `setTimeout` 関数を使って 1 秒後に `"callback function is executed!"` と出力してください。 14 | 15 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 16 | 17 | `javascripting verify timeout.js` 18 | 19 | もしも余裕がある人は `console.time` / `console.timeEnd` 関数を使ってコールバック関数が呼ばれるまでに掛かった時間を計測して出力してみましょう。 20 | 21 | - `console.time(label)`: 時間計測を開始します 22 | - `console.timeEnd(label)`: 対応する `label` の時間計測を終了し、経過した時間を出力します。 23 | -------------------------------------------------------------------------------- /menu.json: -------------------------------------------------------------------------------- 1 | [ 2 | "INTRODUCTION", 3 | "VARIABLES", 4 | "STRINGS", 5 | "STRING LENGTH", 6 | "REVISING STRINGS", 7 | "NUMBERS", 8 | "ROUNDING NUMBERS", 9 | "NUMBER TO STRING", 10 | "BOOLEANS", 11 | "IF STATEMENT", 12 | "FOR LOOP", 13 | "ARRAYS", 14 | "ACCESSING ARRAY VALUES", 15 | "LOOPING THROUGH ARRAYS", 16 | "OBJECTS", 17 | "OBJECT PROPERTIES", 18 | "OBJECT KEYS", 19 | "OBJECT SPREADING", 20 | "FUNCTIONS", 21 | "FUNCTION ARGUMENTS", 22 | "ARROW FUNCTIONS", 23 | "NULL UNDEFINED", 24 | "DESTRUCTURING", 25 | "CALLBACK", 26 | "PROMISE", 27 | "PROMISE ALL", 28 | "ASYNC AWAIT", 29 | "ARRAY FILTERING", 30 | "ARRAYS MORE", 31 | "FETCH", 32 | "FIZZBUZZ", 33 | "USE REGEX LUKE", 34 | "SCOPE", 35 | "CLOSURE", 36 | "PAGINATION" 37 | ] 38 | -------------------------------------------------------------------------------- /problems/functions/problem_ja.md: -------------------------------------------------------------------------------- 1 | 関数はコードのまとまりです。入力を受け取ります。受け取った入力を処理し、結果を返します。 2 | 3 | たとえば... 4 | 5 | ```js 6 | function example(x) { 7 | return x * 2; 8 | } 9 | ``` 10 | 11 | 上の関数を、次のように **呼び出す** と、数値 `10` が得られます... 12 | 13 | ```js 14 | example(5); 15 | ``` 16 | 17 | 上記の例では、 `example` 関数が1つの数値を引数 (入力) として取り、その数に2を掛けて返します。 18 | 19 | ## やってみよう 20 | 21 | `functions.js` ファイルを作りましょう。 22 | 23 | ファイルの中で、関数 `eat` を定義します。 24 | `eat` は、ひとつの引数 `food` を受け取ります。 25 | その引数は文字列であることを期待します。 26 | 27 | 関数内で、 `food` 引数を次のように処理して返してください... 28 | 29 | ```js 30 | return food + " tasted really good."; 31 | ``` 32 | 33 | `console.log()` の括弧の中で、 `eat()` 関数を呼んで、引数として `bananas` という文字列を与えてください。 34 | 35 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 36 | 37 | ```bash 38 | javascripting verify functions.js 39 | ``` 40 | -------------------------------------------------------------------------------- /problems/accessing-array-values/problem_ja.md: -------------------------------------------------------------------------------- 1 | 配列の要素には添え字を使ってアクセスできます。 2 | 3 | 添え字は `0` から `配列の長さ - 1` までの数です。 4 | 5 | 以下に例を示します... 6 | 7 | ```js 8 | const pets = ["cat", "dog", "rat"]; 9 | 10 | console.log(pets[0]); 11 | ``` 12 | 13 | 上記のコードは配列 `pets` の最初の要素、つまり文字列 `cat` を表示します。 14 | 15 | 配列の要素には角括弧を使うとアクセスできます。 16 | 17 | 有効な書き方 18 | 19 | ```js 20 | console.log(pets[0]); 21 | ``` 22 | 23 | `pets.0` のようにドット表記を使ってもアクセスできません。 24 | 25 | ## やってみよう 26 | 27 | `accessing-array-values.js` ファイルを作りましょう。 28 | 29 | ファイルの中で、次の配列 `food` を定義します。 30 | 31 | ```js 32 | const food = ["apple", "pizza", "pear"]; 33 | ``` 34 | 35 | `console.log()` を使って、配列の `2` 番目の値をターミナルに出力してください。 36 | 37 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 38 | 39 | ```bash 40 | javascripting verify accessing-array-values.js 41 | ``` 42 | -------------------------------------------------------------------------------- /problems/variables/problem_ja.md: -------------------------------------------------------------------------------- 1 | 変数は特定の値を示す名前です。 2 | `const` や `let` を使って変数を定義します。 `const`, `let` につづけて変数の名前を書きます。 3 | 4 | 次の例は変数を定義します。定義した変数は特定の値を示します。 5 | 6 | ```js 7 | const example = "some string"; 8 | ``` 9 | 10 | `const` を使って **宣言** します。つづいて、等号を使い、変数が示す値を **定義** します。 11 | 12 | これを「変数に値を代入する」と言います。 13 | 14 | ## `const` or `let` ? 15 | 16 | `const` と `let` の違いは **再代入ができるか** です。 17 | 18 | `const` で宣言した変数には再代入ができませんが、 `let` の場合は再代入ができます。 19 | 20 | 意図しない再代入を防ぐために、基本的には `const` を使いましょう。 21 | `let` は再代入が必要な場合のみに利用してください。 22 | 23 | ## やってみよう 24 | 25 | `variables.js` ファイルを作りましょう。 26 | 27 | ファイルの中で `example` 変数を宣言します。 28 | 29 | **変数** `example` に値 `"some string"` を代入します。 30 | 31 | そして `console.log()` を使い、変数 `example` をコンソールに表示します。 32 | 33 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 34 | 35 | `javascripting verify variables.js` 36 | -------------------------------------------------------------------------------- /problems/strings/problem_ja.md: -------------------------------------------------------------------------------- 1 | **文字列** は引用符でくくった値です。 2 | 3 | 引用符は一重引用符と二重引用符のどちらも使えます。例えば... 4 | 5 | ```js 6 | 'this is a string'; 7 | 8 | "this is also a string"; 9 | ``` 10 | 11 | ## 注意 12 | 13 | どちらかの引用符を使うルールを決め、守りましょう。 14 | このワークショップでは二重引用符だけを使います。 15 | 16 | ## 文字列結合 17 | 18 | 文字列の結合には `+` 演算子を使います。 19 | 20 | 例えば... 21 | 22 | ```js 23 | "名前: " + "progfay"; 24 | "価格: " + 1000 + "円"; 25 | ``` 26 | 27 | また、バッククウォートを使った **テンプレートリテラル** も使えます。 28 | 29 | ```js 30 | `名前: ${'progfay'}`; 31 | `価格: ${1000}円`; 32 | ``` 33 | 34 | ## やってみよう 35 | 36 | `strings.js` ファイルを作りましょう。 37 | 38 | ファイルの中で、次のように変数 `someString` を作りましょう。 39 | 40 | ```js 41 | const someString = "this is a string"; 42 | ``` 43 | 44 | `console.log` を使い、変数 **someString** をターミナルに表示しましょう。 45 | 46 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 47 | 48 | `javascripting verify strings.js` 49 | -------------------------------------------------------------------------------- /problems/function-arguments/problem_ja.md: -------------------------------------------------------------------------------- 1 | 関数の引数はいくつでも宣言できます。引数はどんな型でも大丈夫です。文字列、数値、配列、オブジェクト、関数さえも引数になり得ます。 2 | 3 | たとえば... 4 | 5 | ```js 6 | function example(firstArg, secondArg) { 7 | console.log(firstArg, secondArg); 8 | } 9 | ``` 10 | 11 | 引数が 2 つの関数を **呼び出す** には、次のようにします。 12 | 13 | ```js 14 | example("hello", "world"); 15 | ``` 16 | 17 | 上の例を実行すると、ターミナルに `hello world` と出力されるでしょう。 18 | 19 | ## やってみよう 20 | 21 | `function-arguments.js` ファイルを作りましょう。 22 | 23 | ファイルの中で、関数 `math` を定義します。引数は三つです。 24 | 25 | 重要なことがあります。引数名は引数の値を参照するためだけに使います。引数名は好きに決めてかまいません。 26 | 27 | `math` 関数は、 2 番目と 3 番目の引数を掛け、その結果に 1 番目の引数を足します。そうして得られた値を返してください。 28 | 29 | その後、 `console.log()` の括弧の内側で、 `math()` 関数を呼びます。 30 | 1 番目の引数に数値 `53` を、 2 番目に `61` を、 3 番目に `67` を指定してください。 31 | 32 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 33 | 34 | ```bash 35 | javascripting verify function-arguments.js 36 | ``` 37 | -------------------------------------------------------------------------------- /problems/object-keys/problem_ja.md: -------------------------------------------------------------------------------- 1 | JavaScriptはオブジェクトの利用可能なキーを全て列挙する方法を提供しています。 2 | これは、ループ処理によってオブジェクトに応じた値の操作に役立ちます。 3 | 4 | これは **Object.keys()** を使って全てのオブジェクトのキーを列挙する例です。 5 | 6 | ```js 7 | const car = { 8 | make: "Toyota", 9 | model: "Camry", 10 | year: 2020, 11 | }; 12 | const keys = Object.keys(car); 13 | 14 | console.log(keys); // -> ["make", "model", "year"] 15 | ``` 16 | 17 | 上記のコードでは、文字列の配列が表示されます。 18 | 各文字列はオブジェクトのキーです。 19 | 20 | ## やってみよう 21 | 22 | `object-keys.js` ファイルを作りましょう。 23 | 24 | ファイルの中で、変数 `car` を定義します。 25 | 26 | ```js 27 | const car = { 28 | make: "Honda", 29 | model: "Accord", 30 | year: 2020, 31 | }; 32 | ``` 33 | 34 | そして、別の変数 `keys` を定義します。 35 | 36 | ```js 37 | const keys = Object.keys(car); 38 | ``` 39 | 40 | `console.log()` を使って、変数 `keys` をターミナルに表示しましょう。 41 | 42 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 43 | 44 | ```bash 45 | javascripting verify object-keys.js 46 | ``` 47 | -------------------------------------------------------------------------------- /solutions/async-await/index.js: -------------------------------------------------------------------------------- 1 | const fetchPosts = (user) => { 2 | return new Promise((resolve, reject) => { 3 | setTimeout(() => { 4 | resolve([ 5 | `${user}: post1`, 6 | `${user}: post2`, 7 | `${user}: post3`, 8 | `${user}: post4`, 9 | `${user}: post5`, 10 | ]); 11 | }, 1000); 12 | }); 13 | }; 14 | 15 | const users = ["user1", "user2", "user3", "user4", "user5"]; 16 | 17 | const displayAllPosts = async () => { 18 | for (const user of users) { 19 | const posts = await fetchPosts(user); 20 | for (const post of posts) { 21 | console.log(post); 22 | } 23 | } 24 | }; 25 | 26 | displayAllPosts(); 27 | 28 | const displayAllPostsWithPromiseAll = async () => { 29 | const posts = ( 30 | await Promise.all(users.map((user) => fetchPosts(user))) 31 | ).flat(); 32 | for (const post of posts) { 33 | console.log(post); 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /problems/arrow-functions/problem_ja.md: -------------------------------------------------------------------------------- 1 | アロー関数を使うと `function` で宣言する関数をより簡素に書くことができます。 2 | 3 | たとえば... 4 | 5 | ```js 6 | function example(x) { 7 | return x * 2; 8 | } 9 | 10 | const example = (x) => { 11 | return x * 2; 12 | }; 13 | ``` 14 | 15 | 上記の 2 つの `example` 関数は全く同じ処理をする関数になります。 16 | 17 | また、 `return` のみの関数はより省略して以下のように書くこともできます。 18 | 19 | ```js 20 | const example = (x) => x * 2; 21 | ``` 22 | 23 | `function` で宣言した関数との主な違いは、関数内で `this` が指し示すものが異なる点があります。 24 | しかし `this` の挙動は分かりづらくバグを生む原因となりやすいため、現代の JavaScript では `this` の使用は避けるべきです。 25 | 26 | ## やってみよう 27 | 28 | `arrow-functions.js` ファイルを作りましょう。 29 | 30 | 一つ前の課題で実装した `eat` 関数をアロー関数で書き直してみましょう。 31 | 32 | ```js 33 | function eat(food) { 34 | return food + " tasted really good."; 35 | } 36 | ``` 37 | 38 | `console.log()` の括弧の中で、 `eat()` 関数を呼んで、引数として `apples` という文字列を与えてください。 39 | 40 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 41 | 42 | ```bash 43 | javascripting verify arrow-functions.js 44 | ``` 45 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const fs = require("fs"); 3 | const problem = require("./lib/problem"); 4 | 5 | const i18nDir = path.join(__dirname, "i18n"); 6 | const languages = ["ja"].concat( 7 | fs 8 | .readdirSync(i18nDir) 9 | .filter((f) => f.match(/\w+\.json/)) 10 | .map((f) => f.replace(".json", "")) 11 | .filter((f) => f !== "ja"), 12 | ); 13 | const jsing = require("workshopper-adventure")({ 14 | appDir: __dirname, 15 | languages, 16 | header: require("workshopper-adventure/default/header"), 17 | footer: require("./lib/footer.js"), 18 | }); 19 | 20 | jsing.addAll( 21 | require("./menu.json").map(function (name) { 22 | return { 23 | name, 24 | fn: function () { 25 | const p = name.toLowerCase().replace(/\s/g, "-"); 26 | const dir = require("path").join(__dirname, "problems", p); 27 | return problem(dir); 28 | }, 29 | }; 30 | }), 31 | ); 32 | 33 | module.exports = jsing; 34 | -------------------------------------------------------------------------------- /solutions/promise-all/index.js: -------------------------------------------------------------------------------- 1 | const fetchData = (key) => { 2 | return new Promise((resolve, reject) => { 3 | switch (key) { 4 | case "quick": 5 | setTimeout(() => { 6 | resolve("quick: hi!"); 7 | }, 1000); 8 | break; 9 | 10 | case "medium": 11 | setTimeout(() => { 12 | resolve("medium: hello!!"); 13 | }, 2000); 14 | break; 15 | 16 | case "slow": 17 | setTimeout(() => { 18 | resolve("slow: good morning!!!"); 19 | }, 3000); 20 | break; 21 | 22 | default: 23 | reject(new Error(`unknown key: ${key}`)); 24 | break; 25 | } 26 | }); 27 | }; 28 | 29 | Promise.all([fetchData("quick"), fetchData("medium"), fetchData("slow")]).then( 30 | (dataList) => { 31 | console.log(dataList); 32 | }, 33 | ); 34 | 35 | Promise.any([fetchData("quick"), fetchData("medium"), fetchData("slow")]).then( 36 | (dataList) => { 37 | console.log(dataList); 38 | }, 39 | ); 40 | -------------------------------------------------------------------------------- /problems/object-spreading/problem_ja.md: -------------------------------------------------------------------------------- 1 | スプレッド構文 `...` を使うと、オブジェクトを展開することができます。 2 | 3 | たとえば... 4 | 5 | ```js 6 | const obj1 = { key1: "value1" }; 7 | const obj2 = { key2: "value2" }; 8 | 9 | console.log({ ...obj1, ...obj2 }); // -> { key1: "value1", key2: "value2" } 10 | ``` 11 | 12 | 他にも配列を展開することもできます。 13 | 14 | ```js 15 | const arr1 = [0, 1, 2]; 16 | const arr2 = [3, 4, 5]; 17 | 18 | console.log([...arr1, ...arr2]); // -> [0, 1, 2, 3, 4, 5] 19 | ``` 20 | 21 | ## やってみよう 22 | 23 | 展開したオブジェクトのキーに重複があるとどうなるでしょうか? 24 | 25 | 検証のために `object-spreading.js` ファイルを作りましょう。 26 | 27 | ファイルの中で、変数 `obj1` と `obj2` を次のようにして定義してください... 28 | 29 | ```js 30 | const obj1 = { 31 | key1: "A", 32 | key2: "A", 33 | }; 34 | 35 | const obj2 = { 36 | key2: "B", 37 | key3: "C", 38 | }; 39 | ``` 40 | 41 | スプレッド構文を使って `obj1`, `obj2` の順番で展開し合成したオブジェクトを生成してください。 42 | 43 | そして `console.log()` を使って、合成したオブジェクトをターミナルに表示しましょう。 44 | 45 | 次のコマンドを実行し、あなたのプログラムがどのように動くか確認しましょう... 46 | 47 | ```bash 48 | javascripting verify object-spreading.js 49 | ``` 50 | -------------------------------------------------------------------------------- /problems/looping-through-arrays/problem_ja.md: -------------------------------------------------------------------------------- 1 | この課題では、 **for ループ** を使用して、配列の中の値を取得したり変更したりします。 2 | 3 | 配列の値にアクセスするには、整数を使用します。 4 | 5 | 配列の中のそれぞれの要素は、 `0` からはじまる数値で識別されます。 6 | 7 | たとえば、次の配列内の `hi` は、数値 `1` で識別できます... 8 | 9 | ```js 10 | const greetings = ["hello", "hi", "good morning"]; 11 | ``` 12 | 13 | 次のようにアクセスします... 14 | 15 | ```js 16 | greetings[1]; 17 | ``` 18 | 19 | **for ループ** の中では、変数 `i` を角括弧の中に入れて使います。整数を直接使うことはありません。 20 | 21 | ```js 22 | for (let i = 0; i < greetings.length; i++) { 23 | console.log(greetings[i]); 24 | } 25 | ``` 26 | 27 | ## for...of 28 | 29 | 配列に入った要素を先頭から順に処理する場合、 `for...of` 構文が使えます。 30 | 31 | ```js 32 | for (const greeting of greetings) { 33 | console.log(greeting); 34 | } 35 | ``` 36 | 37 | ## やってみよう 38 | 39 | `looping-through-arrays.js` ファイルを作りましょう。 40 | 41 | ファイルの中で、次の配列を表す、変数 `pets` を定義しましょう。 42 | 43 | ```js 44 | ["cat", "dog", "rat"]; 45 | ``` 46 | 47 | for ループを作って、配列内の各文字列を複数形にしてターミナルに表示しましょう。 48 | 49 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 50 | 51 | ```bash 52 | javascripting verify looping-through-arrays.js 53 | ``` 54 | -------------------------------------------------------------------------------- /i18n/ja.json: -------------------------------------------------------------------------------- 1 | { 2 | "exercise": { 3 | "INTRODUCTION": "はじめの一歩", 4 | "VARIABLES": "変数", 5 | "STRINGS": "文字列", 6 | "STRING LENGTH": "文字列の長さ", 7 | "REVISING STRINGS": "文字列を変更", 8 | "NUMBERS": "数値", 9 | "ROUNDING NUMBERS": "数値丸め", 10 | "NUMBER TO STRING": "数値を文字列に", 11 | "BOOLEANS": "真偽値", 12 | "IF STATEMENT": "if文", 13 | "FOR LOOP": "forループ", 14 | "ARRAYS": "配列", 15 | "ARRAY FILTERING": "配列のフィルター", 16 | "ACCESSING ARRAY VALUES": "配列の値にアクセスする", 17 | "LOOPING THROUGH ARRAYS": "配列をループする", 18 | "OBJECTS": "オブジェクト", 19 | "OBJECT PROPERTIES": "オブジェクトのプロパティ", 20 | "OBJECT KEYS": "オブジェクトのキー", 21 | "OBJECT SPREADING": "スプレッド構文", 22 | "FUNCTIONS": "関数", 23 | "FUNCTION ARGUMENTS": "関数の引数", 24 | "ARROW FUNCTIONS": "アロー関数", 25 | "CLOSURE": "クロージャ", 26 | "DESTRUCTURING": "分割代入", 27 | "CALLBACK": "コールバック関数", 28 | "PROMISE": "Promiseオブジェクト", 29 | "PROMISE ALL": "Promise.all", 30 | "ASYNC AWAIT": "async/await", 31 | "SCOPE": "スコープ", 32 | "USE REGEX LUKE": "正規表現を使え、ルーク", 33 | "FETCH": "Fetch API" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /problems/for-loop/problem_ja.md: -------------------------------------------------------------------------------- 1 | for ループを使うと、コードの塊を何回も繰り返し実行できます。 2 | 3 | 次の for ループはコンソールにログを 10 回書きます... 4 | 5 | ```js 6 | for (let i = 0; i < 10; i++) { 7 | // log the numbers 0 through 9 8 | console.log(i); 9 | } 10 | ``` 11 | 12 | for ループでは、最初の部分 `let i = 0` をループの最初に一回だけ実行します。 13 | ループを実行した回数を数えるために、変数 `i` を使います。 14 | 15 | 第二の部分 `i < 10;` は、ループの繰り返し毎にチェックする条件式です。 16 | チェックした式が真の時、ループ内のコードを実行します。 17 | チェックした式が偽の時、ループを終了します。 18 | 式 `i < 10;` の場合、 `i` が `10` 未満の間、ループを繰り返します。 19 | 20 | 最後の部分 `i++` を、ループが終わるたびに実行します。 21 | この式は、ループを一回まわるたびに、変数 `i` の値を `1` 増やします。 22 | `i` が `10` に達すると、ループを終了します。 23 | 24 | ## やってみよう 25 | 26 | `for-loop.js` ファイルを作りましょう。 27 | 28 | ファイルの中で、数値 `0` の変数 `total` を定義します。 29 | 30 | つづいて、数値 `10` の変数 `limit` を定義します。 31 | 32 | forループを作りましょう。変数 `i` を0から始めループのたびに1増やします。 33 | `i` が `limit` より小さい間、ループを続けましょう。 34 | 35 | ループを繰り返すたびに、 数値 `i` を `total` に足しましょう。こんな風に... 36 | 37 | ```js 38 | total += i; 39 | ``` 40 | 41 | ループが終わったら、 `console.log()` を使い、変数 `total` をターミナルに表示しましょう。 42 | 43 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 44 | 45 | ```bash 46 | javascripting verify for-loop.js 47 | ``` 48 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | ## Copyright (c) 2014 Javascripting contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /solutions/pagination/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @description `range` 関数はこのまま使ってください。 3 | * 4 | * @param {number} start 範囲の開始となる数値 (整数) 5 | * @param {number} end 範囲の終了となる数値 (整数) 6 | * @returns {number[]} 範囲を示す配列 (`[start, end)`) 7 | * @throws {Error} `start` が `end` より大きい場合にエラーが throw されます 8 | * 9 | * @example range(2, 5); // [2, 3, 4] 10 | */ 11 | function range(start, end) { 12 | if (start > end) { 13 | throw new Error( 14 | `range 関数の第一引数 \`start\` は第二引数 \`end\` の値以下である必要があります (start: ${start}, end: ${end})`, 15 | ); 16 | } 17 | 18 | return new Array(end - start).fill(0).map((_, i) => i + start); 19 | } 20 | 21 | function getPageNums(current, total, size) { 22 | const s = current - Math.floor((size - 1) / 2); 23 | const start = s < 1 ? 1 : s + size > total ? total - size + 1 : s; 24 | return range(start, start + size); 25 | } 26 | 27 | console.log(getPageNums(1, 5, 5)); 28 | console.log(getPageNums(3, 5, 5)); 29 | console.log(getPageNums(4, 6, 5)); 30 | console.log(getPageNums(3, 8, 6)); 31 | console.log(getPageNums(4, 8, 6)); 32 | console.log(getPageNums(4, 8, 3)); 33 | console.log(getPageNums(8, 8, 3)); 34 | -------------------------------------------------------------------------------- /problems/if-statement/problem_ja.md: -------------------------------------------------------------------------------- 1 | 条件文を使って、次に実行する文を変更します。プログラムの流れを変更できます。条件は真理値で指定します。 2 | 3 | たとえば... 4 | 5 | ```js 6 | if (n > 1) { 7 | console.log("変数 `n` は 1 より大きい"); 8 | } else { 9 | console.log("変数 `n` は 1 以下だ"); 10 | } 11 | ``` 12 | 13 | カッコの間に論理式を指定します。論理式の結果は真か偽である必要があります。 14 | 15 | `else` ブロックはつけても、つけなくても構いません。つけた場合は、論理式の結果が偽の時に実行されます。 16 | 17 | ## もし ? そうなら : ちがうなら 18 | 19 | if 文の近い存在として三項演算子が存在します。 20 | 三項演算子は `(条件) ? (真のとき) : (偽のとき)` というように記述します。 21 | 22 | たとえば先ほどの if 文は三項演算子を使って次のようにも書けます... 23 | 24 | ```js 25 | const msg = n > 1 ? "1 より大きい" : "1 以下だ"; 26 | 27 | console.log("変数 `n` は " + msg); 28 | ``` 29 | 30 | 短いコード量で条件式を記述できる三項演算子ですが、何重にもネストすると可読性が下がってしまうことがあります。 31 | プロジェクトによってはこれを避けるべく、三項演算子の多用を避ける場合もあるので注意しましょう。 32 | 33 | ## やってみよう 34 | 35 | `if-statement.js` ファイルを作りましょう。 36 | 37 | ファイルの中で、変数 `fruit` を定義しましょう。 38 | 39 | 変数 `fruit` は **文字列型** の **orange** を表します。 40 | 41 | `fruit` の文字数が5より大きかったら、console.log() を使い、 **The fruit name has more than five characters.** をターミナルに表示しましょう。 42 | そうでなければ **The fruit name has five characters or less.** を表示しましょう。 43 | 44 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 45 | 46 | ```bash 47 | javascripting verify if-statement.js 48 | ``` 49 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Code contributions are welcome and highly encouraged! For instructions on and help with creating a great pull request, please read the [workshopper contributing document](https://github.com/workshopper/org/blob/master/CONTRIBUTING.md). 4 | 5 | If you have questions about contributing, please create an issue. 6 | 7 | ## Lead Maintainers 8 | 9 | The role of lead maintainers is to triage and categorize issues, answer questions about contributing to the repository, review and give feedback on PRs, and maintain the quality of a workshopper's codebase and repository. 10 | 11 | **Current Lead Maintainers** 12 | 13 | - Seth Vincent [@sethvincent](https://github.com/sethvincent) 14 | - Adam Brady [@SomeoneWeird](https://github.com/SomeoneWeird) 15 | - Anshul [@AnshulMalik](https://github.com/AnshulMalik) 16 | - Martin Splitt [@AVGP](https://github.com/AVGP) 17 | - Seth [@itzsaga](https://github.com/itzsaga) 18 | - Lawal Sauban [@sauban](https://github.com/sauban) 19 | 20 | ### Volunteer 21 | 22 | Submitting many PRs? Please volunteer to lead this repository! Lead maintainers are selected in the philosophy of [Open Open Source](http://openopensource.org/): 23 | 24 | > Individuals making significant and valuable contributions are given commit-access to the project to contribute as they see fit. 25 | -------------------------------------------------------------------------------- /lib/compare-solution.js: -------------------------------------------------------------------------------- 1 | require("colors"); 2 | 3 | const path = require("path"); 4 | const diff = require("diff"); 5 | const run = require(path.join(__dirname, "run-solution")); 6 | 7 | module.exports = function (solution, attempt, i18n, cb) { 8 | run(solution, i18n, function (err, solutionResult) { 9 | if (err) { 10 | console.error(err); 11 | return cb(err, false); 12 | } 13 | 14 | run(attempt, i18n, function (err, attemptResult) { 15 | if (err && err.code !== 8) { 16 | console.error(err); 17 | return cb(err, false); 18 | } 19 | 20 | if (solutionResult === attemptResult) { 21 | return cb(err, true); 22 | } 23 | 24 | cb(null, false, { 25 | solution: solutionResult, 26 | attempt: err || attemptResult, 27 | diff: generateDiff(solutionResult, attemptResult), 28 | }); 29 | }); 30 | }); 31 | }; 32 | 33 | function generateDiff(solution, attempt) { 34 | const parts = diff.diffChars(solution, attempt); 35 | 36 | let result = ""; 37 | 38 | parts.forEach(function (part) { 39 | if (part.added) { 40 | result += part.value.bgRed; 41 | } else if (part.removed) { 42 | result += part.value.bgGreen; 43 | } else { 44 | result += part.value; 45 | } 46 | }); 47 | 48 | return result; 49 | } 50 | -------------------------------------------------------------------------------- /problems/object-properties/problem_ja.md: -------------------------------------------------------------------------------- 1 | オブジェクトのプロパティの値を取得したり変更したりできます。 2 | プロパティはオブジェクトに含まれるキーと値の組み合わせです。 3 | オブジェクトのプロパティは配列とよく似た方法で操作します。 4 | 5 | 次の例のように角括弧を使います... 6 | 7 | ```js 8 | const example = { 9 | pizza: "yummy", 10 | }; 11 | 12 | console.log(example["pizza"]); 13 | ``` 14 | 15 | 上のコードは、 `"yummy"` とターミナルに出力します。 16 | 17 | 別のやりかたとして、ドット記法を使って同じ結果を得ることもできます... 18 | 19 | ```js 20 | example.pizza; 21 | 22 | example["pizza"]; 23 | ``` 24 | 25 | 上の二つの行は、両方とも `yummy` という値を返します。 26 | 27 | ## 存在しないプロパティへのアクセス 28 | 29 | 以下のようなアクセスはどうなるでしょうか? 30 | 31 | ```js 32 | const obj = {}; 33 | obj.a; 34 | ``` 35 | 36 | 結果は `undefined` が返ってきます。 37 | 38 | また `obj.a.b` のように `undefined` のプロパティにアクセスしようとすると、以下のようなエラーが出ます。 39 | 40 | ```console 41 | Uncaught TypeError: Cannot read properties of undefined (reading 'b') 42 | ``` 43 | 44 | もし `undefined` かもしれないオブジェクトのプロパティにアクセスしたい場合は、 Optional Chaining `?.` を使うと良いでしょう。 45 | 46 | ```js 47 | const obj = {}; 48 | obj.a?.b; // -> undefined 49 | ``` 50 | 51 | ## やってみよう 52 | 53 | `object-properties.js` ファイルを作りましょう。 54 | 55 | ファイルの中で、変数 `food` を次のように定義してください... 56 | 57 | ```js 58 | const food = { 59 | types: "only pizza", 60 | }; 61 | ``` 62 | 63 | `console.log()` を使って、 `food` オブジェクトの `types` プロパティをターミナルに表示しましょう。 64 | 65 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 66 | 67 | ```bash 68 | javascripting verify object-properties.js 69 | ``` 70 | -------------------------------------------------------------------------------- /lib/run-solution.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const exec = require("child_process").exec; 3 | 4 | /** 5 | * @param {!string} filePath 6 | * @return {Promise} 7 | */ 8 | function exists(filePath) { 9 | return new Promise(function (resolve, reject) { 10 | fs.stat(filePath, function (err, d) { 11 | if (err) { 12 | resolve(false); 13 | } 14 | 15 | resolve(true); 16 | }); 17 | }); 18 | } 19 | 20 | /** 21 | * @param {!string} filePath 22 | * @return {Promise} 23 | */ 24 | function executeSolution(filePath) { 25 | return new Promise(function (resolve, reject) { 26 | exec('node "' + filePath + '"', function (err, stdout, stderr) { 27 | if (err) { 28 | return reject(err); 29 | } 30 | 31 | return resolve(stdout); 32 | }); 33 | }); 34 | } 35 | 36 | /** 37 | * @param {string} solutionPath 38 | * @param {!{__: function(string, object)}} i18n 39 | * @param {function} cb 40 | */ 41 | module.exports = function (solutionPath, i18n, cb) { 42 | exists(solutionPath) 43 | .then(function (solutionExists) { 44 | if (!solutionExists) { 45 | throw new Error( 46 | i18n.__("error.exercise.missing_file", { 47 | exerciseFile: solutionPath, 48 | }), 49 | ); 50 | } 51 | 52 | return executeSolution(solutionPath); 53 | }) 54 | .then(function (stdout) { 55 | cb(null, stdout); 56 | }) 57 | .catch(cb); 58 | }; 59 | -------------------------------------------------------------------------------- /problems/destructuring/problem_ja.md: -------------------------------------------------------------------------------- 1 | 分割代入とは、配列やオブジェクトから値を取り出して変数に代入する操作のことです。 2 | 3 | JavaScript では以下のような分割代入ができます。 4 | 5 | ```js 6 | const [first, second] = [1, 2]; 7 | console.log(first, second); // -> 1 2 8 | 9 | const object = { 10 | hoge: "fuga", 11 | piyo: "buzz", 12 | }; 13 | const { hoge, piyo } = object; 14 | console.log(hoge, piyo); // -> fuga buzz 15 | ``` 16 | 17 | また、スプレッド構文 `...` を使って残りの値をまとめて変数に入れることもできます。 18 | 19 | ```js 20 | const [first, second, ...rest] = [1, 2, 3, 4]; 21 | console.log(rest); // -> [3, 4] 22 | ``` 23 | 24 | ```js 25 | const object = { 26 | hoge: "fuga", 27 | piyo: "buzz", 28 | foo: "bar", 29 | }; 30 | const { hoge, ...rest } = object; 31 | console.log(rest); // -> { piyo: "buzz", foo: "bar" } 32 | ``` 33 | 34 | 更には関数の引数など、さまざまな場所で使うことができます。 35 | 36 | ```js 37 | function f({ hoge, piyo }) { 38 | console.log(hoge, piyo); 39 | } 40 | f({ hoge: "fuga", piyo: "buzz" }); // -> fuga buzz 41 | ``` 42 | 43 | ## やってみよう 44 | 45 | `destructuring.js` ファイルを作りましょう。 46 | 47 | ファイルの中で、変数 `pizza` を次のようにして定義してください... 48 | 49 | ```js 50 | const pizza = { 51 | toppings: ["cheese", "sauce", "pepperoni"], 52 | crust: "deep dish", 53 | serves: 2, 54 | }; 55 | ``` 56 | 57 | 変数 `pizza` から `toppings` プロパティの値を分割代入を使って新しい変数に入れてください。 58 | 59 | そして `toppings` の 1 番目と 2 番目の値を、また分割代入を使って新しい変数に入れてください。 60 | 61 | 最後に 2 番目 1 番目の順に `console.log` を使って出力してください。 62 | 63 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 64 | 65 | ```bash 66 | javascripting verify destructuring.js 67 | ``` 68 | -------------------------------------------------------------------------------- /problems/closure/problem_ja.md: -------------------------------------------------------------------------------- 1 | JavaScriptでは、関数定義の内側から外側の変数を参照できます。 2 | 3 | ```js 4 | const makeCounter = () => { 5 | // makeCounterを実行すると、count変数が宣言される 6 | let count = 0; 7 | // count変数は、incrementの関数定義の外側にある 8 | 9 | // incrementの関数定義 10 | const increment = () => { 11 | // incrementの関数定義の内部にcount変数はない 12 | 13 | count++; // 外側のcount変数を参照して更新できる 14 | return count; // 外側のcount変数を参照してreturnできる 15 | }; 16 | 17 | return [increment]; 18 | }; 19 | 20 | const [increment] = makeCounter(); 21 | console.log(increment()); // 1 22 | console.log(increment()); // 2 23 | ``` 24 | 25 | このような動作は、クロージャ(定義時の外側の環境を知っている関数)によって実現されますが、詳細な説明は割愛します。ここでは「JavaScriptの関数では、定義の内側から外側の変数を参照できる」ということがわかっていれば大丈夫です。 26 | 27 | また、`increment`実行時に「`makeCounter`の実行が終了しているにもかかわらず`count`変数を利用できる」ことに驚くかもしれません。 28 | 29 | 一部の言語(C言語など)では、関数内で定義された変数は、その関数の実行が終了すると同時に消えてしまって利用不可能になります。しかしJavaScriptでは、関数によって参照される可能性のある変数は消えません。 30 | 31 | ## やってみよう 32 | 33 | `increment`(プラス1)だけではなく、`decrement`(マイナス1)もできるカウンターを作りましょう。 34 | 35 | `closure.js`ファイルを作成し、以下のテンプレートをコピペしてコードを書いてみてください。 36 | 37 | ```js 38 | // テンプレート 39 | const makeCounter = () => { 40 | // ここにコードを書く 41 | }; 42 | 43 | // 以下は変更しない 44 | const [increment, decrement] = makeCounter(); 45 | console.log(increment()); // 1 46 | console.log(increment()); // 2 47 | console.log(decrement()); // 1 48 | console.log(decrement()); // 0 49 | console.log(increment()); // 1 50 | ``` 51 | 52 | コードが書けたら次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 53 | 54 | ```bash 55 | javascripting verify closure.js 56 | ``` 57 | -------------------------------------------------------------------------------- /problems/use-regex-luke/problem_ja.md: -------------------------------------------------------------------------------- 1 | 文字列の中身にとあるパターンがあり、そのパターンを見つけたい時があります。 2 | 3 | たとえば、文字列の中に電話番号がある (9 桁以上の数字がある) 時などです。 4 | 5 | そのような場合、以下のように正規表現を使用してマッチしているものを見つけます。 6 | 7 | ```js 8 | const example = 9 | "Hello World My Phone Number is 111222333. and this is my zip-code 1112222"; 10 | const result = example.match(/(\d{9,})/g); 11 | console.log(result[0]); //1111222333 12 | ``` 13 | 14 | ## やってみよう 15 | 16 | `regex-strings.js` ファイルを作りましょう。 17 | 18 | 与えられた文字列の中から全ての郵便番号を見つけましょう。 19 | 20 | 郵便番号の定義は 7 文字の数字が並んでいるものと 3 文字と 4 文字の数字がハイフンでつながっているものを指します。 21 | 22 | 以下のものは郵便番号です。 23 | 24 | ``` 25 | 1234567 26 | 111-2222 27 | ``` 28 | 29 | 以下のものは郵便番号ではありません。 30 | 31 | ``` 32 | 12345678 33 | 1111-222 34 | ``` 35 | 36 | まずは下記のように文字列を定義しましょう。 37 | 38 | ```js 39 | const zipcodes = ` 40 | correct zipcode 1234567 41 | correct zipcode 111-2222 42 | incorrect zipcode 12345678 43 | incorrect zipcode 1111-222 44 | `; 45 | ``` 46 | 47 | この文字列に対して、郵便番号のみにマッチする正規表現と `.match()` メソッドを使って郵便番号を抜き出して `console.log` を使って出力しましょう。 48 | 必要があれば `.trim()` メソッドを使って余分な空白や改行などを削除してください。 49 | 50 | 結果が 1234567 と 111-2222 の 2 つが出て、それ以外が出ないことを確認してください。 51 | 52 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 53 | 54 | `javascripting verify regex-strings.js` 55 | 56 | もしも余裕がある人は以下の文字列で正規表現を使って郵便番号かどうかをチェックしましょう。 57 | 58 | ```js 59 | const zipcodes = ` 60 | correct zipcode 1234567 61 | correct zipcode 111-2222 62 | incorrect zipcode 12345678 63 | incorrect zipcode 1111-222 64 | incorrect zipcode 12345678 65 | incorrect zipcode 1111-222 66 | `; 67 | ``` 68 | 69 | 結果が 1234567 と 111-2222 の 2 つが出てそれ以外が出ないことを確認してください。 70 | ヒント:否定 (`^`) を使うといいかもしれません。 71 | -------------------------------------------------------------------------------- /problems/fetch/problem_ja.md: -------------------------------------------------------------------------------- 1 | Fetch API は JavaScript で HTTPリクエストを実行するためのAPIです。 2 | `fetch` 関数の戻り値は `Promise` です。第一引数に URL、第二引数には任意でリクエストのメソッド(デフォルトは `GET`)、ヘッダー、リクエストボディなどを設定できます。 3 | 以下のコードは使用例です。 4 | 5 | ```js 6 | // async awaitを利用する場合 7 | async function fetchData() { 8 | const response = await fetch("https://example.com"); 9 | // 200 – 299 の範囲外のステータスの時 10 | if (!response.ok) { 11 | throw new Error(`Error! Status: ${response.status}`); 12 | } 13 | // レスポンスのボディをJSONとして解析 14 | const data = await response.json(); 15 | return data; 16 | } 17 | 18 | // fetchData関数を呼び出す 19 | const data = await fetchData(); 20 | ``` 21 | 22 | `fetch` 関数の戻り値の `Promise` が解決されると、HTTPレスポンスが `Response` オブジェクトとして取得できます。 23 | この `Response` オブジェクトはいくつかのメソッドを持っています。例えば `.json()` メソッドは、レスポンスボディの中身を JSON として解析し、オブジェクトなどの結果を `Promise` で返します。 24 | 25 | ## やってみよう 26 | 27 | `fetch.mjs` ファイルを作りましょう。 28 | 29 | 今回は、https://dummyjson.com というサイトを利用して、HTTPリクエストを送ってみましょう。 30 | 下記は、https://dummyjson.com へのリクエストとレスポンスの例です。https://dummyjson.com/todos/1 を GET すると、ステータスコードが200で、ボディが「Todoを表すJSON文字列」であるレスポンスが得られます。 31 | 32 | ```js 33 | await fetch("https://dummyjson.com/todos/1"); 34 | 35 | /* response body */ 36 | // {"id":1,"todo":"Do something nice for someone you care about","completed":false,"userId":152} 37 | ``` 38 | 39 | `console.log()` を使って、https://dummyjson.com/todos/1 のレスポンスボディの一部である `todo` プロパティの値を表示しましょう。 40 | 41 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 42 | 43 | ```bash 44 | javascripting verify fetch.mjs 45 | ``` 46 | 47 | ここでは詳しくは述べませんが、ファイル拡張子を `.mjs` にすることで Top-level awaitを利用できます。(Top-level await を使用しているファイル全体が1つの大きな `async` 関数のように機能します。) 48 | -------------------------------------------------------------------------------- /problems/arrays-more/problem_ja.md: -------------------------------------------------------------------------------- 1 | # 配列を使いこなそう 2 | 3 | 配列の中でいくつかの便利なメソッドが有ります。 4 | `map`, `forEach`, `filter`, `find`, `some` などです。 5 | これらの配列を使いこなせるようになると for ループや if 条件分岐などの愚直な処理を関数を組み合わせることで表現できます。 6 | 7 | 例えば以下のコードを見てみましょう。 8 | 9 | ```js 10 | const sports = [ 11 | "football", 12 | "baseball", 13 | "basketball", 14 | "hockey", 15 | "iceskate", 16 | "boxing", 17 | "swimming", 18 | ]; 19 | 20 | for (let i = 0; i < sports.length; i++) { 21 | if (sports[i].includes("ball")) { 22 | console.log(sports[i]); 23 | } 24 | } 25 | ``` 26 | 27 | このコードでは for ループと if 文を使いましたが、 `Array` の `filter` 関数をうまく使うともう少し短く書くことが可能です。 28 | 29 | ```js 30 | sports 31 | .filter((item) => item.includes("ball")) 32 | .forEach((item) => console.log(item)); 33 | ``` 34 | 35 | では `sports` の文字列を大文字に変換してみましょう。 36 | for ループを使うとこうでしょうか。 37 | 38 | ```js 39 | for (let i = 0; i < sports.length; i++) { 40 | console.log(sports[i].toUpperCase()); 41 | } 42 | ``` 43 | 44 | これを `map` 関数を使ってみましょう。 45 | 46 | ```js 47 | sports 48 | .map((item) => item.toUpperCase(item)) 49 | .forEach((item) => console.log(item)); 50 | ``` 51 | 52 | `map` 関数と `filter` 関数は配列から新しい配列を作るための関数です。 53 | 元の配列を変換するのが `map` 関数で、元の関数から条件にあった要素を見つけて抜き出すのが `filter` 関数です。 54 | 55 | `some` 関数はこれらとは違って、条件を満たした要素が一つでも存在するなら真を、そうじゃなければ偽を返す関数です。 56 | `find` 関数は条件を満たした要素を取得するための関数です。 57 | 58 | この他にも色んな関数が存在します。 59 | `reduce` や `slice` 等、他にも便利なものがあるので是非確認すると良いでしょう。 60 | 61 | # 問題 62 | 63 | `array-more.js` ファイルを作りましょう。 64 | 65 | `filter` と `map` を使って以下の配列 `numbers` から素数だけを導き出し、 16 進数に変換してください。 66 | 67 | ```js 68 | // 0 - 99 までの数字 69 | const numbers = [...Array(100).keys()]; 70 | ``` 71 | 72 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 73 | 74 | `javascripting verify array-more.js` 75 | 76 | hint: 16 進数への変換は `Number(i).toString(16)` でできます。 77 | -------------------------------------------------------------------------------- /problems/scope/problem_ja.md: -------------------------------------------------------------------------------- 1 | 「スコープ」は参照できる変数・オブジェクト・関数の集合です。 2 | 3 | JavaScriptには、二つのスコープがあります。グローバルとローカルです。 4 | 関数定義の外側で定義した変数はグローバルスコープです。プログラムのどこからでも参照して変更することができます。 5 | 関数定義の内側で定義した変数はローカルスコープです。関数が実行されるときに作られ、関数が終了すると破棄されます。 6 | 関数外のプログラムからは参照できません。 7 | 8 | 他の関数の中で定義した関数を「ネストした関数」と呼びます。「ネストした関数」からは親関数のスコープを参照できます。 9 | 10 | 次のソースコードのコメントを読んでください... 11 | 12 | ```js 13 | const a = 4; // a はグローバル変数です。下の全ての関数から参照できます。 14 | 15 | function foo() { 16 | const b = a * 3; // b は foo 関数の外からは参照できません。 foo 関数の中で定義した関数 bar からは参照できます。 17 | 18 | function bar(c) { 19 | const b = 2; // bar 関数の中でもう一つ b 変数を定義します 20 | // 新しい b を変更しても、元の b 変数は変わりません。 21 | console.log(a, b, c); 22 | } 23 | 24 | bar(b * 4); 25 | } 26 | 27 | foo(); // 4, 2, 48 28 | ``` 29 | 30 | 即時実行関数式 (Immediately Invoked Function Expression : IIFE) という共通パターンで、ローカルスコープを作れます。 31 | 例えば... 32 | 33 | ```js 34 | (function () { 35 | // 関数式をカッコで括ります 36 | // 変数はここで定義します 37 | // 関数の外からは参照できません 38 | })(); // 関数を即座に実行します 39 | ``` 40 | 41 | ## やってみよう 42 | 43 | `scope.js` ファイルを作りましょう。 44 | ファイルの中に、次のソースコードをコピーしましょう... 45 | 46 | ```js 47 | const a = 1; 48 | const b = 2; 49 | const c = 3; 50 | 51 | (function firstFunction() { 52 | const b = 5; 53 | const c = 6; 54 | 55 | (function secondFunction() { 56 | const b = 8; 57 | 58 | (function thirdFunction() { 59 | const a = 7; 60 | const c = 9; 61 | 62 | (function fourthFunction() { 63 | const a = 1; 64 | const c = 8; 65 | })(); 66 | })(); 67 | })(); 68 | })(); 69 | ``` 70 | 71 | 変数のスコープを活用しましょう。次のコードを関数の中に配置してください。`scope.js` の中の関数です。 72 | そして、目指す出力は `a: 1, b: 8,c: 6` です。 73 | 74 | ```js 75 | console.log(`a: ${a}, b: ${b}, c: ${c}`); 76 | ``` 77 | 78 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 79 | 80 | `javascripting verify scope.js` 81 | -------------------------------------------------------------------------------- /problems/promise/problem_ja.md: -------------------------------------------------------------------------------- 1 | `Promise` は非同期処理を簡潔に記述するためのオブジェクトです。 2 | 3 | 以下は指定時間だけ待機する Promise を返す `sleep` 関数です。 4 | 5 | ```js 6 | const sleep = (ms) => { 7 | return new Promise((resolve, reject) => { 8 | if (ms < 0) { 9 | reject(new Error("sleep duration should be positive number")); 10 | return; 11 | } 12 | 13 | setTimeout(resolve, ms); 14 | }); 15 | }; 16 | ``` 17 | 18 | この `sleep` 関数は以下のように扱うことができます。 19 | 20 | ```js 21 | sleep(1000) 22 | .then(() => { 23 | console.log("after sleep 1000ms"); 24 | }) 25 | .catch((e) => { 26 | console.error(e); 27 | }); 28 | ``` 29 | 30 | また、 `.then` や `.catch` は `Promise` オブジェクトを返すため、非同期処理を繋げて書くことができます。 31 | 32 | ```js 33 | fetch(url) 34 | .then((res) => res.text()) 35 | .then((text) => { 36 | console.log(text); 37 | }) 38 | .catch((e) => { 39 | console.error(e); 40 | }); 41 | ``` 42 | 43 | ## コールバック地獄の解消 44 | 45 | コールバック関数を `Promise` に変換して取り扱うことで、 "コールバック地獄" と呼ばれるようなコールバック関数のネストを解消することが可能です。 46 | 47 | コールバック地獄とは以下のような記述のことです。 48 | 49 | ```js 50 | a(() => { 51 | b(() => { 52 | c(() => { 53 | d(() => { 54 | // : 55 | }); 56 | }); 57 | }); 58 | }); 59 | ``` 60 | 61 | これを `Promise` を使うことで以下のように書くことができるでしょう。 62 | 63 | ```js 64 | a().then(b).then(c).then(d); 65 | ``` 66 | 67 | ## やってみよう 68 | 69 | `promise.js` ファイルを作りましょう。 70 | 71 | まずは下記のように関数を定義しましょう。 72 | 73 | ```js 74 | const fetchData = (key) => { 75 | return new Promise((resolve, reject) => { 76 | if (key !== "greeting") { 77 | reject(new Error(`unknown key: ${key}`)); 78 | return; 79 | } 80 | 81 | setTimeout(() => { 82 | resolve("Hello"); 83 | }, 1000); 84 | }); 85 | }; 86 | 87 | const processData = (data) => `data: ${data}`; 88 | ``` 89 | 90 | `fetchData` 関数で得られた値を `processData` 関数で加工し、 `console.log` で出力するコードを書いてみましょう。 91 | `fetchData` 関数の引数には `"greeting"` を渡すパターンと `"credential"` を渡すパターンを書き、エラーが発生した際はそのエラーを `console.error` を使って出力してください。 92 | 93 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 94 | 95 | `javascripting verify promise.js` 96 | -------------------------------------------------------------------------------- /problems/pagination/problem_ja.md: -------------------------------------------------------------------------------- 1 | # Pagination!! 2 | 3 | あなたは以下の仕様を持つ、ページネーションを作成しなさいと言われました。どのように作成しますか?作ってみて、テストを pass させてください。 4 | 5 | # 問題 6 | 7 | `pagination.js` ファイルを作りましょう。 8 | 9 | 次の条件を満たす `getPageNums` 関数を作ってください。 10 | 11 | `current`, `total`, `size` の 3 つの変数が与えられます。 12 | `total` は総ページ数を表します。 13 | `current` は現在のページ数を表します。 14 | `size` は返却したいページの長さを表します。 15 | `total` からはみ出ないように、現在のページを中央値としてページの長さ分の配列の数字を返してください。 16 | 17 | ```javascript 18 | /** 19 | * @description `range` 関数はこのまま使ってください。 20 | * 21 | * @param {number} start 範囲の開始となる数値 (整数) 22 | * @param {number} end 範囲の終了となる数値 (整数) 23 | * @returns {number[]} 範囲を示す配列 (`[start, end)`) 24 | * @throws {Error} `start` が `end` より大きい場合にエラーが throw されます 25 | * 26 | * @example range(2, 5); // [2, 3, 4] 27 | */ 28 | function range(start, end) { 29 | if (start > end) { 30 | throw new Error( 31 | `range 関数の第一引数 \`start\` は第二引数 \`end\` の値以下である必要があります (start: ${start}, end: ${end})`, 32 | ); 33 | } 34 | 35 | return new Array(end - start).fill(0).map((_, i) => i + start); 36 | } 37 | 38 | function getPageNums(current, total, size) { 39 | // ここにロジックを書いてください 40 | } 41 | 42 | console.log(getPageNums(1, 5, 5)); 43 | console.log(getPageNums(3, 5, 5)); 44 | console.log(getPageNums(4, 6, 5)); 45 | console.log(getPageNums(3, 8, 6)); 46 | console.log(getPageNums(4, 8, 6)); 47 | console.log(getPageNums(4, 8, 3)); 48 | console.log(getPageNums(8, 8, 3)); 49 | ``` 50 | 51 | - `current = 1`, `total = 5`, `size = 5` 52 | - return: `[1, 2, 3, 4, 5]` 53 | - `current = 3`, `total = 5`, `size = 5` 54 | - return: `[1, 2, 3, 4, 5]` 55 | - `current = 4`, `total = 6`, `size = 5` 56 | - return: `[2, 3, 4, 5, 6]` 57 | - `current = 3`, `total = 8`, `size = 6` 58 | - return: `[1, 2, 3, 4, 5, 6]` 59 | - `current = 4`, `total = 8`, `size = 6` 60 | - return: `[2, 3, 4, 5, 6, 7]` 61 | - `current = 4`, `total = 8`, `size = 3` 62 | - return: `[3, 4, 5]` 63 | - `current = 8`, `total = 8`, `size = 3` 64 | - return: `[6, 7, 8]` 65 | 66 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 67 | 68 | `javascripting verify pagination.js` 69 | 70 | ヒント: 配列の始まりは現在のページから `size` の半分の長さ分引いたものを開始位置、半分の長さ分足したものを終了位置とすると定式化しやすいです。 71 | -------------------------------------------------------------------------------- /problems/async-await/problem_ja.md: -------------------------------------------------------------------------------- 1 | `async` / `await` は `Promise` を同期的な記述で取り扱うための糖衣構文です。 2 | 3 | `Promise` では `.then` と `.catch` を使って非同期処理を記述していました。 4 | しかし、以下のような入れ子になってしまうようなコードを書くと可読性に問題が生じます。 5 | 6 | ```js 7 | const displayMyPosts = () => { 8 | return fetchMe() 9 | .then((me) => { 10 | fetchPosts({ userId: me.id }) 11 | .then((posts) => { 12 | console.log(posts); 13 | }) 14 | .catch((e) => { 15 | console.error(e); 16 | }); 17 | }) 18 | .catch((e) => { 19 | console.error(e); 20 | }); 21 | }; 22 | ``` 23 | 24 | そこで `async` キーワードと `await` キーワードを使うことで、可読性を保ちながら非同期処理が記述できます。 25 | 26 | ```js 27 | const displayMyPosts = async () => { 28 | try { 29 | const me = await fetchMe(); 30 | const posts = await fetchPosts({ userId: me.id }); 31 | console.log(posts); 32 | } catch (e) { 33 | console.error(e); 34 | } 35 | }; 36 | ``` 37 | 38 | 関数宣言や関数定義の前に `async` キーワードをつけることで、その関数が非同期処理を扱うことを示すことができます。 39 | `async` キーワードをつけた関数内では `await` キーワードを利用することができるようになり、関数の返り値に `Promise` で wrap されます。 40 | 41 | `await` キーワードは `Promise` の前につけることで、その `Promise` が解決されるまで関数の実行を待機させることができます。 42 | また、関数の返り値は `Promise` によって解決された値になり、 `Promise` が拒否された場合にはエラーを `throw` します。 43 | 44 | ## やってみよう 45 | 46 | `async-await.js` ファイルを作りましょう。 47 | 48 | まずは下記のように関数と配列を定義しましょう。 49 | 50 | ```js 51 | const fetchPosts = (user) => { 52 | return new Promise((resolve, reject) => { 53 | setTimeout(() => { 54 | resolve([ 55 | `${user}: post1`, 56 | `${user}: post2`, 57 | `${user}: post3`, 58 | `${user}: post4`, 59 | `${user}: post5`, 60 | ]); 61 | }, 1000); 62 | }); 63 | }; 64 | 65 | const users = ["user1", "user2", "user3", "user4", "user5"]; 66 | ``` 67 | 68 | `users` 配列の中に入った文字列をそれぞれ `fetchPosts` 関数に渡し、各ユーザーの投稿を標準出力に表示する `displayAllPosts` 関数を定義し実行してください。 69 | 70 | 出力は以下のようになるでしょう... 71 | 72 | ``` 73 | user1: post1 74 | user1: post2 75 | user1: post3 76 | user1: post4 77 | user1: post5 78 | user2: post1 79 | : 80 | ``` 81 | 82 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 83 | 84 | `javascripting verify async-await.js` 85 | 86 | もしも余裕がある人は `Promise.all` 関数を使ってデータ取得を並列に実行してみましょう。 87 | -------------------------------------------------------------------------------- /problems/promise-all/problem_ja.md: -------------------------------------------------------------------------------- 1 | 非同期処理を取り扱うための `Promise` には便利な関数がいくつか用意されています。 2 | 3 | ここでは `Promise.all` 関数と `Promise.any` 関数について紹介します。 4 | この二つの関数は `Promise` を要素に持つ配列を引数に受け、 `Promise` を返します。 5 | 6 | `Promise.all` 関数の返り値の `Promise` は、引数の配列内の `Promise` が全て解決されると解決されます。 7 | 返り値の `Promise` によって解決される値は、引数の配列の要素の `Promise` によって解決された値の配列です。 8 | また、配列内の `Promise` のうちのいづれかが拒否されると返り値の `Promise` も拒否されます。 9 | 10 | ```js 11 | // resolved after 3000ms 12 | Promise.all([ 13 | sleep(1000).then(() => "quick"), 14 | sleep(2000).then(() => "medium"), 15 | sleep(3000).then(() => "slow"), 16 | ]).then((v) => { 17 | console.log(v); 18 | }); // ['quick', 'medium', 'slow'] 19 | ``` 20 | 21 | `Promise.any` 関数では引数の配列の要素内の全ての `Promise` の解決のを待つのとは逆に、どれかひとつが解決されることで返り値の `Promise` も解決されます。 22 | 返り値の `Promise` によって解決される値は、引数の配列の要素の `Promise` の中で一番最初に解決された値になります。 23 | また、配列内の `Promise` のうちのいづれかが拒否されると返り値の `Promise` も拒否されます。 24 | 25 | ```js 26 | // resolved after 1000ms 27 | Promise.any([ 28 | sleep(1000).then(() => "quick"), 29 | sleep(2000).then(() => "medium"), 30 | sleep(3000).then(() => "slow"), 31 | ]).then((v) => { 32 | console.log(v); 33 | }); // 'quick' 34 | ``` 35 | 36 | ## やってみよう 37 | 38 | `promise-all.js` ファイルを作りましょう。 39 | 40 | まずは下記のように関数を定義しましょう。 41 | 42 | ```js 43 | const fetchData = (key) => { 44 | return new Promise((resolve, reject) => { 45 | switch (key) { 46 | case "quick": 47 | setTimeout(() => { 48 | resolve("quick: hi!"); 49 | }, 1000); 50 | break; 51 | 52 | case "medium": 53 | setTimeout(() => { 54 | resolve("medium: hello!!"); 55 | }, 2000); 56 | break; 57 | 58 | case "slow": 59 | setTimeout(() => { 60 | resolve("slow: good morning!!!"); 61 | }, 3000); 62 | break; 63 | 64 | default: 65 | reject(new Error(`unknown key: ${key}`)); 66 | break; 67 | } 68 | }); 69 | }; 70 | ``` 71 | 72 | `fetchData("quick")` , `fetchData("medium")` , `fetchData("slow")` の三つの返り値が全て解決されるまで待ち、その返り値を標準出力に表示してください。 73 | また、 `fetchData("quick")` , `fetchData("medium")` , `fetchData("slow")` の三つの返り値のうちどれかひとつが解決されるまで待ち、最も早かった Promise の返り値を標準出力に表示してください。 74 | 75 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 76 | 77 | `javascripting verify promise-all.js` 78 | 79 | もしも余裕がある人は `console.time` / `console.timeEnd` 関数を使ってそれぞれの処理が完了するまでに掛かった時間を計測して出力してみましょう。 80 | 81 | - `console.time(label)`: 時間計測を開始します 82 | - `console.timeEnd(label)`: 対応する `label` の時間計測を終了し、経過した時間を出力します 83 | -------------------------------------------------------------------------------- /problems/booleans/problem_ja.md: -------------------------------------------------------------------------------- 1 | 真偽値 (boolean) には `true` と `false` の二つの値があります。 2 | 3 | ## Truthy / Falsy 4 | 5 | JavaScript において、真値 (truthy value) と偽値 (falsy value) は if 文などの真偽の判定が必要な場面でそれぞれ真・偽と判定される値のことです。 6 | 7 | 偽値は `false`, `0`, `-0`, `0n` `""`, `null`, `undefined`, `NaN` のことです。 8 | 9 | 一方、真値は偽値以外の全ての値を指します。 10 | たとえば `true`, `{}`, `[]`, `"0"` などの値は真値になります。 11 | 12 | ## 比較演算子 13 | 14 | 比較演算子には `==`, `===`, `!=`, `!==`, `>`, `<`, `<=`, `>=` などがあります。 15 | 16 | 特に `==` と `===` 、 `!=` と `!==` は何が違うのでしょうか? 17 | 18 | `==` や `!=` では、暗黙の型変換が発生します。 19 | 例えば、 `36 == "36"` は真になります。 20 | 21 | 一方、 `===` や `!==` では暗黙の型変換が発生しません。 22 | よって、 `36 === "36"` は偽になります。 23 | 24 | 基本的に暗黙の型変換を避けるべく `==` や `!=` は使用せず、 `===` や `!==` などを利用しましょう。 25 | 26 | ## 論理演算子 27 | 28 | 論理演算子には主に `!` や `&&`, `||` などがあります。 29 | 30 | `!` は論理否定演算子であり、真偽値の先頭につけることで真偽が反転します。 31 | また、真値 / 偽値の先頭につけることで反転した真偽値を得ることができます。 32 | 33 | ```js 34 | !true; // -> false 35 | !false; // -> true 36 | 37 | !""; // -> true 38 | !!""; // -> false 39 | ``` 40 | 41 | `&&` は論理積、 `||` は論理和を表す演算子です。 42 | `&&` は左が偽値であればそれを返し、真値であれば右を返します。 43 | `||` は左が真値であればそれを返し、偽値であれば右を返します。 44 | `true` や `false` を返すわけではないことに注意しましょう。 45 | 46 | ```js 47 | "" && "0"; // -> "" 48 | "0" && ""; // -> "" 49 | "0" && "1"; // -> "1" 50 | 51 | "0" || ""; // -> "0" 52 | "" || "0"; // -> "0" 53 | 0 || ""; // -> "" 54 | ``` 55 | 56 | ## 短絡評価 57 | 58 | `&&` と `||` には短絡評価があります。 59 | 60 | 短絡評価とは「条件付き評価」を表す用語です。 61 | たとえば `A && B` において `A` が偽値であった場合、 `B` は評価されません。 62 | 同様に `A || B` において `A` が真値であった場合、 `B` は評価されません。 63 | 64 | この振る舞いは特に関数の呼び出しに影響します。 65 | もし関数について理解が浅い場合は、課題「関数」を読んだ後にまたここを読み返すと良いでしょう。 66 | 67 | ```js 68 | function f() { 69 | console.log("f is called!"); 70 | } 71 | 72 | true && f(); // "f is called!" 73 | false && f(); // not printed 74 | 75 | true || f(); // not printed 76 | false || f(); // f is called! 77 | ``` 78 | 79 | ## やってみよう 80 | 81 | 真偽値や真値、偽値の性質を整理するために、ドリルを解きましょう。 82 | 83 | `booleans.js` ファイルを作り、以下のコードをコピーしてください。 84 | 85 | ```js 86 | console.log((0 == 1) === ""); 87 | console.log((0 === 1) === ""); 88 | 89 | console.log((10 == "10") === ""); 90 | console.log((10 === "10") === ""); 91 | 92 | console.log((0 && "") === ""); 93 | console.log((1 && "") === ""); 94 | console.log((0 && 10) === ""); 95 | console.log((1 && 10) === ""); 96 | 97 | console.log((0 || "") === ""); 98 | console.log((1 || "") === ""); 99 | console.log((0 || 10) === ""); 100 | console.log((1 || 10) === ""); 101 | ``` 102 | 103 | 全ての `console.log` による出力が `true` となるように、`''` と書かれた場所を書き換えてください。 (文字列である必要はありません。) 104 | 105 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 106 | 107 | ```bash 108 | javascripting verify booleans.js 109 | ``` 110 | -------------------------------------------------------------------------------- /lib/problem.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const fs = require("fs"); 3 | const getFile = require("./get-file"); 4 | const compare = require("./compare-solution"); 5 | 6 | module.exports = function createProblem(dirname) { 7 | const exports = {}; 8 | 9 | let problemName = dirname.split(path.sep); 10 | let i18n; 11 | 12 | problemName = problemName[problemName.length - 1]; 13 | 14 | exports.init = function (workshopper) { 15 | i18n = workshopper.i18n; 16 | const postfix = 17 | workshopper.i18n.lang() === "en" ? "" : "_" + workshopper.i18n.lang(); 18 | this.problem = { file: path.join(dirname, "problem" + postfix + ".md") }; 19 | this.solution = { file: path.join(dirname, "solution" + postfix + ".md") }; 20 | 21 | // Check for the existence of index.[js, mjs, cjs] 22 | const jsSolutionPath = path.resolve( 23 | __dirname, 24 | "..", 25 | "solutions", 26 | problemName, 27 | "index.js", 28 | ); 29 | const mjsSolutionPath = path.resolve( 30 | __dirname, 31 | "..", 32 | "solutions", 33 | problemName, 34 | "index.mjs", 35 | ); 36 | const cjsSolutionPath = path.resolve( 37 | __dirname, 38 | "..", 39 | "solutions", 40 | problemName, 41 | "index.cjs", 42 | ); 43 | // Set solutionPath to the first existing file 44 | if (fs.existsSync(jsSolutionPath)) { 45 | this.solutionPath = jsSolutionPath; 46 | } else if (fs.existsSync(mjsSolutionPath)) { 47 | this.solutionPath = mjsSolutionPath; 48 | } else if (fs.existsSync(cjsSolutionPath)) { 49 | this.solutionPath = cjsSolutionPath; 50 | } else { 51 | throw new Error(`No solution file found for problem: ${problemName}`); 52 | } 53 | 54 | this.troubleshootingPath = path.join( 55 | __dirname, 56 | "..", 57 | "i18n", 58 | "troubleshooting" + postfix + ".md", 59 | ); 60 | }; 61 | 62 | exports.verify = function (args, cb) { 63 | const attemptPath = path.resolve(process.cwd(), args[0]); 64 | compare( 65 | this.solutionPath, 66 | attemptPath, 67 | i18n, 68 | function (_, match, obj) { 69 | if (match) { 70 | return cb(null, true); 71 | } 72 | 73 | if (!obj) { 74 | // An error occured, we've already printed an error 75 | return; 76 | } 77 | 78 | let message = getFile(this.troubleshootingPath); 79 | 80 | message = message.replace(/%solution%/g, obj.solution); 81 | message = message.replace(/%attempt%/g, obj.attempt); 82 | message = message.replace(/%diff%/g, obj.diff); 83 | message = message.replace(/%filename%/g, args[0]); 84 | 85 | exports.fail = [{ text: message, type: "md" }, require("./footer.js")]; 86 | 87 | cb(null, false); 88 | }.bind(this), 89 | ); 90 | }; 91 | 92 | return exports; 93 | }; 94 | -------------------------------------------------------------------------------- /problems/null-undefined/problem_ja.md: -------------------------------------------------------------------------------- 1 | `undefined` と `null` はどちらも JavaScript におけるプリミティブ型の一つです。 2 | この 2 値はまとめて "nullish value" とも呼ばれます。 3 | 4 | `undefined` は存在しないプロパティや未指定の引数、返り値などに入る値です。 5 | 6 | たとえば... 7 | 8 | ```js 9 | {}.a; // -> undefined 10 | [][0]; // -> undefined 11 | 12 | function f(x) { return x } 13 | f(); // -> undefined 14 | 15 | function g() { return } 16 | g(); // -> undefined 17 | ``` 18 | 19 | `null` は意図的にオブジェクトの値が存在しないことを表します。 20 | 21 | ## 違い 22 | 23 | `null` と `undefined` の異なる点として `typeof` 演算子に渡した際の結果があります。 24 | 25 | ```js 26 | typeof null; // -> "object" 27 | typeof undefined; // -> "undefined" 28 | ``` 29 | 30 | どちらも偽値であり共通点も多いですが、異なる値であることに注意してください。 31 | 32 | ```js 33 | null === undefined; // -> false 34 | ``` 35 | 36 | ## 「`null` か `undefined` の場合」 37 | 38 | 課題「真偽値」の説明の中で、基本的には `==` ではなく `===` を使うよう説明しました。 39 | 40 | しかし、「`null` か `undefined` の場合」という条件を書きたい場合には `==` の使用を許容するプロジェクトもあります。 41 | `obj == null` または `obj == undefined` は `obj === null || obj === undefined` と同じ意味になり、短く書くことができるからです。 42 | 43 | ## Nullish Coalescing 44 | 45 | 変数などの値が nullish value の場合にのみデフォルト値を指定したい場合があります。 46 | このときに `||` を使用すると、 `null` や `undefined` 以外の偽値 (`false` や `""` など) も上書きしてしまいます。 47 | 48 | これを解決するために登場したのが nullish coalescing (`??`) です。 49 | 50 | ```js 51 | const nullable1 = {}; 52 | nullable1 || "default"; // -> {} 53 | nullable1 ?? "default"; // -> {} 54 | 55 | const nullable2 = null; 56 | nullable2 || "default"; // -> "default" 57 | nullable2 ?? "default"; // -> "default" 58 | 59 | const nullable3 = false; 60 | nullable3 || "default"; // -> "default" 61 | nullable3 ?? "default"; // -> false 62 | ``` 63 | 64 | `??` でも `&&` や `||` と同様に短絡評価が発生します。 65 | (短絡評価を忘れた場合は、課題「真偽値」の説明を読み直しましょう。) 66 | 67 | ## やってみよう 68 | 69 | `null` と `undefined` の性質を整理するために、ドリルを解きましょう。 70 | 71 | `null-undefined.js` ファイルを作り、以下のコードをコピーしてください。 72 | 73 | ```js 74 | const obj = {}; 75 | console.log(obj.a === ""); 76 | 77 | const arr = []; 78 | console.log(arr[0] === ""); 79 | 80 | const id = (x) => x; 81 | console.log(id() === ""); 82 | 83 | const noop = () => {}; 84 | console.log(noop() === ""); 85 | 86 | console.log(typeof null === ""); 87 | console.log(typeof undefined === ""); 88 | 89 | console.log((obj || "default") === ""); 90 | console.log((obj ?? "default") === ""); 91 | 92 | console.log((undefined || "default") === ""); 93 | console.log((undefined ?? "default") === ""); 94 | 95 | console.log((false || "default") === ""); 96 | console.log((false ?? "default") === ""); 97 | ``` 98 | 99 | 全ての `console.log` による出力が `true` となるように、`''` と書かれた場所を書き換えてください。 (文字列である必要はありません。) 100 | 101 | 次のコマンドを実行し、あなたのプログラムが正しく動くか確認しましょう。 102 | 103 | ```bash 104 | javascripting verify null-undefined.js 105 | ``` 106 | --------------------------------------------------------------------------------