20210728のJavaScriptに関する記事は14件です。

【LINE Messaging API&Custom Search API】LINEでGoogle検索してみた

はじめに 興味本位でLINEBOTを作成してみました。 既に多くの方が解説してくださっていますが自身の備忘録として一通りやったことを残します。 目的 LINEBOTを作ってみたかったので遊びで実装しました。 アウトプット このようになります。 目次 ・LINE Developersの登録とチャンネル作成 ・Google APIの登録とCustom Search APIの登録 ・githubの登録とコード管理 ・サンプルBOT作成 ・Herokuの登録とデプロイ ・動作検証 その1 ・Custom Search APIコール準備 ・カルーセル表示 ・検索結果のマッピング ・デプロイと動作検証 その2 開発環境 Node.js:v14.16.1 yarn:1.15.2 LINE Developersの登録とチャンネル作成 こちらにアクセスしてログインします。 LINEアカウントを持っていてば特に問題なくログインできます。 LINE Developers公式ドキュメントに記載されている通りに作業します。 Google APIの登録とCustom Search APIの登録 Google検索を行うためにCustom Search APIを使いました。 こちらで解説してくださっています。手順通りに作業します。 githubの登録とコード管理 説明は不要だと思うので割愛します。 サンプルBOT作成 右も左もわからなかったので、まずチュートリアルでサンプルBOTを作成しました。 これをベースとして実装を行いました。 デプロイと動作検証が完了したら検索部分の実装を行います。 Herokuの登録とデプロイ デプロイにはHerokuを使用します。 アカウント作成後にアプリケーションを作成します。 デプロイはコマンドラインからではなくgithubを連携させて手動で行いました。 こちらで解説してくださっているので手順通りの作業でgithubからデプロイできるようになります。 私の場合エラーなくデプロイできていると、真っ白な背景の左上にOKとだけ表示されます。 動作検証 その1 テキトーにメッセージを投げてみたところLINEBOTからメッセージが返ってきました。 ※SSを添付したかったのですが1か月近く前なのでLINEの履歴から消えてしまっていました… もしうまくデプロイできていなかったり、メッセージを投げて結果が返ってこなかった場合には ログを確認することになります。 まずコマンドラインからherokuにログインします。 heroku login 何かボタンを押せと言われるので押します。 heroku: Press any key to open up the browser to login or q to exit: ブラウザが立ち上がるorタブが追加されてログイン画面が表示されるのでログインします。 その後以下コマンドでログを確認できます。 heroku logs --tail --app アプリ名 Custom Search APIコール準備 APIに設定することができるパラメータは結構ありましたが、 検索ができればよかったので必要最低限のパラメータで実装しました。 以下サンプルです。 customSearch.cse.list({ // APIキー auth: "AIzaSyD~~~~~~~~~~", // カスタムエンジンID cx: "2ab139~~~~~~~~~", // クエリ q: query }); APIキーとカスタムエンジンIDはそれぞれ以下から取得します。 APIキー カスタムエンジンID また、より高度な検索を行う場合はパラメータ一覧をご参照ください。 カルーセル表示 LINEBOTからの返信では検索結果をカルーセル表示させます。 カルーセルテンプレートに記載されている通りに検索結果を加工することになります。 注意点として ・imageSize:containに設定しなければサムネイルが見切れてしまいます。 ・defaultAction:設定すると画像部分をタップしてもリンクが開けるようになります。 ・action:URIアクションのlebelはただのカルーセルの場合必須です。また20文字制限があります。 検索結果のマッピング マッピングの前にレスポンスの形式を確認します。 この中のitemsに検索結果が入っています。 ・items[i].link:検索結果のリンクが入っています。 ・items[i].title:タイトルが入っています。 ・items[i].pagemap:サムネイルのURLが取得できるのですが、下記注意が必要です。 注意の前にまず「焼き肉」で検索したときの検索結果のうち1つのpagemapを見てみます。 { "cse_thumbnail": [ { "src": "https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcQJ9azqHAYG_X-xfzPIZ8quePzAOXoQd_9L-UJB0iFfyZsPgboeSKg3whGw", "width": "225", "height": "225" } ], "metatags": [ { "og:image": "https://www.yakiniku-king.jp/wp-content/uploads/2020/10/og.png", "og:type": "website", "twitter:card": "summary", "twitter:title": "焼肉きんぐ|お席で注文 焼肉食べ放題!", "og:site_name": "焼肉きんぐ", "viewport": "width=device-width, initial-scale=1.0, minimum-scale=1.0", "twitter:description": "焼肉きんぐはおいしい焼肉が食べ放題のお店です。テー ブルバイキングだからお席まで出来たての商品をお持ちします。焼肉満腹保証つき!食べ放題コース:幼児無料、小学生半額、60歳以上500円引き。WEBから受付予約できます。", "og:title": "焼肉きんぐ|お席で注文 焼肉食べ放題!", "og:url": "https://www.yakiniku-king.jp/", "og:description": "焼肉きんぐはおいしい焼肉が食べ放題のお店です。テーブルバイキングだからお席まで出来たての商品をお持ちします。焼肉満腹保証つき!食べ放題コース:幼児無料、小学生半額、60歳以上500 円引き。WEBから受付予約できます。", "og:image:secure_url": "https://www.yakiniku-king.jp/wp-content/uploads/2020/10/og.png", "twitter:image": "https://www.yakiniku-king.jp/wp-content/uploads/2020/10/og.png" } ], "cse_image": [ { "src": "https://www.yakiniku-king.jp/wp-content/uploads/2020/10/og.png" } ] } items[i].pagemapの中にはcse_thumbnailやmetatags、cse_imageがあります。 サムネイルと書かれているのでcse_thumbnailを使用するのですが、データによってはcse_thumbnailが存在しない場合がありました。 そもそもpagemapが存在しない場合もありました。 (metatagsとcse_imageも存在しない場合がありました。) 以下カルーセルのmessages部分のの実装例です。 messages: [ { "type": "template", "altText": req.body.events[0].message.text + "の検索結果", "template": { "type": "carousel", "imageSize": "contain", "columns": commonFunction.createCarouselColumns(formattedResult) } } ] 以下マッピング部分の実装例です。 createCarouselColumns(response) { // サムネイルが存在しないサイトはのぞく return response.items.filter(item => item.pagemap !== undefined && item.pagemap !== null && item.pagemap.cse_thumbnail !== undefined).map(item => ({ "thumbnailImageUrl": item.pagemap.cse_thumbnail[0].src, "text": item.title, "defaultAction": { "type": "uri", "label": item.title.substr(0,20), "uri": item.link }, "actions": [ { "type": "uri", "label": item.title.substr(0,20), "uri": item.link } ] })); } デプロイと動作検証 その2 コードをpushしてHerokuからデプロイします。 焼き肉で検索をしてみると…想定通り検索結果を取得することができました!!! 最後に 遊びで作っていたのでテキトーな実装かつ簡単な機能ですが、楽しんで作ることができました。 何か思いついたらまた作ってみたいです。 この備忘録がどなたかの参考になりましたら幸いです。 参考 Messaging APIを始めよう Custom Search APIを使ってGoogle検索結果を取得する (チュートリアル)Node.jsを使ってサンプル応答ボットを作る heroku 初級編 - GitHub から deploy してみよう - URIアクション
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptの日時ライブラリを比較してみた

 ネイティブJavaScriptで日時を取り扱う場合、ビルトインされているDateオブジェクトを使うことになるのだが、このDateオブジェクトは取り扱いにクセが多く、直感的に日時を操作できない点でも有名である。そこで、専らサードパーティ製のプラグインmoment.jsやdayjsを使うのが一般的になっている。最新では、オワコン宣言したmoment.jsの後継と云われるLuxonや、次期JavaScriptへの実装が期待されているTemporalモジュールなどが出て来ていて、では結局どれを使うのが良いのか? という悩みを抱えている人もいるのではないだろうか。私がまさにその問題にぶち当たった次第である。  そこで、それぞれの日時処理用プラグインやモジュール(本稿では統一してライブラリと称することにする)を比較してみることにした。 各種日時ライブラリの比較  まず、ネイティブJSのDateオブジェクトと、Luxon、dayjs、Temporalをそれぞれ仕様や機能別に単純に比較してみた結果を一覧化してみた。  オワコン宣言されているmoment.jsについては、公式でも「もう使わないで」と謳われているので除外してある。またTemporalについては仕様策定中とあって、実装が確定していない(公式GitHubをwatchしていると毎日のように議論が起票されている)ので、ここでは2020年7月22日時点での実装内容なので注意が必要だ。 比較項目 Date Object Luxon dayjs Temporal バージョン(2021/7/22時点) - 2.0.1 1.10.6 0.1.0 公式サイト MDN moment.github.io/luxon day.js.org tc39.es 日本語ドキュメント あり なし READMEのみ なし コア (ネイティブ) Dateのラッパー Dateのラッパー 独自モデル インストール(npm) - npm i --save luxon npm i --save dayjs ※詳細は後述 CDN - 配布あり 配布あり × ファイルサイズ(minify後) - 68kB 6.34kB(コアのみ) 286kB(配布版にはminifyなし) プリミティブ値 UNIX時間(ミリ秒)のNumber UNIX時間(ミリ秒)のNumber(Dateのラッパーなので) UNIX時間(ミリ秒)のNumber(Dateのラッパーなので) UNIX時間(ナノ秒)のBigInt 保持値特性 ミュータブル イミュータブル イミュータブル イミュータブル タイムゾーン対応 オフセットのみ フルサポート(IANA Time Zone Database と独自拡張) 要プラグイン フルサポート(IANA Time Zone Database か TZ database 準拠) DST対応 特になし サポート済み なし サポート済み カレンダー(歴)対応 Intl.Localeによるサポート グレゴリオ暦とISO Week暦をサポート 要プラグイン サポートあり(太陰太陽暦など) 使用法(コード) - const { DateTime } = require("luxon") もしくは <script src="luxon.js"></script> const dayjs = require('dayjs') もしくは <script src="dayjs.min.js"></script> const { Temporal } = require('proposal-temporal') 初期化 new Date() const DateTime = luxon.DateTimeなど dayjs() Temporal 現在日時 const now = new Date() const now = DateTime.now() const now = dayjs() const now = Temporal.Now フォーマッター Intl.DateTimeFormat()によるサポート Intl.DateTimeFormat()依存の独自拡張 独自書式(YYYY/MM/DD等) Intl.DateTimeFormat()依存の独自拡張 国際化 Intl.DateTimeFormat()によるサポート Intl.DateTimeFormat()によるサポート 要プラグイン Intl.DateTimeFormat()によるサポート 日時比較 なし インスタンスメソッド(hasSame等) インスタンスメソッド(diff) インスタンスメソッド(compare) 日時更新 Setter インスタンスメソッド(plus, minus等) インスタンスメソッド(add, subtract等) インスタンスメソッド(add, subtract等) 期間算出 なし Duration API(Duration.fromObject({ hours: 2, minutes: 7 })) 要プラグイン(duration) インスタンスメソッド(Duration) 二点間の間隔 なし Interval API(Interval.fromDateTimes(now, later)) 要プラグイン(isBetween) インスタンスメソッド(Duration, until) 拡張性 あり 不明(公式ドキュメントには記述なし) 高い(プラグイン追加が可能) 未知 ライセンス - MIT MIT BSD-3-Clause 補足: Temporalのインストール手順  Temporalは現在策定中のため、正式なインストール手順が公開されていない(GitHubのレポジトリのREADMEから奥深くに辿って行くとちょっとだけ記載されている程度だ)。現状では、評価バージョンであるPolyfillを自前でビルドして使うことになる。その手順を紹介しておこう。 git clone https://github.com/tc39/proposal-temporal.git temporal cd temporal npm run build:polyfill  これでpolyfillディレクトリ内にscript.jsとscript.js.mapがビルドされる。ビルドされたスクリプトはMinifyされていないので、520kBオーバーの巨大スクリプトになる。このファイルが、Temporalの実体とそのソースマップである。これをHTML側で読み込むことでTemporalがJavaScriptのグローバルスコープ内で使用できるようになる。 <script src="/path/to/temporal/polifill/script.js"></script> <script> const current = Temporal.Now console.log(current.timeZone().id)// "Asia/Tokyo" console.log(current.plainDate('japanese').era)// "reiwa" console.log(current.instant().toString())// "2021-07-22T04:22:31.771751767Z" </script>  実際の使用例は上記のような感じだ。  さて、ライブラリの比較はここまで。  次に、それぞれのライブラリを実際に使用してみての私個人の所感をまとめてみた。 Luxonの所感  今回比較したライブラリの中では、最もモダンでスマートなパッケージという感じだった。moment.jsの後継と謳っていることもあって、個人的にmoment.jsのフォーマッター仕様が苦手だったことから、そこが踏襲されていると嫌だなぁ……と思っていたが、幸いにもネイティブJSのIntl APIに準拠する形に落ち着いていたので好感度UPだったw  タイムゾーンや更新系、算出系のインスタンスメソッドが豊富で、それらが元からコアにビルトインされているので、Luxonの1ファイルを読み込むだけでJavaScriptの日時処理は全てまかなえてしまうのがお手軽である。  さらに、ファイルサイズも小さめで、全体的に無難で隙がない優秀なライブラリと云ったところだ。 DAYJSの所感  とにかくファイルサイズが小さいのがウリだ。それゆえ、コアファイルに含まれる処理はかなり限定的である。ただ、JavaScript側で大仰な日時処理を必要としないのであれば、ネットワーク帯域を圧迫しない点でこのライブラリは最良であると云えるだろう。  公式プラグインを追加することで様々な拡張処理に対応できるのも魅力的で、リッチな日時処理が必要であっても、必要最小限のプラグイン追加で機能が実装できるので、ネットワーク帯域を限界まで最適化したいアプリなどでは光るものがある。とはいえ、必要な機能を選別して都度プラグインをインポートする手間は面倒でもあり、国際化などで多言語対応を求められると各言語ごとのプラグインを読み込む煩雑なデプロイが必要になる可能性もある。また、拡張プラグインを多用するようなアプリなどでは極小ファイルサイズのメリットが薄れてしまうだろう。  個人的にはフォーマッター仕様がmoment.js互換なのがいただけない点である。逆に、moment.jsからの乗り換えであれば、後継と云われるLuxonよりこちらのDAYJSの方が適しているかも知れない。 Temporalの所感  前者2つのライブラリがネイティブJSのDateオブジェクトのラッパーであったのと比較すると、こちらは完全独立型のモジュールである。Dateオブジェクトの弱点であるタイムゾーン処理や各種比較・算出処理にも対応していて、これがネイティブJavaScriptの標準として追加されたら幸せになれそうな予感が半端ない。  ただ、現状ではファイルサイズが大きすぎて商用としては使えない(ビルドしたスクリプトをMinifyしてみたが、それでも286kBオーバーだったので、かなり重い)。  仕様的に国際化部分はIntl APIに準拠しているので、これが今後の日時国際化の標準仕様になるのだろうと思われる。特筆すべきはエポックタイムをナノ秒まで算出できるところだ。おそらくここまで精緻な時間が必要なケースは稀だろうが、面白い仕様である(まぁ、ナノ秒のBigIntを処理するコードなんて書きたくないが……w)。  使い勝手的にはインスタンスメソッド名が長すぎるのが難点なのと、有用なフォーマッターを実装していないところが気になるところだ。まぁ、策定中でもあるし、今後どのように改善されていくのかが非常に気になるモジュールではある。 Dateオブジェクトの不満点への対応  ここからは一部個人的な嗜好も含まれるのだが、ネイティブJavaScriptのDateオブジェクトを取り扱う上でよく難儀するケースに対して、それぞれのライブラリでの対応がどのようになっているかを調査してみた。 イミュータブル性  一度インスタンス化した日時オブジェクトの値については、プリミティブ値として不変(イミュータブル)であることが望ましい。日時の利用ケース的に、できる限りSetterによるプリミティブ値の上書きを抑止して、インスタンスメソッドによる値の更新時にはその都度新たなインスタンスとして値を返すような仕組みが最適だと思うのだ。つまりは、起点となる日時が変動しないことで、どんな処理からでも起点日時を安定して参照できるようになり、それが処理全体の不確実性を低下させられるメリットを得られる。  その点、ネイティブJSのDateオブジェクト以外は3つともイミュータブル性を持っているので、どれを選んでも日時の取り扱いは格段にし易くなっている。 検証: Dateオブジェクト  Dateオブジェクトでは、インスタンスとして保持される日時データがミュータブルな値(状態が変化する値)であることを、実例で示してみる。 let oneDate = new Date(2021, 5, 9, 12, 0, 0, 0) ──と定義した日時データoneDateは、システムタイムゾーンがAsia/Tokyo(日本標準時)だった場合にUTCで2021-06-09T03:00:00.000Zとなる。この日時を1日進めてみよう。 oneDate.setDate(oneDate.getDate() + 1) console.log(oneDate.toISOString())// "2021-06-10T03:00:00.000Z"  まぁ、Setter使ってオブジェクト内のプリミティブ値を上書きしているので、挙動的には至極真っ当で、ここに不満を云っても仕方ない(オブジェクトのプリミティブ値というのは基本不変な値なのだが、Setterによる上書きは許可されるのだ)。そしてこの時点でoneDateが保持している日時データは、初期値より1日進んだプリミティブ値となる。そのため、これ以降に初期値としての日時が欲しい場合、再びSetterで1日前の日時データを作成するか、もとから初期日時をconstとして変更不可を宣言した定数に格納しておく必要がある(まぁ、JavaScriptではLint等でルールを縛らないと定数でも変更できてしまうが……)。通常は後者だろう(下記参照)。 const baseDate = new Date(2021, 5, 9, 12, 0, 0, 0), DAY_MS = 1 * 24 * 60 * 60 * 1000 let oneDate = new Date(baseDate.getTime() + DAY_MS) console.log(oneDate.toISOString())// "2021-06-10T03:00:00.000Z"  なんともまどろっこしいうえに、JavaScript自体にシステム的な不変の縛りがないため、定数baseDateのプリミティブ値が不変であることが以降の処理で担保されない不安定さが残る。  もっと実践的な例として、現在日から一週間分の日付を取得して、それを配列に格納してみる。 const baseDate = new Date() let weekDates = [] for (let add = 0; add <= 7; add++) { weekDates.push(new Date(baseDate.setDate(baseDate.getDate() + add))) } console.log(weekDates.map(date => date.toISOString())) // 結果: [ // 0: "2021-07-28T12:53:24.355Z" <- baseDateが 2021-07-28 +0日で上書きされる // 1: "2021-07-29T12:53:24.355Z" <- baseDateは 2021-07-28 +1日で上書きされる // 2: "2021-07-31T12:53:24.355Z" <- baseDateは 2021-07-29 +2日で上書きされる // 3: "2021-08-03T12:53:24.355Z" <- baseDateは 2021-07-31 +3日で上書きされる // 4: "2021-08-07T12:53:24.355Z" <- baseDateは 2021-08-03 +4日で上書きされる // 5: "2021-08-12T12:53:24.355Z" <- baseDateは 2021-08-07 +5日で上書きされる // 6: "2021-08-18T12:53:24.355Z" <- baseDateは 2021-08-12 +6日で上書きされる // 7: "2021-08-25T12:53:24.355Z" <- baseDateは 2021-08-18 +7日で上書きされる // ] console.log(baseDate.toISOString()) // "2021-08-25T12:53:24.355Z" <- 起点日が変わっている  Dateオブジェクトがミュータブルな値を持つことを考慮せずに、上記のように直感的な処理でコーディングしてしまうと、思わぬ結果となって混乱してしまうだろうw  期待値通りの処理結果を得るためには、forループ内にて定数baseDateとは別に起点日時をクローンしたテンポラリ変数を定義して、それに対して日数加算を行う必要がある。 for (let add = 0; add <= 7; add++) { let tempDate = new Date(baseDate.valueOf())// `let tempDate = baseDate` ではダメ weekDates.push(new Date(tempDate.setDate(tempDate.getDate() + add))) }  なお、JavaScriptではオブジェクトを変数に単純に代入してしまうと、プリミティブ値は参照扱いとなり実体はbaseDateの値になってしまうので、baseDateのプリミティブ値を使って新たにDateオブジェクトのインスタンスをtempDateに格納しないと完全なクローンができないのがさらにややこしい。また日付値の加算等ができるインスタンスメソッドもないので、愚直にGetterで値を取って加工してSetterで上書きしてあげる必要があるのも面倒だ。なんとももどかしい上に、処理のオーバーヘッドも高くて、およそ褒められる点が見つからない。 検証: Luxon  では、Luxonで同じように現在日から一週間分の日付を取得してみよう。Luxonの場合、インスタンスメソッドplus()を使えるので簡単だ(減算時はminus()を使う)。このメソッドの戻り値は独立した日付インスタンスになるので、起点日を格納したbaseDateは処理後も不変(イミュータブル)である。 const baseDate = DateTime.now() let weekDates = [] for (let add = 0; add <= 7; add++) { weekDates.push(baseDate.plus({days: add})) } console.log(weekDates.map(date => date.toISO())) // 結果: [ // 0: "2021-07-28T21:56:57.886+09:00" // 1: "2021-07-29T21:56:57.886+09:00" // 2: "2021-07-30T21:56:57.886+09:00" // 3: "2021-07-31T21:56:57.886+09:00" // 4: "2021-08-01T21:56:57.886+09:00" // 5: "2021-08-02T21:56:57.886+09:00" // 6: "2021-08-03T21:56:57.886+09:00" // 7: "2021-08-04T21:56:57.886+09:00" // ] console.log(baseDate.toISO()) // "2021-07-28T21:56:57.886+09:00" <- 起点日は変わっていない 検証: DAYJS  DAYJSの場合、日時の加減計算はインスタンスメソッドのadd()とsubtract()で簡単に行える。このメソッドの戻り値は新規日時インスタンスになるので、起点日を格納したbaseDateは処理後も不変(イミュータブル)である。 const baseDate = dayjs() let weekDates = [] for (let add = 0; add <= 7; add++) { weekDates.push(baseDate.add(add, 'day')) } console.log(weekDates.map(date => date.toISOString())) // 結果: [ // 0: "2021-07-28T12:58:53.287Z" // 1: "2021-07-29T12:58:53.287Z" // 2: "2021-07-30T12:58:53.287Z" // 3: "2021-07-31T12:58:53.287Z" // 4: "2021-08-01T12:58:53.287Z" // 5: "2021-08-02T12:58:53.287Z" // 6: "2021-08-03T12:58:53.287Z" // 7: "2021-08-04T12:58:53.287Z" // ] console.log(baseDate.toISOString()) // "2021-07-28T12:58:53.287Z" <- 起点日は変わっていない 検証: Temporal  Temporalでの日時の加減計算はインスタンスメソッドのadd()とsubtract()で行えるが、加減値はDuration APIで初期化する必要がある。また、起点日時としてインスタンス化した書式がそのまま戻り値となる。ちょっとクセが強いが、起点日時のイミュータブル性は確保されている。 const baseDate = Temporal.Now.zonedDateTimeISO() let weekDates = [] for (let add = 0; add <= 7; add++) { weekDates.push(baseDate.add(Temporal.Duration.from({days: add}))) } console.log(weekDates.map(date => date.toString())) // 結果: [ // 0: "2021-07-28T22:00:30.124230122+09:00[Asia/Tokyo]" // 1: "2021-07-29T22:00:30.124230122+09:00[Asia/Tokyo]" // 2: "2021-07-30T22:00:30.124230122+09:00[Asia/Tokyo]" // 3: "2021-07-31T22:00:30.124230122+09:00[Asia/Tokyo]" // 4: "2021-08-01T22:00:30.124230122+09:00[Asia/Tokyo]" // 5: "2021-08-02T22:00:30.124230122+09:00[Asia/Tokyo]" // 6: "2021-08-03T22:00:30.124230122+09:00[Asia/Tokyo]" // 7: "2021-08-04T22:00:30.124230122+09:00[Asia/Tokyo]" // ] console.log(baseDate.toString()) // "2021-07-28T22:00:30.124230122+09:00[Asia/Tokyo]" <- 起点日時は変わっていない  ミュータブルなDateオブジェクトを使っていて一番やっかいなのが、起点日時を格納したbaseDate定数は「いじらない!」というコーダー側の強い覚悟を常に持っていないと、どこかで日時が書き換わってしまっている不安にさいなまれることになることだ……w  それに比べて他のライブラリはインスタンス化した日時はイミュータブルであることが担保されているので、心穏やかに日付を取り扱うことができる。 2桁年の自動マッピング  Dateオブジェクトの最もヒドイ仕様は、与えられた年の数値引数が2桁以下(0~99)だった場合に、1900~1999年に自動でマッピングしてしまうことだ。さらに、年のみの指定ではインスタンス化できない点も地味に使いづらい。例えば、下記のコードを参照してみて欲しい。 for (let y = 0; y <= 100; y++) { // コンストラクタ引数が1つだけの数値の場合、UNIX時間が与えられたとしてインスタンス化される console.log(new Date(y).toISOString())// -> 1970-01-01T00:00:00.000Z ~ 1970-01-01T00:00:00.100Z // ローカルタイムゾーンでのインスタンス化の場合、オフセットによるUTC日時がズレるのであえて月の2日目を指定している console.log(new Date(y, 0, 2).getFullYear())// -> 1900 ~ 1999 最後は 100 // UTCメソッドは年のみの指定でUNIX時間が得られるので、それを元にインスタンス化できる console.log(new Date(Date.UTC(y)).getUTCFullYear())// -> 1900 ~ 1999 最後は 100 }  もし2桁以下の年を取得したい場合、このように書くことになる。 let twoDigitYearDate = new Date() for (let y = 0; y < 100; y++) { twoDigitYearDate = new Date(twoDigitYearDate.setFullYear(y)) console.log(twoDigitYearDate.getFullYear())// 0 ~ 99 console.log(twoDigitYearDate.toISOString())// 0000-07-22T01:10:10.057Z ~ 0099-07-22T01:10:10.057Z }  一度テンポラリーなインスタンスを生成しておいて、Setterでプリミティブ値を上書きするという方法だ。美しくないうえに、無駄に処理コストが高くて、どうも好きになれない。理想的というか直感的に、2桁以下の年は、そのまま0~99年(BCE.1~CE.99)でインスタンス化されて欲しいんだよね。  ちゅーわけで、これに対応できているライブラリを調査してみた。 検証: Luxon  Luxonでの結果は下記の通り。理想的なマッピングが行われている。完璧だ! const DateTime = luxon.DateTime for (let y = 0; y <= 100; y++) { const date = DateTime.local(y) console.log(date.toString()) // 結果(システムタイムゾーンは Asia/Tokyo) // 0000-01-01T00:00:00.000+09:18 ~ 0100-01-01T00:00:00.000+09:18 } 検証: DAYJS  DAYJSでの結果は下記の通り。自動マッピングの処理に規則性がなく散々な結果だった。実際のところ、2桁年でのインスタンス化には非対応と云った方がよいだろう。 // 配列引数での日時インスタンス化にはプラグインが必要 dayjs.extend(window.dayjs_plugin_arraySupport) for (let y = 0; y <= 100; y++) { let date = dayjs([y]) console.log(date.format()) // 結果(システムタイムゾーンは Asia/Tokyo) // y = 0: 2000-01-01T00:00:00+09:00 // y = 1 ~ 12: 2001-01-01T00:00:00+09:00 ~ 2001-12-01T00:00:00+09:00 (月だけ変わる) // y = 13 ~ 31: Invalid Date (`year()`メソッドでは`NaN`となる) // y = 32 ~ 49: 2032-01-01T00:00:00+09:00 ~ 2049-01-01T00:00:00+09:00 // y = 50 ~ 99: 1950-01-01T00:00:00+09:00 ~ 1999-01-01T00:00:00+09:00 // y = 100: 100-01-01T00:00:00+09:15 } 検証: Temporal  Temporalでの結果は下記の通り。2桁年に対しての自動マッピングは行われないものの、年のみでのインスタンス化が出来ない。また、インスタンスメソッドのfrom()は親となるPlain系メソッドに依存した日付データとなってしまい、ISO-8601形式等他の形式の日付が取得はできないためちょっと使い勝手が悪い。 for (let y = 0; y <= 100; y++) { // Temporalには年指定のみで日付をインスタンス化できるメソッドがないので、最低でも月指定が必要 const date = Temporal.PlainYearMonth.from({ year: y, month: 1 }) console.log(date.year, date.toString()) // 結果 // 0 ~ 100, "+000000-01" ~ "+000100-01" }  以上、この項目について私的な期待値を満たしてくれるライブラリはLuxonだけだった。  まぁ、UNIX元期(1970年1月1日0時0分0秒)より前の時刻を取り扱うようなケースは稀なのかもしれないが、私的にはここがかなり重要なポイントでもある。 「月」の指定レンジが 0~11  Dateオブジェクトでは、1月は0、12月は11と云うように配列の数値添え字の感覚で月を指定しないといけない。これが直感的でなく、コードの可読性を著しく阻害している要因でもある。一応12進数として繰り上がりが行われるので、月に12と指定してもエラーにはならず、ただ繰り上がって翌年の1月になってしまいバグの温床にもなり易いのだ。  ちゅーわけで、直感的で、開発者に優しい1~12の数値で月が指定できるライブラリを調査してみた。 検証: Luxon const date = DateTime.local(2021, 7, 22) console.log(date.month, date.monthLong, date.monthShort)// 7 "July" "Jul"  さすがはLuxon! 渡した月の数値をそのまま月としてインスタンス化してくれる。 検証: DAYJS const date = dayjs([2021, 7, 22]) console.log(date.toISOString(), date.format(), date.month(), date.get('month')) // 結果 // date.toISOString(): "2021-08-21T15:00:00.000Z" // date.format(): "2021-08-22T00:00:00+09:00" // date.month(): 7 // date.get('month'): 7  DAYJSはちょっと微妙……というかむしろ危険だ。インスタンス化した日付を日付文字列やフォーマッターを介して出力すると、ネイティブJSと同じように+1の月となるが、個別に日付要素を取得するインスタンスメソッドで取得すると引数で渡した月が返る。これはどちらかに統一しないとバグの温床になり得ないか!?  特に、get('month')メソッドについては公式ドキュメントに0開始の月が返ると書いてあることもあって、ちょっと混乱してしまったw 検証: Temporal const yearMonth = Temporal.PlainYearMonth.from({ year: 2021, month: 7 }), monthDay = Temporal.PlainMonthDay.from({ month: 7, day: 22 }), date = monthDay.toPlainDate({ year: 2021 }) console.log( yearMonth.month, monthDay.monthCode, date.toString() ) // 結果 // yearMonth.month: 7 // monthDay.monthCode: "M07" // date.toString(): "2021-07-22"  Temporalも与えられた月の数値をそのまま月として日付をインスタンス化してくれる。ただ、Temporalはインスタンスを生成する際に使われたメソッドによって生成される日付のプリミティブ値が異なる。「年と月」から生成した場合と「月と日」から生成した場合とでは全く別の断片的な日付インスタンスが生成されるのだ。そして、生成したインスタンスの欠けている日時要素を補完することで断片データから完全な日時データを作成していくことができる。  従来のJavaScriptのDateオブジェクトと全く異なる概念性を持っているので、特性に馴れないと逆に使いづらいかもしれない。 タイムゾーンオフセットのゆらぎ  あまり知られていないが、JavaScriptのタイムゾーンオフセットは固定値ではない。歴史的経緯や年代によって同じタイムゾーンでも時差が異なるのだ。以前気になって独自に調べてみたところ、下記の例のように結構な頻度でブレている。 年 America/New_York (UTC-05:00) America/Danmarkshavn (Coordinated Universal Time) Europe/London (GMT Standard Time) UTC Africa/Monrovia (Greenwich Standard Time) Asia/Kathmandu Asia/Tokyo (Japan Standard time) Pacific/Tongatapu (UTC+13:00) 2021 -05:00 +00:00 +00:00 +00:00 +00:00 +05:45 +09:00 +13:00 2000 ~ 2002, 2017 - - - - - - - +14:00 1917 ~ 1995 - -03:00 - - - - - - 1920 ~ 1985 - - - - - +5:30 - - 1920 ~ 1972 - - - - -00:44:30 - - - 1943 ~ 1945 -04:00 - - - -00:44:30 - - - ~ 1942 -05:00 - - - -00:44:30 - - - ~ 1919 - - - - -00:43:08 +05:41:16 - - ~ 1916 - -01:14:40 - - - - - - 1901 ~ 1940 - - - - - - - +12:20 ~ 1900 - - - - - - - +12:19:20 ~ 1888 - - - - - - +09:18:59 - ~ 1883 -04:56:02 - - - - - - - ~ 1847 - - -00:01:15 - - - - -  システム時制として一般的なUNIXエポック元期(1970/1/1)以降でも結構なブレが発生している。同一タイムゾーンにおいて時差が異なる二点間のUTC日時のインターバルを取得する場合、その差分はどのように取り扱われているのかが気になるところだろう。  以前、GMT(グリニッジ標準時)においてこのタイムゾーンのキャズム(溝、境界)間のDateオブジェクトのプリミティブ値がどうなっているか調べたことがあるが、その結果、キャズムポイントである1847年12月1日0:0:0~0:1:15において時間が消失していることが分かった。つまり、消失時間中の日時は取得できないのだが、消失することで前後の差分が吸収されて、結果として丸く収まる具合だ(これってあまりにもやっつけな仕様だと思うが……)。一方で、日本標準時の場合は時間消失は起きなかった(つまりは差分吸収がされないために丸く収まらないということだ)。  これらのタイムゾーンオフセットの揺らぎとキャズム間の挙動は一見するとバグに近しいのだが、あまり表立って問題にもならないので、深く突っ込むのは止めておこうかと思うw  差し当って、同一タイムゾーン間で時差が異なる二点間のUTC日時の期間をそれぞれのライブラリで取得してみた。調査ポイントとしては、差分吸収が行われていない日本標準時のキャズム日時を利用する。 検証: Dateオブジェクト  まず、ネイティブJSのDateオブジェクトでの挙動を確認しておく。日時比較はそれぞれの日時のミリ秒を取得して差分を取ることになる。 const date1 = new Date(1888, 0, 1, 0, 18, 58, 999),// Sun Jan 01 1888 00:18:58 GMT+0918 (JST) date2 = new Date(1888, 0, 1, 0, 18, 59, 0),// Sun Jan 01 1888 00:18:59 GMT+0900 (JST) diffMs = date2.getTime() - date1.getTime() console.log(diffMs)// 1139001  重要な点はタイムゾーンオフセットのキャズム時刻が 1888-01-01T00:18:58.999 になることと、論理的には二点間日時の時差が1ミリ秒のはずなのに、1,139,001ミリ秒(18分59秒1ミリ秒)の差が出てしまうことだ。これが、GMTと異なり時差吸収が行われないタイムゾーンオフセットのキャズム挙動である。 検証: Luxon  Luxonでは二点間の日時の差分を取得できるインスタンスメソッドdiff()が実装されているので、これを使う。  そして、重要なのはタイムゾーンオフセットのキャズム時刻が 1888-01-01T00:00:00.000 になることだ。 const end = DateTime.local(1888, 1, 1, 0, 0, 0, 0),// 1888-01-01T00:00:00.000+09:00 (UTC+09:00) start = DateTime.local(1887, 12, 31, 23, 59, 59, 999),// 1887-12-31T23:59:59.999+09:18 (UTC+09:18) diff = end.diff(start), diffMs = diff.toObject().milliseconds console.log(diffMs)// 1080001  日時として日本標準時の 1887-12-31T23:59:59.999 と 1888-01-01T00:00:00.000 の差は1ミリ秒なのだが、この二点間日時の間にはタイムゾーンオフセットに1,080,001ミリ秒(18分1ミリ秒) の時差が発生しているため、差分計算を行うとその時差が吸収されずに算出される。 検証: DAYJS  DAYJSで日時比較するにはインスタンスメソッドdiff()が使える。このメソッドはプラグインなしでも利用可能だ。  そして、重要なのがタイムゾーンオフセットのキャズム時刻が 1888-01-01T00:18:58.999 になることだ。これはネイティブJSのDateオブジェクトと同じである。 dayjs.extend(window.dayjs_plugin_arraySupport) const date1 = dayjs([1888, 0, 1, 0, 18, 58, 999]),// Sun Jan 01 1888 00:18:58 GMT+0918 (JST) date2 = dayjs([1888, 0, 1, 0, 18, 59, 0]),// Sun Jan 01 1888 00:18:59 GMT+0900 (JST) diffMs = date2.diff(date1) console.log(diffMs)// 1139001  日時として日本標準時の 1888-01-01T00:18:58.999 と 1888-01-01T00:18:59.000 の差は1ミリ秒だが、この二点間日時の間にはタイムゾーンオフセットに1,139,001ミリ秒(18分59秒1ミリ秒)の時差が発生している。時差の値についてもネイティブJSと同じなので、DAYJSのコア処理はかなりDateオブジェクトに依存していることがわかる。 検証: Temporal  Temporalではインスタンスメソッドのuntil()を使うことで2点間日時の差分を取得できる。  重要なタイムゾーンオフセットのキャズム時刻は 1888-01-01T00:18:58.999999999 である。Temporalではナノ秒までの精度で日時をインスタンス化できるので高精度な値になっているが、キャズム時刻はネイティブJSやDAYJSと同じポイントになっている。 const date1 = Temporal.ZonedDateTime.from({ // 1888-01-01T00:18:58.999999999+09:18:59 timeZone: 'Asia/Tokyo', year: 1888, month: 1, day: 1, hour: 0, minute: 18, second: 58, millisecond: 999, microsecond: 999, nanosecond: 999 }), date2 = Temporal.ZonedDateTime.from({ // 1888-01-01T00:18:59.000000000+09:00 timeZone: 'Asia/Tokyo', year: 1888, month: 1, day: 1, hour: 0, minute: 18, second: 59, millisecond: 0, microsecond: 0, nanosecond: 0 }), diffTimes = date1.until(date2, {largestUnit: 'minute', smallestUnit: 'nanosecond'}) console.log(diffTimes.toLocaleString())// PT18M59.000000001S  日時として日本標準時の 1888-01-01T00:18:58.999999999 と 1888-01-01T00:18:59.000000000 の差は1ナノ秒だが、この二点間日時の間にはタイムゾーンオフセットに18分59秒1ナノ秒の時差が発生している。精度の差こそあるが、この差分値はネイティブJSやDAYJSと同じである。  この問題、本来バグっぽい仕様なこともあって、どの仕様を正とするべきかが判断できないのだが、あえて総括するならば、多数決でDateオブジェクト準拠のDAYJSとTemporalの挙動が正しいのかもしれない。Luxonだけオフセットのキャズム時刻のタイミング自体がズレているのは、なかなか整合性を取りづらいのだ。とはいえ、Luxonのキャズム時刻はちょうど年が変わる時点になっていてわかりやすいので、個人的にはこっちの方が扱いやすくて好ましい。  ちゅーか、今回この調査していて、ローカルタイムゾーンやDST(夏時間)といったローカルルールに影響を受けるような時制システムを構築しては駄目だな…と痛感した。システム内で取り扱う日時は一貫してUTCで統一しておくのが最も無難で安心できる。一般的にUTCと同一と云われているGMTですら時差が発生するようでは、タイムゾーンで信じられるのは唯一UTCだけなのだ。もはや、ITシステムの時制にローカルタイムゾーンなんて要らないぐらいだw UNIX時間の単位  これについてはそこまで不満はないのだが、まぁ可用性があると嬉しいな的な感じだ。サーバーサイドや外部との連携時にUNIX時間(UNIXタイムスタンプ)の単位を揃えられると便利じゃないかなぁ……と思った次第。  まず、主要な各高級言語で取り扱われる日時データのUNIX時間として、取得できる値の単位を一覧化してみると、下記のようになった。 言語 メソッドなど 取得できるUNIX時間の単位(最小) PHP time() , date_format('U') 秒 PHP microtime() マイクロ秒 Ruby Time.now.usec マイクロ秒 Ruby Time.now.strftime('%N') ナノ秒 Python time.time(), datetime.timestamp() 秒 Python datetime.strftime('%f') マイクロ秒 Java System.currentTimeMillis() ミリ秒 Java System.nanoTime() ナノ秒  うーん……思ってた以上にバラバラだねぇ……。  現状のJavaScriptのDateオブジェクトでもミリ秒まで取り扱っているし、特に問題は出なさそうだ。  結局、JavaScript側ができる最良の互換性としては、サーバーサイド側で取り扱われ得る最小単位のナノ秒まで対応しておくことぐらいなのかもしれない。そう考えると、ナノ秒まで取り扱われるTemporalはその辺の互換性まで考慮して策定しているってことになる。 まとめ  現状、JavaScriptにおける日時処理をスマートに開発したいのであれば、「Luxon」を選択するのが最適解のような気がする。他にも、今回比較対象に含めなかったdate-fnsなどもJS界隈では人気があるので、あくまでLuxon推しは今回の比較対象の内でということになるんだが……。  確実に云えることは、Temporalだけはまだ採用しない方がいいということだ。ただし、将来的にネイティブJSにTemporalがビルトインされた場合、他のライブラリは不要になって淘汰されてしまう可能性はある。今回Temporalを実際に触ってみて、その性能とパフォーマンスに改めて期待が膨らんだのも確かなのだ。  まぁ何はともあれ、今回の調査でネイティブJavaScript用のライブラリのソースコードを色々読んだのが、最大の収穫だった。ソースコード的には、DAYJSのコードが自分好みで非常に読みやすく、インスピレーションが刺激された。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptで任意の長さのランダム文字列を生成する方法

0-9,a-z,A-Zを用いて任意の長さのランダム文字列を生成したい。 JavaScriptはイケてる書き方ができますが、ここではだれでもわかるソースコードを提示します。 ソースコード 準備用コード function getRandomInt(max) { return Math.floor(Math.random() * max); } let candidateCharactor=new Array();//利用文字の一覧となる変数 for(let i=48;i<=57;i++){ candidateCharactor.push(i);//0-9を配列に追加 } for(let i=65;i<=90;i++){ candidateCharactor.push(i);//A-Zを配列に追加 } for(let i=97;i<=122;i++){ candidateCharactor.push(i);//a-zを配列に追加 } 文字列生成関数 function randomStringGenerator(length){ let randomString=""; for(i=1;i<=length;i++){ randomString+=String.fromCharCode(candidateCharactor[getRandomInt(candidateCharactor.length)]); //getRandomIntにより、0-61の中からランダムな数字になります。 } return randomString; } 解説 今回の肝は「fromCharCode関数」です。 実引数(数値)から、UTF-16文字を返します。 このプログラムでは、0-9,a-z,A-Zを表すコードを配列にまとめます。 それから添え字をランダムに生成し、その要素を取得するプログラムです。 利用文字一覧の生成 let candidateCharactor=new Array(); for(let i=48;i<=57;i++){ candidateCharactor.push(i); } for(let i=65;i<=90;i++){ candidateCharactor.push(i); } for(let i=97;i<=122;i++){ candidateCharactor.push(i); } cadidateCharactorは利用文字の一覧になる配列(Array)です。 それに対して、Arrayクラスのpushメソッドを使って、次々と末尾に要素を追加していきます。 candidateCharactor=["0","1" ... "9" ... "A" ... "Z" ... "a" ... "z"] 上記のような書き方でも結果は変わりません。 ただ、ほかの文字をランダム生成文字列に使いたい場合、A-Zは生成文字列に使わなくなった場合などのことを考慮したため、プログラム実行時に毎回一覧を生成するようにしました。 文字列生成 文字列生成関数 function randomStringGenerator(length){ let randomString=""; for(i=1;i<=length;i++){ randomString+=String.fromCharCode(candidateCharactor[getRandomInt(candidateCharactor.length)]); //getRandomIntにより、0-61の中からランダムな数字になります。 } return randomString; } 引数に生成する文字列長を指定すると、その長さのランダム文字列が生成される関数です。 以下の部分が少しわかりづらいかもしれませんので、少しかみ砕きます。 randomString+=String.fromCharCode(candidateCharactor[getRandomInt(candidateCharactor.length)]); getRandomInt関数は、以下のページに記載の関数です。 簡単に言えば、0~[実引数-1]までの値を生成します。ここでは、3が生成されたとしましょう。 randomString+=String.fromCharCode(candidateCharactor[3]); candidateCharactor[3]は51です。 randomString+=String.fromCharCode(51); この場合右式は、3になります。 randomStringの一文字目は3になります。これが指定された文字列長分だけ繰り返されます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ドラッグ&ドロップでデータ転送jsライブラリgoogle/transmat

はじめに ことし、グーグルが新しいJavaScriptライブラリ Transmatをリリースしました。現時点GithubStar数からみると、まだ多く知られないよう。 TransmatはJavaScript DataTransfer APIの機能を提供した。 Transmatを使ったら、簡単にアプリ間(主にブラウザ)のデータをドラッグ、ドロップ転送を実現できる。 なぜかこのライブラリが面白いというと、ドラッグ&ドロップはローコードにおいて、重要な操作方法と考えていて、transmatの出番が多いかもしれません。 以下は私作ったデモ 同じ転送元でも、転送先のインタフェースによって、異なるデータを受け取れる。 詳細 ソースコードが非常に簡単なので、ホームページやソースコードを読んだら十分と思う、以下簡単にサンプルコードで説明。 デモを実装するために、転送元、転送先、それぞれの実装が必要。 転送元 転送元はtransmit というEventの処理(データの発送)が必要。 データ発送する際様々なフォーマットのデータ設定が可能。 サンプルは以下通り: <div id="source" draggable="true" tabindex="0"> Drag me and drop to another place </div> <script> const {Transmat, addListeners} = transmat; const source = document.getElementById('source') addListeners(source, 'transmit', event => { const transmat = new Transmat(event); transmat.setData({ 'text/plain': 'hello trulli introduction', 'text/html': `<h2>trulli</h2> <div>A trullo (plural, trulli) is a traditional Apulian dry stone hut with a conical roof. Their style of construction is specific to the Itria Valley, in the Murge area of the Italian region of Apulia. </div> <img src="https://www.w3schools.com/html/pic_trulli.jpg" alt="Trulli" width="500" height="333" > `, 'text/uri-list': 'https://en.wikipedia.org/wiki/Trullo', 'application/json': { name: 'trulli', type: 'storehouses', country: 'italy', } }); }); </script> 転送先 転送先はreceive というEventの処理(データの取得)が必要。 必要なデータフォーマットだけ解析で良い。 サンプルは以下通り: <div id="targetHtml" class="target" draggable="true" tabindex="0"> Recieve HTML </div> <div id="targetJson" class="target draggable="true" tabindex="0"> Recieve JSON </div> <script> const { Transmat, addListeners, TransmatObserver } = transmat; const targetJson = document.getElementById('targetJson') addListeners(targetJson, 'receive', event => { const transmat = new Transmat(event); if (transmat.hasType('application/json') && transmat.accept()) { const jsonString = transmat.getData('application/json'); const data = JSON.parse(jsonString); targetJson.textContent = jsonString; } }); const targetHtml = document.getElementById('targetHtml') addListeners(targetHtml, 'receive', event => { const transmat = new Transmat(event); if (transmat.hasType('text/html') && transmat.accept()) { const htmlString = transmat.getData('text/html'); targetHtml.innerHTML = htmlString; } }); const obs = new TransmatObserver((entries => { for (const entry of entries) { const transmat = new Transmat(entry.event); if (transmat.hasType("application/json")) { entry.target.classList.toggle("drag-active", entry.isActive); entry.target.classList.toggle("drag-over", entry.isTarget); } } })); obs.observe(targetJson); obs.observe(targetHtml); </script>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【TypeScript】型定義の指定したプロパティのみ利用したい(Pick, Omit)

はじめに TypeScriptのPickとOmitの基本的な使い方について書きます。 両方とも使い方を簡単に言うと、 「すでに存在する型から、利用したいプロパティをのみを抽出して新しい型を定義する」イメージ 便利でした。 書いてみる このTodoオブジェクト型を元に、利用したいプロパティのみで構成された新たな型を定義する。 // interface はオブジェクト型に名前をつけることができるもの interface Todo { title: string; description: string; completed: boolean; createdAt: number; } Pick 書き方: Pick<型名(元の), "利用するプロパティ名" | "利用するプロパティ名">; type TodoInfo = Pick<Todo, "title" | "completed">; 下記のような型が定義されたことと同じになる。 type TodoInfo = { title: string; completed: boolean; } Omit 書き方: Omit<型名(元の), "利用しないプロパティ名" | "利用しないプロパティ名">; type TodoInfo = Omit<Todo, "description" | "createdAt"> 下記のような型が定義されたことと同じになる。 type TodoInfo = { title: string; completed: boolean; } 最後に ありがとうございました!! https://www.typescriptlang.org/docs/handbook/utility-types.html https://qiita.com/k-penguin-sato/items/e2791d7a57e96f6144e5
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【TypeScript】型定義の一部プロパティのみ利用したい(Pick, Omit)

はじめに TypeScriptのPickとOmitの基本的な使い方について書きます。 両方とも使い方を簡単に言うと、 「すでに存在する型から、利用したいプロパティをのみを抽出して新しい型を定義する」イメージ 便利でした。 書いてみる このTodoオブジェクト型を元に、利用したいプロパティのみで構成された新たな型を定義する。 // interface はオブジェクト型に名前をつけることができるもの interface Todo { title: string; description: string; completed: boolean; createdAt: number; } Pick 書き方: Pick<型名(元の), "利用するプロパティ名" | "利用するプロパティ名">; type TodoInfo = Pick<Todo, "title" | "completed">; 下記のような型が定義されたことと同じになる。 type TodoInfo = { title: string; completed: boolean; } Omit 書き方: Omit<型名(元の), "利用しないプロパティ名" | "利用しないプロパティ名">; type TodoInfo = Omit<Todo, "description" | "createdAt"> 下記のような型が定義されたことと同じになる。 type TodoInfo = { title: string; completed: boolean; } 最後に ありがとうございました!! https://www.typescriptlang.org/docs/handbook/utility-types.html https://qiita.com/k-penguin-sato/items/e2791d7a57e96f6144e5
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

天気予報を表示する JXA

天気予報のAPIサービス 天気予報をJSON形式で取得できる「livedoor 天気」が2020年7月でサービス提供を終了しましたが、この互換サービスの「天気予報 API(livedoor 天気互換)」があることを知ったので使ってみました。 JXA のコード 私はMacを使っているので、AppleScriptを使うのですが、JSONを扱うには JavaScript の方が楽かと思うので、スクリプトエディタをJavaScriptモードにして使用します。 天気予報.scpt // 緯度、軽度から住所を求める // https://weather.tsukumijima.net/ のサービスを利用 // city コードは上記URLに一覧へのURLがありますので、参考にして設定してください // このコードサンプルでは岩手県盛岡市のコード:030010 をデフォルトに設定しています // 戻り値は JSON 形式 var app = Application.currentApplication() app.includeStandardAdditions = true var baseURL = '"https://weather.tsukumijima.net/api/forecast/city/' var city = app.displayDialog("都市コードを入力", {defaultAnswer: "030010"}).textReturned var URL = baseURL + city + '"' var ans = app.doShellScript('curl -s ' + URL) var jsonData = JSON.parse(ans) app.displayDialog(jsonData['title']) app.displayDialog(jsonData['description']['headlineText']) app.displayDialog(jsonData['description']['bodyText']) // 今日の天気を表示 app.displayDialog(jsonData['forecasts'][0]['date'] + 'の天気:' + jsonData['forecasts'][0]['telop']) app.displayDialog(jsonData['forecasts'][0]['detail']['weather'] + '、\r風:' + jsonData['forecasts'][0]['detail']['wind']) var temp = '最高気温:' + jsonData['forecasts'][0]['temperature']['max']['celsius'] + '度' app.displayDialog(temp) // 明日の天気を表示 app.displayDialog(jsonData['forecasts'][1]['date'] + 'の天気:' + jsonData['forecasts'][0]['telop']) app.displayDialog(jsonData['forecasts'][1]['detail']['weather'] + '、\r風:' + jsonData['forecasts'][1]['detail']['wind']) var temp = '最低気温:' + jsonData['forecasts'][1]['temperature']['min']['celsius'] + '度' temp = temp + '、最高気温:' + jsonData['forecasts'][1]['temperature']['max']['celsius'] + '度' app.displayDialog(temp) 好きな場所を表示するには 「天気予報 API(livedoor 天気互換)」のサイトにある全国の地点定義表(XML)から希望の地点コードを見つけてソースを変更してお使いください。 なお、気象庁でも非公式ながらAPIを提供しているとのことなので、そちらもみてみましたが、こちらの方が使いやすいと思います。(私見) 天気予報APIのサービスに感謝いたします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptでアプリを作成しました【3】【超基礎TodoList】【随時更新】

はじめに 学習するに至った経緯 2020年より、未経験からエンジニアへの転職を目指し、某プログラミングスクールへ通う。 入学後、『Ruby』を未経験から学ぶ人が多いのと『Ruby』の求人が思っていた以上に少ないので、 卒業後、フロントエンドのエンジニアを目指す事に。 Javascriptの学習した事を言語化し、認識の深化による備忘録として記載。 【作成にあたり学習した事】 Javascriptとは アプリケーションの作り方 データ型、型変換 関数 if文(条件分岐) for文(繰り返し文) オブジェクトの操作 ブラウザーAPI(document) JavaScript JavaScriptとは HTMLからjavascriptを読み込み、ブラウザがjavascriptを実行する。 JavaSciptが見た目を動的に変える事ができる。 ブラウザ上で実行される唯一のプログラミング言語。 JavaScriptで出来ること アニメーション(例 : crazy wedding ) ユーザー操作に合わせた見た目の変更(例 : Nike ) API(APIとは、バックエンドからデータを提供する仕組み事) バックエンドでも実行できる バックエンド実行環境はNode.js ブラウザーAPIとは 『ブラウザーAPI』は、Webブラウザーに組込まれていて、ブラウザーやコンピューターの環境の情報を取得し、これを使って役に立つ複雑な事を行えるようにするもの。 例えば Geolocation API は位置情報を取得するための簡単な JavaScript 構造を提供するので、グーグルマップにあなたの居場所を表示するような事ができるなど。 裏で実際にはブラウザーは低レベル (例えば C++) の複雑なコードをいくつか使ってデバイスの GPS 機器 (あるいは位置情報を得られる他のなんだか) と通信し、位置情報を取得し、コードから利用できるようにブラウザー環境に情報を戻しているが、ここでもこの複雑な事柄は API で抽象化され隠蔽される。 プログラムを書くポイント 小さく作って小さく動かす。 最初にタスクを明確にして、作成順を決める。 TodoListのタスクの明確化と作成順 ①【HTML】Todo入力ホームを整える ②【javascript】 Todoを表示・保存 ③【javascript】 Todoを削除 ④【javascript】 Todoを完了 用語一覧・基本操作・機能 inputタグ 『input』タグとは、formタグで作成したフォームの中でテキスト入力欄やボタンなどの部品を作成する要素。 部品はtype属性の値に指定することが可能で、一行テキストボックス、チェックボックス、ラジオボタン、実行ボタン、リセットボタンなどの部品を作成することができる。input要素に入力された情報は、データとしてサーバに送信される。 例:type="text":1行テキストボックスを作る。 <input type="text" name="text" value="初期値(任意の値)"> autocomplete="" form要素に 『autocomplete=""』 を追加すると、 オートコンプリート機能(入力内容の自動補完)を有効にするかどうかを指定できる。 autocomplete属性を省略した場合は、オートコンプリート機能が有効になる。 オートコンプリート機能が有効になっている場合は、過去に入力した内容が入力候補として表示される。(対応しているブラウザのみ) autocomplete="on" オートコンプリートを有効にする (初期値) autocomplete="off" オートコンプリートを無効にする 参考サイト JavaScriptの「基礎」が1時間で分かる「超」入門講座【初心者向け】 Web API の紹介
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptでアプリを作成しました【3】【超基礎TodoList ①】

はじめに 学習するに至った経緯 2020年より、未経験からエンジニアへの転職を目指し、某プログラミングスクールへ通う。 入学後、『Ruby』を未経験から学ぶ人が多いのと『Ruby』の求人が思っていた以上に少ないので、 卒業後、フロントエンドのエンジニアを目指す事に。 Javascriptの学習した事を言語化し、認識の深化による備忘録として記載。 【作成にあたり学習した事】 Javascriptとは アプリケーションの作り方 データ型、型変換 関数 if文(条件分岐) for文(繰り返し文) オブジェクトの操作 ブラウザーAPI(document) プログラムを書くポイント 小さく作って小さく動かす。 最初にタスクを明確にして、作成順を決める。 TodoListのタスクの明確化と作成順 ①【HTML】Todo入力ホームを整える ②【javascript】 Todoを表示・保存 ③【javascript】 Todoを削除 ④【javascript】 Todoを完了 JavaScript JavaScriptとは HTMLからjavascriptを読み込み、ブラウザがjavascriptを実行する。 JavaSciptが見た目を動的に変える事ができる。 ブラウザ上で実行される唯一のプログラミング言語。 JavaScriptで出来ること アニメーション(例 : crazy wedding ) ユーザー操作に合わせた見た目の変更(例 : Nike ) API(APIとは、バックエンドからデータを提供する仕組み事) バックエンドでも実行できる バックエンド実行環境はNode.js ブラウザーAPIとは 『ブラウザーAPI』は、Webブラウザーに組込まれていて、ブラウザーやコンピューターの環境の情報を取得し、これを使って役に立つ複雑な事を行えるようにするもの。 例えば Geolocation API は位置情報を取得するための簡単な JavaScript 構造を提供するので、グーグルマップにあなたの居場所を表示するような事ができるなど。 裏で実際にはブラウザーは低レベル (例えば C++) の複雑なコードをいくつか使ってデバイスの GPS 機器 (あるいは位置情報を得られる他のなんだか) と通信し、位置情報を取得し、コードから利用できるようにブラウザー環境に情報を戻しているが、ここでもこの複雑な事柄は API で抽象化され隠蔽される。 用語一覧 ・ 基本操作 ・ 機能 inputタグ 『input』タグとは、formタグで作成したフォームの中でテキスト入力欄やボタンなどの部品を作成する要素。部品はtype属性の値に指定することが可能で、一行テキストボックス、チェックボックス、ラジオボタン、実行ボタン、リセットボタンなどの部品を作成することができる。input要素に入力された情報は、データとしてサーバに送信される。 例:type="text":1行テキストボックスを作る。 <input type="text" name="text" value="初期値(任意の値)"> autocomplete="" form要素に 『autocomplete=""』 を追加すると、 オートコンプリート機能(入力内容の自動補完)を有効にするかどうかを指定できる。 autocomplete属性を省略した場合は、オートコンプリート機能が有効になる。 オートコンプリート機能が有効になっている場合は、過去に入力した内容が入力候補として表示される。(対応しているブラウザのみ) autocomplete="on" オートコンプリートを有効にする (初期値) autocomplete="off" オートコンプリートを無効にする document ブラウザAPIの一種 ブラウザに読み込まれたWEBページの情報を扱っている JavaScriptの機能ではないので注意 documentを使ってみる ①『検証ツール』⇨ Console ② >document.getElementById('input')と入力すると③が表示 ③ <input type=​"text" id=​"input" placeholder=​"TODOを入力する" autocomplete=​"off">​ ④ >document.getElementById('input').valueと入力すると⑤が表示 ⑤ text(TODOを入力する)の中身に入力した文字が表示 jsのファイルから値を取る データを取るタイミング ユーザーがエンターを押した時  ⇨  必要な知識:① 変数、② 関数、③ addEventLister ① 変数 データの入れ物 ⇨ 使い所:データを使い回したい時 let:値の再代入が可能 const : 値の再代入が不可 定数の宣言 var : letとほぼ同じで、昔の記法 今はあまり使用しない ② 関数 一連の処理を一つの処理としてまとめたもの ⇨ 使い所:同じ処理を使い回したい時 ③ addEventLister 特定のイベントが起きた時にJavaScriptの処理を追加するためのブラウザAPIの機能⇨ 使い所:イベントが起きた時に処理を追加したい時 ターゲット.addEventListener(イベント名、関数); event.preventDefault() event.preventDefaultメソッドは、submitイベントの発生元であるフォームが持つデフォルトの動作をキャンセルするメソッド。フォームが持つデフォルトの動作とは、フォームの内容を指定したURLへ送信するという動作。 form.addEventListener('submit',function(event) { // submitイベントの本来の動作を止める event.preventDefault(); console.log(input.text) }); 取得したフォームの値をHTML上に追加する ulとliタグを使って、リストとして情報を追加 createElement()メソッド JavaScript で HTML 要素を動的に生成するには createElement() メソッドを使用する。 const element = document.createElement(タグ名) crreateElement() メソッドで生成した要素を、実際の HTML 要素に追加することで HTML を動的に生成することができる。 HTML 要素への追加には appendChild() メソッドなどを使用する。 HTML要素.appendChild(生成した要素) データ型 データ型 = データの種類によってできる事を区別するために存在 JavaScriptのデータ型は大きく2つに分かれる ① プリミティブ型 ⇨ 真偽値 数値 文字列 ② オブジェクト ⇨ オブジェクト 配列 関数 if文 条件式がtrueなら実行する if (条件式) { // 条件式の評価結果がtrueなら実行する処理 } if (true ) { console.log('実行'); } 真偽値の判定 falseになる値 ⇨ false  undefined  null  0  On  NaN  ''(空文字) それ以外は全てtrue ローカルストレージに保存 LocalStrage(ローカルストレージ)とは LocalStrageとは、JavaScriptでデータをブラウザに保存する仕組み。永続的に保存。 データを保存する localStorage.setItem('キー', 値) データを取得する  localStorage.getItem('キー') 配列 値に順序をつけて格納できるオブジェクト ⇨ 使い所:複数の値をまとめて扱いたい時 []で定義 0から順に割り振る const array = [ 'one','two','three']; array[0]; // => 'one' ループ 繰り返し処理を行うもの ⇨ 使い所:同じ処理を繰り返したい時 forEach:配列の全要素に対して反復処理 const array = [1,2,3]; array.forEach(value => { console.log(value * 2); }); //2,4,6 「push」とは 「push」はArray(配列)オブジェクトの組み込みメソッドとして用意されており、主に配列データの末尾に任意の要素を追加するために利用される。 let items = [1,2,3,4]; //配列「items」に数値データを追加する items.push( 5,6,7,8 ); console.log( items ); 実行結果 [1, 2, 3, 4, 5, 6, 7, 8] TODOを削除できる機能 クリックしたら、要素を削除・非表示にする イベントの登録 「イベント」とは、「ブラウザ操作」のこと。 ⇨ クリックやインプット要素への入力、マウスオーバーなど。フロントエンド JavaScript 開発では、「いつ(=イベント)」「何が起こる(=DOM 操作)」か、という軸で発想する。 addEventListener イベントは、addEventListener メソッドで登録する。 // DOM 検索メソッドにより、HTML 要素の参照を得る const button = document.querySelector('#btn-1'); // HTML 要素に対して、イベントのハンドラー関数を登録する button.addEventListener('click', function(event) { // ここに、要素がクリックされたときに実行されるべき処理を記述する 例 button.remove(); }); TODOに完了マークをつける機能 クリックしたら、取り消し線を付ける classListで簡単にクラスを追加・削除する JavaScriptでクラスを追加・削除する場合は、classList を使用すると 簡単に実現でき、クラスを追加する場合は add()、削除する場合は remove()を使う。 toggle()を使用すると、指定したクラスがない場合は追加、すでにある場合は削除する。 // 追加 elem.classList.add('クラス名'); // 削除 elem.classList.remove('クラス名'); // 追加・削除 elem.classList.toggle('クラス名'); TODOアプリ完成 <!DOCTYPE html> <html> <head> <title>TodoList Super basic 1</title> <meta charset="UTF-8" /> </head> <body> <div> <h1>TODOLIST</h1> <form id="form"> <input type="text" id="input" placeholder="TODOを入力する" autocomplete="off"> </form> <ul class="list" id="ul"></ul> </div> <script src="main.js"></script> </body> </html> 'use strict'; { //constでformを定義して、formを指定する const form = document.getElementById('form'); //inputの値を取る const input = document.getElementById('input'); //ulの値を取る const ul = document.getElementById('ul'); //local strageのデータ取得 const todos = JSON.parse(localStorage.getItem('todos')); //todosが空でなければliタグを取得 if (todos) { todos.forEach(todo => { add(todo); }) } //formに対して、イベントを追加 form.addEventListener('submit', function(event) { // submitイベントに関して「preventDefault」する event.preventDefault(); // input.valueでテキスト中身の値を取る // console.log(input.value); // add関数を呼び出す元  add(); }); // add関数を呼び出す function add(todo){ //formに値が追加された時だけ表示 const li-input.value = ''をif文でくくる //todoTextを変数宣言 let todoText = input.value; if (todo) { todoText = todo.text; } //テキストの中身が一文字以上入力されていたら const li-input.value = '' を表示 if (todoText) { //liタグを作成  const li = document.createElement('li'); //ユーザーが取得した値をテキストへ入力  li.innerText = todoText; //liタグにクラスを指定し、追加する  li.classList.add('list'); if (todo && todo.completed) { li.classList.add('text-decoration-line-through'); } //右クリックしたら、liタグを削除する li.addEventListener('contextmenu',function(event) { //右クリックしたら出てくる表示をブロック event.preventDefault(); li.remove(); //ローカルステージに反映 saveData(); }); //左クリックしたら、完了線を付ける li.addEventListener('click',function(){ li.classList.toggle('text-decoration-line-through'); saveData(); }); //ulタグの子としてliを追加 ul.appendChild(li); //投稿をしたら空にする  input.value = ''; //関数追加 saveData(); } } function saveData() { // liタグのデータを取ってくる  const lists = document.querySelectorAll('li'); //console.log(lists); //新しい配列を作成  let todos = []; //liタグのテキスト情報を全て取得  lists.forEach(list => { let todo = { text: list.innerText, completed: list.classList.contains('text-decoration-line-through') }; todos.push(todo); // console.log(list.innerText); }); //ローカルステージに保存  localStorage.setItem('todos', JSON.stringify(todos)); } } 参考サイト JavaScriptの「基礎」が1時間で分かる「超」入門講座【初心者向け】 Web API の紹介 【JavaScript】event.preventDefault()が何をするのか JavaScriptでcreateElementメソッドを使いHTMLを動的生成する方法を現役エンジニアが解説【初心者向け】 JavaScriptのLocalStrage(ローカルストレージ) の使い方を現役エンジニアが解説【初心者向け】 【JavaScript入門】pushで配列に要素を追加する方法(連想配列/pop) JavaScript超基礎講座!イベント処理を学ぶ JavaScript: classListで簡単にクラスを追加・削除する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptでアプリを作成しました【3】【超基礎TodoList ①】【随時更新】

はじめに 学習するに至った経緯 2020年より、未経験からエンジニアへの転職を目指し、某プログラミングスクールへ通う。 入学後、『Ruby』を未経験から学ぶ人が多いのと『Ruby』の求人が思っていた以上に少ないので、 卒業後、フロントエンドのエンジニアを目指す事に。 Javascriptの学習した事を言語化し、認識の深化による備忘録として記載。 【作成にあたり学習した事】 Javascriptとは アプリケーションの作り方 データ型、型変換 関数 if文(条件分岐) for文(繰り返し文) オブジェクトの操作 ブラウザーAPI(document) JavaScript JavaScriptとは HTMLからjavascriptを読み込み、ブラウザがjavascriptを実行する。 JavaSciptが見た目を動的に変える事ができる。 ブラウザ上で実行される唯一のプログラミング言語。 JavaScriptで出来ること アニメーション(例 : crazy wedding ) ユーザー操作に合わせた見た目の変更(例 : Nike ) API(APIとは、バックエンドからデータを提供する仕組み事) バックエンドでも実行できる バックエンド実行環境はNode.js ブラウザーAPIとは 『ブラウザーAPI』は、Webブラウザーに組込まれていて、ブラウザーやコンピューターの環境の情報を取得し、これを使って役に立つ複雑な事を行えるようにするもの。 例えば Geolocation API は位置情報を取得するための簡単な JavaScript 構造を提供するので、グーグルマップにあなたの居場所を表示するような事ができるなど。 裏で実際にはブラウザーは低レベル (例えば C++) の複雑なコードをいくつか使ってデバイスの GPS 機器 (あるいは位置情報を得られる他のなんだか) と通信し、位置情報を取得し、コードから利用できるようにブラウザー環境に情報を戻しているが、ここでもこの複雑な事柄は API で抽象化され隠蔽される。 プログラムを書くポイント 小さく作って小さく動かす。 最初にタスクを明確にして、作成順を決める。 TodoListのタスクの明確化と作成順 ①【HTML】Todo入力ホームを整える ②【javascript】 Todoを表示・保存 ③【javascript】 Todoを削除 ④【javascript】 Todoを完了 用語一覧 ・ 基本操作 ・ 機能 inputタグ 『input』タグとは、formタグで作成したフォームの中でテキスト入力欄やボタンなどの部品を作成する要素。部品はtype属性の値に指定することが可能で、一行テキストボックス、チェックボックス、ラジオボタン、実行ボタン、リセットボタンなどの部品を作成することができる。input要素に入力された情報は、データとしてサーバに送信される。 例:type="text":1行テキストボックスを作る。 <input type="text" name="text" value="初期値(任意の値)"> autocomplete="" form要素に 『autocomplete=""』 を追加すると、 オートコンプリート機能(入力内容の自動補完)を有効にするかどうかを指定できる。 autocomplete属性を省略した場合は、オートコンプリート機能が有効になる。 オートコンプリート機能が有効になっている場合は、過去に入力した内容が入力候補として表示される。(対応しているブラウザのみ) autocomplete="on" オートコンプリートを有効にする (初期値) autocomplete="off" オートコンプリートを無効にする document ブラウザAPIの一種 ブラウザに読み込まれたWEBページの情報を扱っている JavaScriptの機能ではないので注意 documentを使ってみる ①『検証ツール』⇨ Console ② >document.getElementById('input')と入力すると③が表示 ③ <input type=​"text" id=​"input" placeholder=​"TODOを入力する" autocomplete=​"off">​ ④ >document.getElementById('input').valueと入力すると⑤が表示 ⑤ text(TODOを入力する)の中身に入力した文字が表示 jsのファイルから値を取る データを取るタイミング ユーザーがエンターを押した時  ⇨  必要な知識:① 変数、② 関数、③ addEventLister ① 変数 データの入れ物 ⇨ 使い所:データを使い回したい時 let:値の再代入が可能 const : 値の再代入が不可 定数の宣言 var : letとほぼ同じで、昔の記法 今はあまり使用しない ② 関数 一連の処理を一つの処理としてまとめたもの ⇨ 使い所:同じ処理を使い回したい時 ③ addEventLister 特定のイベントが起きた時にJavaScriptの処理を追加するためのブラウザAPIの機能⇨ 使い所:イベントが起きた時に処理を追加したい時 ターゲット.addEventListener(イベント名、関数); event.preventDefault() event.preventDefaultメソッドは、submitイベントの発生元であるフォームが持つデフォルトの動作をキャンセルするメソッド。フォームが持つデフォルトの動作とは、フォームの内容を指定したURLへ送信するという動作。 form.addEventListener('submit',function(event) { // submitイベントの本来の動作を止める event.preventDefault(); console.log(input.text) }); 取得したフォームの値をHTML上に追加する ulとliタグを使って、リストとして情報を追加 createElement()メソッド JavaScript で HTML 要素を動的に生成するには createElement() メソッドを使用する。 const element = document.createElement(タグ名) crreateElement() メソッドで生成した要素を、実際の HTML 要素に追加することで HTML を動的に生成することができる。 HTML 要素への追加には appendChild() メソッドなどを使用する。 HTML要素.appendChild(生成した要素) データ型 データ型 = データの種類によってできる事を区別するために存在 JavaScriptのデータ型は大きく2つに分かれる ① プリミティブ型 ⇨ 真偽値 数値 文字列 ② オブジェクト ⇨ オブジェクト 配列 関数 if文 条件式がtrueなら実行する if (条件式) { // 条件式の評価結果がtrueなら実行する処理 } if (true ) { console.log('実行'); } 真偽値の判定 falseになる値 ⇨ false  undefined  null  0  On  NaN  ''(空文字) それ以外は全てtrue ローカルストレージに保存 LocalStrage(ローカルストレージ)とは LocalStrageとは、JavaScriptでデータをブラウザに保存する仕組み。永続的に保存。 データを保存する localStorage.setItem('キー', 値) データを取得する  localStorage.getItem('キー') 配列 値に順序をつけて格納できるオブジェクト ⇨ 使い所:複数の値をまとめて扱いたい時 []で定義 0から順に割り振る const array = [ 'one','two','three']; array[0]; // => 'one' ループ 繰り返し処理を行うもの ⇨ 使い所:同じ処理を繰り返したい時 forEach:配列の全要素に対して反復処理 const array = [1,2,3]; array.forEach(value => { console.log(value * 2); }); //2,4,6 「push」とは 「push」はArray(配列)オブジェクトの組み込みメソッドとして用意されており、主に配列データの末尾に任意の要素を追加するために利用される。 let items = [1,2,3,4]; //配列「items」に数値データを追加する items.push( 5,6,7,8 ); console.log( items ); 実行結果 [1, 2, 3, 4, 5, 6, 7, 8] TODOを削除できる機能 参考サイト JavaScriptの「基礎」が1時間で分かる「超」入門講座【初心者向け】 Web API の紹介 【JavaScript】event.preventDefault()が何をするのか JavaScriptでcreateElementメソッドを使いHTMLを動的生成する方法を現役エンジニアが解説【初心者向け】 JavaScriptのLocalStrage(ローカルストレージ) の使い方を現役エンジニアが解説【初心者向け】 【JavaScript入門】pushで配列に要素を追加する方法(連想配列/pop)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

javascriptとは?

javaScriptとは? JavaScriptを一言で要約すると、Webを豊かにしてくれる小さくて軽い言葉です。 アメリカのネットスケープコミュニケーションズ社(Netscape Communications)が開発したスクリプト言語で、 Web ブラウザで実行するスクリプト言語を記述します。 小さくて速いため、ウェブ文書を動的に飾るときに最も広く使われます。 言語規格はジャワの部分集合(subset)になっています。 ハイパーテキスト生成言語(HTML)文書を作成するレベルのユーザが使用することを主眼とし、ジャワの言語規格から変数の型(整数型や文字列型など)を省略したり、新しいクラス定義をできないようにしました。 スクリプトは、HTML 文書の中に直接記述し、< script > という荷札を使用します。 プログラミング入門者たちはジャワスクリプトとジャワが似た技術だと思ったりします。 2つの言語ともジャバラは言語を基盤としているからです。 しかしジャバスクリプトはジャバとは違う点が非常に多いです。 機能と使い方まで全く違います。 特徴 1.JavaScriptはオブジェクト基盤の言語です。 しかし、相続とクラスという概念はありません。 2.JavaScriptはインタプリタ言語として、クライアントのWebブラウザによって解析され実行されます。 3. JavaScriptはHTML文書内に記述され、HTML文書と一緒に実行されます。 4.JavaScriptはHTMLに演算制御などプログラミング的な要素を追加し、クライアント資源を活用できます。 可能なこと HTMLページの変更及びHTMLエレメントとコンテンツの追加及び除去 CSS及びHTMLエレメントのスタイル変更 ユーザーとの相互作用、フォームの有効性の検証  マウスとキーボードイベントに対するスクリプト実行 ウェブブラウザ制御、クッキーなどの設定と照会 AJAX技術を利用したウェブサーバーとの通信 動的な効果 イメージ ロールオーバー 状態表示 行に文字列表示など ウェブサイトの機能的な麺クッキー処理、新しいWindowを開くなど
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プログラミング言語別文法早見表(基礎)

1.変数 *値を更新できる箱 項目 RUBY JAVASCRIPT SWIFT PHP 書き方 変数名=値 let 変数名=値 var 変数名=直 $変数名=値 例 money=100 let money=100 var money=100 money=100 2.定数 *値を更新できない箱 項目 RUBY JAVASCRIPT SWIFT PHP 書き方 変数と差異なし const 変数名=値 let 変数名=直 $変数名=値4 例 const=100 const tax=100 let tax=100 tax=100 3.四則演算子 *基本的に同じ 四則演算子 項目 + ー × ÷ 余り 書き方 + - * / % 例 price + tax apple - orange price * count price / tax price % tax インクリメント演算子(足し算) 項目 RUBY JAVASCRIPT SWIFT PHP 書き方 なし ++; なし $++; 例 なし const y = x++; なし $num++; インクリメント演算子(引き算) 項目 RUBY JAVASCRIPT SWIFT PHP 書き方 なし --; なし --; 例 なし const y = x--; なし $num--; 4.配列 配列(記入方法) 項目 RUBY JAVASCRIPT SWIFT PHP 書き方 配列名 = [値1, 値2, 値3] 配列名 = [値1, 値2, 値3] 配列名 = [値1, 値2, 値3] 配列名 = [値1, 値2, 値3] 例 array = [1,2,3] const fruits = ['りんご', 'バナナ'] let fruits = ['りんご', 'バナナ'] $fruits = ['りんご', 'バナナ'] 配列(追加方法) 項目 RUBY JAVASCRIPT SWIFT PHP 書き方 配列名[順番] = 値 配列名[順番] = 値配列名.push('値') 配列名.append(値) $配列名[] = "値" 例 array[4] = "e" array[4] = "e" list1.append("品川") $stack[] = "ぶどう"; 配列(削除方法) 後で更新 配列(抽出方法) 項目 RUBY JAVASCRIPT SWIFT PHP 書き方 配列名[順番] 配列名[順番] 配列名[順番] $配列名[順番] 例 print 配列名[順番] print 配列名[順番] なし print $配列名[順番] 5.配列 ハッシュ 配列(記入方法) 項目 RUBY JAVASCRIPT SWIFT PHP 書き方 配列名 = {"キー" => 値,"キー" => 値} 配列名 = ["キー": 値, "キー": 値] $配列名 = ["キー"=> 値, "キー"=> 値]; 例 hash = {"Lemon" => 100, "Orange" => 150} let dictionary = ["りんご": 青森, "バナナ": フィリピン] $hash = ["Lemon" => 100, "Orange" => 150]; 配列(追加方法) 項目 RUBY JAVASCRIPT SWIFT PHP 書き方 配列名[キー] = 値 配列名[キー] = 値 $配列名[キー] = "値" 例 hash["Banana"] = 90 fruits["いちご"] = 300 $stack["フルーツ"] = "ぶどう";  繰り返し文 for 項目 RUBY JAVASCRIPT SWIFT PHP 書き方 for 変数 in オブジェクト do 実行する処理1 end for (初期化式; 条件式; 変化式){ 実行する処理1;} for 変数 in 開始値 ..< 終了値 {実行する処理1} for(初期値; 条件式; 変化式){実行する処理1} 例 for num in 1..3 doprint("num = ", num, "¥n")endprint("End") for (let i = 0; i < 5; i++) { console.log((i + 1) + '回目の処理です');} for i in 1..<10 {print("i: (i)")} for($i=0;$i<5;$i++){echo $i;}  while  関数 項目 RUBY JAVASCRIPT SWIFT PHP 書き方 def メソッドの名前 やりたい処理endメソッドの名前 function 関数名(変数) {やりたい処理}関数名(変数名) func 関数名 (引数1:引数1の型, ...) -> 戻り値の型 {やりたい処理return 戻り値}関数名(変数) function 関数名(変数){処理内容return 返り値関数名(変数名)} 例 def hello puts "Hello World!"endhello function square(number){{return number * number;}] let arrayData = [3, 5, 8, 10]for data in arrayData{print("data: (data)")} <?phpfunction goaisatsu() {$message = 'Hello world!'; return $message;}echo goaisatsu(); ?> 条件分岐 IF 項目 RUBY JAVASCRIPT SWIFT PHP 書き方 if 条件式1 then処理elsif 条件式2 then処理2elsedo 処理3end if (条件式1) {実行1}else if(条件式2){条件式2} if 条件式1 {処理1} else if 条件式2 {条件式2} else {処理3} if(条件){処理1}else{条件が偽であれば実行}else{条件が偽であれば実行} 例 a = 1if a > 3 thenputs "a is greater than 3"end var num = 70;if (num > 80) {console.log("numは80より大きいです。");} else if (num >= 60) {console.log("numは60~80の間です。"); } else {console.log("numは60未満です。");} var num = 5if ( num > 10 ) {print("10以上です")} else if ( num < 10 ) {print("10未満です")} else {print("それ以外");} $score = 90;if($score >= 80){echo “合格です!おめでとうございます!”;}else($score < 80){echo “不合格です!がんばりましょう!”}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Nuxt]optional chainingでちょっと複雑なAPI埋め込みするときにスッキリ書く

複雑なAPIだとフラットで返ってこないものも多いのではないでしょうか? javascriptのオブジェクトを辿る時、 aaa.bbb.ccc.dddとしますが、途中のcccの返りがnullならエラー。 でも分岐書くの結構辛い・・・ そんな時はoptional chainingですね。 他の言語ではあったりするけど、javascriptはまだ待ちの段階。 いち早く使うならプラグインいれてトランスパイル。 npm i -D @babel/plugin-proposal-optional-chaining nuxt.config.js build: { babel: { plugins: [ '@babel/plugin-proposal-optional-chaining', ], }, }, aaa.bbb.ccc?.ddd これでいけ・・・ なんとtemplate内の埋め込みでは使えないではないですか・・・ scriptブロックでは使えるけど vue2では難しいみたいで、vue3対応を待つしかなさそうです。 Nuxtのvue3はいつ・・・ methods経由かcomputedで対応もありですが、記述減らしたいのに増やしてどうする・・・ lodashで対応させるって記事があったのでとりあえずそれで対応するのが妥協かもですね・・・
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Auth0のアクセストークンを検証する

やりたいこと Auth0でアクセストークンを取得した上でそれが適切なものなのか検証したい。 言語はJSもしくはTS 実装方針 アクセストークンの検証をするには公開されている証明書と署名を使って検証する。 もう少し具体的に書くとSHA256などのハッシュ関数からトークンのペイロードに含まれるMD(メッセージダイジェスト) を作成しそれが証明書と署名から作られたMDと一致するかを検証することで、トークンが改竄されたものでないことを確かめる。 調査 証明書の取得 このやりとりを見る限り https://[your_domain].auth0.com/pem で公開鍵を取得できる模様です。 もちろん[your_domain]の部分は自身のAuth0のコンソール画面から取得してください。 Auth0コンソール→Applications->APIS->Auth0 Management API に記載されているはずです。 証明書の検証 公開鍵の証明書を用いた署名の検証をするのにいい方法ないかなと探っているとAWSが手頃な記事を出していました。 jsonwebtoken というライブラリを利用している模様。Cognitoのトークンの検証のために出している記事の模様ですがこの際活用させていただきます。 実装 今回実装するに当たってフォルダ構成はこんな感じにしました。 verify-auth0-token L index.js L public.pem 先ほどのライブラリを活用するために yarn add jsonwebtoken もしくは npm install jsonwebtoken でこのライブラリをインストールしてください。 今回の場合はもちろんcd verify-auth0-tokenでディレクトリの移動をしてからインストールします。 先ほどの調査で取得した証明書はpublic.pemとして保存してます。 それでは index.js を記載していきます。 fs で pem ファイルを呼び込んでそれをライブラリの中に使ってトークンと一緒に突っ込みます。 const jwt = require('jsonwebtoken'); const fs = require('fs'); const pem = fs.readFileSync('./public.pem') // token = アクセストークン const token = 'eyJhbGc...L9CcGw' jwt.verify(token, pem, { algorithms: ['RS256'] }, function(err, decodedToken) { console.log(decodedToken) }); あとはターミナルで実行するとコンソール上にトークンの中身が見れます。 node index.js レスポンスはこんな感じでJSONで見れます。    実際にはトークンをAPIのリクエストで受け取ったり、証明書もバックエンドに保存しておいたり設計する必要がありますが、ひとまずこれでAuth0で公開鍵の証明書を用いた署名の検証方法を認識していただければ幸いです。 最後に Youtubeチャンネルはじめてます! エンジニアの姿は十人十色。 今後も色んなエンジニア像を捉えて、それを目指す人たちの参考になる動画を作っています。 あと、プログラミングもメンタで教えているので興味があったらみてください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む