20210508のJavaScriptに関する記事は29件です。

map()とfilter()の比較(備忘録)

TodoAppの作成時に、mapメソッドとfilterメソッドの違いがいまいちピンとこなかったので、 改めて調べなおした備忘録です。 MDNによると、 map( ): 与えられた関数を配列のすべての要素に対して呼び出し、その結果からなる新しい配列を生成 filter( ): 提供された関数によって実装されたテストに合格したすべての要素を含む新しい型付き配列を生成 例:Todoアプリでイベントで発火する関数内でmap(),filter()を使用。 const tasks = [ { id: 1, title: "買い物", completed: false }, { id: 2, title: "英語の課題", completed: false },   { id: 3, title: "筋トレ", completed:true }, ] 完了したtaskに、打ち消し線をひく時 同じ数の要素を返すが、要素の中のvalueは変化する(ここでは、completedプロパティのfalseとtrueが入れ替わっている) toggleCompleted(id) { this.tasks = this.tasks.map((task) => task.id === id ? { ...task, completed: !task.completed } : task ); }, taskを削除する時 同じ数または、それより少ない数の要素を返す。要素内の変化はなし。 deleteTask(id) { this.tasks = this.tasks.filter((task) => task.id !== id); },
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

map, filter を object にも使う方法【fp-ts の紹介】

結論 map, filter を object にも使う方法の一つとして、fp-ts というライブラリを利用する という方法があります。 fp-ts の map, filter は基本的には pipe関数と共に用います。1 以下は filter, map を object に使うシンプルな例です。 .ts import { pipe } from "fp-ts/function" import { array as A, record as R } from "fp-ts" // utils const isEven = (n: number) => n % 2 === 0 const double = (n: number) => n * 2 // data let data1 = [1, 2, 3, 4, 5, 6] let data2 = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 } // data1. filter(isEven). map(double) // ES6 const result1 = pipe(data1, A.filter(isEven), A.map(double)) // fp-ts Array const result2 = pipe(data2, R.filter(isEven), R.map(double)) // fp-ts Record ← filter, map を object に使う例 console.log(result1) // [ 4, 8, 12 ] console.log(result2) // { b: 4, d: 8, f: 12 } 対象読者 Array の map, filter を Object にも使いたいと思ったことがある方 解説は JavaScript で行うため TypeScript の知識は不要です 関数型プログラミングの知識は不要です 注意 筆者は関数型プログラミングを JavaScript, TypeScript だけで学習している人間です。Haskell等の関数型プログラミング言語を使ったことがない人間の記事だということをご了承ください。 本題 1. メソッドチェーンで書いた場合 下記の単純なコードを fp-ts で書き直す流れで説明していきます。 // utils const isEven = (n) => n % 2 === 0 const double = (n) => n * 2 // data let data = [1, 2, 3, 4, 5, 6] let result // ES6 result = data.filter(isEven).map(double) // 1. メソッドチェーン console.log(result) // [ 4, 8, 12 ] 2. パイプラインで書いた場合 data.filter(isEven) では Array.prototype.filter関数内の this を data、引数を 関数isEven として実行します。 まず、filter と map を this に依存するメソッドではなく、引数のみに依存する関数として定義します。 // filter = (fn) => (thisArg) => thisArg.filter(fn) // Array.prototype.filter を メソッド として利用 const filter = (fn) => (thisArg) => Array.prototype.filter.call(thisArg, fn) // Array.prototype.filter を 関数 として利用 const map = (fn) => (thisArg) => Array.prototype.map.call(thisArg, fn) // filter, map は 『引数:fn(関数), 戻り値:「引数:thisArg(配列), 戻り値:配列 の関数」』の関数 上記 filter と map は関数を返す関数(高階関数)です。 const filter = (fn , thisArg) => Array.prototype.filter.call(thisArg, fn) のように引数を2つ持つ関数として記載しないのは パイプラインによる処理 を可能にするためです。(後述します。) なお、 const filter = (fn , thisArg) => Array.prototype.filter.call(thisArg, fn) を const filter = (fn)=>(thisArg) => Array.prototype.filter.call(thisArg, fn) のように記載することを カリー化 と言います。2 関数を返す関数(高階関数)である filter と map に それぞれ、 関数isEven と 関数double を渡すことで、 配列を受け取って、配列を返す関数(下記 filterIsEven, mapDouble)を作成します。 const filterIsEven = filter(isEven) // filterIsEven は「引数:配列, 戻り値: 配列」の関数 const mapDouble = map(double) // mapDouble は「引数:配列, 戻り値: 配列」の関数 filterIsEven, mapDoubleは一つの引数を受け取って一つの値を返す形の関数なので、後述するようにパイプライン処理ができるようになります。 (本稿では 後述の pipe関数 を使った処理を「パイプライン処理」と呼びますが、用語が正確でないかもしれません。) 以下のように、filterIsEven, mapDoubleを使って、結果([ 4, 8, 12 ])を得ることができます。 const filtered = filterIsEven(data) const result = mapDouble(filtered) console.log(result) // [ 4, 8, 12 ] 関数呼び出しをネストすることで、使う変数を減らす書き方をすると、下記のようになります。 result = mapDouble(filterIsEven(data)) console.log(result) // [ 4, 8, 12 ] しかし、上記のように記載すると、関数(ここでは、filterIsEven, mapDoubleなど)が増えた場合にネストが深くなり少し読みずらく(書きずらく)なります。 そこで、pipe関数 を使うと、下記のように記載できます。 .mjs import { pipe } from "fp-ts/lib/function.js" result = pipe(data, filterIsEven, mapDouble) console.log(result) // [ 4, 8, 12 ] // fp-ts の pipe を簡略化する場合(引数を3つに限定する場合)、 // const pipe = (a, ab, bc) => bc(ab(a)) と記載できます。 // ※ a はデータ、ab, bc は引数が1つの関数 fp-ts の pipe関数3 は 第一引数 に処理対象となるデータを取り、第二引数以降は、『引数を一つのみ受け取り何らかの値を返す関数』を取ります。そのため、filterIsEven, mapDouble を引数が一つの関数になるように作りました。 filterIsEven, mapDouble を 一つ前の状態 (isEven, double をそれぞれ filter, map に渡す前の状態) に戻すと下記のようになります。 // data. filter(isEven). map(double) // 1. メソッドチェーン (前掲したもの) result = pipe(data, filter(isEven), map(double)) // 2. パイプライン console.log(result) // [ 4, 8, 12 ] こうして並べてみると、メソッドチェーン と パイプライン は書き方が似ています。 メソッドチェーン は this(=data)が、 パイプラインでは data自体 が 左から右に順に(パイプを通るかのように?)評価されます。 なお、pipe (function.ts の最下部あたり) は引数が 1個でも、20個でも良いように実装されています。 3. fp-ts を使って書いた場合 Array用に実装された関数(高階関数)であるfilter,mapを使用します。 import * as A from "fp-ts/lib/Array.js" //追加 // data. filter(isEven). map(double) // 1. メソッドチェーン // pipe(data, filter(isEven), map(double)) // 2. パイプライン (filter, map は Array.prototype 由来) result = pipe(data, A.filter(isEven), A.map(double)) // 3. パイプライン (filter, map は fp-ts/lib/Array.js 由来) console.log(result) // [ 4, 8, 12 ] 4. Object に map, filter を使う場合 (タイトル回収ですが) Object型のデータを扱う場合、Object(Record4)用に実装された高階関数であるfilter,map を使用します。 import * as R from "fp-ts/lib/Record.js" //追加 data = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6 } // data. filter(isEven). map(double) // 1. メソッドチェーン // pipe(data, filter(isEven), map(double)) // 2. パイプライン (filter, map は Array.prototype 由来) // pipe(data, A.filter(isEven), A.map(double)) // 3. パイプライン (filter, map は fp-ts/lib/Array.js 由来) result = pipe(data, R.filter(isEven), R.map(double)) // 4. パイプライン (filter, map は fp-ts/lib/Record.js 由来) console.log(result) // { b: 4, d: 8, f: 12 } 5. (補足)もし Pipeline operator が使えるようになったら Pipeline 演算子 (「|>」) を JavaScript に導入しようという 提案 があり、これを使えるようにあったら pipe関数 は不要になります。 // data. filter(isEven). map(double) // 1. メソッドチェーン // pipe(data, filter(isEven), map(double)) // 2. パイプライン result = data |> filter(isEven) |> map(double) // 5. Pipeline operator fp-ts に関する補足 mapは(配列等の)各要素を引数に取る関数しか扱いませんが、「index (object なら key) +各要素」を引数に取る関数を扱えるmapWithIndexも用意されています mapと同様に、reduceも用意されています Array や Object (Record) 以外にも、Map や Set、Tuple(タプル / fp-tsでは「要素が2つの配列」を Tuple としています)など、様々なデータ型を扱う関数(or 高階関数)が用意されています Array や Object, Map, Set 等の既存の“構造” だけでなく、Option や Either といった関数型プログラミング言語特有の“構造”、及びそれらを扱う関数も用意されています Gist flow関数も頻繁に使いますが、本稿では割愛します。 ↩ ここでは“手動”でカリー化していますが、“自動”でカリー化する関数(curry)を提供している有名な関数型プログラミングライブラリ(Ramda)があります。(もっとも、TypeScriptでは型に難があり筆者はcurryはほぼ使いません。) ↩ 同じ pipe という名前の関数でも、別のライブラリ(例えば ramda)だと機能が異なっている場合があります。 ↩ TypeScript 未学習者向けに補足すると、ここでは「Record は Object」とざっくりとした理解で良いです。(Record は Object の部分集合。) ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Vue.js 勉強メモ】v-ifとv-showの違い

はじめに 仕事で使う事になったので1からVue.jsについて学んだ(元々Angularでプロダクト開発をやっていた事はあるがAngularはだめか・・・)。 ちゃんと覚えておかないとまずそうな事を備忘録として1つ1つ残しておく。 v-ifとv-showの違い これまた見た目の動きは同じ(真偽値の条件で表示・非表示を切り替える)だが、動きには大きな違いがあるのでちゃんと使い分けないといけない。 それぞれの違いは以下の表のとおりで、使い所も違っている。 # 内部の動き デメリット 使い所 v-if HTMLに要素を描画する・しないで表示・非表示を切り替える 表示・非表示が変わるたびに再描画されるのでレンダリングのコストが高くなる 初期時の表示制御など頻繁でない表示切替に用いる v-show 常にHTMLには描画されるが、styleに"display: none;"を付与する・しないで表示・非表示を切り替える ・初期時に必ず描画されるので初期時のレンダリングのコストが高くなる・template構文が使えない・elseに相当するものがないので自前で真偽値の逆バージョンを用意する必要がある 高頻度な表示切替に用いる ※レンダリングのコストが高くなる=Webサイト動作が遅くなる 実際の動きは以下の通り。 動画のソースコードは以下。 sample.html <body> <div id="app"> <button @click="ok = !ok">ボタン</button> <p v-if="ok">If</p> <p v-show="ok">Show</p> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script> <script> new Vue({ el: '#app', data: { ok: true } }) </script> </body> ※v-showのデメリット「template構文が使えない」について、実際にtemplate構文を使うと以下のようにtemplateタグがdisplay: none;になるだけで、template内部は表示されてしまうので使えない。(templateタグは実際には描画されないので見えないが)。 sample.html <body> <div id="app"> <template v-show="ok"> <p>隠したい</p> </template> </div> <script src="https://cdn.jsdelivr.net/npm/vue@2.6.12/dist/vue.js"></script> <script> new Vue({ el: '#app', data: { ok: false } }) </script> </body> Vue.jsの勉強メモ一覧記事へのリンク Vue.jsについて勉強した際に書いた勉強メモ記事のリンクを集約した記事。 https://qiita.com/yuta-katayama-23/items/dabefb59d16a83f1a1d4
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

API初心者向け「さけのわAPIで日本酒お勧めLINEボット」を作って苦戦した、APIレスポンスの処理解説

過去2回の記事では、まずはAPIを使ってみよう!ということで色々触ってきましたが、そろそろコンソール表示だけでは物足りなくなってきました。そこで、今回はAPIと連携したLINEボットの作成に挑戦します。やっぱりインターフェースがあるとテンション上がりますよね。 折角なので複数のAPIを利用して、仕様の違いなどからAPI活用の理解を深めていきます。色々調べていくと、私の大好きな「日本酒」のデータを無償提供してくれているAPIがあることを知り、喜んで今回のボットに組み込ませて頂くことにしました。なお、この記事ではAPIのレスポンスをうまく?処理する辺りに重点を置いて書きたいので、LINEボット周りの説明は薄くなりますが、あらかじめご了承ください。今回の記事を読んで頂きたいターゲットは以下くらいを想定しています。 APIを使い始めたけど、レスポンスの処理がよく分からず苦戦している人(私と同じくらいのJavaScript初心者) とにかく色んなAPIの利用方法やソースコード例を見てみたい人 とりあえず、タイトルに「日本酒」とあったから覗きに来た人 この記事の概要 ユーザーがクリックしたメニューボタンに応じて、呼び出すAPIを切り替え、別の応答を返すLINEボットを作ります。 最初に完成したボットの動作イメージを付けておきます。日本酒にやたら詳しいワンコですね('ω') 使用しているAPI このLINEボットでは以下3種類のAPIを使用しています。 Advice Slip JSON API(https://api.adviceslip.com/#top) さけのわデータAPI(https://muro.sakenowa.com/sakenowa-data/) Azure Translator API(https://azure.microsoft.com/ja-jp/services/cognitive-services/translator/) 動作の流れ ざっくりと以下の流れでAPI連携した結果を返すLINEボットにしました。 「アドバイス」を要求されたら、Advice Slip JSON APIからランダムなアドバイス文章を返答する APIから取得したアドバイス(英文)を、Azure Translator APIで日本語に翻訳する 翻訳された日本語のアドバイス文章を返答する 「お勧めの日本酒」を要求されたら、さけのわデータAPIからお勧めの銘柄情報を返答する 取得した銘柄一覧の要素数を確認して、ランダムな一銘柄を抽出する 続けて、さけのわデータAPIからフレーバー情報を取得する 抽出した銘柄にフレーバー情報が存在するか確認する(存在しない銘柄もある) 銘柄名とフレーバー情報(存在する場合)を返答する 環境 Module Version Node.js 15.13.0 npm 7.7.6 axios 0.21.1 request 2.88.2 uuid 8.3.2 処理の解説(主にAPI周りを中心に) 最初にコード全文を付けておきますが、長いので折りたたみセクションにしておきます。 コード全文はこちら line-bot-proto.js // パッケージを使用します const express = require('express'); const line = require('@line/bot-sdk'); const axios = require('axios'); const request = require('request'); const uuidv4 = require('uuid/v4'); // ローカル(自分のPC)でサーバーを公開するときのポート番号です const PORT = process.env.PORT || 3000; // Messaging APIで利用するクレデンシャル(秘匿情報)です。 const config = { channelSecret: 'YourChannelSecret', channelAccessToken: 'YourChannelAccessToken' }; let pushText = ''; // サンプル関数 const botFunction = async (event) => { const userText = event.message.text; // ユーザーメッセージの識別(2種類なので、「アドバイスほしいなー」か否か) if (userText === 'アドバイス欲しいなー') { // 「リプライ」を使って先に返事しておきます await client.replyMessage(event.replyToken, { type: 'text', text: '調べています……' }); try { // APIでランダムなアドバイスを取得する const response = await axios.get('https://api.adviceslip.com/advice'); const jsonData = response.data; const SourceText = jsonData.slip.advice; // データ翻訳用の関数translateTextを呼び出す translateText(SourceText,); //非同期がうまくいかないので、とりあえず2秒待つ// const _sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); await _sleep(2000); } catch (error) { // APIからエラーが返ってきたらターミナルに表示する pushText = '検索中にエラーが発生しました。ごめんね。'; console.error(error); } // 「プッシュ」で後からユーザーに通知します return await client.pushMessage(event.source.userId, { type: 'text', text: pushText, }); } else { // 「リプライ」を使って先に返事しておきます await client.replyMessage(event.replyToken, { type: 'text', text: '調べています……' }); try { // さけのわデータAPIから「銘柄一覧」を取得する response = await axios.get('https://muro.sakenowa.com/sakenowa-data/api/brands'); const jsonData = response.data; // アイテム数を確認し、ランダムに一つの銘柄を抽出する const itemCount = jsonData['brands'].length; const ran_key = Math.floor(Math.random() * itemCount -1) + 1; const brandName = jsonData['brands'][ran_key]['name']; const brandId = jsonData['brands'][ran_key]['id']; // さけのわデータAPIから「フレーバーチャート」を取得する response2 = await axios.get('https://muro.sakenowa.com/sakenowa-data/api/flavor-charts'); const jsonData2 = response2.data; // 取得したJSONから、対象銘柄のデータを検索する(存在しない場合がある) flavorData = jsonData2['flavorCharts'].find((v) => v.brandId === brandId); // もしフレーバーチャートが存在しない場合は銘柄名のみ、存在する場合はチャート付きで表示する if( typeof flavorData === 'undefined'){ pushText = '【お勧め銘柄】' + brandName; }else{ pushText = '【お勧め銘柄】' + brandName + '\n'; pushText += '華やかさ:' + flavorData['f1'] + '\n'; pushText += '芳醇:' + flavorData['f2'] + '\n'; pushText += '重厚:' + flavorData['f3'] + '\n'; pushText += '穏やか:' + flavorData['f4'] + '\n'; pushText += 'ドライ:' + flavorData['f5'] + '\n'; pushText += '軽快:' + flavorData['f6']; } } catch (error) { // APIからエラーが返ってきたらターミナルに表示する pushText = '検索中にエラーが発生しました。ごめんね。'; console.error(error); } // 「プッシュ」で後からユーザーに通知します return client.pushMessage(event.source.userId, { type: 'text', text: pushText, }); } }; // 英文をTranslator APIにPOSTメソッドで渡し、日本語翻訳を行う function translateText(SourceText){ let options = { method: 'POST', baseUrl: 'https://api.cognitive.microsofttranslator.com/', url: 'translate', qs: { 'api-version': '3.0', 'from': ['en'], 'to': ['ja'] }, headers: { 'Ocp-Apim-Subscription-Key': 'YourSubscriptionKey', 'Ocp-Apim-Subscription-Region': 'YourServiceRegion', 'Content-type': 'application/json', 'X-ClientTraceId': uuidv4().toString() }, body: [{ 'text': SourceText }], json: true, async: true, }; // レスポンスのJSON配列から、翻訳テキスト部分を取得 request(options, function(err, res, body){ pushText = body[0]['translations'][0]['text']; }); }; // ######################################## // LINEサーバーからのWebhookデータを処理する部分 // ######################################## // LINE SDKを初期化します const client = new line.Client(config); // LINEサーバーからWebhookがあると「サーバー部分」から以下の "handleEvent" という関数が呼び出されます async function handleEvent(event) { // 受信したWebhookが「テキストメッセージ以外」であればnullを返すことで無視します if (event.type !== 'message' || event.message.type !== 'text') { return Promise.resolve(null); } // サンプル関数を実行します return botFunction(event); } // ######################################## // Expressによるサーバー部分 // ######################################## // expressを初期化します const app = express(); // HTTP POSTによって '/webhook' のパスにアクセスがあったら、POSTされた内容に応じて様々な処理をします app.post('/webhook', line.middleware(config), (req, res) => { // 検証ボタンをクリックしたときに飛んできたWebhookを受信したときのみ以下のif文内を実行 if (req.body.events.length === 0) { res.send('Hello LINE BOT! (HTTP POST)'); // LINEサーバーに返答します(なくてもよい) console.log('検証イベントを受信しました!'); // ターミナルに表示します return; // これより下は実行されません } else { // 通常のメッセージなど … Webhookの中身を確認用にターミナルに表示します console.log('受信しました:', req.body.events); } // あらかじめ宣言しておいた "handleEvent" 関数にWebhookの中身を渡して処理してもらい、 // 関数から戻ってきたデータをそのままLINEサーバーに「レスポンス」として返します Promise.all(req.body.events.map(handleEvent)).then((result) => res.json(result)); }); // 最初に決めたポート番号でサーバーをPC内だけに公開します // (環境によってはローカルネットワーク内にも公開されます) app.listen(PORT); console.log(`ポート${PORT}番でExpressサーバーを実行中です…`); それでは、私が苦戦した箇所を中心に解説していきます('ω') ほぼほぼ全部ですが・・ Advice Slip JSON APIの利用 まずはココですね。axiosでAPIのGETメソッドを投げて、レスポンスを受け取ります。 const response = await axios.get('https://api.adviceslip.com/advice'); 公式ページで仕様を確認すると、以下の形式でslipオブジェクトを受け取るようです。 { "slip": { "slip_id": "2", "advice": "Smile and the world smiles with you. Frown and you're on your own." } } 私が今回欲しいのは、adviceに入っているアドバイス文章そのものですので、以下の通り取り出します。 const jsonData = response.data; const SourceText = jsonData.slip.advice; これで問題なく、adviceにセットされているテキストが取り出しできました。これは私でもすんなり行けた珍しいケースですね。この後に取り出した英文のテキストを翻訳するためにAzure Translator APIを呼び出しています。 Azure Translator APIの利用 こちらは地味に苦戦しました。苦戦したので単品の記事にしてあります。よければ初心者っぷりを見てあげてください。 今回の記事向けに、レスポンスの形式と、そこからの取り出し部分だけ抜粋しておきます。 [ { "detectedLanguage": { "language": "en", "score": 1 }, "translations": [ { "text": "疑わしい場合は、次の小さな一歩を踏み出してください。", "to": "ja" } ] } ] このレスポンスに対して、欲しい翻訳結果(translationsのtext)の取り出しは、以下のコードになります。 request(options, function(err, res, body){ console.log(body[0]['translations'][0]['text']); }); 日本語にすると「配列の最初の要素のtranslationsプロパティが持つ配列の最初の要素のtextプロパティの値」という感じでしょうか。これで、無事にテキストの取り出しが成功しますが、大分しんどい感じです。(ごめんなさい、このレベルの初心者と思って優しい目で見てください) さけのわデータAPIの利用 それでは、本命のさけのわデータAPIの処理に入ります!本当は色々味の好みとか入力するとお勧めの銘柄を紹介してくれる、さけのわアプリみたいな恰好良い機能を作ってみたいものですが、今の私では叶わないので、以下の機能に留まっています。 さけのわデータAPIから銘柄一覧情報を取得する(3,000銘柄以上登録されてました・・スゴイ・・) 銘柄一覧から、本日のお勧め銘柄を一つランダムに決定する その銘柄にフレーバー情報がある場合は、合わせて返答してあげる まずは銘柄情報の取得からです。 // さけのわデータAPIから「銘柄一覧」を取得する response = await axios.get('https://muro.sakenowa.com/sakenowa-data/api/brands'); const jsonData = response.data; こちらも公式ページで仕様を確認すると、以下の形式でレスポンスを受け取るようです。 { "brands": [ { "id": 4558, "name": "越の一", "breweryId": 1832 }, { "id": 4611, "name": "吉の川", "breweryId": 1128 } ] } なるほど、brandsプロパティが大量の銘柄の配列を持つ形みたいですね。ここから配列内の適当な位置のnameを取り出して終了でも良いのですが、後でフレーバー情報があるか確認しに行くためにid情報も必要になります。そこで、[配列の要素数の確認]→[要素数内でランダムな数字を作成]→[その位置にいる銘柄のnameとidを取得]という流れで処理をしていきます。 // アイテム数を確認し、ランダムに一つの銘柄を抽出する const itemCount = jsonData['brands'].length; const ran_key = Math.floor(Math.random() * itemCount -1) + 1; const brandName = jsonData['brands'][ran_key]['name']; const brandId = jsonData['brands'][ran_key]['id']; 続けてフレーバー情報を取得します。ここで先ほど取得した銘柄のidに一致するフレーバー情報があるか検索(find)を掛けています。この結果一致するアイテムが無い場合には、JavaScriptでお馴染みのundefined(何もセットされていない)となるので、それを判定に使って銘柄情報のみかフレーバー情報付きかを分岐させることができました。 // さけのわデータAPIから「フレーバーチャート」を取得する response2 = await axios.get('https://muro.sakenowa.com/sakenowa-data/api/flavor-charts'); const jsonData2 = response2.data; // 取得したJSONから、対象銘柄のデータを検索する(存在しない場合がある) flavorData = jsonData2['flavorCharts'].find((v) => v.brandId === brandId); // もしフレーバーチャートが存在しない場合は銘柄名のみ、存在する場合はチャート付きで表示する if( typeof flavorData === 'undefined'){ pushText = '【お勧め銘柄】' + brandName; }else{ pushText = '【お勧め銘柄】' + brandName + '\n'; pushText += '華やかさ:' + flavorData['f1'] + '\n'; ここも、そもそも「フレーバー情報が登録されていない銘柄がある」という視点が抜けていて大分ハマってしまいました。やっぱり仕様の確認に加え、実際に取得できているデータの中身をしっかり確認するのは大事ですね。(基本動作ができていない) おまけ(LINE Bot関連) もし、この記事を見て「実際に動かしてみたいぜ」な人がいた場合に、LINE Bot関連の情報に全く触れていないので、少しだけ補足します。 バックエンドサーバは、ローカルPCでNode.jsで動かしています(コード全文にも含んでいます) トンネリングサービスのngrokを利用して、公開用URLを取得しています LINE DevelopersのMessaging APIの設定、WebhookURLの設定を行い、LINEサーバと連携させています 詳細はこちらの記事が分かり易かったので、紹介させてください! ngrokは起動するたびに公開用URLが変わるので、WebhookURLの修正が必要だったりと注意は必要ですが、ローカルPCでこんなに手軽にLINEボットのお試し操作ができるなんて、凄いですよね。色々試してみたくなりました('ω') 終わりに 今回の記事は非常に長文になってしまい・・、最後までお付き合い頂いた方は本当にありがとうございます。 JavaScriptとかAPIとか触り始めたての初心者向けではありますが、私も色々調べて上記内容を何とか動かすことができましたし、きっと何らかのニーズはあるに違いない!と信じて投稿させて頂きます。なるべく期待を裏切らない、変な迷い込みを起こさないタイトル付けを意識しないといけないですね('ω') さて、次は何ネタにしようかな・・。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RESTサービスを作る・入門編

フロントエンドエンジニアは、WebAPIの「使う側」であります。 ですが、API、DataBaseも自分で手を動かして構築し、RESTサービスを包括的に経験する事で視野を広げようと思います。 本編は入門編なので、まずは概要をまとめました。 実際の開発はNode.js, Express, React, SQLite3を使い、続編で紹介します。 RESTとは: REST(REpresentational State Transfer)は、HTTPプロトコル作成者の一人であるRoy Fieldingによって2000年頃に提案され、複数のソフトウェアを連携させるのに適した設計原則です。クライアントとサーバを分離し、両者でデータを送受信するWebアプリケーションの開発に活用されている。 RESTful APIは、次の4つのRESTの原則に従って設計されたAPIとなります。 1. アドレス可能性 そのアプリケーションが提供する情報はURIを通して一意に(ユニークに)表現できること。 APIのバージョン、データを取得するのか、それとも更新するのか、などが一目でわかるようにすること。 2. ステートレス性 すべてのHTTPリクエストが完全に分離している性質であること。セッションなどの状態管理は行われないこと。有名なハンバーガーの注文がわかりやすいです。 3. 接続性 ある情報に「別の情報へのリンク」を含めることができること。そして、リンクを含めることで「別の情報に接続すること」ができること。 4. 統一インターフェース 情報の取得、作成、更新、削除といったリソースの操作は、すべてHTTPメソッドを利用すること。この場合のHTTPメソッドとは、取得「GET」、作成「POST」、更新「PUT」、削除「DELETE」を使用することで統一と認識のしやすさを図ることが出来ます。 RESTの大きな特長はHTTPの技術を効果的に活用したものであり、Web技術との親和性が高いからWebサービスやWebアプリケーションの開発に活用されている。 クライアントとサーバーの分離 RESTサービスではクライアントとサーバーを分離させて開発し、お互いのことを関与しないでよくなります。双方で疎通の決まりごと(リクエスト・レスポンスのインターフェース)を守っていれば、クライアントとサーバー個々で開発・改修が可能になります。 このクライアントサーバーモデルの利点はPC、スマホアプリと複数のプラットフォームから同じAPIを使う事が可能になる。 REST APIの設計: ①エンドポイント定義 エンドポイントはHTTPメソッドとURLの組み合わせです。 HTTPメソッドはこの4つが基本です GET 取得 POST 追加 PUT 更新 DELETE 削除 基本的に、この4つの処理でほとんどのシステム処理を完結させることができます。 URLをリソースと見なします。 HTTPメソッドとURLの組み合わせを、 何=リソース(URL) をどうする =HTTPメソッド と言う形式で定義します。 例を出しましょう。 GET: http://hogehoge.com/api/tickets 何を=チケット情報 どうする=GET / 取得 POST: http://hogehoge.com/api/tickets 何を=チケット情報 どうする=POST / 登録 URL設計で意識すべき点 ・URLにapiを含めてAPIとわかる様にする http\://hogehoge.com/api http\://api.hogehoge.com ・URLにAPIのバージョンを含める http\://api.hogehoge.com/v1/users/ ・URLに動詞は使わず、名詞の複数形だけで構成する user一覧 http\://api.hogehoge.com/v1/users user ID:1の情報を取得 http\://api.hogehoge.com/v1/users/1 users ID:1のphoto一覧取得 http\://api.hogehoge.com/v1/users/1/photos ・アプリケーションや言語に依存する拡張子は含めない URL内に.phpや.plなど言語に関係した拡張子を付けないようにする。悪意あるユーザーから脆弱性を突かれる要因にもなります。 ・リソースの構造が分かるようにする URLを見ただけで、リソースがどこに属しているか、どんなでーたをもってるかのデータ構造が分かるようにする。 このURLを見ると、userは写真のデータを持っている事がわかります。 http\://api.hogehoge.com/v1/users/1/photos ②リクエストおよびレスポンスのJSONの定義 これらは開発において、まずUIと仕様が決まり、それを基にどういうデータが必要か、ユーザーがどう使うのかも踏まえて、定義する必要があると思います(この作業は想像力が必要) 例えば、ログインページのAPIに何が必要なのか?を考えると。 POSTメソッドで、URLは/loginとし、emailとpasswordをサーバー側の認証に使うので、フロントはこれらをリクエストボディに含める必要があります。 リクエストにAPI側で必要なデータを渡し、レスポンスにはフロント側で欲しいデータを返してもらう。(場合によってはフェッチし直して、取り直すケースもある) まとめ 次は実際にNode.js, Express, React, SQLite3を使って簡単なRESTサービスを構築した時の学びを紹介したいと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

M1搭載MacでReact Nativeの環境構築してみた

はじめに M1 Macの環境構築で苦労したので、うまくいった方法をまとめたいと思います。 これから始める方にも分かりやすくしようと思うので、分かるところは飛ばしながら読んでください。 細かい説明は省いているので、随時気になるところは調べてください。 参考にさせていただいた記事 Homebrewのインストール 2021/2/5にAppleSilicon(M1)対応のHomebrew3.0.0がリリースされました。 今回はこちらをインストールしていきたいと思います。 以下サイトからインストールできます https://brew.sh/ Install Homebrewと書かれているところの下のコードをコピーしてターミナルに貼り付けます。 パスワードを入力するとインストールが始まります。 Press RETURN to continue or any other key to abort と表示されたら[Enter]を押します。 インストールが完了したらHomebrewのパスを追加する必要があるので、以下のコードを実行します。 ユーザー名と書かれているところは自身のユーザー名に変更して下さい。 echo 'eval "$(/opt/homebrew/bin/brew shellenv)"' >> /Users/ユーザ名/.zprofile 以下のコマンドを実行し、正常に出力されれば成功です。 brew help Nodeenvのインストール brew install nodenv touch .zshrc インストール出来たらパスを通します eval "$(nodenv init -)" Nodeのインストール ターミナルをRosetta2に切り替えてインストールしてください。 ファインダーのアプリケーションからターミナルを探し、右クリックで「情報を見る」を選択。 Rosettaを使用して開くにチェックを入れて閉じます。 一度ターミナルを終了し再度起動します。 以下コマンドを実行すると現在の状態が確認できます。 ・arm64: M1 ・x86_64: Rosetta2 uname -a # Darwin Kernel Version 20.3.0... x86_64 以下コマンドでNodeをインストールしていきます nodenv install 15.9.0 インストール出来たらバージョンを確認しましょう nodenv -v yarnのインストール brew install yarn インストール出来たらバージョンを確認しましょう yarn -v Watchmanのインストール brew install watchman JDKのインストール brew install --cask adoptopenjdk/openjdk/adoptopenjdk8 Cocoapodsのインストール brew install cocoapods React Native CLIのinstall npm install -g react-native-cli npmはnodeと共にinstallされるので、すでに使用できる状態になっていると思います。 CLI(Command Line Interfaceの略) Xcodeのインストール App Storeからインストールして起動 (結構時間がかかります) Preferences > Locations > Command Line Tools を設定します Android Studioのインストール 以下サイトからインストール出来ます https://developer.android.com/studio?hl=ja&gclid=Cj0KCQjwytOEBhD5ARIsANnRjVj-zR8PvuV40cHP5tnPfqo4sCn9VZigpAvyiMCFWqHrmlxFAZyg0_YaAhhCEALw_wcB&gclsrc=aw.ds 初回起動時は「Custom」を選択してください ・ Android SDK ・ Android SDK Platform ・ Android Virtual Device の3つにチェックを入れ「Next」を押します。 SDK Manager ① ・Configure > SDK Manager を選択 ・"SDK Platforms" > "Show Package Details"にチェックを入れる ・以下にチェックを入れインストールする Android SDK Platform 29 Intel x86 Atom_64 System Image ② "SDK Tools" > "Show Package Details"にチェックを入れる 29.0.2 にチェックを入れインストールする AVD Manager 以下サイトの android-emulator-m1-preview.dmg をダウンロードする https://github.com/741g/android-emulator-m1-preview/releases/tag/0.1 「アプリケーション」フォルダで右クリックして「開く」 これでAndroidエミュレータが起動できるようになりますので、起動した状態でAndroid Studioを再起動すればエミュレータが認識されます。 プロジェクトの作成 以下公式サイトを参考にプロジェクトを作成していきます。 https://reactnative.dev/docs/environment-setup npmを使用してExpoCLIコマンドラインユーティリティをインストールします npm install -g expo-cli 次に「AwesomeProject」という新しいReactNativeプロジェクトを作成します。 expo init AwesomeProject cd AwesomeProject npm start これで開発サーバーが起動します。 動作確認 先ほど作った「AwesomeProject」の中に「App.js」というファイルがあるのでエディターで開いてみましょう。 export default function App() と書かれている中のTextの文字の中身を自由に変更し、ファイルを保存。 開発サーバーの中央左側にある Run on Android device/emulator Run on iOS simulator をクリックしてください。 デバイスが起動し、「AwesomeProject」が実行されて変更した文字列が表記されれば成功です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Firebase Realtime Databaseのデータを降順にソートしてみる【Javascript】

何がしたいか Firebase Realtime Database(以下Firebase)の公式ライブラリでは、引っ張ってきたデータを並び替えることができる関数が用意されているが、なぜか降順にソートできるものはない。しかし、データを降順に引っ張ってきて展開したいという場面もあるので、今回はそれを実現する。 実装 今回は下のような形式で複数のデータがFirebaseにpushされていることを考える。 Firebase data: { -M_A1FKQ2m31jaxrkLgd: { ... }, -M_A1KuD92gfHlWx9rk-: { ... }, -M_A1fq_4HwEICsf4LVe: { ... } } Firebaseにpushされたデータのキーは、pushされた時刻によって生成され、登録された順番に昇順にならぶ仕様になっているので、このままデータを取得すると昇順で取得されてしまう。しかし、前述の通り公式ライブラリには降順に取得してくる関数がないので、データを取得した後にデータを加工する。 取得してきたデータはオブジェクトとして取得されるので、ソートを行う場合には配列に変える必要がある。 firebase.js /*Firebaseの初期化処理は省略*/ firebase.database().ref('data').once('value', (result) => { if (result.val()) { const l = [] Object.keys(result.val()).forEach((key) => { const tmpObj = {} tmpObj[key] = result.val()[key] l.push(tmpObj) }) console.log(l) } }) console [ {-M_A1FKQ2m31jaxrkLgd: { ... }}, {-M_A1KuD92gfHlWx9rk-: { ... }}, {-M_A1fq_4HwEICsf4LVe: { ... }} ] 上記のようにオブジェクトを一つ一つの要素に分割して、配列に入れることによりソートを行うことが可能となる。 あとは、この配列を降順(逆順)にすればよい。 firebase.js /*続き*/ const reversedList = l.slice().reverse() 最後に このように取得してきたオブジェクトとして取得してきたデータを要素ごとに配列に入れることで、これ以外の方法でのソートも行いやすくなるので非常にオススメ。ただ、降順以外のソートは公式のライブラリの方でサポートされているものもあるので、そちらを使った方が良いかもしれない。詳しくは公式のドキュメント参照。 Firebase Realtime Database公式ドキュメント
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ウルトラ簡単に調整・装飾できてしまうBootstrap

前回の記事でBootstrapの導入について記述したので、 今回は超簡単な使い方に触れます。 題材として新規ユーザー登録画面のフォーム周りに変化を加えていきましょう。 まずは最低限の部品だけ設置します(HTMLのみ) sample.html <h2>新規ユーザー登録</h2> <div><input type="text" name="account" placeholder="アカウント名"></div> <div><input type="text" name="name" placeholder="ユーザー名"></div> <div><input type="password" name="password" placeholder="パスワード"></div> <div><input type="password" name="passwordConfirm" placeholder="パスワード確認"></div> <input type="submit" value="ユーザー新規登録"/> 画面表示させるとこのような形 1.テキスト位置の変更 classに「text-center」を追加します。 sample.html <h2>新規ユーザー登録</h2> <div><input class="text-center" type="text" name="account" placeholder="アカウント名"></div> ~以下略~ これでform内のplaceholderの文字が中心に位置されました。 右詰めでも良い気がしてきました...。その際は「text-right」で、左なら「text-left」で変更できます。 このように一つ掴んでしまえばcssファイルを触らずとも直感的に変更できるのが嬉しいですね。 2.間隔を調整 このままだとそれぞれのフォームにおける役割・制約が明記されていない不親切なもののままですね。 ということでformの下の行に注釈を追加します。 sample.html <div><input class="text-center" type="text" name="account" placeholder="アカウント名"></div> <div>ログインに使うアカウント名です。</div> ~以下略~ 気になる点が一気に増えましたね。順を追って変更を加えますからせっかちな人は少し待ってね。 注釈divにclass「mb-2」を追加します。 sample.html <div><input class="text-center" type="text" name="account" placeholder="アカウント名"></div> <div class="mb-2">ログインに使うアカウント名です。</div> ~以下略~ 画面の薄い橙色の部分が今調整を加えた間隔です。 mb-2を記述しましたが「2」の部分は間隔の大きさを表しますので更に幅が欲しい場合は適宜数字のみ変えるだけです。 「mb」の部分はどこに間隔を与えるか指定してるだけです。cssを書いたことがある人ならすぐピンとくるでしょう。「margin-bottom」の略なので上部は「mt」、右や左は「mr」「ml」で指定できます。 逆に指定なく全周に間隔を与えたければ「m-2」と書けばよいわけです。so easy. 感のいい人ならもうお気づきでしょうがpaddingも同じ要領ですが全く同じように...とは行かないので要注意。今回は省略しますが気になる人は調べてね。 3.文字の大きさを調整 現状だとフォームより注釈のほうが主張が大きくて一体どちらが主役なのかわからないですね。 とりあえずclassに「small」を追加してみましょう。 signup.html <div><input class="text-center" type="text" name="account" placeholder="アカウント名"></div> <div class="mb-2 small ">ログインに使うアカウント名です。</div> ~以下略~ 比較のために新旧を並べてみました。 文字サイズの変更によっていい感じのバランスになってきましたね。 4.登録ボタンの装飾 最初に比べたら最低限の調整はいいような気がします。 がここはせっかくなので動きのあるボタンを実装してみましょう。 送信ボタンのinputにclass「btn btn btn-outline-primary」を追加してみましょう。 signup.html ~送信ボタン以外省略~ <input class="btn btn-outline-primary" type="submit" value="ユーザー新規登録"/> 左が表示させただけで右がボタンにカーソルを合わせた状態です。 「btn」だけだと外線もなければ動きもないものです。 「btn-outline-primary」も組み合わせることで外線・角Rやカーソルをあわせた時の動きが実現されるのです。 他にもbtnだけでも様々な変化が実現できるのでこだわり派の方は是非とも調べてカッチョいいボタン設置してみてください。 以上で簡単なform周りをBootstrapで調整・装飾してみました。form-controlを用いてlabel周りの実装や背景色・文字色などまだまだ触る要素があります。 また、form以外にもnavリンクで便利なものが発見できてワクワクしている私としては、時間が無限にあればいくらでも弄り倒したい魅力があります。 今回は私に近い初学者向けをターゲットとしましたのでいくつか省きました。 さらなる機能や発見があればまた記事にしようかなと思っています。 以上。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

jsonファイルを使ってHTMLを半動的に作成

Ovew View Demo jsonファイルをhtmlで読み込んでサーバーサイド側でも半動的な処理をやってみたよ。 たくさんデータがある時、逐一HTMLを複製するのが非効率ですよね!それ、動的にしたら楽じゃない?! data.jsonにデータを格納し index.htmlでデータを動的に生成するよ 今回は2つの小さな処理を実装しました。 月曜日〜日曜日までの曜日ごとの労働時間を計算し、1週間の合計労働時間を自動算出。 三人の人間の名前と年齢からその人の未来が明るいかどうかを判定して自動で出力。 Code index.html <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css" integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l" crossorigin="anonymous"> <title>Hello, world!</title> <script type="text/javascript" src="data.json"></script> <script type="text/javascript"> function putWeekly() { var totalWorking = 0; document.write(`<h2 class="mb-4 text-primary">WorkTime</h2>`); for (let key in data.workTime) { document.write(`<p>${key}day is working for ${data.workTime[key]} hours.</p>`); totalWorking += data.workTime[key]; } document.write(`<p class="text-danger">Totaly I worked ${totalWorking} hours Last week.<p>`); } function putAllMembers() { document.write(`<h2 class="mb-4 text-primary">All Members</h2>`); for(i=0 ; i<data.members.length ; i++) { name = data.members[i].name; age = data.members[i].age; if(age > 20) { comment = "もう手遅れだ!"; } else { comment = "まだまだ先は長い!"; } document.write(`<p class="mb-4">${name}さんは現在${age}歳で、日本人の平均寿命が80歳だとしたら人生の${(age/80)*100}%を経過したことになりますね!${comment}</p>`); } } </script> </head> <body> <div class="p-lg-5"> <h1>Hello, world!</h1> <div class="mt-4 container-fluid"> <div class="row"> <div class="col"> <script type="text/javascript">putWeekly();</script> </div> <div class="col"> <script type="text/javascript">putAllMembers();</script> </div> </div> </div> </div> <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-Piv4xVNRyMGpqkS2by6br4gNJ7DXjqk09RmUpJ8jgGtD7zP9yug3goQfGII0yAns" crossorigin="anonymous"></script> </body> </html> data.json data = { workTime: { sun: 10, mon: 11, tue: 12, wed: 13, thu: 14, fri: 15, sat: 16, }, members: [ {name: "Nobita",age: 27}, {name: "Suneo",age: 26}, {name: "Jaian",age: 18}, ] }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

OSMを使って現在地の都道府県市町村を取得する

はじめに 今作ってるゲームで位置情報を使いたいと考えていて、ただ、厳密に位置を使うのではなくて市町村レベルの情報が取得できればいいなと思って調べたので、整理も兼て書いておきます。 OSMでできないかと思い調べると、Nominatimを使うことでできるようです。 今回はブラウザで動作させているので、WebAPIのGeo Location APIと組み合わせることで実現ができました。 GitHubにソースを公開しています。 Geo Location API ブラウザで位置情報を扱うことのできるAPIです。 使い方は結構簡単でした。 位置情報を取得するAPIは2つあります。 呼び出した時点の現在の位置を取得する Geolocation.getCurrentPosition() 定期的に現在地を取得する Geolocation.watchPosition() 今回は、Geolocation.getCurrentPosition() を使いました MDNを見ると getCurrentPosition(success[, error[, [options]]) となっています。 というわけで以下のように実装してみました。 オプションはMDNの説明を参照してください。 // navigator.geolocationをチェックして、GetLocation APIをサポートしているかの確認 var isGeolocSupport if (navigator.geolocation) { isGeolocSupport = true; } else { isGeolocSupport = false; } document.addEventListener('DOMContentLoaded', function() { if(isGeolocSupport){ navigator.geolocation.getCurrentPosition(function(position){ // 位置情報が取得できた場合 var request = new XMLHttpRequest(); var lat = position.coords.latitude; var lon = position.coords.longitude; // 何か処理する }, function(error){ // 取得できない場合 },{ // オプション enableHighAccuracy : true, timeout : 30 * 1000, maximumAge : 60 * 1000 }); } }); まぁ、こんな感じで簡単に現在地を取得できます。 ちなみに、ブラウザでアクセスすると、以下のように確認ダイアログが表示されます。 Nominatim 私自身、機能を把握しきれていませんが、Wikiを見ると OSMデータを名前や住所で探したり、OSMポイントの住所を合成して生成する(逆ジオコーディング)ツール と説明されています。 検索とかに使えるAPIのようです。 このNominatimを使い、現在位置から住所を取得します。 Nominatimには search, reverse, lookup などが用意されています。 今回は緯度経度から住所を取得したいので、reverseを利用します。 今回は以下のオプションで利用ています。 パラメタ 値 説明 format json json形式で結果を取得する zoom 18 家/建物レベルを指定 addressdetails 1 要素内で細分化した住所を含む(この指定の必要があるかは未検証) 戻ってくるjsonですが、addressに住所の情報が入ってきます。 住所の情報は地域で入ってくるキーが異なるようです。 そのあたりを考慮して結果を取得する必要があります。 キー 説明 province 都道府県 state 州 region 地方 county 郡 city 市町村 district ??? suburb 区 town 町 village 村 neighbourhood 小字 / 字 / 丁 / 丁目 / 島嶼部 road 道? で、その辺を考慮して実装していますが・・・ダサい。 まぁ、それはおいておいて、これで都道府県市町村を取得できます。 var request = new XMLHttpRequest(); request.onload = function () { var data = this.response; var result = document.getElementById('result'); var addr1 = ""; var addr2 = ""; if(data != null && data.address != null){ if(data.address.province){ addr1 = data.address.province; } if(data.address.state){ if(!addr1){ addr1 = data.address.state; }else if(!addr2){ addr2 = data.address.state; } } if(data.address.region){ if(!addr1){ addr1 = data.address.region; }else if(!addr2){ addr2 = data.address.region; } } if(data.address.county){ if(!addr1){ addr1 = data.address.county; }else if(!addr2){ addr2 = data.address.county; } } if(data.address.city){ if(!addr1){ addr1 = data.address.city; }else if(!addr2){ addr2 = data.address.city; } } if(data.address.district){ if(!addr1){ addr1 = data.address.district; }else if(!addr2){ addr2 = data.address.district; } } if(data.address.suburb){ if(!addr1){ addr1 = data.address.suburb; }else if(!addr2){ addr2 = data.address.suburb; } } if(data.address.town){ if(!addr1){ addr1 = data.address.town; }else if(!addr2){ addr2 = data.address.town; } } if(data.address.village){ if(!addr1){ addr1 = data.address.village; }else if(!addr2){ addr2 = data.address.village; } } if(data.address.neighbourhood){ if(!addr1){ addr1 = data.address.neighbourhood; }else if(!addr2){ addr2 = data.address.neighbourhood; } } if(data.address.road){ if(!addr1){ addr1 = data.address.road; }else if(!addr2){ addr2 = data.address.road; } } } result.innerText = addr1 + addr2; } var url = "https://nominatim.openstreetmap.org/reverse?" + "format=json" + "&lat=" + lat + "&lon=" + lon + "&zoom=18" + "&addressdetails=1"; request.open('GET', url, true); request.responseType = 'json'; request.send(); ついでに近辺の情報も取得したい 欲が出て、周辺の情報も取得したくなりました。 その場合、Overpass APIを使うことで実現できます。 Overpass APIは利用するサーバーにより条件があったります。 詳しくは JA:Overpass API - OpenStreetMap Wiki を参照してください。 今回は、現在の位置を中心に、50kmの範囲にあるコンビニを取得してみました。 緯度経度を距離に換算する情報は 緯度経度のメートル換算 - teratail を参考にさせていただきました。 Overpass APIにリクエストする場合、JSONで値を送ることができないようで、formデータとして送信します。 (もし、JSONで送る方法があるならコメントで教えてくださいm(_ _)m ) いろいろ指定できるのですが、実際に利用する前に overpass turbo でパラメタを指定してどんな値が返ってくるのかを確認できます。 なので、ここで動いた条件を、formデータとして利用すると良いと思います。 var url = "https://overpass-api.de/api/interpreter?" ; // 0.00001 が 1m var areaLen = 0.00001 * 50 * 1000; var formData = "data=" + "[out:json][timeout:25];" + "(" + 'node["shop"="convenience"](' + (lat + areaLen * -1) + ',' + (lon + areaLen * -1) + ',' + (lat + areaLen) + ',' + (lon + areaLen) + ');' + ");" + "out body;"; var overpass = new XMLHttpRequest(); var logArea = document.getElementById("log"); logArea.value = ""; overpass.onload = function () { var data = this.response; var logArea = document.getElementById("log"); data.elements.forEach(poi => { logArea.value += poi.tags.name + "\r\n"; }); } overpass.open('POST', url, true); overpass.responseType = 'json'; overpass.send(formData); 実行するとこんな感じになります。 50kmは広すぎですね(縦横100kmになるからなぁ・・・) 最後に どうやってこれを使っていくかは、まだ検討段階です。 IngressやポケGoのように割と精度の必要となる位置情報ゲームではなく、駅メモのような、一番近いものにアクセスするようなものを作る場合には、こういった使い方が生かせるかもしれないと思います。 参考 projectdev/geo - GitHub 位置情報 API - MDN JA:Nominatim - OpenStreetMap Wiki overpass turbo JA:Overpass API - OpenStreetMap Wiki JA:Overpass turbo - OpenStreetMap Wiki JA:住所 - OpenStreetMap Wiki 緯度経度のメートル換算 - teratail
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

TypeScriptでよくわかるカリー化

TypeScriptでよくわかるカリー化 カリー化で安全で便利な関数生成 環境 typescript 4.1.5 Node v15.8.0 カリー化とは カリー化 (currying, カリー化された=curried) とは、複数の引数をとる関数を、引数が「もとの関数の最初の引数」で戻り値が「もとの関数の残りの引数を取り結果を返す関数」であるような関数にすること(あるいはその関数のこと)である。(wiki) 簡単に言うと引数を省略しても省略した引数を受け取る関数を生成する関数です コードにするとこんな感じのことができる関数です function Pow(num: number, n: number) { return num ** n; } console.log(Pow(8))//(n:number) => num ** n カリー化のやり方 簡単な例 functionをオーバーロードして実装します function sum(a: number, b: number): number; function sum(a: number): (b: number) => number; function sum(a: number, b?: number) { if (b === undefined) { return (b: number) => a + b; } else { return a + b; } } console.log(sum(8)(9));//17 引数をカリー化する関数 引数にfunctionを渡すことでカリー化してくれます ジェネリクスを活用することで型も自動で宣言されます const curry = <T extends (a: A, b: B) => ReturnType<T>, A, B>(fn: T) => { function curry(a: A, b: B): ReturnType<T>; function curry(a: A): (b: B) => ReturnType<T>; function curry(a: A, b?: B) { return b === undefined ? (b: B) => curry(a, b) : fn(a, b); } return curry; }; メリット 繰り返し同じ処理を書かなくていい 非同期通信の関数がある場合同じurlに何回も送る時urlを何回も入力するのは疲れるので こんな感じの関数を作ることでurlの入力を一回で済ませられます async function get<J extends object, T>(url: string, callback: (data: J) => T, init?: RequestInit): Promise<T>; async function get<J extends object, T>(url: string, callback: (data: J) => T): Promise<(init?: RequestInit) => Promise<T>>; async function get<J extends object, T>(url: string): Promise<(callback: (data: J) => T, init?: RequestInit) => Promise<T>>; async function get<J extends object, T>(url: string, callback?: (data: J) => T, init?: RequestInit) { if (url !== undefined && callback !== undefined) { return callback(await (await fetch(url, init)).json()); } else if (url !== undefined && callback === undefined) { return async (callback: (data: J) => T) => get(url, callback, init); } else if (url === undefined && callback === undefined) { return async (url: string, callback: (data: J) => T) => get(url, callback, init); } } 可視化性が上がる 最大値、最小値を決めて範囲内なら近い方を 範囲外ならそのまま返す関数があるとします 下記の例だとどれがどの引数がわかりにくいです const Between = (min: number, max: number, x: number) => { return x < min ? min : max < x ? max : x; }; const n = Between(-10, 10, 20) カリー化すると一気に可視化性が上がります const Between = (min: number, max: number) => (x: number) => (x < min ? min : max < x ? max : x); const n = Between(-10, 10)(20);//20 まとめ カリー化でみんな幸せ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LeafletでGPSログ(GPX)地図:標高グラフ追加。

LeafletでGPSログ(GPX)地図:標高グラフ追加。 グラフ作成には、「Highcharts」を使用。 詳細は以下。 https://2ndart.hatenablog.com/entry/2021/05/08/160620
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

0~9までの数字を全て使い10桁の整数を作成する

0~9までの数字を全て使い、10桁の整数を作成する。 考えたこと ①0~9までの数字をランダムに作る =>Math.randomを使う ②空配列を作り、①でできた数字を入れていく ただし、配列に同じ数字が入らないように考慮する =>ifとincludeを使えば同じ数字は省ける ③上記の操作を10回繰り返す =>breakを使うことを忘れない const min = 0; const max = 9; const array = []; for (let i = min; i < max - min + 1; i++) { while (true) { // 0~9までのランダムな数字を作成 const random = Math.floor(Math.random() * (max - min + 1)); // 配列内に追加予定の数字が入っていないことを確認する if (!array.includes(random)) { array.push(random); // while文を使っているのでbreakを入れることを忘れない break; } } } const result = array.join(""); console.log(result); //出力結果 //2487051396 仮に先頭が1~9までの数字にしてくれと言われた場合は、最初の空配列の下に以下の条件を付け足して、for文内のi<max-min+1をi<max-minに変更すれば完了します。 //1~9までのランダムな数字を作成する場合 array.push(Math.floor(Math.random() * (max - min))+1)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Nuxt.jsでasync/asyncData/awaitがわからなかったのでまとめた

はじめに Rails+Nuxt.jsをやっていてわからなかったので頭の整理も兼ねてまとめます。 今回わからなかったコード async asyncData ({ $axios }) { let users = [] //空配列 await $axios.$get('/api/v1/users') //nuxt axiosの記述でデータを取得する .then(res => (users = res)) //返ってきたデータをusers配列に格納 return { users } //usersの配列をtemplateで使用できるように返す async asyncData ({$axios}) { async Promiseを返してくれる。 Promiseとは外部からデータを取得した際に成功した処理と失敗した処理を返してくれるクラス asyncData() コンポーネントの作成前に実行させる。axiosは読み込みに時間がかかるため最初に読み込みたいのでここで記載する。Nuxt.js作成の際にaxiosを選択した為、今回の場合はNuxtのmoduleからaxiosを持ってきている。 await $axios.$get('/api/v1/users') await Promiseを返すまでJavaScriptを待機させる。 axiosの通信は時間がかかるため、確実に処理を実行するためにawaitをつける \$axios.$get(取得先) axiosで取得先を指定しています。$がつくのはNuxt.jsの書き方。 .then(res => (users = res)) .then(res => (users = res)) 先ほどPromiseは成功した時の処理と失敗した時の処理を返すと書いたが、.then(処理)では成功した時の処理を書くことができる 最後returnをしてtemplate内で使えるようにしてあげる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

猿でも分かる!Vueのリアクティブシステム

Vueのリアクティブシステムを理解する (Zennにも同じ記事を書いています。そちらにはcodesandboxを貼ってあります) 皆さん、Vue.jsを使っていますか?個人的には結構好きでよく使っているのですが、あのリアクティブ性はどうやって実現しているのか気になりませんか?本記事ではVue2系のリアクティブシステムの原理を簡単に説明していきます。 フロントは流行り廃りの激しい分野だからこそ、主要技術がどうやって実現しているのかを知ることが今後にも生きるはずです。 今回使用したコード(sandbox)を記事最下部に貼っておきます。 今回の設定 itemオブジェクトには価格priceと量quantityプロパティがあります。 それらの総額に相当するtotalプロパティをitemオブジェクトの変更を検知して自動的に自動的に再計算されて欲しい。 vue.js的に書くとこんな感じ。 example.vue <script> export default { data() { item: { price: 100, quantity: 3, } }, computed: { total() { return this.item.price * this.item.quantity; // -> 300 } } } </script> (vueの原理を解説するので以降はバニラjsで説明します。やりたいことは変わりません。) もしリアクティブ性がないと... item.quantityに5を代入しても、totalが再計算されないので300のままになってしまいます。 これが自動的に500になるようにしたい。 level1.ts const item = { price: 100, quantity: 3 }; let total: number = 0; const calcTotal = () => (total = item.price * item.quantity); calcTotal(); console.log(total); // -> 300 item.quantity = 5; console.log(total); // -> 300(これが500になって欲しい) どんな機能が必要か 上の例から、リアクティブ性というのは、 プロパティが変更されたらそれを検知してそのプロパティが使用されている関数を自動的に再計算すること と言い換えることができます。つまり、これを実現するには プロパティ毎にそのプロパティがどんな関数で使われているかを保存しておく そのプロパティの更新時に関連する関数を全て再計算する 機能があれば良いわけです。どうですか?なんだかできそうな気がしてきませんか? quantityに対してこれを実装してみる level2.ts const item = { price: 100, quantity: 3 }; let total: number = 0; const storageForQuantity: Function[] = []; const record = (func: Function) => { storageForQuantity.push(func); }; const reCalculate = () => { storageForQuantity.forEach((func) => func()); }; const calcTotal = () => (total = item.price * item.quantity); calcTotal(); // 初期totalの計算 record(calcTotal); // calcTotalはquantityに依存しているのでこの関数をstorageに保存 console.log(total); // -> 300 item.quantity = 5; reCalculate(); // quantityを変更したのでstorage内部の関数を全て再実行 console.log(total); // -> 500 まだ手動で再計算をしていますが、なんとなく処理の流れは掴めたでしょうか。 1. item.quantityに対して、依存関数を入れておく 2. item.quantityが変更されたら、依存関数を全て再計算する では、上の機能をDepというクラスにまとめてみましょう!(Dep: Dependancy) Depクラスの導入 vueの内部で使われている命名と合わせるために、先程とは名前を変えていますが、機能は変わりません! storageForQuantity -> subscribers: 依存関数を保存する配列 record -> depend: 依存関数を追加するメソッド reCalculate -> notify: 依存関数を再計算するメソッド また、targetという変数を導入しました。dependする時にtargetの中に入っている関数を依存関数として追加します。 (これによってdependが副作用のある関数になってしまうのですが、こうしないと後々困るので甘んじて受け入れてください...本家vueもこのやり方です...) level3.ts let target: Function = () => {}; // 依存関数を保存する際の対象関数を入れておく変数 interface Dep { subscribers: Function[]; } class Dep { constructor() { this.subscribers = []; } depend() { if (target && !this.subscribers.includes(target)) { this.subscribers.push(target); } } notify() { this.subscribers.forEach((func) => func()); } } const item = { price: 100, quantity: 3 }; let total: number = 0; const calcTotal = () => (total = item.price * item.quantity); target = calcTotal; // quantityの依存先をtargetに入れておくことで後でdependできる calcTotal(); // 初期totalの計算 const dep = new Dep(); dep.depend(); console.log(total); // -> 300 item.quantity = 5; dep.notify(); console.log(total); // -> 500 そろそろ手動で依存関数を追加したり再実行するのに飽きてきましたね...次のセクションではこの部分を自動化したいと思います。 Object.definePropertyの導入 Object.definePropertyというメソッドを使います。 詳細はMDNドキュメントを見ていただきたいですが、このメソッドはオブジェクトのプロパティを宣言する際にgetter, setterを定義できるというものです。 詳しくはこちら これを用いて、 get() { depend(`プロパティを呼び出した関数`) // 依存関数を保存 return `プロパティの値` } set(value) { `value`をセット notify() // 依存関数を再計算 } のように書けば、 値を参照した(item.quantity)時にgetterが呼ばれて関数をsubscribesに保存 値を変更した(item.quantity = 5)時にsetterが呼ばれて依存関数を全て再計算 することができます。これを実装すればほぼ完成です!! level4.ts let target: Function = () => {}; // 依存関数を保存する際の対象関数を入れておく変数 interface Dep { subscribers: Function[]; } class Dep { constructor() { this.subscribers = []; } depend() { if (target && !this.subscribers.includes(target)) { this.subscribers.push(target); } } notify() { this.subscribers.forEach((func) => func()); } } const item = { price: 100, quantity: 3 }; let total: number = 0; const calcTotal = () => (total = item.price * item.quantity); // itemのそれぞれのプロパティに対してDepを作成し、getterではdepend, setterではnotifyをする Object.keys(item).forEach(key => { let _value = item[key]; const dep = new Dep(); Object.defineProperty(item, key, { get() { dep.depend(); return _value; }, set(value) { _value = value dep.notify() } }) }) target = calcTotal; // quantityの依存先をtargetに入れておくことで後でdependできる calcTotal(); // 初期totalの計算 console.log(total); // -> 300 item.quantity = 5; console.log(total); // -> 500 (quantityを書き換えただけなのに!!!!) 最後を見てください!!! item.quantityを書き換えただけなのにも関わらず自動的にtotalが更新されました? これにてリアクティブ性の獲得を達成することができました。 最後はもう少し処理を抽象化します。 watcherの追加(おまけ) 前回まではtargetに依存関数を入れてから関数を実行して...という処理を行なっていました。しかし、これは関数が複数になった場合に大変なことになってしまいます。 そこで、関数群をまとめて上記の処理を行なってくれるwatcher関数を作成します。 今回はitem.taxRateを追加し、税込みの総額を入れておくtotalWithTaxもリアクティブな変数にしてあります。 おまけ程度に、オブジェクトを渡すとリアクティブにしてくれるinitData関数も作成しました。 level5.ts let target: Function | null = null; // 依存関数を保存する際の対象関数を入れておく変数 interface Dep { subscribers: Function[]; } class Dep { constructor() { this.subscribers = []; } depend() { if (target && !this.subscribers.includes(target)) { this.subscribers.push(target); } } notify() { this.subscribers.forEach((func) => func()); } } const watcher = (funcObj: Record<string, Function>) => { Object.values(funcObj).forEach((func) => { target = func; func(); target = null; }); }; const initData = (dataObj: Object) => { Object.keys(dataObj).forEach((key) => { let _value = dataObj[key]; const dep = new Dep(); Object.defineProperty(dataObj, key, { get() { dep.depend(); return _value; }, set(value) { _value = value; dep.notify(); } }); }); } const item = { price: 100, quantity: 3, taxRate: 1.1, }; let total = 0; let totalWithTax = 0; const calcTotal = () => (total = item.price * item.quantity); const calcTotalWithTax = () => (totalWithTax = item.price * item.quantity * item.taxRate); // itemをリアクティブに initData(item) // vueで言うところのcomputedのような関数をwatcherに渡す。 watcher({ calcTotal, calcTotalWithTax, }) console.log(`total: ${total}, totalWithTax:${totalWithTax}`); // -> 300 // -> total: 300, totalWithTax:330 item.quantity = 5; console.log(`total: ${total}, totalWithTax:${totalWithTax}`); // -> 300 // -> total: 500, totalWithTax:550 おわりに ここまで読んでくださりありがとうございます! Vueのリアクティブシステムがどのように実現されているかを説明しました。実際のvueもこのような実装になっているので興味がある方は覗いてみると面白いと思います!(vueのレポジトリ内でdepend()やnotify()で検索すると出てくると思います) Vue3系のリアクティブシステムはProxyを使っているらしく、こちらも勉強したら記事を書こうと思います。 少しでも参考になったという方はいいね!お願いします! 今回使ったコード
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScript】配列の値から平均値を計算する関数calc_aveを定義し、配列dataの平均値を表示するプログラムを作成せよ。

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>課題</title> </head> <body> <script> var data = [59, 39, 100, 2, 15, 40, 84, 97]; var ave; // 平均値 // 関数calc_aveを実行する function calc_ave() { var sum = 0; // 平均値 for(var i = 0; i < data.length; i++){ sum = sum + data[i] document.write('<p>' + sum + '</p>'); } ave = sum / data.length; document.write('<p>平均値:' +ave+ '</p>'); } calc_ave(); </script> </body> </html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Gatsby.jsで.envファイルを使用する方法

ふとGatsby.jsで.eveファイルを使って環境変数を使いたいと思い、同じような境遇にいらっしゃる方の参考になればなと思い、この記事を書きます。 実際、公式ドキュメントにも書いてるので、詳しい説明を見たいという方は下記URLでご覧ください。 ・https://www.gatsbyjs.com/docs/how-to/local-development/environment-variables/ やり方はさほど難しくありません。 すぐ終わるので、肩の力を抜いてご覧ください! それでは説明していきます!! パッケージのインストール dotenvというパッケージをインストールします。 これは主にNode.jsで.envファイルを参考する際に使うものです。 Gatsbyではこれを使って.envファイルを参照していきます。 npm install dotenv dotenvの設定 次に、gatsby-config.jsかgatsby-node.jsで下記のコードをコピペしてください。 require("dotenv").config({ path: `.env.${process.env.NODE_ENV}` }) envファイルの作成、呼び出し 最後に.env.developmentを作成し、任意の変数名を付けて下さい。 env.development FAVORITES_FOOD = POTATO あとは呼び出すだけ。 console.log(process.env.FAVORITES_FOOD) 簡単! ちなみにビルド時は.env.productionを作成すれば、同じように環境変数を参照できますのでぜひ忘れないうちに.env.productionを作成してください。 以上、「Gatsby.jsで.envファイルを使用する方法」でした! Thank you for reading
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScript】税込み価格を計算する関数including_taxを作成せよ

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>関数課題</title> </head> <body> <script> // 税抜き価格を定義 var price = window.prompt('<p>税抜き価格を入力してください<p>'); // 関数including_taxを実行する function including_tax(price) { price = price * 1.08; price = Math.floor(price); document.write('税込み価格は' + price + 'です'); } // 税込み価格を計算する関数including_taxを作成する including_tax(price); </script> </body> </html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScript】【サイコロ問題】関数を作成・利用し、サイコロを振った数と合計値を表示。

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>ユーザー定義関数の利点</title> </head> <body> <script> function throw_dice(num){ var sum = 0; for (var i = 0; i < num; i++) { // 1以上7未満の乱数を加算する sum += Math.floor(Math.random() * 6) +1 ; } return sum; } document.write('<p>サイコロを1個振る: ' + throw_dice(1) + '</p>'); document.write('<p>サイコロを1個振る: ' + throw_dice(1) + '</p>'); document.write('<p>サイコロを2個振る: ' + throw_dice(2) + '</p>'); document.write('<p>サイコロを2個振る: ' + throw_dice(2) + '</p>'); document.write('<p>サイコロを3個振る: ' + throw_dice(3) + '</p>'); document.write('<p>サイコロを3個振る: ' + throw_dice(3) + '</p>'); </script> </body> </html> Math.random() * 6 で 0以上61未満の整数が得られる。 sum += Math.floor(Math.random() * 6) ; ↓それに1を加えているので、「1以上7未満」の範囲の整数が得られるわけです。 つまり1〜6のサイコロで出来上がり sum += Math.floor(Math.random() * 6) + 1 ;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

配列の要素を変更するメソッドをまとめてみました。(JavaScript)

はじめに JavaScriptを触っている内に配列の要素に対してのアクションが理解できていないところがあり、 色々調べていたので簡単にですが少しまとめて見ました。 配列に要素を追加するメソッド push unshift pushメソッド pushメソッドとは、配列の末尾に要素を追加することができます。 例: Array[a, b, c, d, (push)] MDN Web Docs "use strict"; { const scores = [80, 90, 40, 70]; scores.push(6, 5); console.log(scores); //実行結果 [80, 90, 40, 70, 6, 5] } unshiftメソッド unshiftメソッドは、配列の先頭に要素を追加することができます。 例: Array[(unshift), a, b, c, d] MDN Web Docs "use strict"; { const scores = [80, 90, 40, 70]; scores.unshift(5); console.log(scores); //実行結果 [5, 90, 40, 70] } 配列に要素を削除するメソッド pop shift popメソッド popメソッドは、配列から最後の要素を一つだけ削除することができます。 例: Array[a, b, c, 削除->d] MDN Web Docs "use strict"; { const scores = [80, 90, 40, 70]; scores.pop(); console.log(scores); //実行結果 [80, 90, 40] } shiftメソッド shiftメソッドは、配列から最初の要素を一つだけ削除することができます。 例: Array[削除->a, b, c, d] MDN Web Docs "use strict"; { const scores = [80, 90, 40, 70]; scores.shift(); console.log(scores); //実行結果 [90, 40, 70] } 削除, 追加まとめてするメソッド spliceメソッド spliceメソッドは、要素を削除、追加したりすることができます。 spliceメソッドの使い方配列.splice(変更する開始位置, 削除数, 追加したい要素); 例: Array[a, (splice), b, c, d]  : Array.splice(1, 0, 1000000); MDN Web Docs "use strict"; { const scores = [80, 90, 40, 70]; scores.splice(1, 0, 1000000); console.log(scores); //実行結果 [80, 1000000, 90, 40, 70] } スプレッド構文 スプレッド構文とは配列の前に...を書くことで配列の要素を展開してくれます。 MDN Web Docs "use strict"; { const otherScore = [12, 14] const scores = [80, 90, 40, 70, ...otherScore]; console.log(scores); //実行結果 [80, 90, 40, 70, 12, 14] } 分割代入 分割代入とは個別に変数に代入することが出来る構文です。 MDN Web Docs "use strict"; { const scores = [80, 90, 40, 70,]; const [a, b, ...others] = scores; console.log(a); //実行結果 80 console.log(b); //実行結果 90 console.log(others);//実行結果 array[40, 70] }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

複数の数値が定義されている配列data1とdata2から「data1とdata2を合わせた平均値」と「平均値以上の数値」を表示せよ

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>課題</title> <script> var data1 = [59, 39, 100, 2, 15, 40, 84, 97]; var data2 = [63, 18, 64, 97, 50, 98]; document.write('<p>【data1】' +data1 + '</p>'); document.write('<p>【data2】' +data2 + '</p>'); var data3 = []; var sum = 0; var ave = 0; for(var i = 0; i < data1.length; i++){ data3.push(data1[i]); } for(var i = 0; i < data2.length; i++){ data3.push(data2[i]); } document.write('<p>【マージ後】' +data3 + '</p>'); for(var i = 0; i < data3.length; i++){ sum = sum + data3[i] } ave = sum / data3.length; document.write('<p>data1とdata2を合わせた平均値' +ave+ '</p>'); document.write('<p>平均値以上の数値は以下</p>'); for(var i = 0; i < data1.length; i++){ if( data1[i] >= ave) document.write('<p>data1:' +data1[i]+'</p>'); } for(var i = 0; i < data2.length; i++){ if( data2[i] >= ave) document.write('<p>data2:' +data2[i]+'</p>'); } </script> </head> <body> </body> </html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LeafletでGPSログ(GPX)地図:移動距離、所要時間、出発時間、到着時間、最高地点、最低地点表示。

LeafletでGPSログ(GPX)地図に、移動距離、所要時間、出発時間、到着時間、最高地点、最低地点表示。 Google マップ、OpenStreetMap、国土地理院地図、Esri World Topo Mapの切り替えが可能。 詳細は以下のブログに。 https://2ndart.hatenablog.com/entry/2021/05/08/114448
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【JavaScript】複数の数値が定義されている配列dataから「各数値」と「40未満の数値がいくつあるか」を表示する

<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>40点未満の人を割り出す</title> <script> var count=0; var data = [59, 39, 100, 2, 15, 40, 84, 97, 39, 41, 39.9, 40.1]; for(var i = 0;i<data.length;i++) { document.write(data[i]+'<br>'); // 配列データの表示 if(data[i]<40){ count++; } } document.write('<h1>40点未満の人は' + count + '人です</h1>'); // 40未満の数値の個数表示 </script> </head> <body> </body> </html>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React】モジュール[ES2015] import/export をちゃんと理解する

モジュール [ES2015]import/export export defaultって何??、なんでこのimportはimport {App} from './src/App.js'って書くのに、こっちはimport hoge from './src/App.js'なの?とか不思議に思ったことはありませんか? (私はあります? ) みんな大好きReactを書く時に、いつも書いているimport exportやimport/exportをちゃんと理解してちゃんと使うべきなので、メモとして残します。 ES2015で登場したJavaScriptのモジュールの機能により、外部のリソースをインポートして利用できるようになりました。 (念のためですが、モジュールはReactの機能ではありません) インポートを利用する前提として、別ファイルで利用したい変数や関数などをあらかじめエクスポートしておく必要があります。 モジュールの機能により、便利な変数や関数を再利用できる、モジュールごとにスコープがあることでグローバル変数名に対して上書きしてしまうリスクを回避できるなど、コードの保守性が高まリます。 Reactでは、モジュールのエクスポートとインポート機能を利用してコンポーネント間における変数や関数のやりとりをします。 エクスポートとインポートには名前付きとデフォルトがあります。 名前付きexportとimport 名前付きエクスポートとインポートについて見ていきましょう。 名前付きexport 別ファイルからアクセスできるようにするため、名前を付けて作成した変数や関数を名前付きエクスポートします。 // 変数 sampleVariable を 宣言 const sampleVariable = "sampleVariable" // 関数 sampleFunc を 宣言 const sampleFunc = () => console.log('Hello,React!'); // 作成した変数や関数をエクスポートすることで、別ファイルにてインポートできるようになる export {sampleVariable, sampleFunc} 名前付きエクスポートでは、作成した変数や関数の前にexportを付けることで、作成時の宣言と同時にエクスポートすることもできます。 // 変数 sampleVariable を 宣言と同時にエクスポート export const sampleVariable = "sampleVariable" // 関数 sampleFunc を 宣言と同時にエクスポート export const sampleFunc = () => console.log('Hello, Vue.js!'); 名前付きimport 次に名前付きエクスポートされた関数や変数を、名前付きインポートします。 namedExportModule.jsからエクスポートされている変数sampleVariableと関数sampleFuncをインポートするには次のように記述します。 import { sampleVariable, sampleFunc } from "./namedExportModule.js"; // 呼び出し console.log(sampleVariable); // sampleVariable console.log(sampleFunc); // sampleFunc() {} console.log(sampleFunc()); // Hello,React! 名前付きexportとimportのエイリアス エイリアスの仕組みを利用することで、宣言済の変数や関数に宣言時と異なる名前を指定してインポートすることができます。エイリアスを付けるためにはasの後に別の名前を指定します。 namedExportModule.jsからエクスポートされている変数sampleVariableをmyVariable、sampleFuncをmyFuncという名前でインポートするには次のように記述します。 import { sampleVariable as myVariable, sampleFunc as myFunc } from "./namedExportModule.js"; // 呼び出し console.log(myVariable); // sampleVariable console.log(myFunc); // sampleFunc() {} console.log(myFunc()); // Hello,React! 名前つきエクスポートをmyModuleオブジェクトとしてまとめてインポートすることもできます。namedExportModule.jsから、MyModuleという名前でインポート、myModule.sampleVariable、myModule.sampleFuncと書いて呼び出します。 // 名前つきエクスポートをmyModuleオブジェクトとしてまとめてインポート // import の後の {} は不要 import * as myModule from "./namedExportModule.js"; // 呼び出し console.log(myModule.sampleVariable); // sampleVariable console.log(myModule.sampleFunc); // sampleFunc() {} console.log(myModule.sampleFunc()); // Hello,React! デフォルトexportとimport デフォルトエクスポートとインポートについて見ていきましょう。 デフォルトexport デフォルトエクスポートは、モジュールごとに1つだけエクスポートできる特殊なエクスポートです。 次のコード例では、関数の作成と同時にデフォルトエクスポートしています。 // defaultエクスポートは、モジュールごとに1つだけエクスポートできる export default function App(){ console.log("Hello,React!"); } export defaultは、ファイルごとに1つだけエクスポートするため、インポートする側も何をインポートすればよいか明確です。そのため関数の作成と同時にデフォルトエクスポートする場合、関数名は省略可能です。 // defaultエクスポートは、モジュールごとに1つだけエクスポートできる // 関数名は省略できる export default function () { console.log("Hello,React!"); } 複数の変数を同時に作成できる変数については、変数宣言と同時にデフォルトエクスポートすることはできないので注意しましょう。 デフォルトimport 名前付きインポートの場合にはimportの後に{}が必要ですが、デフォルトインポートの場合には不要です。 また名前付きエクスポートの場合、指定したモジュールから同じ変数名や関数名を指定してインポートしますが、デフォルトエクスポートの場合、任意の名前をつけてインポートします。 // デフォルトエクスポートされたモジュールをインポートする場合、import {App} ではなく import App // App は任意の名前 import App from './defaultExportModule.js' console.log(App) // App() {} console.log(App()) // Hello,React! 再エクスポート 再エクスポートとは、1度インポートしたモジュールを別ファイルが利用できるようにエクスポートし直すことです。export ... from ...構文を利用して、インポートした直後にエクスポートできます。 再エクスポートは、複数のモジュールからエクスポートされたものをまとめたモジュールを作るときなどに利用されます。 // namedExportModule.js から sampleVariable と sampleFunc をインポートした直後に再エクスポート export { sampleVariable, sampleFunc } from "./namedExportModule.js"; // namedExportModule.js から sampleVariable を myVariable、 sampleFunc を myFunc としてインポートした直後に再エクスポート export { sampleVariable as myVariable, sampleFunc as myFunc } from "./namedExportModule.js"; // 名前つきエクスポートを myModule オブジェクトとしてまとめてインポート import * as myModule from "./namedExportModule.js"; // myModule オブジェクトを再エクスポート export {myModule} // 上記の2行を1行で記述できるようになった[ES2020] // myModule オブジェクトを再エクスポート export * as myModule from "./namedExportModule.js"; HTMLファイルからモジュールを呼び出す HTMLファイルからモジュールを利用しているJavaScriptファイルを呼び出す場合、type="module" 属性が必要です。 html :index.html <script type="module" src="./modules/importModule.js"></script> JavaScriptの基本をしっかり固めて、ますます楽しいReactライフを!!? 参考サイト: - JavaScript Primer - MDN Web Dogs
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

React入門 - Tips3 - スプレッド構文

目次 React入門 スプレッド構文 Reactというよりかは、javascriptの話ですね。 簡単に言うと、配列やオブジェクトを...で簡単に展開できます。 ってことだと思います。 最近よく利用することが多いので紹介しておきます。 こういうサイトを使うと、 サクッと試していただけると思います。 説明はしません。 先程のサイトなどで実行して試してもらうと、すぐ理解できると思います。 スプレッド構文の例(配列) const arr1 = [1,2,3,4]; // 配列のクローン const arr2 = [...arr1]; console.log(arr2); // arr1を展開しつつ、他の値も追加 const arr3 = [0, ...arr1, 5,6,7]; console.log(arr3); // 複数の配列を展開 const arr4 = [...arr1,...arr3]; console.log(arr4); スプレッド構文の例(オブジェクト) const obj1 = { a: 1, b: 2} const obj2 = { ...obj1 } console.log('オブジェクトのクローン1: ' + JSON.stringify(obj2)) const obj3 = { ...obj1, c: 3 } console.log('オブジェクトのクローン2: ' + JSON.stringify(obj3)) const obj4 = { ...obj1, ...{ c: 3, d: 4} } console.log('オブジェクトのマージ: ' + JSON.stringify(obj4)) const obj5 = { ...obj1, b: 5 } console.log('値を上書き: ' + JSON.stringify(obj5)) const obj6 = { ...obj1, ...{ a:9, d: 7 }} console.log('値を上書き2: ' + JSON.stringify(obj6)) 以上
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

関数の引数をオブジェクトのプロパティ名に使用できない話

関数の引数を用いたオブジェクトの出力方法についてつまづいた箇所をメモしました。 どんな問題が発生したのか? apiで情報を取得しようとした際にapiのオブジェクト情報を関数にして取り出そうと考えて以下のような関数を作成しました。非同期関数の説明は今回の内容と外れるので割愛します(asyncの部分)。内容としてはapiの取得した情報はオブジェクトが配列になっており、そのオブジェクトのプロパティ名にquestionやdifficultyなどがあったため、各々の値を関数の引数を用いて取得しようと考えました。まずはquestionの値を取得しようと以下の関数を考えました。 上記の部分です。 main.js 'use strict'; { async function getApi(key) { const res = await fetch('https://opentdb.com/api.php?amount=10'); const users = await res.json(); const items = users.results; const array = []; items.forEach(item => { array.push(item.key); }) console.log(array); console.log(items); } getApi(question); } 重要なのは以下の部分です。 main.js 'use strict'; {  items.forEach(item => { array.push(item.key); }) } 関数の使い方 上記の内容を簡単にわかりやすくすると以下の問題になります。(上のコードは後に私がどの箇所で詰まったかを知るために載せています。今回の記事の内容はこの下から見てもらえればわかりやすいと思います) 配列内にオブジェクトがある状態を考えます。 todosの中身をコンソールに出力する関数arrを作成します。 関数にしてnameとageの値を出力したいと考えました。 まずは私の最初にした失敗例を記述します。 main.js 'use strict'; { const todos = [ {name:'ばなな',age: 32}, {name:'はにわ',age: 12}, ]; function arr(todos) { console.log(todos[0].key); } arr(name); } これでは出力されずエラーになります。 では何故このようにしたのかというと、オブジェクトの出力方法から説明します。 オブジェクトの出力方法 以下配列内のオブジェクトの出力方法です。 値を取得したい場合は以下のように記述します。 main.js 'use strict'; { const todos1 = [ {name:'ばなな',age: 32}, {name:'はにわ',age: 12}, ]; const todos2 = [ {name:'熱海',age: 40}, {name:'伊豆',age: 30}, ]; console.log(todos1[0].name);//出力結果「ばなな」 console.log(todos1[0].age);//出力結果「32」 console.log(todos1[1].name);//出力結果「はにわ」 console.log(todos1[1].age);//出力結果「12」 console.log(todos2[0].name);//出力結果「熱海」 console.log(todos2[0].age);//出力結果「40」 console.log(todos2[1].name);//出力結果「伊豆」 console.log(todos2[1].age);//出力結果「30」 } 上記のように配列が二つあってめんどくさいので関数にまとめようと考えました。 関数の引数の使い方 main.js 'use strict'; { const todos1 = [ {name:'ばなな',age: 32}, {name:'はにわ',age: 12}, ]; const todos2 = [ {name:'熱海',age: 40}, {name:'伊豆',age: 30}, ]; function todos1() { console.log(todos1[0].name);//出力結果「ばなな」 console.log(todos1[0].age);//出力結果「32」 console.log(todos1[1].name);//出力結果「はにわ」 console.log(todos1[1].age);//出力結果「12」 } function todos2() { console.log(todos2[0].name);//出力結果「熱海」 console.log(todos2[0].age);//出力結果「40」 console.log(todos2[1].name);//出力結果「伊豆」 console.log(todos2[1].age);//出力結果「30」 } todos1(); todos2(); } 上記のように関数にすることで出力が楽になります。 更にまとめるために関数の引数を使用すると以下になります。 main.js 'use strict'; { const todos1 = [ {name:'ばなな',age: 32}, {name:'はにわ',age: 12}, ]; const todos2 = [ {name:'熱海',age: 40}, {name:'伊豆',age: 30}, ]; function arr(item) { console.log(item[0].name); console.log(item[0].age); console.log(item[1].name); console.log(todos1[1].age); } arr(todos1); arr(todos2); } これで更に簡単に書くことができます。 長くなりましたが、ここから本題です。 それならnameとageの部分も引数にしたらもっと簡単に書けるよね?って考えました。 説明のためにtodos2はいらないので割愛しました。 main.js 'use strict'; { const todos1 = [ {name:'ばなな',age: 32}, {name:'はにわ',age: 12}, ]; function arr(item) { console.log(todos[0].item); console.log(todos[1].item); } arr(name); arr(age); } 上記のようにオブジェクトの値のプロパティ名を関数の引数にするとエラーになってしまいます。 結論 関数の引数をオブジェクトのプロパティ名に使用することはできない 長くなってしまいましたが、最後までお読みいただきありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

IntersectionObserver APIを使った遅延読み込み 実装方法の概要メモ

IntersectionObserverAPIを使用するメリット Intersection(交差点)に達した時だけイベントを走らせてくれるのでパフォーマンスが良い。 (画面スクロール位置を読み込み続けるようなことが避けられる) IntersectionObserverAPIの概要 遅延読み込みをしたい要素(ターゲット)が指定した地点に交差するたびにコールバック関数を呼び出す。 実装方法の概要 ①遅延読み込みをしたい要素(ターゲット)を取得 例 const section = document.querySelector('.section'); ②オブジェクトを記載 例 const options = { root: null, //viewport全体を監視対象にする場合null threshold: 0.15, //0~1で指定。ターゲット要素の何%が見えているか } ③コールバック関数を記載 例 const callbackfunc = function(entry) { if(!entry[0].isIntersecting) return; //交差してない時はその時点でreturnする(交差してない時はentry[0].isIntersectingはfalseになっています) entry[0].target.classList.remove('section--hidden'); //行いたい処理を記載。ちなみにentry[0].targetにはターゲット要素の情報が入っています observer.unobserve(entry[0].target); //一度実行したらそれ以降ターゲットが交差してもイベントを走らせないようにする } 引数のentryにはAPIから返ってきたオブジェクトが配列で入る。(console.log(entry[0])でみてみると分かりやすいです!) ④コンストラクター定義 例 let observer = new IntersectionObserver(callbackfunc, options); 第一引数に③で記載したコールバック関数、第二引数に②で記載したコールバックを実行したいタイミング等を記載したオブジェクトを渡します。 ⑤コンストラクターを実行 例 observer.observe(section);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

reacthooksを利用して楽天APIで簡単ホテル検索

apiを利用したことがなかったので、勉強のために実装したので備忘録 開発環境 macOSX Catalina バージョン10.15.7 VisualStudioCode ディズニーという文字が入ったホテルのリストを取得して、ホテル名とアクセスを表示する Promiseオブジェクトが - awaitとすることでjsonとしてデータ取得ができる。 - asyncにしている関数内ではないとawaitは使用できない - asyncは関数の定義に含めなければならない(非同期処理の指定だから) - useEffect内で関数を実行することにより、任意の関数内でasyncを実行できる 上記の情報を考慮して記述 import './App.css'; import axios from 'axios'; import { useEffect, useState } from 'react'; const getHotels = () => { const q = "ディズニー" return axios.get(`https://app.rakuten.co.jp/services/api/Travel/KeywordHotelSearch/XXXXXXXXXXXXXX?&applicationId=XXXXXXXXXXXXXXXXX&format=json&keyword=${q}`) } const App =()=> { const [hotels, setHotels] = useState([]) useEffect(async () => { const res = await getHotels() const hotels = res.data setHotels(hotels.hotels) }, []) // mapがうまくいかない仮説:配列になってない console.log(hotels) // console.log(hotels[0].hotel[0]) return ( <div className="App"> {hotels.length > 1 && // mapする時にkeyidを入れることで、後から指定してスタイル変更などができなくなる hotels.map((hotel, id)=>{ console.log(hotel.hotel[0]) return( <div className="hotel" key={id}> <div className="hotel-name">{hotel.hotel[0].hotelBasicInfo["hotelName"]}</div> <div className="hotel-access">{hotel.hotel[0].hotelBasicInfo["access"]}</div> </div> ) }) } </div> ); } export default App;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Safariで動画を再生したいがレンタルサーバーがRange Requestに対応していない場合

本題 注意: この方法は小さいサイズの動画のみに使用できます。でかいファイルを使用すると再生が可能になるまでとんでもない時間が掛かったり、メモリ不足で再生できなかったりする事があります。また、ここに載っているコードをそのまま使うとモバイル回線ユーザーに迷惑です。よく考えて使いましょう。 Safariで動画を再生するにはRange Requestが必要 Safariで動画を表示する際、サーバーのHTTP Range Request対応が必須になっている なのだが、レンタルサーバーによっては対応していなかったりする。 その時の回避方法 <html> <head> </head> <body> <video id="video"></audio> <script> var video = document.getElementById("video"); var request = new XMLHttpRequest(); var requestURL = "test.mp4"; //動画のurlを挿入 request.open("GET", requestURL, true); request.responseType = "blob"; request.onload = function () { var video_src = window.URL.createObjectURL(this.response); video.src = video_src; }; request.send(); </script> </body> </html> 一回XMLHttpRequestで取得する。(fetch,ajax等でもOKというかこっちの方が良いかも。IE対応位?) その後、Blob urlを生成して、videoタグのsrcに設定
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む