20210103のJavaScriptに関する記事は30件です。

【初心者必見】ポートフォリオを作成途中ですが、今までの知見をまとめました。

はじめに
私は転職活動のための、ポートフォリオを作成中です。
PHPとSQLの学習に入る前に、それまで行った事をまとめました。

作成中のポートフォリオサイト:https://neptune.sakura.ne.jp/Hanatachi/
ポートフォリオサイトのGitHub:https://github.com/fujioka8700/Hanatachi

1.サイトの目的の明確化
道端に咲いている花たちについて、語れるコミュニティの作成、運用。

2.サイトの狙い、目的
 道に咲いている花たちの紹介。
コミュニティを作り、情報交換の場を作ります。

3.ターゲット
 ウォーキングをしている人たち。
これから、ウォーキングを、始めようとしている人たち。
花が好きな人たち。男女は問いません。

4.サイトを作ろうとした動機
 私は健康維持のために、ウォーキングをしています。
ウォーキングをしていると、初めて知るお店や、
見たことのない景色に、遭遇することがよくあります。
目の前の大きな発見があるとともに、小さな発見もよくあります。

 それは足元に咲いている花たちです。
道端に咲いている花をよく見てみると、
色鮮やかに、キレイにかわいく、たくさん咲いています。

 しかし、歩く人々は、イヤホンで音楽を聴いたり、
知人と話し合って、歩いているので、花たちに見向きもしません。

 私は、普段何気なく歩いている道には、
花たちが、キレイに咲いていることを、見てほしいと思いました。
そして、この花たちについて、語れるコミュニティを作りたいと思い、
このサイトを作ろうと思いました。

5.サイト制作スケジュールと、製作方法

 サイト制作に必要な作業を列挙して、Googleスプレッドシートで、WBSを作成しました。 
 https://docs.google.com/spreadsheets/d/135Wihnksz9lRj_IjUm0-P7GtRTXzRmpXG-Jp-oinOLQ/edit?usp=sharing 

 サイトのざっくりとしたイメージを、ラフスケッチに描きます。
 ラフスケッチの写真を、一部抜粋し、掲載します。
ラフスケッチのTOP画面
ラフスケッチの検索画面

 ラフスケッチから、GIMPにてサイトのスマホ版とPC版の
 デザインカンプの作成をします。
 作成したデザインカンプの画像を、一部抜粋し掲載します。

デザインカンプ、PC版のTOP画面
デザインカンプ、スマホ版のTOP画面

  スマホ版とPC版の、各1枚ずつ。計18枚、作成。
   TOPページ
   道端の花たちとは
   花を楽しむ
   ウォーキングのすすめ
   花の検索(TOP画面)
   花の検索(検索結果一覧)
   花の検索(花の詳細表示)
   掲示板
   更新情報・お知らせ

 素材となる写真は、以下の2つの方法で集めました。
  ・私がウォーキング中に、見つけた花をスマホで撮影しました。
  ・pakutaso.com様から、写真からお借りしました。

 作成したデザインカンプをもとに、VisualStudioCodeにて、
 マークアップとコーディングを行いました。

  スマホとPCに対応させたサイトを各1ページずつ。計7枚、作成。
   TOPページ
   道端の花たちとは
   花を楽しむ
   ウォーキングのすすめ
   (仮)花の検索(TOP画面)
   (仮)掲示板
   更新情報・お知らせ

 使用言語
  HTML
  CSS
  SCSS
  JavaScript

 使用したプラグイン
  jQuery(Slickを使うために、導入必須)
  Slick(TOP画面の画像のスライダー)
 
 その他
  ハンバーガーメニューは、自作しました。

6.結果と考察
 GIMPでのデザインカンプの作成が苦戦しました。
なぜなら、コーディングの技術は一切使わないからです。
マウスとキーボードで、1px単位で画像と文字の調整を行って、
サイトの完成図を、作るのは大変でした。

 マークアップとコーディングに関しては、
1ページ、確実なものを作れば、他のページは作りやすいことがわかりました。
あとプラグインとしてあるものは、自分自身で作るべきではないです。
スライダーを自作しようとしましたが、使い勝手も見栄えも、SlickSliderには敵いません。
プログラマの中で格言である、「車輪の発明はするべきではない」、
ということが、よくわかりました。

 ただ、JavaScriptの勉強にはなりました。
スライダーを作ろうとしたときに、
オブジェクトとノードのことを、よく理解できたためです。

7.感想と今後の課題
 デザインカンプの作成時、素材として撮影した写真は、
かわいく見えるよう加工できるようにしたいです。

 検索と掲示板は、まで制作できていません。
それはPHPとSQLの知識がないためです。
今後はPHPとSQLの基礎を勉強して、サイトの完成を目指します。

8.参考文献
 境祐司 著 「Webデザイン標準テキスト―変化に流されない制作コンセプトと基本スタイル―」
 https://gihyo.jp/dp/ebook/2012/978-4-7741-5086-4

9.サイト作成時、使用した主なソフト
 GIMP(デザインカンプの作成) https://www.gimp.org/
 Visual Studio Code(マークアップ、コーディング)
 https://azure.microsoft.com/ja-jp/products/visual-studio-code/
  便利だった拡張機能
   Japanese Language Pack for Visual Studio Code
   https://marketplace.visualstudio.com/items?itemName=MS-CEINTL.vscode-language-pack-ja
   Beautify css/sass/scss/less
   https://marketplace.visualstudio.com/items?itemName=michelemelluso.code-beautifier
   Live Sass Compiler
   https://marketplace.visualstudio.com/items?itemName=ritwickdey.live-sass
   Live Server
   https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer
   Visual Studio IntelliCode
   https://marketplace.visualstudio.com/items?itemName=VisualStudioExptTeam.vscodeintellicode
 SourceTree(GitHub使用のため) https://www.sourcetreeapp.com/
 FFFTP(ホームページを公開するため) https://ja.osdn.net/projects/ffftp/
 Windows付属の電卓

 ホームページの動作確認ブラウザー
  Chrome(PC、スマホ)
  Firefox(PC)
  Edge(PC)

10.素材を、お借りしたサイト様
 PAKUTASO様 https://www.pakutaso.com
 GAHAG様 http://gahag.net

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ポートフォリオを作成途中ですが、今までの知見をまとめました。

はじめに
私は転職活動のための、ポートフォリオを作成中です。
PHPとSQLの学習に入る前に、それまで行った事をまとめました。

作成中のポートフォリオサイト:https://neptune.sakura.ne.jp/Hanatachi/
ポートフォリオサイトのGitHub:https://github.com/fujioka8700/Hanatachi

1.サイトの目的の明確化
道端に咲いている花たちについて、語れるコミュニティの作成、運用。

2.サイトの狙い、目的
 道に咲いている花たちの紹介。
コミュニティを作り、情報交換の場を作ります。

3.ターゲット
 ウォーキングをしている人たち。
これから、ウォーキングを、始めようとしている人たち。
花が好きな人たち。男女は問いません。

4.サイトを作ろうとした動機
 私は健康維持のために、ウォーキングをしています。
ウォーキングをしていると、初めて知るお店や、
見たことのない景色に、遭遇することがよくあります。
目の前の大きな発見があるとともに、小さな発見もよくあります。

 それは足元に咲いている花たちです。
道端に咲いている花をよく見てみると、
色鮮やかに、キレイにかわいく、たくさん咲いています。

 しかし、歩く人々は、イヤホンで音楽を聴いたり、
知人と話し合って、歩いているので、花たちに見向きもしません。

 私は、普段何気なく歩いている道には、
花たちが、キレイに咲いていることを、見てほしいと思いました。
そして、この花たちについて、語れるコミュニティを作りたいと思い、
このサイトを作ろうと思いました。

5.サイト制作スケジュールと、製作方法

 サイト制作に必要な作業を列挙して、Googleスプレッドシートで、WBSを作成しました。 
 https://docs.google.com/spreadsheets/d/135Wihnksz9lRj_IjUm0-P7GtRTXzRmpXG-Jp-oinOLQ/edit?usp=sharing 

 サイトのざっくりとしたイメージを、ラフスケッチに描きます。
 ラフスケッチの写真を、一部抜粋し、掲載します。
ラフスケッチのTOP画面
ラフスケッチの検索画面

 ラフスケッチから、GIMPにてサイトのスマホ版とPC版の
 デザインカンプの作成をします。
 作成したデザインカンプの画像を、一部抜粋し掲載します。

デザインカンプ、PC版のTOP画面
デザインカンプ、スマホ版のTOP画面

  スマホ版とPC版の、各1枚ずつ。計18枚、作成。
   TOPページ
   道端の花たちとは
   花を楽しむ
   ウォーキングのすすめ
   花の検索(TOP画面)
   花の検索(検索結果一覧)
   花の検索(花の詳細表示)
   掲示板
   更新情報・お知らせ

 素材となる写真は、以下の2つの方法で集めました。
  ・私がウォーキング中に、見つけた花をスマホで撮影しました。
  ・pakutaso.com様から、写真からお借りしました。

 作成したデザインカンプをもとに、VisualStudioCodeにて、
 マークアップとコーディングを行いました。

  スマホとPCに対応させたサイトを各1ページずつ。計7枚、作成。
   TOPページ
   道端の花たちとは
   花を楽しむ
   ウォーキングのすすめ
   (仮)花の検索(TOP画面)
   (仮)掲示板
   更新情報・お知らせ

 使用言語
  HTML
  CSS
  SCSS
  JavaScript

 使用したプラグイン
  jQuery(Slickを使うために、導入必須)
  Slick(TOP画面の画像のスライダー)
 
 その他
  ハンバーガーメニューは、自作しました。

6.結果と考察
 GIMPでのデザインカンプの作成が苦戦しました。
なぜなら、コーディングの技術は一切使わないからです。
マウスとキーボードで、1px単位で画像と文字の調整を行って、
サイトの完成図を、作るのは大変でした。

 マークアップとコーディングに関しては、
1ページ、確実なものを作れば、他のページは作りやすいことがわかりました。
あとプラグインとしてあるものは、自分自身で作るべきではないです。
スライダーを自作しようとしましたが、使い勝手も見栄えも、SlickSliderには敵いません。
プログラマの中で格言である、「車輪の発明はするべきではない」、
ということが、よくわかりました。

 ただ、JavaScriptの勉強にはなりました。
スライダーを作ろうとしたときに、
オブジェクトとノードのことを、よく理解できたためです。

7.感想と今後の課題
 デザインカンプの作成時、素材として撮影した写真は、
かわいく見えるよう加工できるようにしたいです。

 検索と掲示板は、まで制作できていません。
それはPHPとSQLの知識がないためです。
今後はPHPとSQLの基礎を勉強して、サイトの完成を目指します。

8.参考文献
 境祐司 著 「Webデザイン標準テキスト―変化に流されない制作コンセプトと基本スタイル―」
 https://gihyo.jp/dp/ebook/2012/978-4-7741-5086-4

9.サイト作成時、使用した主なソフト
 GIMP(デザインカンプの作成) https://www.gimp.org/
 Visual Studio Code(マークアップ、コーディング)
 https://azure.microsoft.com/ja-jp/products/visual-studio-code/
  便利だった拡張機能
   Japanese Language Pack for Visual Studio Code
   https://marketplace.visualstudio.com/items?itemName=MS-CEINTL.vscode-language-pack-ja
   Beautify css/sass/scss/less
   https://marketplace.visualstudio.com/items?itemName=michelemelluso.code-beautifier
   Live Sass Compiler
   https://marketplace.visualstudio.com/items?itemName=ritwickdey.live-sass
   Live Server
   https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer
   Visual Studio IntelliCode
   https://marketplace.visualstudio.com/items?itemName=VisualStudioExptTeam.vscodeintellicode
 SourceTree(GitHub使用のため) https://www.sourcetreeapp.com/
 FFFTP(ホームページを公開するため) https://ja.osdn.net/projects/ffftp/
 Windows付属の電卓

 ホームページの動作確認ブラウザー
  Chrome(PC、スマホ)
  Firefox(PC)
  Edge(PC)

10.素材を、お借りしたサイト様
 PAKUTASO様 https://www.pakutaso.com
 GAHAG様 http://gahag.net

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【ポートフォリオ】PHPとSQLを学習する前に、今まで行った事を、レポートにまとめました。

はじめに
私は転職活動のための、ポートフォリオを作成中です。
PHPとSQLの学習に入る前に、それまで行った事をまとめました。

作成中のポートフォリオサイト:https://neptune.sakura.ne.jp/Hanatachi/
ポートフォリオサイトのGitHub:https://github.com/fujioka8700/Hanatachi

1.サイトの目的の明確化
道端に咲いている花たちについて、語れるコミュニティの作成、運用。

2.サイトの狙い、目的
 道に咲いている花たちの紹介。
コミュニティを作り、情報交換の場を作ります。

3.ターゲット
 ウォーキングをしている人たち。
これから、ウォーキングを、始めようとしている人たち。
花が好きな人たち。男女は問いません。

4.サイトを作ろうとした動機
 私は健康維持のために、ウォーキングをしています。
ウォーキングをしていると、初めて知るお店や、
見たことのない景色に、遭遇することがよくあります。
目の前の大きな発見があるとともに、小さな発見もよくあります。

 それは足元に咲いている花たちです。
道端に咲いている花をよく見てみると、
色鮮やかに、キレイにかわいく、たくさん咲いています。

 しかし、歩く人々は、イヤホンで音楽を聴いたり、
知人と話し合って、歩いているので、花たちに見向きもしません。

 私は、普段何気なく歩いている道には、
花たちが、キレイに咲いていることを、見てほしいと思いました。
そして、この花たちについて、語れるコミュニティを作りたいと思い、
このサイトを作ろうと思いました。

5.サイト制作スケジュールと、製作方法

 サイト制作に必要な作業を列挙して、Googleスプレッドシートで、WBSを作成しました。 
 https://docs.google.com/spreadsheets/d/135Wihnksz9lRj_IjUm0-P7GtRTXzRmpXG-Jp-oinOLQ/edit?usp=sharing 

 サイトのざっくりとしたイメージを、ラフスケッチに描きます。
 ラフスケッチの写真を、一部抜粋し、掲載します。
ラフスケッチのTOP画面
ラフスケッチの検索画面

 ラフスケッチから、GIMPにてサイトのスマホ版とPC版の
 デザインカンプの作成をします。
 作成したデザインカンプの画像を、一部抜粋し掲載します。

デザインカンプ、PC版のTOP画面
デザインカンプ、スマホ版のTOP画面

  スマホ版とPC版の、各1枚ずつ。計18枚、作成。
   TOPページ
   道端の花たちとは
   花を楽しむ
   ウォーキングのすすめ
   花の検索(TOP画面)
   花の検索(検索結果一覧)
   花の検索(花の詳細表示)
   掲示板
   更新情報・お知らせ

 素材となる写真は、以下の2つの方法で集めました。
  ・私がウォーキング中に、見つけた花をスマホで撮影しました。
  ・pakutaso.com様から、写真からお借りしました。

 作成したデザインカンプをもとに、VisualStudioCodeにて、
 マークアップとコーディングを行いました。

  スマホとPCに対応させたサイトを各1ページずつ。計7枚、作成。
   TOPページ
   道端の花たちとは
   花を楽しむ
   ウォーキングのすすめ
   (仮)花の検索(TOP画面)
   (仮)掲示板
   更新情報・お知らせ

 使用言語
  HTML
  CSS
  SCSS
  JavaScript

 使用したプラグイン
  jQuery(Slickを使うために、導入必須)
  Slick(TOP画面の画像のスライダー)
 
 その他
  ハンバーガーメニューは、自作しました。

6.結果と考察
 GIMPでのデザインカンプの作成が苦戦しました。
なぜなら、コーディングの技術は一切使わないからです。
マウスとキーボードで、1px単位で画像と文字の調整を行って、
サイトの完成図を、作るのは大変でした。

 マークアップとコーディングに関しては、
1ページ、確実なものを作れば、他のページは作りやすいことがわかりました。
あとプラグインとしてあるものは、自分自身で作るべきではないです。
スライダーを自作しようとしましたが、使い勝手も見栄えも、SlickSliderには敵いません。
プログラマの中で格言である、「車輪の発明はするべきではない」、
ということが、よくわかりました。

 ただ、JavaScriptの勉強にはなりました。
スライダーを作ろうとしたときに、
オブジェクトとノードのことを、よく理解できたためです。

7.感想と今後の課題
 デザインカンプの作成時、素材として撮影した写真は、
かわいく見えるよう加工できるようにしたいです。

 検索と掲示板は、まで制作できていません。
それはPHPとSQLの知識がないためです。
今後はPHPとSQLの基礎を勉強して、サイトの完成を目指します。

8.参考文献
 境祐司 著 「Webデザイン標準テキスト―変化に流されない制作コンセプトと基本スタイル―」
 https://gihyo.jp/dp/ebook/2012/978-4-7741-5086-4

9.サイト作成時、使用した主なソフト
 GIMP(デザインカンプの作成) https://www.gimp.org/
 Visual Studio Code(マークアップ、コーディング)
 https://azure.microsoft.com/ja-jp/products/visual-studio-code/
  便利だった拡張機能
   Japanese Language Pack for Visual Studio Code
   https://marketplace.visualstudio.com/items?itemName=MS-CEINTL.vscode-language-pack-ja
   Beautify css/sass/scss/less
   https://marketplace.visualstudio.com/items?itemName=michelemelluso.code-beautifier
   Live Sass Compiler
   https://marketplace.visualstudio.com/items?itemName=ritwickdey.live-sass
   Live Server
   https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer
   Visual Studio IntelliCode
   https://marketplace.visualstudio.com/items?itemName=VisualStudioExptTeam.vscodeintellicode
 SourceTree(GitHub使用のため) https://www.sourcetreeapp.com/
 FFFTP(ホームページを公開するため) https://ja.osdn.net/projects/ffftp/
 Windows付属の電卓

 ホームページの動作確認ブラウザー
  Chrome(PC、スマホ)
  Firefox(PC)
  Edge(PC)

10.素材を、お借りしたサイト様
 PAKUTASO様 https://www.pakutaso.com
 GAHAG様 http://gahag.net

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript基礎まとめ

DOMとは

  • Document Object Model
  • HTMLやXMLを扱うためのAPI
  • JSからHTMLにアクセスするための窓口
  • HTMLの探索やスタイルの変更、イベントの設定、HTML要素の取得などができる
  • また、ユーザーが操作したときの処理を設定できる

DOMの特徴

  • ツリー構造(階層構造)
  • ノード(NODE)で表現される

パースとは

  • JSONをHTMLに変換すること

スコープの種類

  • グローバルスコープ
  • スクリプトスコープ
  • 関数スコープ
  • ブロックスコープ
  • レキシカルスコープ

グローバルスコープ

  • windowオブジェクトもグローバルオブジェクトの一つ
  • グローバルスコープもスクリプトスコープも挙動に変わりはないため、一般的には同じ認識を持たれている

スクリプトスコープ

  • グローバルスコープの内側にあるスコープ
  • グローバルスコープにもスクリプトスコープにも同じ変数名がある場合は、スクリプトスコープが優先して参照される

関数スコープ

  • 関数の波括弧の中身を指す

ブロックスコープ

  • 波括弧の中身を指す
  • 条件:変数宣言で「let」「const」で宣言すること。「var」を使用するとブロックスコープが生成されない

レキシカルスコープ

  • コードを記述する場所によって参照できる変数が変わるスコープ
  • コードを記述した時点で決定するため、「静的スコープ」とも呼ばれる
  • ①実行中のコードから見た外部スコープ(内側のスコープから外部スコープへ参照可能)②どのようにしてスコープを決定するかの仕様のこと

スコープチェーン

  • 内側から外側のスコープへと変数が定義されているか順番に探す仕組み
  • グローバルスコープまで参照した結果、該当しない場合はエラーとなる

厳格な等価性と抽象的な等価性

  • 【厳格な等価性】( === )は対象のデータ型の両方が検知対象
  • 【抽象的な等価性】( == )は対象ののみを検知
  • 特別な理由がない限りは厳格な等価性を使用する

falsyな値

  • 0
  • ""(空文字)
  • null
  • undefined
  • NaN(Not a Number)

※NaN:計算結果で数値を期待するが、数値として処理できなかった場合に返す値

関数

  • 関数は実行可能なオブジェクト
  • 関数名が重複したとき、後から宣言した関数が実行される
  • argumentsというオブジェクトには実引数が入ってくる
  • returnは指定した値を返す。指定しなかった場合は、undefinedが返る

this

  • 呼び出し元のオブジェクトへの参照を保持するキーワード
  • 実行コンテキストによってthisの参照先が変わる
  • 一般的には関数コンテキストによってthisの参照先が変わるケースが多い
  • 関数として実行すれば、グローバルオブジェクトを参照
  • メソッドとして実行すれば、呼び出し元のオブジェクトを参照

thisの挙動(アロー関数と通常関数)

  • 通常関数においては、thisは呼び出し元に依存するため、関数の実行時(動的)に決定する
  • アロー関数におけるthisが、どの値を参照するかは関数の定義時(静的)に決定する
  • アロー関数はthisを持たないため、アロー関数内のthisはスコープチェーン同様に外側の関数を探しにいく

hasOwnPropertyとin

  • hasOwnPropertyは自分自身(own)のpropertyまでしか探しに行かない
  • inは自分自身のプロトタイプチェーンまで遡る(Object.prototypeまで)

同期処理

  • 一つの処理が完了するまでは(絶対に)次の処理には進まない

非同期処理

  • 一時的にメインスレッドから処理が切り離される
  • 非同期APIの例:setTimeoutやPromiseなど

タスクキュー(Task Queue)

  • 実行待ちの非同期処理の行列

変数

var

  • 再代入・再宣言ともに可能
  • スコープの外からでも参照できる
  • 非推奨

let

  • 再代入は可能
  • 再宣言は不可
  • スコープの外からは参照できない

const

  • 再代入・再宣言ともに不可
  • 配列やオブジェクトであれば書き換え可能

配列の要素を更新

sample.js
const name = ["masa", "nao", "takumi"];
console.log(name[0]);  //masa
name[0] = masato;  //masatoに書き換え
console.log(name[0]);   //masato

配列メソッド

map | 新しい配列を生成

  1. 配列をイテレート
  2. 一つずつの要素に処理を実行
  3. 新しい配列を生成
sample.js
const numArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];
//mapで各index(値)に*2を行い、その結果をresultArray変数に代入
const resultArray = numArray.map(num => num * 2);
console.log(resultArray);  //[ 2, 4, 6, 8, 10, 12, 14, 16, 18 ]

filter | 条件に合う要素を抽出

  1. 配列をイテレート
  2. 条件がtrueの要素のみを配列で返す
sample.js
const objectArray = [
  {id: 'hoge', text: 'fuga'},
  {id: 'foo', text: 'bar'},
  {id: 'fiz', text: 'buzz'},
];

const result = objectArray.filter(object => {
  return object.id === 'hoge';  //条件(idが'hoge'と合致するものだけをreturn)
});
console.log(result);  //[ { id: ‘hoge’, text: ‘fuga' } ]

findIndex | 要素の何番目なのかを返す

  1. 配列をイテレート
  2. 条件がtrueの要素が「何番目なのか」を返す
sample.js
const objectArray = [
  {id: 'hoge', text: 'fuga'},
  {id: 'foo', text: 'bar'},
  {id: 'fiz', text: 'buzz'},
];

const index = objectArray.findIndex(object => {
  return object.id === 'hoge';
});
console.log(index, object[index]);  //0, { id: ‘hoge’, text: ‘fuga' }

Typed for(型付けのfor)

  • 「 |0 」と記述することで数値型であることを定義している
  • 事前に数値型であることを定義し、実行時に型判定を行う手間を省く
sample.js
for (let i=0; i < 10; i=(i+1)|0) {
  console.log(i);
}

オブジェクト

  • 配列と同じく、複数のデータをまとめて管理できる
  • それぞれの値にプロパティを付けて管理する
sample.js
// 構文
const obj = {
  property: "vaule",
}

オブジェクトの値を更新

sample.js
const human = {name: masa, age: 21};
console.log(human.name);  //masa
human.name = masato;  //masatoに書き換え
console.log(human.name);  //masato

オブジェクト in 配列

sample.js
const human = [
    { name: masa, age: 21 },  //[0]
    { name: nao, age: 11 },  //[1]
];

プロパティの値を配列で表現

sample.js
const human = {
    name: masa,
    age: 21,
    favoriteFoods: [ ラーメン, 寿司, カレー" ],
}

プロパティの値をオブジェクトで表現

sample.js
const human = {
    name: masa,
    age: 21,
    favorite: {
        food: ラーメン,
        sports: サッカー,
        color: yellow,
  },
}

文字列結合

古い記述(+結合)

sample.js
const name = foo;
const aisatsu = こんにちは;
console.log(name + さん + aisatsu);  //fooさんこんにちは

新しい記述(テンプレートリテラル)

sample.js
const name = foo;
const aisatsu = こんにちは;
console.log(`${name}さん${aisatsu}`);  //fooさんこんにちは

コールバック関数

  • 引数に関数を受け取る関数を高階関数と呼ぶ
  • 関数の中で関数を実行する関数を高階関数
  • 引数に渡される関数をコールバック関数と呼ぶ
// 構文
function 高級関数(コールバック関数) {
    コールバック関数();
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScript】個人メモ

はじめに

本記事は、JavaScriptの個人的なメモです。
間違い等ございましたらご指摘お願い致します。

DOMとは

  • Document Object Model
  • HTMLやXMLを扱うためのAPI
  • JSからHTMLにアクセスするための窓口
  • HTMLの探索やスタイルの変更、イベントの設定、HTML要素の取得などができる
  • また、ユーザーが操作したときの処理を設定できる

DOMの特徴

  • ツリー構造(階層構造)
  • ノード(NODE)で表現される

パースとは

  • JSONをHTMLに変換すること

スコープの種類

  • グローバルスコープ
  • スクリプトスコープ
  • 関数スコープ
  • ブロックスコープ
  • レキシカルスコープ

グローバルスコープ

  • windowオブジェクトもグローバルオブジェクトの一つ
  • グローバルスコープもスクリプトスコープも挙動に変わりはないため、一般的には同じ認識を持たれている

スクリプトスコープ

  • グローバルスコープの内側にあるスコープ
  • グローバルスコープにもスクリプトスコープにも同じ変数名がある場合は、スクリプトスコープが優先して参照される

関数スコープ

  • 関数の波括弧の中身を指す

ブロックスコープ

  • 波括弧の中身を指す
  • 条件:変数宣言で「let」「const」で宣言すること。「var」を使用するとブロックスコープが生成されない

レキシカルスコープ

  • コードを記述する場所によって参照できる変数が変わるスコープ
  • コードを記述した時点で決定するため、「静的スコープ」とも呼ばれる
  • ①実行中のコードから見た外部スコープ(内側のスコープから外部スコープへ参照可能)②どのようにしてスコープを決定するかの仕様のこと

スコープチェーン

  • 内側から外側のスコープへと変数が定義されているか順番に探す仕組み
  • グローバルスコープまで参照した結果、該当しない場合はエラーとなる

厳格な等価性と抽象的な等価性

  • 【厳格な等価性】( === )は対象のデータ型の両方が検知対象
  • 【抽象的な等価性】( == )は対象ののみを検知
  • 特別な理由がない限りは厳格な等価性を使用する

falsyな値

  • 0
  • ""(空文字)
  • null
  • undefined
  • NaN(Not a Number)

※NaN:計算結果で数値を期待するが、数値として処理できなかった場合に返す値

関数

  • 関数は実行可能なオブジェクト
  • 関数名が重複したとき、後から宣言した関数が実行される
  • argumentsというオブジェクトには実引数が入ってくる
  • returnは指定した値を返す。指定しなかった場合は、undefinedが返る

this

  • 呼び出し元のオブジェクトへの参照を保持するキーワード
  • 実行コンテキストによってthisの参照先が変わる
  • 一般的には関数コンテキストによってthisの参照先が変わるケースが多い
  • 関数として実行すれば、グローバルオブジェクトを参照
  • メソッドとして実行すれば、呼び出し元のオブジェクトを参照

thisの挙動(アロー関数と通常関数)

  • 通常関数においては、thisは呼び出し元に依存するため、関数の実行時(動的)に決定する
  • アロー関数におけるthisが、どの値を参照するかは関数の定義時(静的)に決定する
  • アロー関数はthisを持たないため、アロー関数内のthisはスコープチェーン同様に外側の関数を探しにいく

hasOwnPropertyとin

  • hasOwnPropertyは自分自身(own)のpropertyまでしか探しに行かない
  • inは自分自身のプロトタイプチェーンまで遡る(Object.prototypeまで)

同期処理

  • 一つの処理が完了するまでは(絶対に)次の処理には進まない

非同期処理

  • 一時的にメインスレッドから処理が切り離される
  • 非同期APIの例:setTimeoutやPromiseなど

タスクキュー(Task Queue)

  • 実行待ちの非同期処理の行列

変数

var

  • 再代入・再宣言ともに可能
  • スコープの外からでも参照できる
  • 非推奨

let

  • 再代入は可能
  • 再宣言は不可
  • スコープの外からは参照できない

const

  • 再代入・再宣言ともに不可
  • 配列やオブジェクトであれば書き換え可能

配列の要素を更新

sample.js
const name = ["masa", "nao", "takumi"];
console.log(name[0]);  //masa
name[0] = masato;  //masatoに書き換え
console.log(name[0]);   //masato

配列メソッド

map | 新しい配列を生成

  1. 配列をイテレート
  2. 一つずつの要素に処理を実行
  3. 新しい配列を生成
sample.js
const numArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];
//mapで各index(値)に*2を行い、その結果をresultArray変数に代入
const resultArray = numArray.map(num => num * 2);
console.log(resultArray);  //[ 2, 4, 6, 8, 10, 12, 14, 16, 18 ]

filter | 条件に合う要素を抽出

  1. 配列をイテレート
  2. 条件がtrueの要素のみを配列で返す
sample.js
const objectArray = [
  {id: 'hoge', text: 'fuga'},
  {id: 'foo', text: 'bar'},
  {id: 'fiz', text: 'buzz'},
];

const result = objectArray.filter(object => {
  return object.id === 'hoge';  //条件(idが'hoge'と合致するものだけをreturn)
});
console.log(result);  //[ { id: ‘hoge’, text: ‘fuga' } ]

findIndex | 要素の何番目なのかを返す

  1. 配列をイテレート
  2. 条件がtrueの要素が「何番目なのか」を返す
sample.js
const objectArray = [
  {id: 'hoge', text: 'fuga'},
  {id: 'foo', text: 'bar'},
  {id: 'fiz', text: 'buzz'},
];

const index = objectArray.findIndex(object => {
  return object.id === 'hoge';
});
console.log(index, object[index]);  //0, { id: ‘hoge’, text: ‘fuga' }

Typed for(型付けのfor)

  • 「 |0 」と記述することで数値型であることを定義している
  • 事前に数値型であることを定義し、実行時に型判定を行う手間を省く
sample.js
for (let i=0; i < 10; i=(i+1)|0) {
  console.log(i);
}

オブジェクト

  • 配列と同じく、複数のデータをまとめて管理できる
  • それぞれの値にプロパティを付けて管理する
sample.js
// 構文
const obj = {
  property: "vaule",
}

オブジェクトの値を更新

sample.js
const human = {name: masa, age: 21};
console.log(human.name);  //masa
human.name = masato;  //masatoに書き換え
console.log(human.name);  //masato

オブジェクト in 配列

sample.js
const human = [
    { name: masa, age: 21 },  //[0]
    { name: nao, age: 11 },  //[1]
];

プロパティの値を配列で表現

sample.js
const human = {
    name: masa,
    age: 21,
    favoriteFoods: [ ラーメン, 寿司, カレー" ],
}

プロパティの値をオブジェクトで表現

sample.js
const human = {
    name: masa,
    age: 21,
    favorite: {
        food: ラーメン,
        sports: サッカー,
        color: yellow,
  },
}

文字列結合

古い記述(+結合)

sample.js
const name = foo;
const aisatsu = こんにちは;
console.log(name + さん + aisatsu);  //fooさんこんにちは

新しい記述(テンプレートリテラル)

sample.js
const name = foo;
const aisatsu = こんにちは;
console.log(`${name}さん${aisatsu}`);  //fooさんこんにちは

コールバック関数

  • 引数に関数を受け取る関数を高階関数と呼ぶ
  • 関数の中で関数を実行する関数を高階関数
  • 引数に渡される関数をコールバック関数と呼ぶ
// 構文
function 高級関数(コールバック関数) {
    コールバック関数();
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Axios / Get

本日のゴール

  • axios.get を使えるようになる

アジェンダ

  1. 下準備
  2. import axios
  3. getData の出力

1. 下準備

  • html, jsonは下記のように準備

HTML

<ul class="js-AxiosTest">
<!-- 
  // この中にgetしたデータを出力予定
  <li>Heading 1<br>text 1</li>
  <li>Heading 2<br>text 2</li>
  <li>Heading 3<br>text 3</li>
 -->
</ul>

json

[{
  "title": "Heading 1",
  "text": "text 1"
}, {
  "title": "Heading 2",
  "text": "text 2"
}, {
  "title": "Heading 3",
  "text": "text 3"
}]

2. import axios

Github

https://github.com/axios/axios

CDN

<script src="https://unpkg.com/axios/dist/axios.min.js" defer></script>

3. getData の出力

class AxiosGet {
  constructor(el) {
    this.el = el
    this.srcHtml = ''
  }

  async init() {
    this.items = await this.getData()
    this.srcHtml = this.createHtml(this.items)
    this.el.innerHTML = this.srcHtml
  }

  async getData() {
    const { data } = await axios.get('http://localhost:3000/data/index.json') // 取得したいjsonのパスを記載
    return data
  }

  createHtml(items) {
    let elements = ''
    for (let item of items) {
      elements += `
        <li>${item.title}<br>${item.text}<li>
      `
    }
    return elements
  }
}

const el = document.querySelector('.js-AxiosTest')
new AxiosGet(el).init()
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Robocode】JavaScriptを勉強しながら戦車ゲームを攻略していく その1

はじめに

前回記事で構築したRobocodeを遊びながら攻略していきます。
https://qiita.com/abemaki/items/54712e50e4a4a25c229b

ゲームを起動すると以下のような画面が出てきます。
初期段階でもステージ0であれば、五分五分の戦いです。
今回は軽く触りながら、ステージ0での勝率を高めていきたいと思います。

反響があればGithubに改良版をアップしたり続編を書いてみようかな。

 
画面イメージと画面の見方
image.png

ソースコードを理解する

公式の説明を読む前にちょっとだけソースコードを見ていきます

ソースコードを見ていくと
boss-.jsといたファイルとmyrobot.jsといったファイルがあるのがわかります。
myrobot.jsは自機で、boss-
.jsは敵機を表しているものであることがファイル名からわかると思います。
ファイルを開いてみると、何やらファンクションがずらりと並んでいるのがわかりますがこのままだと詳細がよくわかりません。
この理解のまま先には進めません。
image.png

公式の説明を読んでみる

https://github.com/youchenlee/robocode-js

公式のロボットHOWTOを見てみると以下のことがわかります

入手可能な情報:

自己情報
・ me.id
・ me.x
・ me.y
・ me.hp
・ me.angle-現在の角度(タンク角度+タレット角度)
・ me.tank_angle
・ me.turret_angle

敵情報
・ enemy-spot [N] .id
・ enemy-spot [N] .hp
・ enemy-spot [N] .angle-敵に対する角度(方向)

シーケンシャルアクション:
・turn_left(角度)
・turn_right(角度)
・move_forwards(距離)
・move_backwards(距離)
・move_opposide(distance)-このアクションはOnWallCollide()でのみ使用できます

並列アクション:
・turn_turret_left(角度)
・turn_turret_right(角度)
・シュート()
・yell(メッセージ)
 
イベント:
OnIdle()-アイドル時にトリガーされます(実装する必要があります)
OnWallCollide()-タンクが壁に衝突したとき
OnHit()-弾丸が当たったとき
OnEnemySpot()-砲塔が敵に直接面している場合(発砲しない理由はないようです!)

 
 

試しに自機と敵機のセリフを変えてみます。

 
セリフはyell(メッセージ)で定義します。 
ファイルを変更したら保存して、ブラウザを更新しましょう
image.png

 

・・・超賑やかになった。
robo.gif

ファイルに変更を加えるとしっかりと結果に反映されるのがわかります。

 
 
 

ソースコードを改良して、勝率100%を目指してみる。

現状の勝率が何故5割程度なのか整理してみる

両者同じような動きをしていて
クルクル回って、相手を見つけたら弾を発射するだけなので、そのあと発見場所から近い場所を探す等の動作をせずに
またひたすらクルクル相手を探しはじめます。 その為、五分五分の戦いをしていることがわかります。

・自分の動き
 右に動き回りながら相手を探して見つけたら弾を発射するだけ 
 上記を繰り返す

・相手の動き
 クルクル砲台を回転させながら相手を探して見つけたら弾を発射するだけ
 上記を繰り返す

 
 
 

敵に対面した後の動作を変更してみる

そこで小刻みに右に動き回って
相手を見つけたら、できるだけ近い場所で相手を左利回りに探して
攻撃をしかけるようにソースを修正してみようかと思います。
 

小刻みに敵を探して、敵を発見したらできるだけ近い場所を探して敵を攻撃するように修正してみます。
 
対面フラグを追加してアイドル時の処理を以下のように分岐させます。

■アイドル時
対面フラグ=敵を未発見(false)の際の処理:
 小刻みに右回りで敵を探す

対面フラグ=敵を発見(true)の際の処理:
 小刻みに左回りで敵を探す
 この際に敵を発見できなかった場合に対面フラグを対面フラグを敵を未発見(false)に変更します

■敵発見時
 攻撃をしかけて
 対面フラグを敵を発見(true)に変更します

修正前後の自機のソースコード(myrobot.js)

 

修正前のmyrobot.js(クリックして展開)

// Generated by LiveScript 1.2.0
(function(){
  var MyRobot, tr;
  importScripts('../base-robot.js');
  MyRobot = (function(superclass){
    var prototype = extend$((import$(MyRobot, superclass).displayName = 'MyRobot', MyRobot), superclass).prototype, constructor = MyRobot;
    prototype.onIdle = function(){
      this.move_forwards(50);
      this.turn_turret_left(10);
      this.turn_right(90);
    };
    prototype.onWallCollide = function(){
      this.move_opposide(10);
      this.turn_left(90);
    };
    prototype.onHit = function(){
      this.yell("Oops!");
    };
    prototype.onEnemySpot = function(){
      this.yell("Fire!");
      this.shoot();
    };
    function MyRobot(){
      MyRobot.superclass.apply(this, arguments);
    }
    return MyRobot;
  }(BaseRobot));
  tr = new MyRobot("MyRobot");
  function extend$(sub, sup){
    function fun(){} fun.prototype = (sub.superclass = sup).prototype;
    (sub.prototype = new fun).constructor = sub;
    if (typeof sup.extended == 'function') sup.extended(sub);
    return sub;
  }
  function import$(obj, src){
    var own = {}.hasOwnProperty;
    for (var key in src) if (own.call(src, key)) obj[key] = src[key];
    return obj;
  }
}).call(this);


修正後のmyrobot.js(クリックして展開)
// Generated by LiveScript 1.2.0
(function(){
  var MyRobot, tr;
  importScripts('../base-robot.js');
  MyRobot = (function(superclass){
    var discoveryFired,prototype = extend$((import$(MyRobot, superclass).displayName = 'MyRobot', MyRobot), superclass).prototype, constructor = MyRobot;

    // 対面フラグ
    discoveryFired = false;

    // アイドル時にトリガーされます(実装する必要があります)
    prototype.onIdle = function(){
      if(this.discoveryFired){
        // 対面後の動作 小刻みに左に動いで相手を探す

        // 前進(距離)
        this.move_forwards(10);
        // 砲塔を左に向ける(角度)
        this.turn_turret_left(10);
        // 左に曲がる(角度)
        this.turn_left(10);

        // 対面フラグリセット
        this.discoveryFired = false;

      } else {
        // 対面前の動作 小刻みに右に動いで相手を探す

        // 前進(距離)
        this.move_forwards(10);
        // 砲塔を右に向ける(角度)
        this.turn_turret_right(10);
        // 右に曲がる(角度)
        this.turn_right(10);
      }
    };
    // タンクが壁に衝突したとき
    prototype.onWallCollide = function(){
      // 反対に移動(距離)
      this.move_opposide(10);
      // 左に曲がる(角度)
      this.turn_left(90);
    };
    // 自機に弾丸が当たったとき
    prototype.onHit = function(){
      // セリフ
      this.yell("痛いっ");
    };
    // 砲塔が敵に直接面している場合(発砲しない理由はないようです!)
    prototype.onEnemySpot = function(){
      // セリフ
      this.yell("当たれ~っ");
      // 発射
      this.shoot();

      // 対面フラグを立てる
      this.discoveryFired = true;
    };
    function MyRobot(){
      MyRobot.superclass.apply(this, arguments);
    }
    return MyRobot;
  }(BaseRobot));
  tr = new MyRobot("MyRobot");
  function extend$(sub, sup){
    function fun(){} fun.prototype = (sub.superclass = sup).prototype;
    (sub.prototype = new fun).constructor = sub;
    if (typeof sup.extended == 'function') sup.extended(sub);
    return sub;
  }
  function import$(obj, src){
    var own = {}.hasOwnProperty;
    for (var key in src) if (own.call(src, key)) obj[key] = src[key];
    return obj;
  }
}).call(this);

 

 

改良した戦車で闘ってみる

いざっ 勝負!!!
robo3.gif

 
圧勝です。 このステージに関しては勝率100%です。

遊びながらちゃんとエンジニアの基礎中の基礎が経験できるような仕組みになっているのは面白いですね。

・既存ソースコードを見て把握する
・公式ドキュメントを読んで理解を深める
・既存ソースコードに公式ドキュメントで得た理解をコメント文に落とし込んでみる
・現状の動きから課題点を洗い出す
・課題点を改善する方法を考える
・課題点を改善する
・動作確認して結果に超自己満足(←超大事)

ちなみに今回の改良でステージ0は余裕ですが以降はステージが進むにつれて勝率が下がっていきます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Javascript】BigIntの使い方

競プロなどで Javascript を採用していると、稀にロジックは正しいはずなのにクリアしない時がある。
これは、Number 型で定義されている「Number.MAX_SAFE_INTEGERより大きい」または「Number.MIN_SAFE_INTEGERより小さい」数値で演算されており、丸め誤差が発生している可能性が高い。

これを解決するには BigInt 型を使用すると良い。(var の自動変換に BigInt が含まれていない為、今回のようなエラーが表示される)
しかし、使用するにあたって直感的に使用できなかったので使い方を備忘録程度に記載しておく。

宣言方法

BigIntの宣言方法は、2通り存在する。
①代入する数値に n を追記する。
②代入する数値の型を設定する。

initialaize.js
//①
var a = 0n;

//②
var b = BigInt(before_BigInt);

演算方法

2021年1月時点では BigInt に Math などの演算パッケージが対応しておらず、基本的な演算子(+,-,*,/,%)のみが使用可能な演算子となっている。
その為、小数点切り捨てなどは以下のように記述するなど工夫が必要になる。

また、BigInt の演算及び比較は BigInt 同士である必要がある。
他の型が含まれているとTypeError: Cannot mix BigInt and other types, use explicit conversions (BigInt と他の型を一緒に使うことは出来ません)が表示される。

calculate.js
// value を 100 で割った時の商を算出する。
var floor = (value - (value % 100n)) / 100n;   

//@il9437 さんのコメントを参照お願いします。(2020.01.04 追記)
var floor2 = value / 100n;

最後に

Java などには long があったり、パッケージが発展してたりするので競プロのシーンでは Javascript はあまり向かないのかもしれない。そもそも、実際のシステムで Number の許容桁数をオーバーする数値を運用したことがないのでニッチかもしれない。
そんな中で、この記事を読んで少しでも解決のきっかけになれば最高です。

MDN Web Docs を参照:https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/BigInt

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

javascriptによる並列処理

概要

普段javascriptを書いているとよく使う非同期処理(Promise)だが、言語仕様上(
シングルスレッドのため)非同期処理は処理の順番を変えているだけで厳密には同期処理のようだった。

ざっくり図

同期処理
実行→結果→実行→結果...

非同期処理
実行→実行→結果→結果...

並列処理
実行→結果...
実行→結果...

よくよく調べているとWorkerオブジェクトを使用すれば並列処理ができるみたいなので試してみた

Document
- Docs Worker

ブラウサでの使用

※メインスレッド以外では、domの更新などができない

index.js
var worker = new Worker("./greeting-worker.js");

// データが送られてきたら発火
worker.onmessage = function (message) {
  console.log(message)
  // workerの停止
  this.terminate();
};

// Worker作成時かWorker実行中でエラーとなった場合に発火
worker.onerror = function (err) {
  console.error("onerror", err.message);
};

// データ送信
worker.postMessage("Hi");
greeting-worker.js
// worker.postMessageが呼ばれたら発火
self.onmessage = function (message) {
  // 送られてきたデータ
  console.log(message);
  // workerにデータを送る
  self.postMessage("I'm good.");
};

バックエンド(Node.js)での使用

index.js
var { Worker } = require("worker_threads");
var worker = new Worker("./greeting-worker.js");
// データが送られてきたら発火
worker.on("message", function (message) {
  console.log(message);
  // workerの停止
  worker.terminate();
});

// Worker作成時かWorker実行中でエラーとなった場合に発火
worker.on("error", function (err) {
  console.error("onerror", err.message);
  // workerの停止
  worker.terminate();
});

// workerが停止したら発火
worker.on("exit", function () {
  console.log("Bye!!");
});

// データ送信
worker.postMessage("Hi, how are you?");
greeting-worker.js
// worker.postMessageが呼ばれたら発火
self.onmessage = function (message) {
  // 送られてきたデータ
  console.log(message);
  // workerにデータを送る
  self.postMessage("I'm good.");
};
// スレッドを増やしたい場合
var worker1 = new Worker("./worker1.js")
var worker2 = new Worker("./worker2.js")
var worker3 = new Worker("./worker3.js")
...

感想

あまり並列にすることもない処理でしたが、意外と簡単に扱うことができました。
使い所としては、処理が重い計算処理などやindexedDB(ブラウザ)があるそうです。
またワーカースレッドでデータをやりとりできるMessageChannelというのもありました。(他ArrayBufferやFileHandleというものもあった)

まとめ

  • javascriptは非同期処理の他に並列処理もできる
  • ブラウザ/Node.jsともにAPIが用意されている.(使用感もほぼ同じ)
  • メインスレッド以外では、domの更新などができない
  • ワーカースレッドを増やしたい場合は複数Workerを呼び出す
  • ワーカースレッド間でのデータのやりとりはMessageChannelを使用して行うことができる。 
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptで文字がはみ出している時に自動横スクロールする

目標

コレ↓ を作ります。
コンポ 1.gif

完成形

function StartScroll(target_id){
    const ele = document.getElementById(target_id);
    var style = ele.style;
    style.overflowY = "scroll";//横スクロールする
    style.whiteSpace = "nowrap";//改行しない
    style.setProperty("-ms-overflow-style","none");
    style.setProperty("scrollbar-width","none");
    style.setProperty("-webkit-scrollbar","none");

    /**
     * この値がno以外になったらスクロールを終了する
     */
    let scroll_exit = "no";

    function scroll(){
        if(scroll_exit == "no"){//スクロールが終了に設定されていない事を確認
            if(!ele.scrollWidth == 0){//スクロールが必要な場合
                let lastLeft = ele.scrollLeft;//現在のスクロール位置を記録
                function move_left(){//実際にスクロールする関数
                    ele.scrollLeft++;//1スクロールする
                    if(lastLeft == ele.scrollLeft){//最後までスクロールした事を確認
                        setTimeout(function(){//1000ms(1秒)後に一番左に戻す
                            ele.scrollLeft = 0;//1000ms(1秒)後に一番左に戻す
                            setTimeout(scroll,2000);//一番左に戻してから2000ms(2秒)後にスクロールを再開する
                        },1000);//1000ms(1秒)後に一番左に戻す
                    }else{//最後までスクロールしていない場合
                        lastLeft = ele.scrollLeft;//現在のスクロール位置を更新
                        setTimeout(move_left,20)//20はスクロール速度(値が小さい方が早くスクロール)
                    };
                };
                move_left();//最初の一回を実行
            }else{//スクロールが不要な場合
                setTimeout(scroll,2000)//2000ms(2秒)後にもう一度スクロールが必要か確認
            };
        };
    };

    new Promise(() => {//非同期で
        scroll();//最初のスクロールを開始する
    });

    return function(){
        scroll_exit = "yes";
    };
};

作り方

複数の要素をスクロールできるように関数を作ります。

function scroll(target_id){

}

まず getElementById をします。

function scroll(target_id){
    const ele = document.getElementById(target_id);
}

次にstyleを設定します。

function scroll(target_id){
    const ele = document.getElementById(target_id);
    var style = ele.style;
    style.overflowY = "scroll";//横スクロールする
    style.whiteSpace = "nowrap";//改行しない
    style.setProperty("-ms-overflow-style","none");
    style.setProperty("scrollbar-width","none");
    style.setProperty("-webkit-scrollbar","none");
}

自動でスクロール

ここから自動でスクロールできるようにします。

まず、スクロールを終了できるようにします。

function scroll(target_id){
    const ele = document.getElementById(target_id);
    var style = ele.style;
    style.overflowY = "scroll";//横スクロールする
    style.whiteSpace = "nowrap";//改行しない
    style.setProperty("-ms-overflow-style","none");
    style.setProperty("scrollbar-width","none");
    style.setProperty("-webkit-scrollbar","none");


    /**
     * この値がno以外になったらスクロールを終了する
     */
    let scroll_exit = "no";
}

スクロールする関数を作ります。

function scroll(target_id){
    const ele = document.getElementById(target_id);
    var style = ele.style;
    style.overflowY = "scroll";//横スクロールする
    style.whiteSpace = "nowrap";//改行しない
    style.setProperty("-ms-overflow-style","none");
    style.setProperty("scrollbar-width","none");
    style.setProperty("-webkit-scrollbar","none");


    /**
     * この値がno以外になったらスクロールを終了する
     */
    let scroll_exit = "no";

    function scroll(){

    };
}

scroll_exitno の時以外実行しないようにします。

    function scroll(){
        if(scroll_exit == "no"){//スクロールが終了に設定されていない事を確認

        };
    };

スクロール可能な横幅が0になっているか確認して、スクロールが必要か確認します。

    function scroll(){
        if(scroll_exit == "no"){//スクロールが終了に設定されていない事を確認
            if(!ele.scrollWidth == 0){//スクロールが必要な場合

            }else{//スクロールが不要な場合

            };
        };
    };

スクロールが不要な場合2秒後にもう一度スクロールが不要か確認します。

    function scroll(){
        if(scroll_exit == "no"){//スクロールが終了に設定されていない事を確認
            if(!ele.scrollWidth == 0){//スクロールが必要な場合

            }else{//スクロールが不要な場合
                setTimeout(scroll,2000)//2000ms(2秒)後にもう一度スクロールが必要か確認
            };
        };
    };

スクロールが必要な場合の処理

ここからスクロールが必要な場合の処理です。

初めに、現在どのくらいスクロールしているか取得しておきます。

    function scroll(){
        if(scroll_exit == "no"){//スクロールが終了に設定されていない事を確認
            if(!ele.scrollWidth == 0){//スクロールが必要な場合

                let lastLeft = ele.scrollLeft;//現在のスクロール位置を記録

            }else{//スクロールが不要な場合
                setTimeout(scroll,2000)//2000ms(2秒)後にもう一度スクロールが必要か確認
            };
        };
    };

左にスクロールする関数を作ります。

   function scroll(){
        if(scroll_exit == "no"){//スクロールが終了に設定されていない事を確認
            if(!ele.scrollWidth == 0){//スクロールが必要な場合
                let lastLeft = ele.scrollLeft;//現在のスクロール位置を記録

                function move_left(){//実際にスクロールする関数

                };

            }else{//スクロールが不要な場合
                setTimeout(scroll,2000)//2000ms(2秒)後にもう一度スクロールが必要か確認
            };
        };
    };

左に1スクロールします。

   function scroll(){
        if(scroll_exit == "no"){//スクロールが終了に設定されていない事を確認
            if(!ele.scrollWidth == 0){//スクロールが必要な場合
                let lastLeft = ele.scrollLeft;//現在のスクロール位置を記録
                function move_left(){//実際にスクロールする関数

                    ele.scrollLeft++;//1スクロールする

                };
            }else{//スクロールが不要な場合
                setTimeout(scroll,2000)//2000ms(2秒)後にもう一度スクロールが必要か確認
            };
        };
    };

現在のスクロール位置を取得して、事前に取得しておいた位置と同じか比較する事で最後までスクロールしたか確認します。

    function scroll(){
        if(scroll_exit == "no"){//スクロールが終了に設定されていない事を確認
            if(!ele.scrollWidth == 0){//スクロールが必要な場合
                let lastLeft = ele.scrollLeft;//現在のスクロール位置を記録
                function move_left(){//実際にスクロールする関数
                    ele.scrollLeft++;//1スクロールする

                    if(lastLeft == ele.scrollLeft){//最後までスクロールした事を確認

                    }else{//最後までスクロールしていない場合

                    };

                };
            }else{//スクロールが不要な場合
                setTimeout(scroll,2000)//2000ms(2秒)後にもう一度スクロールが必要か確認
            };
        };
    };

最後までスクロールしていない場合

次のスクロールを開始する前に、現在のスクロール位置を事前に取得しておきます。

    function scroll(){
        if(scroll_exit == "no"){//スクロールが終了に設定されていない事を確認
            if(!ele.scrollWidth == 0){//スクロールが必要な場合
                let lastLeft = ele.scrollLeft;//現在のスクロール位置を記録
                function move_left(){//実際にスクロールする関数
                    ele.scrollLeft++;//1スクロールする
                    if(lastLeft == ele.scrollLeft){//最後までスクロールした事を確認
                    }else{//最後までスクロールしていない場合

                        lastLeft = ele.scrollLeft;//現在のスクロール位置を更新

                    };
                };
            }else{//スクロールが不要な場合
                setTimeout(scroll,2000)//2000ms(2秒)後にもう一度スクロールが必要か確認
            };
        };
    };

20ms待機してからもう一度スクロールします。

    function scroll(){
        if(scroll_exit == "no"){//スクロールが終了に設定されていない事を確認
            if(!ele.scrollWidth == 0){//スクロールが必要な場合
                let lastLeft = ele.scrollLeft;//現在のスクロール位置を記録
                function move_left(){//実際にスクロールする関数
                    ele.scrollLeft++;//1スクロールする
                    if(lastLeft == ele.scrollLeft){//最後までスクロールした事を確認
                    }else{//最後までスクロールしていない場合
                        lastLeft = ele.scrollLeft;//現在のスクロール位置を更新

                        setTimeout(move_left,20)//20はスクロール速度(値が小さい方が早くスクロール)

                    };
                };
            }else{//スクロールが不要な場合
                setTimeout(scroll,2000)//2000ms(2秒)後にもう一度スクロールが必要か確認
            };
        };
    };

最後までスクロールできた時

一番右で1000ms待機してから一番左に移動します。

    function scroll(){
        if(scroll_exit == "no"){//スクロールが終了に設定されていない事を確認
            if(!ele.scrollWidth == 0){//スクロールが必要な場合
                let lastLeft = ele.scrollLeft;//現在のスクロール位置を記録
                function move_left(){//実際にスクロールする関数
                    ele.scrollLeft++;//1スクロールする
                    if(lastLeft == ele.scrollLeft){//最後までスクロールした事を確認



                        setTimeout(function(){//1000ms(1秒)後に一番左に戻す
                            ele.scrollLeft = 0;//1000ms(1秒)後に一番左に戻す
                        },1000);//1000ms(1秒)後に一番左に戻す



                    }else{//最後までスクロールしていない場合
                        lastLeft = ele.scrollLeft;//現在のスクロール位置を更新
                        setTimeout(move_left,20)//20はスクロール速度(値が小さい方が早くスクロール)
                    };
                };
            }else{//スクロールが不要な場合
                setTimeout(scroll,2000)//2000ms(2秒)後にもう一度スクロールが必要か確認
            };
        };
    };

2000ms(2秒)待機してからスクロールを再び開始します。

    function scroll(){
        if(scroll_exit == "no"){//スクロールが終了に設定されていない事を確認
            if(!ele.scrollWidth == 0){//スクロールが必要な場合
                let lastLeft = ele.scrollLeft;//現在のスクロール位置を記録
                function move_left(){//実際にスクロールする関数
                    ele.scrollLeft++;//1スクロールする
                    if(lastLeft == ele.scrollLeft){//最後までスクロールした事を確認
                        setTimeout(function(){//1000ms(1秒)後に一番左に戻す
                            ele.scrollLeft = 0;//1000ms(1秒)後に一番左に戻す



                            setTimeout(scroll,2000);//2000ms(2秒)後にスクロールを再開する



                        },1000);//1000ms(1秒)後に一番左に戻す
                    }else{//最後までスクロールしていない場合
                        lastLeft = ele.scrollLeft;//現在のスクロール位置を更新
                        setTimeout(move_left,20)//20はスクロール速度(値が小さい方が早くスクロール)
                    };
                };
            }else{//スクロールが不要な場合
                setTimeout(scroll,2000)//2000ms(2秒)後にもう一度スクロールが必要か確認
            };
        };
    };


関数の1回目を実行する

関数の中から関数を実行していますが、最初の1回は関数の外から実行しないといけないので最初の一回を実行します。

    function scroll(){
        if(scroll_exit == "no"){//スクロールが終了に設定されていない事を確認
            if(!ele.scrollWidth == 0){//スクロールが必要な場合
                let lastLeft = ele.scrollLeft;//現在のスクロール位置を記録
                function move_left(){//実際にスクロールする関数
                    ele.scrollLeft++;//1スクロールする
                    if(lastLeft == ele.scrollLeft){//最後までスクロールした事を確認
                        setTimeout(function(){//1000ms(1秒)後に一番左に戻す
                            ele.scrollLeft = 0;//1000ms(1秒)後に一番左に戻す
                            setTimeout(scroll,2000);//一番左に戻してから2000ms(2秒)後にスクロールを再開する
                        },1000);//1000ms(1秒)後に一番左に戻す
                    }else{//最後までスクロールしていない場合
                        lastLeft = ele.scrollLeft;//現在のスクロール位置を更新
                        setTimeout(move_left,20)//20はスクロール速度(値が小さい方が早くスクロール)
                    };
                };



                move_left();//最初の一回を実行



            }else{//スクロールが不要な場合
                setTimeout(scroll,2000)//2000ms(2秒)後にもう一度スクロールが必要か確認
            };
        };
    };

同じようにscroll()も最初の一回を外から実行します。
これは非同期で実行します。

    function scroll(){
        if(scroll_exit == "no"){//スクロールが終了に設定されていない事を確認
            if(!ele.scrollWidth == 0){//スクロールが必要な場合
                let lastLeft = ele.scrollLeft;//現在のスクロール位置を記録
                function move_left(){//実際にスクロールする関数
                    ele.scrollLeft++;//1スクロールする
                    if(lastLeft == ele.scrollLeft){//最後までスクロールした事を確認
                        setTimeout(function(){//1000ms(1秒)後に一番左に戻す
                            ele.scrollLeft = 0;//1000ms(1秒)後に一番左に戻す
                            setTimeout(scroll,2000);//一番左に戻してから2000ms(2秒)後にスクロールを再開する
                        },1000);//1000ms(1秒)後に一番左に戻す
                    }else{//最後までスクロールしていない場合
                        lastLeft = ele.scrollLeft;//現在のスクロール位置を更新
                        setTimeout(move_left,20)//20はスクロール速度(値が小さい方が早くスクロール)
                    };
                };
                move_left();//最初の一回を実行
            }else{//スクロールが不要な場合
                setTimeout(scroll,2000)//2000ms(2秒)後にもう一度スクロールが必要か確認
            };
        };
    };





    new Promise(() => {//非同期で
        scroll();//最初のスクロールを開始する
    });

スクロールを終了する

最後にスクロールを止められるようにします。

    function scroll(){
        if(scroll_exit == "no"){//スクロールが終了に設定されていない事を確認
            if(!ele.scrollWidth == 0){//スクロールが必要な場合
                let lastLeft = ele.scrollLeft;//現在のスクロール位置を記録
                function move_left(){//実際にスクロールする関数
                    ele.scrollLeft++;//1スクロールする
                    if(lastLeft == ele.scrollLeft){//最後までスクロールした事を確認
                        setTimeout(function(){//1000ms(1秒)後に一番左に戻す
                            ele.scrollLeft = 0;//1000ms(1秒)後に一番左に戻す
                            setTimeout(scroll,2000);//一番左に戻してから2000ms(2秒)後にスクロールを再開する
                        },1000);//1000ms(1秒)後に一番左に戻す
                    }else{//最後までスクロールしていない場合
                        lastLeft = ele.scrollLeft;//現在のスクロール位置を更新
                        setTimeout(move_left,20)//20はスクロール速度(値が小さい方が早くスクロール)
                    };
                };
                move_left();//最初の一回を実行
            }else{//スクロールが不要な場合
                setTimeout(scroll,2000)//2000ms(2秒)後にもう一度スクロールが必要か確認
            };
        };
    };

    new Promise(() => {//非同期で
        scroll();//最初のスクロールを開始する
    });






    return function(){
        scroll_exit = "yes";//スクロールを止める
    };

実際に使ってみる

今作成した関数を実行する事でスクロールを開始できます。

StartScroll("display");//スクロールを開始する
StartScroll("ココはスクロール対象のid");//スクロールを開始する

スクロールを終了するには、関数実行時に取得した関数を実行する事で、一番左に戻ったタイミングでスクロールが終了します。

        var end = StartScroll("display");//スクロールを開始する



        //終了ボタンが押されたときの処理
        document.getElementById("exit").onclick = function(){
            end();
        };

今すぐ試す

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id='display'>
        ああああああああああああああああああああああああああああああああ
    </div>

    <button id="exit">
        スクロール終了
    </button>

    <style>
        #display{
            width: 100px;
        }
    </style>
    <script>
        function StartScroll(target_id){
            const ele = document.getElementById(target_id);
            var style = ele.style;
            style.overflowY = "scroll";//横スクロールする
            style.whiteSpace = "nowrap";//改行しない
            style.setProperty("-ms-overflow-style","none");
            style.setProperty("scrollbar-width","none");
            style.setProperty("-webkit-scrollbar","none");

            /**
             * この値がno以外になったらスクロールを終了する
             */
            let scroll_exit = "no";

            function scroll(){
                if(scroll_exit == "no"){//スクロールが終了に設定されていない事を確認
                    if(!ele.scrollWidth == 0){//スクロールが必要な場合
                        let lastLeft = ele.scrollLeft;//現在のスクロール位置を記録
                        function move_left(){//実際にスクロールする関数
                            ele.scrollLeft++;//1スクロールする
                            if(lastLeft == ele.scrollLeft){//最後までスクロールした事を確認
                                setTimeout(function(){//1000ms(1秒)後に一番左に戻す
                                    ele.scrollLeft = 0;//1000ms(1秒)後に一番左に戻す
                                    setTimeout(scroll,2000);//一番左に戻してから2000ms(2秒)後にスクロールを再開する
                                },1000);//1000ms(1秒)後に一番左に戻す
                            }else{//最後までスクロールしていない場合
                                lastLeft = ele.scrollLeft;//現在のスクロール位置を更新
                                setTimeout(move_left,20)//20はスクロール速度(値が小さい方が早くスクロール)
                            };
                        };
                        move_left();//最初の一回を実行
                    }else{//スクロールが不要な場合
                        setTimeout(scroll,2000)//2000ms(2秒)後にもう一度スクロールが必要か確認
                    };
                };
            };

            new Promise(() => {//非同期で
                scroll();//最初のスクロールを開始する
            });

            return function(){
                scroll_exit = "yes";
            };
        };




        var end = StartScroll("display");//スクロールを開始する



        //終了ボタンが押されたときの処理
        document.getElementById("exit").onclick = function(){
            end();
        };
    </script>
</body>
</html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【備忘】【JavaScript】動かしながらthisについて理解する

この記事の意図

thisが何か分からなくなるので、忘れないようにメモ

JavaScriptのthisってなに

thisは、呼び出す場所でころころ変わる特殊なオブジェクト

呼び出す場所で変わるってどういうこと

下の例だと、一方はhelloと出力され、もう一方はundefinedになる。

class Example {
    constructor(param) {
        this.param = param
        console.log(this.param);
    }
    lateHello() {
        setTimeout(function() {
            console.log(this.param);
        });
    }
}

const example = new Example('hello'); // → hello
example.lateHello(); // → undefined

「なぜlateHello()だと、this.paramがundefinedなんだー」って時は、実際にthisそのものをコンソールに出力 して調べてみる。

class Example {
    constructor(param) {
        this.param = param
        // thisを出力
        console.log(this);
    }
    lateHello() {
        setTimeout(function() {
            // thisを出力
            console.log(this);
        });
    }
}

const example = new Example('hello'); // → Example {param: "hello"}
example.lateHello(); // → Window {0: Window, window: Window, self: Window, document: document, name: "", location: Location, …}

上記の結果から、thisが参照しているところが違ってたから、lateHello()の方は、this.paramがundefinedになっていたことがわかる。

じゃあ、この window ってなんだ?

windowはグローバルオブジェクトといいます

ブラウザの開発者ツールでコンソールを開いてthisと打って実行すると
Window {0: Window, window: Window, self: Window, document: document, name: "", location: Location, …}
と表示されます。これがグローバルオブジェクト。

グローバルオブジェクトは、グローバルスコープ上に常時存在するオブジェクトです。
https://developer.mozilla.org/ja/docs/Glossary/Global_object

window(グローバルオブジェクト)には、たくさんの便利な関数やプロパティが入っていて、JavaScriptを使う時にみんなお世話になっています。

そして、そんな関数の一つに `setTimeout()'があります。

実はお世話になっているwindowオブジェクト

↓こんな風に何気なく使っている関数は

setTimeout(xxxxx, 1000);

↓実はこれの省略形でした。

window.setTimeout(xxxxx, 1000);

thisの特性

基本的にthisは「直近で囲まれているオブジェクトを参照する」という特性を持つ。

最初の例に戻ります。
setTimeoutは、実はwindow.setTimeoutの省略形であることがわかったので、下記のように書き直します。

class Example {
    constructor(param) {
        this.param = param
        // thisを出力
        console.log(this);
    }
    lateHello() {
        // thisの直近のオブジェクトはwindowになっている
        window.setTimeout(function() {
            // thisを出力
            console.log(this);
        });
    }
}

const example = new Example('hello'); // → Example {param: "hello"}
example.lateHello(); // → Window {0: Window, window: Window, self: Window, document: document, name: "", location: Location, …}

すると、lateHelloのsetTimeout内の直近のオブジェクトはwindowになっています。
だから、thisがwindowオブジェクトに一致しています。

thisをコロコロ変えない方法

thisに意図しないオブジェクトが入ることはよくあります。
なので、thisを思い通りにコントロールする必要があります。

その手段はいくつかすでに用意されているので、その一部を抜粋。

手段①:bind(this)で束縛する

よく使われる手法です。
bind()は、thisに入れる値を設定するための関数です。

こんなかんじで使います。

class Example {
    constructor(param) {
        this.param = param
        // thisを出力
        console.log(this);
    }
    lateHello() {
        const _self = this; // ここでは、thisはExampleオブジェクト自身を参照している

        // thisの直近のオブジェクトはwindowになっている
        window.setTimeout(function() {
            // thisを出力
            console.log(this);
        }).bind(_self); // bindした_selfには、window.setTimeoutの直前のthisと同じオブジェクトが入っており、setTimeout内のthisを_selfに束縛する
    }
}

const example = new Example('hello'); // → Example {param: "hello"}
example.lateHello(); // → Example {param: "hello"}

ただこの書き方は、冗長な書き方です(分かりやすいので、_selfをつかいました)
下記のように書かれるのが一般的です。

class Example {
    constructor(param) {
        this.param = param
        // thisを出力
        console.log(this);
    }
    lateHello() {
        window.setTimeout(function() {
            // thisを出力
            console.log(this);
        }).bind(this); // bindしたthisには、window.setTimeoutの直前のthisと同じオブジェクトが入っている
    }
}

const example = new Example('hello'); // → Example {param: "hello"}
example.lateHello(); // → Example {param: "hello"}

手段②:thisを変数に格納して使う

bind()を使わない書き方です。

class Example {
    constructor(param) {
        this.param = param
        // thisを出力
        console.log(this);
    }
    lateHello() {
        const _self = this;
        window.setTimeout(function() {
            console.log(_self);
        });
    }
}

const example = new Example('hello'); // → Example {param: "hello"}
example.lateHello(); // → Example {param: "hello"}

この方が直感的でわかりやすいです。
ただ、bind()を使っている人は多いと思うので、どちらでも書けるようにしておくのがいいと思います。

実際にbind()を使う具体的な例

ボタンをクリックしたら、コンソールにhelloと出力させるプログラムです。

下記のコードではundefinedとなってしまいます。
理由は、this.paramthisに、btnオブジェクトが入ってしまってるからです。(実際にconsole.log(this)して確認すればわかります)

index.html
<button id="btn">ボタン</button>
main.js
class Hello {
    constructor(param) {
        this.hello = param;
    }
    sayHello() {
        console.log(this.param)
    }
}

const hello = new Hello('hello');

// ボタン要素をセレクト
const btn = document.querySelector('#btn');
// NG例:クリックしたらhelloとコンソールに出力する
btn.addEventListener('click', hello.sayHello()); // → undefined 

これを下記のように書き直すときちんとhelloと出力されるはずです。

main.js
class Hello {
    constructor(param) {
        this.hello = param;
    }
    sayHello() {
        console.log(this.param)
    }
}

const hello = new Hello('hello');

// ボタン要素をセレクト
const btn = document.querySelector('#btn');
// helloオブジェクトをbindする
btn.addEventListener('click', hello.sayHello().bind(hello)); // → hello

他にもthisを制御する方法はあると思いますが、ここら辺でおわり。

おわりに

だいぶthisについて理解できた。
ただコードが複雑になれば「あれ、動かん。。。」ってなると思うから、プロジェクトを通して、コードに触れるのが大事なんだろうなと思います。

けどそういう時はあわてず、コンソールとかで現在のthisをちまちま確認していくのが近道なのかな。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Google Chrome】拡張機能の作成方法を分かりやすく解説してみた Part. 2

準備

前回は"manifest.json"を作成し、Chromeで確認した所で終わっていましたね。今回はスクリプト(純正JavaScript)も作成していきます。では、前回の"example_extension"フォルダを開いて下さい。

9.png
background.js //名称通りバックグラウンドで動作するスクリプトです
"example_extension"フォルダ上に作成して下さい。

自作拡張機能を追加した際にログを表示させるコードをbackground.jsに書き込みます。しかし、このままではbackground.jsが認識されないのでmanifest.jsonを開き、下記の内容を追加して下さい。

manifest.json
{

    "name": "example_extension",
    "version": "1.0",
    "description": "hoge",
    "manifest_version": 2 ,

    "permissions" : ["storage" , "declarativeContent"] ,
    "background" : {
      "scripts" : ["background.js"]
    }

}

(新) "permissions" //付与する権限を指定します
(新) "background" //バックグラウンドで動作するスクリプトの指定

作成

10.png

作成したbackground.jsファイルをエディタで開き、下記のコードを入力して下さい。

background.js
(function(){
    //拡張機能インストール時に実行されるメソッド
    function onInstall(){
        console.log("hoge");
    }
    //chrome.runtime.onInstalledイベントに
    //ラムダ式を使用してonInstall()をトリガーします
    chrome.runtime.onInstalled.addListener( () => {
        onInstall();
    });
})();

終わったら保存してGoogle Chromeで動作チェックしてみましょう!
Chromeを開き、URLの欄にchrome://extensionsと入力してください。
拡張機能の一覧が出てくるので、前回と同じ様に右上のデベロッパーモードを有効にし、パッケージ化されていない拡張機能を読み込むをクリックしてください。

エクスプローラが出現するので"example_extension"フォルダーを選択し、読み込ませます。
今回はログが出力されているか確認するので、下の画像の下線が引かれている所をクリックしてください。

11.png
するとChromeのデバッグツールが出現し、Console上にhogeと出力されていることが確認出来ると思います。
12.png
成功しましたね。でもこれじゃ寂しすぎるので次は拡張機能っぽく右上の拡張機能のアイコンをクリックした時に出てくるポップアップも作成してみましょう!
今度はpopupdayo.htmlという名称のファイルを"example_extension"フォルダ上に作成して下さい。
13.png
hogedayoと表示させてみましょう
エディタでpopupdayo.htmlを開いて下記の内容を入力して下さい。

popupdayo.html
<!DOCTYPE html>
<html>
    <body>
        <h1>hogedayo</h1>
    </body>
</html>

終わったら次はmanifest.jsonに、popupdayo.htmlを指定させてあげます。

manifest.json
{

    "name": "example_extension",
    "version": "1.0",
    "description": "hoge",
    "manifest_version": 2 ,

    "permissions" : ["storage" , "declarativeContent"] ,
    "background" : {
      "scripts" : ["background.js"]
    } ,

    "browser_action" : {
      "default_popup" : "popupdayo.html"
    }

  }

(新) "browser_action" 右上バーのアイコンやツールチップ、ポップアップ等のアクション
(新) "default_popup" ポップアップした際に表示するデフォルトHTMLファイルの指定

入力し終わったら、先程の手順でもう一度拡張機能のテストをしてみましょう!

実行

"example_extensions"を読み込ませ、自身の拡張機能アイコンをクリックしてみると...
14.png
表示されましたね!(´・ω・`)
ひとまずここで終了です。お疲れ様でした( ^^) _旦~~

Chrome拡張機能APIリファレンスのリンクを貼っておくので、kwskの方は下記リンク
https://developer.chrome.com/docs/extensions/reference/

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptのわかりずらかったことメモ

Javascriptでわかりずらかったことのメモです。

可変引数

コード
function test(...args) {
    console.log(args);
}

test("1", "2");
結果
[ '1', '2' ]

論理演算子と代入

コード
var a = "1";
var b = "2";

var c = a && b;
console.log(c);

var d = a || b;
console.log(d);
結果
2
1

a && bは!a ? a : b; と同じ。
a || bはa ? a : b; と同じ。

こちらを参考
https://qiita.com/masakazu_ca/items/3ce9228a6c009499cb79

キーの名前でメソッド的

コード
var map = {a:"1"};
console.log(map.a);
結果
1

変数名がキー名になる

var b = "2";
console.log({a:"1",b});
結果
{ a: '1', b: '2' }

ドット三つの奴を使う

ドット三つを使うコード
var b = {'B': { "C": 'Cのvalue', }};
console.log({a:"Aのvalue",...b});
結果
{ a: 'Aのvalue', B: { C: 'Cのvalue' } }

ドット三つの奴を使わないと

ドット三つを使わないコード
var b = {'B': { "C": 'Cのvalue', }};
console.log({a:"Aのvalue",b});
結果
{ a: 'Aのvalue', b: { B: { C: 'Cのvalue' } } }

letとvarの違い

varは再宣言可能
letは再宣言不可

varのコード
var a = "1";
var a = "2";

console.log(a);
結果
2
letのコード
let a = "1";
let a = "2"; // letで宣言された変数名はスコープ内に一つだけ

console.log(a);
結果
ERROR:
let a = "2";
    ^

こちらを参考。
https://qiita.com/y-temp4/items/289686fbdde896d22b5e

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

緯度経緯をURLへ変換するサービス、マップクリエイター

マップクリエイターとは、どんなWebサービスですか?
Googleマップの任意の地点をWebページ化するサービスです。場所をWebページ化することで空間にテキストが紐付くので、検索サイトから検索した時スムーズにその場所がどこにあるのかが、日本国民全員に分かるようになります。

マップクリエイターを作ろうと思ったきっかけは何だったのでしょうか?
旅行に行った時よくバスをよく利用するのですが、田舎のほうになるとバス停がどこにあるのか分からなかったり、バス停が分かってもどのバスがどこへ向かうのかが分からないことが多々あったので、それを上手い具合に解決したいと思って作りました。

そこで、ITとかにあまり詳しくない人でも、特定の場所に対して簡単にテキストを埋め込めるサービスがあれば、Googleで検索した時にその場所の詳細がすぐ分かるだろうと思って作りました。

バス停だけにとどまらず、地元の名所やつっこんだ観光案内(雑学など)を書けば、地域復興にも繋がるかなと思います。

機能面でこだわった点などありますか?
Google マップでは場所によっては緯度経緯が表示されず、プラスコードというアルファベットだけの表示になることもあるので、プラスコードにも対応させました。また悪用防止のため、作成したページを削除する機能も付けました。

(マップクリエイターは2018年に作ったwebサービスです)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactでいい感じのサブウィンドウを実装する ⑤ 表示する場所を指定する

Reactでサブウィンドウを表示する際に表示する場所を指定したい時が、よくあると思います。

今回は、この方法について紹介します。

やり方

Rndのdefaultプロパティに値を指定してあげると指定した箇所に表示することができます

例1 画面の真ん中にサブウィンドウを表示する

<Rnd
  default={{ 
    x: document.documentElement.clientWidth / 2, 
    y: document.documentElement.clientHeight / 2
  }}
>
  test
</Rnd>

例2 画面の右上に表示する

<Rnd
  default={{ 
    x: 0, 
    y: 0
  }}
>
  test
</Rnd>

おまけ

defaultプロパティにwidthとheightを指定すると、 サブウィンドウの初期表示時のサイズを調整できます。

<Rnd
  default={{ 
    x: 0, 
    y: 0,
    width: 200,
    height: 100
  }}
>
  test
</Rnd>

最後に

今回は、サブウィンドウの初期表示の設定方法について説明しました。

最後まで読んでよかったらLGTMお願いします!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactでいい感じのサブウィンドウを実装する ⑤ 初期表示の設定方法

今回は、Reactでサブウィンドウの初期表示の設定方法について説明していきます。

やり方

Rndのdefaultプロパティに値を指定してあげると指定した箇所に表示することができます

例1 画面の真ん中にサブウィンドウを表示する

<Rnd
  default={{ 
    x: document.documentElement.clientWidth / 2, 
    y: document.documentElement.clientHeight / 2
  }}
>
  test
</Rnd>

例2 画面の右上に表示する

<Rnd
  default={{ 
    x: 0, 
    y: 0
  }}
>
  test
</Rnd>

おまけ

defaultプロパティにwidthとheightを指定すると、 サブウィンドウの初期表示時のサイズを調整できます。

<Rnd
  default={{ 
    x: 0, 
    y: 0,
    width: 200,
    height: 100
  }}
>
  test
</Rnd>

最後に

今回は、サブウィンドウの初期表示の設定方法について説明しました。

最後まで読んでよかったらLGTMお願いします!

まとめ記事 もあるのでよければこちらもみてください

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コメントによるセクシー構文 (仮)

(JavaScript や C 言語の系列等の、ブロックコメントを  /* (´ε` ) */  で表す言語でのお話です)

はじめまして。
数年ぶりにプログラミングを趣味として再開した、うらしま状態の中年です。
技術情報の知識が 10年くらい空いているので、別世界に転移してきた気分です。(異世界転移、しかし激弱体化・・・)
そんな訳で、昔からのローテクな観点からの投稿です。
今回は、コメントについて記します。


プログラムを書いている最中に、ちょっと試してみたい事って、ありますよね?

今書いているコードの一部を別の書き方を試してみたくなったり。
JavaScript で DOM を操作する関数をコーディング中、上手くいっているかを試すために、その関数を様々な引数で呼び出してみたり。

そんな時は、既に書いた部分をコメント化してその場に保存しながら、他のいろいろなチャレンジをしていくことになると思います。

していきますよね?
え? もっと高度な事をしていたりします?
・・・そんな高尚な方には縁の無い、泥臭いコメント化のテクニックをご紹介いたします。

まずは基本の、コメント による if 文です。

if 文
/**/
  Master.batton();    //  素早く隠したいコード
/**/

はいっ!
こちらの商品の特徴はですね、行末の一文字でコメント化を制御できる点です。
1行めの行末の / にご注目下さい。
この一文字を書いたり消したりするとどうなるか? 想像してみてください。

前記の記述だと、1行めと 3行めの 2箇所に空のコメントが存在します。
そこから、/ をひとつ外すと、1行めから 3行めまで続くひとかたまりのブロックコメントに早替わりです。

お分かり頂けましたか?
ただこれだけで、コメントにしたり、コメントを外したりができます。

ここで注目して頂きたいのは、既にコメント化していたブロックを「ちょっとココら辺を有効に戻して〜」とコメントを解除したくなった時の、作業量です。

これがですね〜〜。
わずかに、スラッシュを付け加えるだけ! 付け加えるだけです!!

更に!
「よし、もっかいコメント化して〜」と思った時には、わずか BS キーをひと押しするだけ!!
/ 記号の後ろを選択してから、たった、ひと押し! たったのひと押し!
/ 記号をひと文字消すだけ!

どうです? この最強のコストパフォーマンス。
お買い得ですよね〜〜。

え? マウスで範囲選択して、キーバインドでコメント領域を反転させれば一瞬で済む?
あー、、、まあ、その、ね?
そういった素敵なエディタを使ってない人とか、範囲選択ですら面倒なスマートフォンなんかでコーディングしている人もいるのですよ。私のような・・・。

はい。気を取り直して解説を続けます。

この書き方は、タッチまたはクリックが楽なのです。
1行コメントの // を加える時、消す時、を思い出してください。
画面上の x - y 軸でピンポイントに一点を選択してから、// を書いたり消したりします。
これに対して、行末の一文字の / を選択する時は、行末以降の行全体のどこをタッチしても良いのです。
適当に 1行のどこかをタッチするだけで良いのです。

「ええ!? あの、ミスタッチで違う文字の後ろにカーソルがいってしまう、あの苦痛から解放されるんですかー?」

「はいっ。実はそうなんですよー。もうこれからは、一文字単位のズレで苦しむことはありませんっ!」

そんなお買い得テクニックです。

この応用で、ブロックコメントを使って if-else や switch も一文字操作で実現できます。

「今なら、if-else も付いてきます! ええーい! 更に更に、switch までつけちゃいましょう!」

どうすれば実現できるのか、考えて見てください。


なんて書いて終わると、興味をもってくださった方にも石を投げられそうなので、ちゃんとご紹介いたします。
自力で考えつく快感が欲しい人だけ、じっくり考えてみてください。

ですがそれよりも大切なのは、名前です。
この書き方に名前が欲しい!
というか、既に名前がついているのでしょうか?
この後にご紹介する if-else や switch まで含めると、一時的な使い捨てコードとしては、わりと有用なテクニックなのですが。
私は特に、誰からも教わった訳でもなく、ウェブで見かけたことも無いので、呼び方が分かりません。
ご存知の方、教えて下さい。

ホント、名前が無いと困るのですよね。
使っていない期間が長くなるとあっさり忘れて、なかなか思い出せなくなるんです。
数年ぶりに使おうとして 「あ、ここは確かアレで楽できたはず。アレ使えば・・・、あれ? アレってあれ? どうやるんだったっけ?」 なんてことになってしまいました。

「これが○○というやつか、なんて恐ろしい・・・」

という訳で、お願いです。
これに、名前を考えて下さい。
忘れられなくなるような押しの強い名前を希望です!

私案:

/ を素敵な脚に見立てて、/ を付けたり消したりを、セクシーなお姉さんが脚をパカパカ開いたり閉じたりしていると想像するのです。それによって隠していた部分が見えたり見えなかったり。
 ちらっ ちらっ
そんな所から、セクシー構文と名付けるのは、どうでしょうか?
片仮名でセクシーステートメン!

何かまともな良い案があれば、是非、ご教示ください。


さて、そろそろ、残りの if-else と switch をご紹介いたします。

セクシー if 構文はこの書き方でした。
パカッ パカッ。 ちらっ ちらっ。

if : /**/ A /**/

こちらが見えればアチラが隠れ、あちらを見つめれば此方が隠れ。ああ、もどかしい! な、セクシー if-else 構文はこちら。

if-else :  /**/ A /*/ B /**/

アチラもコチラも、ああ! もう見えたり見えなかったり、なにコレ、もどかしい! な、セクシー switch 構文はこちら。

switch : /** A /** B /** C /** D /**/

あえて、分かりやすくしてくれるコード記述じゃなく、ベタに 1行で書きました。

こういった初見では分からないものを、ちょっと考えて悩んだ末に、ハッ! と理解する、その瞬間って気持ちいいですよね。
ええと、確か、アハン体験とかいった名前がついてませんでしたっけ?
だから、詳しい解説はいたしません。
よろしければ、どういう動きをするのか考えて見てください。
自力で理解してみてください。
そして、これを読んでくださった何人かでも、アハンに気持ちよくなって頂ければ嬉しいです。


「そんな事してられない!」 という気の短い方も、ご安心ください。
以下の記述をコピーして、ご自分のエディタで試して頂けます。
コメントブロックが色分けされるエディタを使って、素早くコメント化を ON/OFF できる喜びを体感してください。

if-else 文
function studyHours(){
 /**/
    Mastur.bation();    //  素早く隠したいコード
  /*/
    Moti.vation();    //  見せたいコード
  /**/
}
switch 文
let solo = new You();

/**
  solo.play( "movie" );    //  テストケース 1
/**
  solo.play( "comic" );    //  テストケース 2
/**
  solo.play( "toy" );    //  テストケース 3
/**/
  solo.play( "forbidden" );    //  テスト中
/**/

room.dispatchEvent(new Event( "mama-knocked" ));

ちなみに、コメント付きで記述するのでしたら、こんな風に書くと、追加・削除をする / の位置とコメントが同じ行で近くなるので、把握や編集が容易になります。

switch with comment
/*  布団を被る  *
  solo.style.visibility = "hidden";

/*  クローゼットに隠れる  *
  solo.style.display = "none";

/*  混乱する  */
  solo.style.overflow = "scroll";

/*  脱出する  *
  solo.scrollBy( 999999, 999999 );    //  しかし回り込まれた

/**/

以上、セクシー構文(仮) の解説でした。
ここまでお付き合い頂き、ありがとうございます。


最近の私の使い道としては、
CSS の width に max-content や min-content が追加されていたのを知り 「何これ!? 素敵な予感?」 と、if-else 文で切り替えながら、max-width や min-width に display 等との調和を試してみたり、
DOM 操作や CSS の修整の際に、ブラウザでの読み込みと同時に該当の場面に強制的に遷移させるテスト用のコードを切り替えたり、
といった利用をしています。

皆様にとっても、有効な利用方法があれば良いのですが。

なお、他の種類のブロックコメントでも同じ事が可能です。

こうして、まとめてみると、switch というよりは multiple select と呼んだ方がしっくりくるような気がしてきました。
でも、プログラムコードとしては、if に合わせて switch と呼ぶ方が気持ちいいのですよね。

どう思います?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【フロントエンド学習①】フロントエンドとバックエンド

これは?

フロントエンドの学習をして、その理解のアウトプットとして作りました。
初学者にもわかりやすい文章を心がけます。
理解に間違いがありましたら、ご指摘いただけると幸いです。

フロントエンドとは

主にHTML、CSS、JavaScriptで構成されている
サーバーとの通信や、ブラウザに表示されるもの

  • HTML・・・規則に則ってコンテンツを記述する
    →文章、画像、動画、など

  • CSS・・・HTMLで記述されたものにデザインを付与する
    →文字や画像の色や大きさ、コンテンツの配置、など

  • JavaScript・・・ページに機能を持たせる場合に使用する
    →ボタンを押した時の動作、サーバーとの通信の定義、など
    →ブラウザ上で動作するほぼ唯一のプログラミング言語!(ここ重要)
    →ライブラリやフレームワークが豊富(jQuery、Bootstrap、React.js、Vue.js、Node.js、など)

バックエンドとは

フロントエンドと比べて、使用できる言語は多い。(PHP、Java、Python、Ruby、など)
大きく「静的メージ」と「動的ページ」に分けられる

  • 静的ページ
    →リクエストに応じてサーバーに用意されているファイルを返却、ブラウザに表示される

  • 動的ページ
    →リクエストに応じてサーバーにあるプログラムがページを生成して返却、ブラウザに表示される

おわり

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LeetCode回答例【JavaScript】(Good率80%以上の良問厳選)

LeetCodeのEasyレベルの良問をJavaScriptで解きました。
問題の解き方はここに載せているもの以外にもたくさんあるので、実際に自分で打って確かめてみてください。

https://leetcode.com/problemset/algorithms/?difficulty=Easy

LeetCodeはすべて英語ですが、Google翻訳を使うと質問の意図は伝わるくらいに訳してくれます。

問題 1047. Remove All Adjacent Duplicates In String

https://leetcode.com/problems/remove-all-adjacent-duplicates-in-string/

回答例

/**
 * @param {string} S
 * @return {string}
 */
var removeDuplicates = function (S) {
  const stack = [];
  for (const char of S) {
    stack[stack.length - 1] == char ? stack.pop() : stack.push(char);
  }
  return stack.join("");
};

問題 922. Sort Array By Parity II

https://leetcode.com/problems/sort-array-by-parity-ii/

回答例

/**
 * @param {string} S
 * @return {string}
 */
var removeDuplicates = function (S) {
  const stack = [];
  for (const char of S) {
    stack[stack.length - 1] == char ? stack.pop() : stack.push(char);
  }
  return stack.join("");
};

問題 1337. The K Weakest Rows in a Matrix

https://leetcode.com/problems/the-k-weakest-rows-in-a-matrix/

回答例

/**
 * @param {number[][]} mat
 * @param {number} k
 * @return {number[]}
 */
var kWeakestRows = function (mat, k) {
  return mat
    .map((value, index) => [index, value.reduce((pre, cur) => pre + cur)])
    .sort((a, b) => a[1] - b[1])
    .slice(0, k)
    .map((pair) => pair[0]);
};
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LeetCode回答例【JavaScript】(Good率80%以上の良問厳選)※随時更新

LeetCodeのEasyレベルの良問をJavaScriptで解きました。
問題の解き方はここに載せているもの以外にもたくさんあるので、実際に自分で打って確かめてみてください。

https://leetcode.com/problemset/algorithms/?difficulty=Easy

LeetCodeはすべて英語ですが、Google翻訳を使うと質問の意図は伝わるくらいに訳してくれます。

問題 1047. Remove All Adjacent Duplicates In String

https://leetcode.com/problems/remove-all-adjacent-duplicates-in-string/

回答例

/**
 * @param {string} S
 * @return {string}
 */
var removeDuplicates = function (S) {
  const stack = [];
  for (const char of S) {
    stack[stack.length - 1] == char ? stack.pop() : stack.push(char);
  }
  return stack.join("");
};

問題 922. Sort Array By Parity II

https://leetcode.com/problems/sort-array-by-parity-ii/

回答例

/**
 * @param {string} S
 * @return {string}
 */
var removeDuplicates = function (S) {
  const stack = [];
  for (const char of S) {
    stack[stack.length - 1] == char ? stack.pop() : stack.push(char);
  }
  return stack.join("");
};

問題 1337. The K Weakest Rows in a Matrix

https://leetcode.com/problems/the-k-weakest-rows-in-a-matrix/

回答例

/**
 * @param {number[][]} mat
 * @param {number} k
 * @return {number[]}
 */
var kWeakestRows = function (mat, k) {
  return mat
    .map((value, index) => [index, value.reduce((pre, cur) => pre + cur)])
    .sort((a, b) => a[1] - b[1])
    .slice(0, k)
    .map((pair) => pair[0]);
};

問題 1356. Sort Integers by The Number of 1 Bits

https://leetcode.com/problems/sort-integers-by-the-number-of-1-bits/

回答例

/**
 * @param {number[]} arr
 * @return {number[]}
 */
var sortByBits = function (arr) {
  const bitCount = (num) => {
    let sum = 0;
    while (num) {
      sum += num & 1;
      num >>= 1;
    }
    return sum;
  };

  return arr.sort((a, b) => bitCount(a) - bitCount(b) || a - b);
};
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LeetCode easy問題回答例【JavaScript(good率80%以上厳選)】

LeetCodeのeasyレベルの問題を厳選しました。
Google翻訳を使ったため訳がめちゃくちゃなところがありますが、なんとなく意味は掴めると思うので察してください。

問題 1047. Remove All Adjacent Duplicates In String

S小文字の文字列が与えられた場合、重複する削除は、2つの隣接する等しい文字を選択し、それらを削除することで構成されます。
できなくなるまで、Sで重複した削除を繰り返し行います。
このような重複した削除がすべて行われた後、最後の文字列を返します。答えはユニークであることが保証されています。

例1:
入力:"abbaca"
出力:"ca"
説明:
たとえば、「abbaca」では、文字が隣接していて等しいため、「bb」を削除できます。これが唯一の可能な移動です。この移動の結果、文字列は「aaca」になり、そのうち「aa」しか使用できないため、最終的な文字列は「ca」になります。

回答例

/**
 * @param {string} S
 * @return {string}
 */
var removeDuplicates = function (S) {
  const stack = [];
  for (const char of s) {
    stack[stack.length - 1] === char ? stack.pop() : stack.push(char);
  }
  return stack.join("");
};

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LeetCode解答例【JavaScript】(Good率80%以上の良問厳選)※随時更新

LeetCodeのEasyレベルの良問をJavaScriptで解きました。
問題の解き方はここに載せているもの以外にもたくさんあるので、実際に自分で打って確かめてみてください。

https://leetcode.com/problemset/algorithms/?difficulty=Easy

LeetCodeはすべて英語ですが、Google翻訳を使うと問題の意図は伝わるくらいに訳してくれます。

問題 461. Hamming Distance

https://leetcode.com/problems/hamming-distance/

解答例

/**
 * @param {number} x
 * @param {number} y
 * @return {number}
 */
var hammingDistance = function (x, y) {
  return (x ^ y)
    .toString(2)
    .split("")
    .filter((n) => n == 1).length;
};

問題 557. Reverse Words in a String III

https://leetcode.com/problems/reverse-words-in-a-string-iii/

解答例

/**
/**
 * @param {string} s
 * @return {string}
 */
var reverseWords = function(s) {
  return s.split("").reverse().join("").split(" ").reverse().join(" ")
};

問題 905. Sort Array By Parity

https://leetcode.com/problems/sort-array-by-parity/

解答例

/**
 * @param {number[]} A
 * @return {number[]}
 */
var sortArrayByParity = function (A) {
  const temp = [];
  A.forEach((a) => {
    a % 2 == 0 ? temp.unshift(a) : temp.push(a);
  });

  return temp;
};

問題 922. Sort Array By Parity II

https://leetcode.com/problems/sort-array-by-parity-ii/

解答例

/**
 * @param {string} S
 * @return {string}
 */
var removeDuplicates = function (S) {
  const stack = [];
  for (const char of S) {
    stack[stack.length - 1] == char ? stack.pop() : stack.push(char);
  }
  return stack.join("");
};

問題 977. Squares of a Sorted Array

https://leetcode.com/problems/squares-of-a-sorted-array/

解答例

/**
 * @param {number[]} nums
 * @return {number[]}
 */
var sortedSquares = function (nums) {
  return nums.map((a) => a * a).sort((a, b) => a - b);
};

問題 1047. Remove All Adjacent Duplicates In String

https://leetcode.com/problems/remove-all-adjacent-duplicates-in-string/

解答例

/**
 * @param {string} S
 * @return {string}
 */
var removeDuplicates = function (S) {
  const stack = [];
  for (const char of S) {
    stack[stack.length - 1] == char ? stack.pop() : stack.push(char);
  }
  return stack.join("");
};

問題 1207. Unique Number of Occurrences

https://leetcode.com/problems/unique-number-of-occurrences/

解答例

/**
 * @param {number[]} arr
 * @return {boolean}
 */
var uniqueOccurrences = function (arr) {
  const myMap = new Map();
  for (const num of arr) {
    if (myMap.has(num)) {
      myMap.set(num, myMap.get(num) + 1);
    } else {
      myMap.set(num, 1);
    }
  }

  const mySet = new Set();
  for (const val of myMap.values()) {
    if (mySet.has(val)) {
      return false;
    } else {
      mySet.add(val);
    }
  }
  return true;
};

問題 1337. The K Weakest Rows in a Matrix

https://leetcode.com/problems/the-k-weakest-rows-in-a-matrix/

解答例

/**
 * @param {number[][]} mat
 * @param {number} k
 * @return {number[]}
 */
var kWeakestRows = function (mat, k) {
  return mat
    .map((value, index) => [index, value.reduce((pre, cur) => pre + cur)])
    .sort((a, b) => a[1] - b[1])
    .slice(0, k)
    .map((pair) => pair[0]);
};

問題 1351. Count Negative Numbers in a Sorted Matrix

https://leetcode.com/problems/count-negative-numbers-in-a-sorted-matrix/

回答例

/**
 * @param {number[][]} grid
 * @return {number}
 */

var countNegatives = function (grid) {
  let sum = 0;
  for (let i = 0; i < grid.length; i++) {
    for (let j = 0; j < grid[i].length; j++) {
      if (grid[i][j] < 0) {
        sum++;
      }
    }
  }
  return sum;
};

問題 1356. Sort Integers by The Number of 1 Bits

https://leetcode.com/problems/sort-integers-by-the-number-of-1-bits/

解答例

/**
 * @param {number[]} arr
 * @return {number[]}
 */
var sortByBits = function (arr) {
  const bitCount = (num) => {
    let sum = 0;
    while (num) {
      sum += num & 1;
      num >>= 1;
    }
    return sum;
  };

  return arr.sort((a, b) => bitCount(a) - bitCount(b) || a - b);
};

問題 1502. Can Make Arithmetic Progression From Sequence

https://leetcode.com/problems/can-make-arithmetic-progression-from-sequence/

解答例

/**
 * @param {number[]} arr
 * @return {boolean}
 */
var canMakeArithmeticProgression = function (arr) {
  arr.sort((a, b) => a - b);
  for (let i = 1; i < arr.length; i++) {
    if (arr[1] - arr[0] != arr[i] - arr[i - 1]) {
      return false;
    }
  }
  return true;
};

問題 1700. Number of Students Unable to Eat Lunch

https://leetcode.com/problems/number-of-students-unable-to-eat-lunch/

解答例

/**
 * @param {number[]} students
 * @param {number[]} sandwiches
 * @return {number}
 */
var countStudents = function (students, sandwiches) {
  while (students.length > 0 && students.indexOf(sandwiches[0]) != -1) {
    if (students[0] == sandwiches[0]) {
      students.shift();
      sandwiches.shift();
    } else {
      students.push(students.shift());
    }
  }
  return students.length;
};
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LeetCode回答例 Good率80%以上厳選【JavaScript】

LeetCodeのEasyレベルの良問を厳選しました。(good率80%以上)
Google翻訳を使うと質問の意図は伝わるくらいに訳してくれるので問題なく解くことができます。

問題 1047. Remove All Adjacent Duplicates In String

https://leetcode.com/problems/remove-all-adjacent-duplicates-in-string/

Given a string S of lowercase letters, a duplicate removal consists of choosing two adjacent and equal letters, and removing them.
We repeatedly make duplicate removals on S until we no longer can.
Return the final string after all such duplicate removals have been made. It is guaranteed the answer is unique.

Example 1:

Input: "abbaca"
Output: "ca"
Explanation: 
For example, in "abbaca" we could remove "bb" since the letters are adjacent and equal, and this is the only possible move.  The result of this move is that the string is "aaca", of which only "aa" is possible, so the final string is "ca".

Note:
1 <= S.length <= 20000
S consists only of English lowercase letters.

回答例

/**
 * @param {string} S
 * @return {string}
 */
var removeDuplicates = function (S) {
  const stack = [];
  for (const char of S) {
    stack[stack.length - 1] == char ? stack.pop() : stack.push(char);
  }
  return stack.join("");
};

問題 922. Sort Array By Parity II

https://leetcode.com/problems/sort-array-by-parity-ii/

Given an array A of non-negative integers, half of the integers in A are odd, and half of the integers are even.
Sort the array so that whenever A[i] is odd, i is odd; and whenever A[i] is even, i is even.
You may return any answer array that satisfies this condition.

Example 1:

Input: [4,2,5,7]
Output: [4,5,2,7]
Explanation: [4,7,2,5], [2,5,4,7], [2,7,4,5] would also have been accepted.

Note:
2 <= A.length <= 20000
A.length % 2 == 0
0 <= A[i] <= 1000

回答例

/**
 * @param {string} S
 * @return {string}
 */
var removeDuplicates = function (S) {
  const stack = [];
  for (const char of S) {
    stack[stack.length - 1] == char ? stack.pop() : stack.push(char);
  }
  return stack.join("");
};

問題 1337. The K Weakest Rows in a Matrix

https://leetcode.com/problems/the-k-weakest-rows-in-a-matrix/

Given a m * n matrix mat of ones (representing soldiers) and zeros (representing civilians), return the indexes of the k weakest rows in the matrix ordered from the weakest to the strongest.
A row i is weaker than row j, if the number of soldiers in row i is less than the number of soldiers in row j, or they have the same number of soldiers but i is less than j. Soldiers are always stand in the frontier of a row, that is, always ones may appear first and then zeros.

Example 1:

Input: mat = 
[[1,1,0,0,0],
 [1,1,1,1,0],
 [1,0,0,0,0],
 [1,1,0,0,0],
 [1,1,1,1,1]], 
k = 3
Output: [2,0,3]
Explanation: 
The number of soldiers for each row is: 
row 0 -> 2 
row 1 -> 4 
row 2 -> 1 
row 3 -> 2 
row 4 -> 5 
Rows ordered from the weakest to the strongest are [2,0,3,1,4]

Example 2:

Input: mat = 
[[1,0,0,0],
 [1,1,1,1],
 [1,0,0,0],
 [1,0,0,0]], 
k = 2
Output: [0,2]
Explanation: 
The number of soldiers for each row is: 
row 0 -> 1 
row 1 -> 4 
row 2 -> 1 
row 3 -> 1 
Rows ordered from the weakest to the strongest are [0,2,3,1]


Constraints:

m == mat.length
n == mat[i].length
2 <= n, m <= 100
1 <= k <= m
matrix[i][j] is either 0 or 1.

Constraints:
m == mat.length
n == mat[i].length
2 <= n, m <= 100
1 <= k <= m
matrix[i][j] is either 0 or 1.

回答例

/**
 * @param {string} S
 * @return {string}
 */
var removeDuplicates = function (S) {
  const stack = [];
  for (const char of S) {
    stack[stack.length - 1] == char ? stack.pop() : stack.push(char);
  }
  return stack.join("");
};

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【備忘】【JavaScript】JavaScriptのclassをざっと理解する

classとは

プロパティとメソッドをひとまとまりにして、特定の機能を実現するように設計されたオブジェクト。
特定の機能:日時に関する処理を扱う、とか、文字列を操作する、とか...etc

classを定義するわけ

  • 同じような処理をクラスにまとめて、コードをすっきりさせるため(可読性向上)
  • クラスのロジックを修正すれば、一か所の修正で全てが修正できるため(保守性向上)
  • クラスの使い方さえ知っていれば、中身のコードを知らなくても似た処理を書けるようにするため(開発効率向上)

classからオブジェクトを生成する(インスタンス化)

new [Class名] でclassの定義に従ってオブジェクトを生成する。

classの定義方法とインスタンス化①

// クラスを作る
class Example {
    // constructor関数内は、インスタンス生成時に実行される
    constructor(param) {
        console.log(param);
    }
}

// インスタンス生成
new Example('hello world'); // コンソール:hello world

classの定義方法とインスタンス化②

class Example {
    constructor(param) {
        // 値を自身のオブジェクト(this)に値を持たせる
        this.param = param;
    }
}

// インスタンス化:exampleにオブジェクトを格納
const example = new Example('hello world');
console.log(example.param); // コンソール:hello world

このときのexampleは下記のようなオブジェクトになっている(だいぶ簡略化)。

example = {
  param: 'hello world'
}

classの定義方法とインスタンス化③

メソッドを定義する。

class Example {
    constructor(param) {
        this.param = param;
    }
    saySomething() {
        console.log(this.param);
    }
}

const example = new Example('hello world');
// メソッドを使用
example.saySomething();

このときのexampleは下記のようなオブジェクトになっている(だいぶ簡略化)。

example = {
  param: 'hello world',
  // classで定義したメソッドは、__proto__の中にある。
  __proto__: {
    saySomething: function() {
      console.log(this.param);
    }
  }
}

// これでも呼び出せる
example.__proto__.saysamething();

// が、__proto__を省略して書けるので、普通省略する。意味は変わらない。
example.saysamething();

class定義時のお作法【プライベート変数&メソッドには _ アンダースコアをつける】

class Example {
    constructor(param) {
        this.param = param;
    }
    // 内部関数は、「これはクラス内でしか利用しない関数なんだな」とわかるように _メソッド名() とすることが多い
    // ただし、プライベートメソッドですよ、と示しているだけで、JavaScritでは外からでも呼べてしまう
    // 暗黙の了解、というだけ。
    _sayHello() {
        console.log('hello')
    }
    saySomething() {
        this._sayHello();
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Next.js】Routingを基礎からしっかり。

前書き

筆者がNext.jsを仕事で書くことになったので、1から勉強するためにアウトプット記事を書くことにしました。
基本的にはドキュメントを噛み砕いて、翻訳した記事です。間違っているところなどあれば、ご指摘していただけるとありがたいです?‍♂️

以下、本題です。

Routing

Next.jsは"page"というコンセプトに基づいて形成された、ファイルシステムベースのルーターがあります。

つまりルールに従って、ファイルを配置すればNext.js側で自動的にルーティングを設定してくれるよ、と言うことです。

pagesディレクトリ配下にファイルを追加すれば、自動的にルーティングが作成されます。

Index routes

indexと言う名前のファイルを自動的にそのディレクトリのrootとしてルーティングします。

pages/index.tsx => `/`
pages/post/index.tsx => `/post`

みたいな感じです。

Nested routes

ルーターは入れ子になったファイルもサポートしています。入れ子構造を持つフォルダーを作成すると、自動的に同じ構造のルーティングを作成してくれます。

pages/hoge.tsx => `/hoge`
pages/post/hoge/foo.tsx => `/post/hoge/foo`

Dynamic route segments

動的なルーティングはブランケット構文を使用することで、実現できます。

pages/post/[hoge].tsx => '/post/:hoge'
pages/post/[:postId] => '/post/:postId'

こんな感じでIDを指定してあげれば、「詳細ページ」みたいなのも簡単に実現できますね。

Linking between pages

Next.jsのルーターはSPAのようにクライアントサイドでページ間をルート遷移することができます。

クライアントサイドでルート遷移をするためには<Link>コンポーネントを使う必要があります。

import Link from 'next/link'

const Home = () => {
  return (
    <>
      <Link href="/">
        <a>Home</a>
      </Link>
      <Link href="/hoge">
        <a>hoge</a>
      </Link>
      <Link href="/Foo">
        <a>foo</a>
      </Link>
    </>
  )
}

上記に例では<a>タグをラップし、Linkコンポーネント内の属性でhrefを指定していますね。上から

  • / => pages/index.tsx
  • /hoge => pages/hoge.tsx
  • /foo => pages/foo.tsx

を表示してくれます。

Linking to dynamic paths

動的なpathに対しては、どのようにLinkコンポーネントを指定してあげれば良いでしょうか。

encodeURIComponentを使っていい感じに書く方法もありますが、個人的にはURLオブジェクトを使う方が見やすいです。

import Link from 'next/link'

const Home = ({ post }) => {
  return (
    <Link 
      href={{
        pathname: 'post/[postId]'
        query: {postId: post.id},
      }}
    >
      <a>post.name</a>
    </Link>
  )
}

pathnameでpathを指定し、queryの部分で動的なクエリパラメータを指定してあげています。

以上です。お疲れ様でした。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

落下物で歯車(?)を回してみた (CANNON.js + THREE.js)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JestでdataProviderを使う

やりたいこと

Jestでテストをする際に、テスト内容は同じで与えられるデータだけが異なる場合に、重複した処理を書かずに済ませたい。

PHPUnitでテストを書いている時に使ったことのある、data providerという仕組みがJestにもないか調べてみた。

実装

以下のように、describe.each()を使えばdata providerと同じようなことができる。

interface Datum {
  hoge: string,
}

const data: Datum[] = [
  {
    hoge: 'hoge'
  },
  .
  .
  .
]

describe.each(data)('hogeのユニットテスト', (datum: Datum) => {
  const { hoge } = datum

  it(`${hoge}の場合。`, () => {
    // テストの実装
  })
})

参考記事

Using data provider pattern for javascript unit tests

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ElectronでデスクトップにOfficeアシスタントのイルカを蘇らせる

はじめに

AIチャットボットなどが実用化されてきた昨今、その先駆けとも言える存在がタイトルにもあるOfficeアシスタント機能です。
下記の画像の様にMicroSoft Officeに現れてはユーザのサポートをしてくれる存在ですね。
(エイプリルフールに蘇ったOfficeアシスタントのClippyのTwitterよりの引用)
昔のOfficeを使用されていた方なら馴染みがあるのではないでしょうか。
BkJr6fyCIAEOGU_.jpg

愛らしいマスコット的な存在の彼らですが、残念なことにOffice2007をもって削除されてしまいました。アシスタントなのに邪魔なことが多かったので・・・

そんな彼らを2021年に蘇せるべくElectronを使ってデスクトップに降臨の儀を執り行うのが今回の趣旨です。(AIなどを作るわけではないので悪しからず)
今回はOfficeアシスタントの中でも私が特に好きだったイルカのカイル君をモチーフに作成していきます。
kyle-icon_400x400.png

カイル2010 Twitterアカウントより
https://twitter.com/kyle_2010

作成方針

  • デスクトップに背景を透明化したカイル君を表示する
  • アシスタントなのでWeb検索(Google検索)くらいは出来るようにする
  • 「お前を消す方法」と検索するとカイル君が消える

「お前を消す方法」は邪険に扱われがちなOfficeアシスタントの有名なネタです。Cortanaなどでもネタにされています。
https://nlab.itmedia.co.jp/nl/articles/1705/24/news146.html
「現代に蘇るExcelイルカの悲劇 Win 10搭載「Cortana」に「お前を消す方法」と質問するとまさかの反応が」

Electronとは

GitHub社が開発したオープンソースのソフトウェアフレームワークです。
HTML・CSS・JavaScriptといったWeb技術を用いてデスクトップアプリケーションを作ることが出来ます。
SlackやVisual Studio Codeなどに使用されていることで有名ですね。

今回Electronを採用した理由は手軽にデスクトップアプリケーションを作成できるという点と、今回の仕様の実装に必要な画面の透明化などが容易そうだった点などが挙げられます。

作成

Electronのインストール

$ npm i electron -g
$ electron main.js # メインプロセスのjsを指定

メインプロセス・レンダラープロセスなどElectronの詳細については割愛させていただきますので、他の方が作成された参考文献の記事などをご参照ください。

メインプロセス

昔Electronを触っていた時はNode.jsの機能をやりたい放題使用していましたがセキュリティ的に問題だったみたいですね(当然)。
今回はプロセス間通信を使って画面制御やWeb検索の実行を行っていきます。

メイン画面

透明化・フレームレスなどの指定のためパラメータをいくつか指定していきます。
また、プロセス間通信のため「webPreferences」オプションを下記に設定しました。

const {app,BrowserWindow,ipcMain} = require('electron');
const path = require('path')

// メイン画面(透明化・フレームレスなどを指定)
let mainWindow = null;
app.on('ready', () => {
  mainWindow = new BrowserWindow({
    width: 245, 
    height: 230,
    transparent: true,
    frame: false,
    resizable: false,
    maximizable: false,
    webPreferences: {
      enableRemoteModule: false,
      nodeIntegration: false,
      contextIsolation: true,
      preload: path.join(app.getAppPath(), 'preload.js')
    }
  });
  mainWindow.loadURL('file://' + __dirname + '/index.html');

  mainWindow.on('closed', function() {
    mainWindow = null;
  });
});

プロセス間通信(contextBridge設定)

上記「preload.js」の設定内容です。
今回は画面終了用のcloseとWeb検索画面起動のopenを用意します。

preload.js
const { contextBridge, ipcRenderer} = require("electron");
contextBridge.exposeInMainWorld(
  "api", {
    close: () => {
      ipcRenderer.send("main_close");
    },
    open: (arg) => {
      ipcRenderer.send("sub_open", arg);
    }
  }
);

プロセス間通信(メイン画面終了)

カイル君が消えるための処理です。

ipcMain.on("main_close", (event) => {
  mainWindow.close();
});

プロセス間通信(検索画面を開く)

引数に渡されたパラメータを検索パラメータとして渡して検索画面を開きます。

ipcMain.on("sub_open", (event, arg) => {
  const subWindow = new BrowserWindow({
    webPreferences: {
      contextIsolation: true,
      enableRemoteModule: false
    }
  });
  const googleBaseURL = 'https://www.google.com/search';
  const query = '?q=' + arg;
  subWindow.loadURL(googleBaseURL + query);
});

レンダラープロセス

プロセス間通信呼び出し

検索ボタンを押下されたタイミングで入力テキストを取得し検索子画面を呼び出します。
「お前を消す方法」と入力された時に限ってはカイルくんに再び消えてもらいます。

document.getElementById('btn_search').addEventListener('click', () => {
  const text = document.getElementById('text_search').value;
  if (text === 'お前を消す方法') {
    window.api.close();
    return;
  }
  window.api.open(text);
})

成果物

時を経てDesktopに降臨したカイル君です。
フリー画像を使用したため見た目が異なるのはご愛嬌。
1.png

検索した結果がこちら
2.png

禁断の質問
image.png

・・・。

4.png

さいごに

今回の成果物はこちらになります。
https://github.com/kanaria42/kyle-electron

もう少し機能を追加するなりすれば実用的なアシスタントになるかもしれません。
いつかアップデートで公式のカイル君が蘇る日を夢見て今回は終了とさせていただきます。

参考文献

ようこそ!Electron入門
ElectronでcontextBridgeによる安全なIPC通信
CSSデザインジェネレータ
↑吹き出し実装に使用させていただいたもの

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Reactでいい感じのサブウィンドウを実装する ④ ウィンドウ動かす機能をON/OFF切り替える

Reactでいい感じのサブウィンドウを表示する際にウィンドウ動かす機能をON/OFF切り替えたい場面がよくあるので、

今回は、この方法について紹介します。

Videotogif (2).gif

やり方

RndのdisableDraggingというプロパティに値を指定してあげるとON/OFFの切り替えがでできます。

例1 ウィンドウを動かす機能 ON 

<Rnd disableDragging={false}>test</Rnd>

※ デフォルトは falseなので指定しなくても大丈夫です。

例2 ウィンドウを動かす機能 OFF

<Rnd disableDragging={true}>test</Rnd>

例3 サンプルGif

import "./App.css";
import React, { useState } from "react";
import { Rnd } from "react-rnd";

function App() {
  const [isDisableDragging, setDisableDragging] = useState(false);

  return (
    <div className="App">
      <header className="App-header">
        <button onClick={() => setDisableDragging(!isDisableDragging)}>
          ウィンドウを動かす機能 {isDisableDragging ? "OFF" : "ON"}
        </button>
        <Rnd
          style={{
            backgroundColor: "#fff0d8"
          }}
          default={{
            x: 0,
            y: 0,
            width: 320,
            height: 200
          }}
          disableDragging={isDisableDragging}
        >
          <span
            style={{
              color: "#000f27"
            }}
          >
            {isDisableDragging ? "動きません" : "動きます"}
          </span>
        </Rnd>
      </header>
    </div>
  );
}

export default App;

最後に

プロパティを一つ指定するだけでウィンドウを動かす機能のON/OFFの切り替えができるようになりましたね

次は、ウィンドウの初期表示の設定方法
ついて紹介していきます。

最後まで読んでよかったらLGTMお願いします!

まとめ記事 もあるのでよければこちらもみてください

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript 非同期処理とPromise、Async/Awaitをまとめてみた(超入門編)

プログラミングを勉強していた時から非同期処理は苦手でした。エンジニアになってから、当然業務でAPIを叩いてるのですが、バックとの通信箇所は既存のコードの見様見真似でも何とかなってしまう事がほとんどなので、、PromiseやらAsync/Awaitやら完全に理解していると言えない状態でした。エンジニアも3年目に入るので、いつまでもこれではいけないので、苦手意識を少しでも減らすべく記事にまとめました。

まず、そもそも非同期処理って何?同期処理とどう違うんだ?

同期処理も、非同期処理も処理の実行自体はコードの上から順番に実行されます。

同期処理: ある処理の完了を待って、次の処理へと順番に進んでいく。つまり順番を守る真面目な奴(でも遅い)
非同期処理: ある処理の完了を待たずに、次の処理へ進む。つまり順番を守らない無礼でせっかちな奴。(でも速い)

JavaScriptは、ご存知の通り時間のかかる処理(AJAX通信など)は完了を待たずに次の処理の実行へ進んでいく非同期言語です。

しかし順番通りに処理を実行してもらわないと困るケースがある。今回その例として扱ったケースは2つのAPIを叩いてデータをFetchして、そのデータを元にUIを構築するというもの。

時間のかかる処理の完了を待てないせっかちな非同期処理に「順番」を守らせる為に、この後詳しく説明するPromiseやAsyncAwaitが生まれた。「非同期処理を同期的に扱う」という表現もよく使われますね。

さて、どんな処理(関数)が非同期処理になるのでしょうか?

APIからデータをフェッチしてきたり等、時間がかかる処理は非同期処理になってしまいます。
つまり実行する関数に依存しているんです。
・HTTPリクエスト系 (XHR, fetch, AJAX通信)は常に非同期
・アニメーション系
・イベント系 (DOM Events)
・タイマー系 (setTimeout, setInterval)

では本題です、そんな非同期処理を同期的に扱うための記法は2種類あります。

・Promise記法(thenでつなぐ)
・async/await

Promiseとは??

詳細は割愛しますが、Promise以前はコールバックを駆使して、この処理が終わったら、これを呼ぶという風にネストさせていたが、可読性、エラー発生時の扱いが大変だった。

それでES2015からPromiseが生まれた(もともと外部ライブラリだったけど、言語の使用に組み込まれた)

Promiseは奥が深くて、内部仕様を全て把握していなくても、フロント開発は基本的にfetchなど最初からPromiseを返してくれるメソッドを使ってthenでつないだり、async/awaitしたりして、処理の順番を担保させて、受け取ったデータをフロント側のコードで使うというやり方が基本なので、自分でPromiseオブジェクトを作るという事はあまりないと思います。しかし完璧に理解までいかなくても基本は整理しようと思います。

まずPromiseは3つの状態を持ってる
・Fulfilled(成功):resolve関数が呼ばれた時→then
・Rejected(失敗):reject関数が呼ばれた時→catch
・Pending(待機):Fulfilled、Rejectedでもなく、newPromiseでインスタンス作成した初期状態

すごいシンプルだけど、Promise構文の実サンプルはこんな感じ。

const resolveSample = new Promise((resolve, reject) => {
    resolve('成功');
})
resolveSample
  .then(value => { 
    console.log(value); //呼ばれて「成功」と出力
  })
  .catch(error => {
    console.log(error); //呼ばれない
  })

const rejectSample = new Promise((resolve, reject) => {
    reject('失敗');
})
rejectSample
  .then(value => { 
    console.log(value); //呼ばれない
  })
  .catch(error => {
    console.log(error); //呼ばれて「失敗」と出力
  })

promiseオブジェクトは、 then() と catch() という2つのメソッドを持っており、promiseオブジェクト内部の状態が Fulfilled になると、 then() メソッドのコールバックが呼ばれ、逆に Rejected になると catch() メソッドのコールバックが呼ばれます。

上記のサンプルでは、resolveSampleは、resolve関数を呼んでるので、thenメソッドが呼ばれ。
rejectSampleは、reject関数を呼んでるので、catchメソッドが呼ばれます。

また、thenもcatchも返り値はPromiseなので、メソッドチェーンにして繋げられます。これをPromiseチェーンと呼んだりします。

では順番を守らない非同期処理を順番に実行させるにはこのPromiseをどう使ったらいいかの超絶シンプルなサンプルでみてみましょう。タイマーで、2つのログを時間差で出力させるという処理です。

まず普通の関数

function delay(timeoutMs) {
    setTimeout(() => {
        console.log('3秒後に出力されるdelay関数のログ')
    }, timeoutMs);
}

delay(3000)
console.log('delay関数の後に出力')

この結果は、以下の通りで、意図した順番になりません。

delay関数の後に出力
3秒後に出力されるdelay関数のログ

ではPromiseを使って、順番通りに実行させましょう。

function delay(timeoutMs) {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve();
        }, timeoutMs);
    })
}
//thenメソッドで成功時のコールバックだけを登録
delay(3000)
    .then(() => {
      console.log('3秒後に出力されるdelay関数のログ')
    })
    .then(() => {
      console.log('delay関数の後に出力')
    })

この結果は、意図した順番になります。

3秒後に出力されるdelay関数のログ
delay関数の後に出力

上記サンプルはPromiseオブジェクトを作りましたが、AJAX通信のライブラリAxiosや、fetchメソッドはPromiseを返してくれるので、new PromiseしてPromiseオブジェクトを作る必要はありません。次のサンプルをご覧ください。fetchメソッドを使う時に、thenを繋げたこんなコードをよく見ますね。

2つのAPIからデータをフェッチしてグローバル変数の配列に入れておき、2つ目のフェッチが終わったらinitと言う名前の関数を呼んでます。

let data1 = [];
let data2 = [];
function fetchData() {
    fetch('http://XXXXX.com/hoge')
        .then(res => res.json())
        .then(data => {
            data1 = data;
            return fetch('http://XXXXX.com/hoge2')
        })
        .then(res => res.json())
        .then(data => data2 = data)
        .then(() => {
            allData = [...data1, ...data2]
            init()
        })
        .catch(err => console.log(err))
        .finally(() => {
          //finallyは成功、失敗に関わらず最後に呼び出される
        })
}

ここで大事なポイントが、thenの中の処理が成功すると、次のthenに結果が渡されているのがわかると思います。Promiseチェーンでは、コールバックで返した値を次のコールバックへ引数として渡されるからです。その性質をわかりやすく解説したのが以下のサンプルです。

fetch('http://XXXXX.com/hoge')
  .then(res=>res.json())
  .then(init)

// ↓と同じ事

const response = fetch('http://XXXXX.com/hoge')
const handledData = response.json()
init(handledData)

余談ですが、先日業務でAPIの実装が間に合ってないけど、フロントは実装を進めたいという時に、仮でこんな実装をしました。(API通信するモジュールにダミーデータをPromise.resolveで返す処理を実装。実際はモジュールも分けてますが便宜上まとめて書いてます)

//APIが返してくれる型のデータをフロントで用意
const dummyData = [
    {name: 'hoge taro', id: 1},
    {name: 'hoge jiro', id: 2},
    {name: 'hoge goro', id: 3}
];

const getHogeData = () => {
    return Promise.resolve({
        ok: true,
        status: 200,
        json: {
            data: dummyData
        }
    })
}

getHogeData().then(res => {
    if(res.ok && res.json){
        setHogeData(res.json.data)
    }
})

要はfetchの擬態みたいなことをしてるんですね。

Async/Awaitとは??

ずっとアシンクアウェイトって勘違いしてました、、正確にはエイシンクアウェイトです!

関数の中でAwaitを使いたかったらまず関数をAsyncとして宣言する必要があります。
そして、処理の完了を待ちたい箇所の頭に、awaitをつけると、その名の通り、完了するまでそこで待ってくれて、次の処理へ行かせなくします

しかし、、注意したいのが awaitできるのはPromiseを返すものだけなのです(Promiseのルールに沿った処理だけがawaitできるという訳です)

つまりはAsync/AwaitはPromiseありきのものだから、ある程度Promiseを知っておいたほうがいいという事なんですね。

では、上で挙げた例をAsync/Awaitで書いてみましょう。

let data1 = [];
let data2 = [];
async function fetchData() {
    try {
        const fetchedData1 = await fetch('http://XXXXX.com/hoge')
        data1 = await fetchedData1.json()

        const fetchedData2 = await fetch('http://XXXXX.com/hoge2')
        data2 = await fetchedData2.json()

        init()
    } catch(e) {
        console.log('error', e)
    }
}

凄い簡潔に書ける様になりますね。

Async/AwaitはPromiseの糖衣構文(Syntax Sugar)ってなんだ??

よく本とか技術ブログでこんな風に書かれてるのを見かけます。糖衣構文(Syntax Sugar)は「同じ意味の処理を元の構文よりもシンプルに書ける別の書き方」の事です。

つまりはAsync/AwaitはPromiseを簡単に扱えるようにしたものという事です。

まとめ

結構長くなってしまいましたが、あまり深いところには触れず、基本だけをまとめました。
間違ってる部分などありましたらご指摘ください。
こうして言語化すると考えが整理されて凄いためになるので、スキル向上のため今後もいろいろ投稿していこうと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む