Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ブラウザでうごく! ES6+ モダンJavaScript

ブラウザでうごく! ES6+ モダンJavaScript

Tatsuya Miyamae

September 07, 2022
Tweet

More Decks by Tatsuya Miyamae

Other Decks in Programming

Transcript

  1. ES6とは何か IE11にも搭載されているJavaScriptの仕様は ECMAScript 5.1 (ES5) JavaScriptは ECMAScript 6 (ES2015) で大規模に拡張された

    その後ES2016, ES2017, …ES2022 と毎年バージョンアップしている (太古) IEでも使えるようにBabelなどでES5に変換(トランスパイル)して利用していた (昔) TypeScriptの処理系にES6->ES5のトランスパイル機能が含まれている (Babel終了) (現在) IEが無くなったのでもうES5を使う必要はない なんと、すでに主要なブラウザでネイティブに最新のES2022が利用可能 ES5との区別から「ES6」と言いがちだが、実際には最新のES2022を使ってok 今日お話しする機能はすべてブラウザだけで利用可能です
  2. これだけは知っておこうES6+ let & const (ES6) オブジェクト初期化子の略記法 (ES6) アロー関数 (ES6) class

    構文 (ES6) 関数のデフォルト引数 (ES6) テンプレートリテラル (ES6) 分割代入 (ES6) スプレッド構文 & 残余構文 (ES6) for … of 構文 (ES6) Promise (ES6) async / await 構文 (ES2017) ESモジュール (import & export) (ES6) オプショナルチェーン演算子 (ES2020)
  3. 変数宣言 let と const は var に代わる変数宣言構文 (ちなみにIE11でも使える) // var

    ( 非推奨) var num = 1; // let ( 再代入可能) let num = 1; num = 2; // OK // const ( 再代入不可) const num = 1; num = 2; // NG
  4. varとlet/const: スコープの違い 注意! var と let は同じものではない var は関数レベルのスコープ let

    / const はブロックスコープ if (true) { var x = 1; }; console.log(x); //=> "1" if (true) { let x = 1; }; console.log(x); //=> Uncaught ReferenceError: x is not defined
  5. varとlet/const: 巻き上げの違い 宣言より前に変数を参照した時の挙動が違う var は変数が宣言され undefined が代入される let / const

    は変数が宣言されるが初期化されない ※ 実際には変数宣言は使う前に書くべきなので、あまり意識することはないが if (true) { console.log(x); var x = 1; //=> undefined } if (true) { console.log(x) //=> Uncaught ReferenceError: Cannot access "x" before initialization let x = 1; }
  6. var/let/const の使い分け 基本は const 必要な時だけ let var は使わない(直感的でなく不具合を起こしやすい仕様) var から

    let への単純な置換は挙動の違いがあるので注意 基本的には let ではなく const を使う どうしても再代入が必要な時だけ let を使う できるだけ変数に再代入しないロジックが望ましい 読むのに負担になるし、バグが入りやすくなるので
  7. 3種類の関数定義 関数定義は3種類の書き方ができるようになった // 関数宣言 function calcDouble(a) { return a *

    2; } // 関数式 const calcDouble = function(a) { return a * 2; }; // アロー関数 const calcDouble = (a) => { return a * 2; };
  8. 関数宣言や関数式で作った関数内の this メソッドを一度別の変数に入れて呼び出すなど、メソッド記法以外の方法で呼び出すと this が変わってしまう this.data = " グローバル"; const

    func = function() { console.log(this.data); }; const f = { data: " オブジェクト内", execute: func }; f.execute(); // => " オブジェクト内" // ↑ レシーバである「f 」がthis になる func(); //=> " グローバル" // ↑ レシーバがないので外側のthis と同じになる const func2 = f.execute; func2(); //=> " グローバル" // 同じメソッドを実行しているのに結果が違う!!
  9. アロー関数内の this 常に宣言時のスコープの this this.data = " グローバル"; const func

    = () => { console.log(this.data); }; const f = { data: " オブジェクト内", execute: func }; f.execute(); //=> " グローバル" func(); //=> " グローバル"
  10. ES5時代のクラス ES5でもクラスは作れる 使うときは普通にクラスっぽく使えるけど、定義のほうが分かりにくい。 function User(lastName, firstName) { this.lastName = lastName;

    this.firstName = firstName; } User.prototype.getFullName = function() { return this.firstName + this.lastName; } var u = new User(" 土方", " 歳三"); console.log(u.getFullName()); //=> " 土方歳三"
  11. ES6のclass宣言 普通な感じで書ける(継承もできる)オーソドックスで扱いやすいクラス機能 詳しい機能は割愛します class User { constructor(lastName, firstName) { this.lastName

    = lastName; this.firstName = firstName; } getFullName() { return this.firstName + this.lastName; } } const u = new User(" 土方", " 歳三"); console.log(u.getFullName()); //=> " 土方歳三"
  12. 分割代入: その他 他にも色々細かいことができてかなり強力な機能 ネストしたオブジェトのプロパティを取り出すこともできる(難解だが) デフォルトを指定することもできる const nested = { obj:

    { foo: "hello", bar: "world" } } const { obj: [foo] } = nested; console.log(foo); //=> "hello" // プロパティobj.foo が存在しなければ99 が代入される const { foo = 99 } = obj;
  13. 配列のスプレッド構文 配列を展開して別の配列に埋め込む 配列の複製、結合などが直感的に書ける 使いやすい機能! const foo = [1, 2]; //

    配列を複製 const bar = [...foo]; //=> [1, 2] // 要素を追加した新しい配列を作成 const baz = [...foo, 3, 4]; //=> [1, 2, 3, 4] // 配列を結合 const hoge = [...foo, ...bar]; //=> [1, 2, 1, 2]
  14. オブジェクトのスプレッド構文 配列の場合と同じように操作できる const foo = { a: 1, b: 2

    }; // オブジェクトを複製 const bar = { ...foo }; //=> { a: 1, b: 2 } // プロパティを追加した新しいオブジェクトを作成 const baz = { ...foo, c: 3 }; //=> { a: 1, b: 2, c: 3 } // オブジェクトを結合 const hoge = { ...foo, ...{ c: 3, d: 4 } }; //=> { a: 1, b: 2, c: 3, d: 4 }
  15. 引数のスプレッド構文 配列を展開して引数に渡せる function sum(x, y, z) { return x +

    y + z; } const numbers = [1, 2, 3]; const result = sum(...numbers); console.log(result); //=> "6"
  16. 引数の残余構文(レスト構文) スプレッド構文の逆で、不定数の引数を集約する function sum(...args) { let total = 0; for

    (let arg of args) { total += arg; } return total; } const result = sum(1, 2, 3); console.log(result); //=> "6"
  17. ES5: foreachしたい(2) forEach 高階関数 for文ではないので break, continue が使えない ループを途中で止められない returnすることでcontinue的なことはできる

    インデックスを取得することができる(メリット) const array = ["value1", "value2", "value3"]; array.forEach(function(elem) { console.log(elem); }); const array = ["value1", "value2", "value3"]; array.forEach(function(elem, index) { console.log(index + ": " + elem); });
  18. Promiseでの解決 Promiseオブジェクトを返却する実装。メソッドチェーンで並列に書ける const aFunc = (val) => { return new

    Promise((resolve) => { // .. 時間のかかる処理.. resolve(val * 2); }); }; const sampleAsync => () { aFunc(100) .then((val) => { console.log(val); //=> "200" return aFunc(val); }) .then((val) => { console.log(val); //=> "400" return aFunc(val); }) .then((val) => { console.log(val); //=> "800" }); };
  19. async / await ES2017からはさらに簡単に、同期関数のように自然に書くことができるようになった await を付けてPromiseを呼ぶと結果が来るまで待ってくれる(超便利) await は async のついた関数の中でのみ使用可能なので、無名関数でラップするテクニックが多用される

    ES2022からこの制約が緩和。トップレベルからの呼び出しの場合は async 関数でラップする必要はなくなった const sampleAsync = async () => { let val = await aFunc(100); console.log(val); //=> "200" val = await aFunc(val); console.log(val); //=> "400" val = await aFunc(val); console.log(val); //=> "800" }; (async () => { let val = await aFunc(100); console.log(val); })();
  20. ESモジュール (import & export) webpackなどモジュールバンドラー環境では以前から import と export が使えた。これなしはありえない 読み込まれる側

    (hello.js) 読み込む側 (index.js) 別名で読み込むこともできる これ実は今ではブラウザでも使える! export const sayHello = (message) => { alert(message); }; import { sayHello } from "./hello.js"; sayHello(" こんにちはこんにちは"); import { sayHello as shout } from "./hello.js"; shout(" こんにちはこんにちは");
  21. HTMLから読み込むには type="text/javascript" の代わりに type="module" を指定 これで import / export 宣言を含むjsが使える

    または、インラインでも つまり、 モジュールバンドラーが使えないClipkitでもスクリプトをモジュール化できるよ <script type="module" src="index.js"></script> <script type="module"> import { sayHello } from "./hello.js"; sayHello(" こんにちはこんにちは"); </script>
  22. オプショナルチェーン演算子 ES2020で追加された、地味ながら超便利機能 Rubyの ぼっち演算子 (&.) と同じもの どれほど便利かは知ってのとおり const user =

    { name: 'John', //... }; console.log(user.profile.age); //=> Cannot read property 'age' of undefined console.log(user.profile?.age); //=> undefined