20210917のJavaScriptに関する記事は17件です。

?インターネット老人?のためのホームページ(死語)リフォーム術

この記事の対象 ~00年代初頭にホームページ作っていて、現在放置中……という人、あるいはそういう人から依頼されて昔のフォルダを受け取った人が対象になります。 スキル的にはjQuery(Bootstrap)なら何とか勢~(バックにも関心がある)SPA初心者勢を想定しています。 手順 1.本当に自前でやる必要があるか考える Webサービスが氾濫する現在、現在サイトにある機能を本当に自前で提供する必要があるか考えましょう。 日記 まぁ最有力はブログへの移行ですね。黒歴史を消す人も多いですが、逆に過去の日記みたいなもんで、残しておきたいと思う人もいるかと思います。ていうかホームページは放置してて日記にあたる部分だけ流石にブログに移行してる人も多いかと思いますね。 何らかの理由でブログに移行できない、不適切だと思う場合はスクレイピングして文章データをmdやらjsonに纏めて、今流行りのGatsbyあたりに手を出すのも良いのではないでしょうか。 イラスト これは現行のシェアとしてもシステム的にもpixivへ丸投げするのが一番妥当かと思います。 画像ギャラリー系のライブラリを入れて自前のサイトで見せることもできますが、pixivと二重管理になって放置する可能性が高いかと。 小説 これは難しい。投稿サイトは昔から山ほどありますが、なろうを始め色がついてたりするので……。(2~3年で閉鎖しないという意味で)安定してて、ジャンル問わずで一強みたいなのがあればいいんですが。 あと00年代初頭って「Web小説ならではリッチ表現を目指そう」的な流れもあって、小説本文中に挿絵画像ぶちこんだり、JSやフォントタグ弄りやってたりする小説もそこそこあるので、そこらへん守る必要がある(ギミックが前提)があったり、その系譜を現代の技術で更に進化させたいという気骨の方は自前も全然アリだと思います。 掲示板 これも難しい。 SNSの直接交流やハッシュタグ交流で代替できちゃってそうで完全には出来てないので、「アカウントを持たなくても書ける、個人管理のフォーラム」のニーズは確かにあるんですよ。 ただ当時でいうところのCGI(死語)がPerl/PHP+ただのログファイルで出来てたのに対し、現在はバックエンド系言語(Ruby/PHP等) + フレームワーク + DBが普通かつ、今時の設計だとバックエンドはAPIのみとなって、表示面はフロントエンドでやる必要があると敷居上がりまくってるんですよね。真っ向からやるにはバックエンドの勉強をガッツリしないときついかと。 OSSのフォーラムアプリも調べましたが、需要がニッチ化したのと、今だとバックエンドAPI+フロントエンドのセット提供になり、なおかつ密結合にならざるを得ないので、今一つ開発が盛り上がってない印象を受けました。現行問題なく動いてるのならそのまま+SNS交流で逃げてもいいのではという感触はありますね。 ゲーム系チャットアプリのイメージが強いですが、discordとかで丸投げできないかなーというのは考えたりしますが、使ったことがないので(ry チャット 掲示板と同じくdiscordに丸投げできないかな~(ry 2. WebスクレイピングしてHTMLから実データを取り出して整形する 昔はHTMLファイルの中に装飾データ(fontタグ)や実データを含めて全てが詰まっていたので、解析してオブジェクトの形に纏める(=スクレイピング)のは必須ですね。DOMを、tableタグを、ひたすら掘り続けるのだ……⛏ ゲーム攻略サイトとかデータ系サイトはここの工数を覚悟しといた方がいいです。抽出もさることながら、使い勝手が悪いとか色々データ整形したくなると思うので、延々とデータ整形することになります(体験談) ところでスクレイピングといえばPython (というかBeautifulSoup)がオススメとされていますが、「Webフロントエンド系の技術は仕方ないにせよ、Pythonまで手出すのはキツイ……」と思う方も多いかと思います。 そういう方は、そもそも自分のサイトであることを活かし、 ローカルの開発サーバー(手っ取り早いのはVSCodeの拡張機能のLiveServerとか)を用意 自サイトにJSのスクレイピングプログラムを仕込んでデータオブジェクトを作る 以下のJSでJSONファイルを生成してダウンロードさせる export const downloadJsonFile = (data: unknown, baseName: string): void => { const blob = new Blob([JSON.stringify(data)], { "type": "application/json" }) const fileName = `${baseName}.json` const url = URL.createObjectURL(blob) //aタグを生成し、クリックしたことにしてDLさせるというアプローチを取る //かなり無理くり感あるが現状これがベストプラクティスな模様。 const aTag = window.document.createElement("a") document.body.appendChild(aTag) aTag.download = fileName aTag.href = url aTag.click() aTag.remove() URL.revokeObjectURL(url) //生成したURLが保持されてしまうので解放する } こういう感じで対処しましょう。ちなみに自分はJSでファイルを生成→DLさせられるのを知らなくて、途中までconsole.logに吐き出し→エディタにコピペでせっせとJSONファイルを作ってました? 参考:JavaScriptでファイルダウンロード処理を実現する - Qiita 3.旧サイトとの連携を気にしつつ好きな技術で作り直す わざわざ作り直したいと思うぐらいですし、サイトの規模としてはそこそこ大きいですよね?となると、旧サイトと繋がりを意識しつつ徐々に入れ替えていく形を取る方が良いかと思います。 技術面に関してはお好きな技術で……としか言いようがありませんが、最近のトレンドから言うと大規模→React/小規模→Vue or Svelteという形になるのかなと思います。 また元が静的なウェブサイトという特性からリフォーム後も静的な特性が強いかと思われるので、SSGとの親和性が高いのかな~とも感じます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[初学者]javascriptのクロージャー

はじめに while文とかfor文とか~文あるけど、あれは関数なのか?の疑問から生まれたものです。 文の正体は分かりませんでした。 目次  1.ループ文の謎  2.ガベージコレクション? ガレージコレクションなら知ってます。  3.静的スコープとはなんですか?  4.クロージャー ループ文の謎 ループ文とはご存知でしょうか?基礎で出てくるあれです。 for(let i = 0; i < 5; i += 1) { console.log(i); } // 0,1,2,3,4と出ます。 基礎の基礎のループ文。 ではあえて関数で書くとどうやって書くのかを疑問に持ちました。 let a = 0; function A() { a += 1; console.log(a); }; A(); //1 A(); //2 A(); //3 A(); //4 A(); //5 普通に出ますね。ではlet a = 0;を関数内に入れてみましょう。 function A() { let a = 0; a += 1; console.log(a); }; A(); //1 A(); //1 A(); //1 A(); //1 A(); //1 関数内に入れたら数字が全て1になってしまいました。 私みたいな初学者には、関数の中と外なんて似たりよったりやんと思いますが結果から見ても違います。 ガベージコレクション? ガレージコレクションなら知ってます。 簡単に言うと必要なタイミングで不要なデータをメモリから解放するものです。 人間が不要な記憶を消すようなもので、ここで重要なのは不要と判断されるタイミングです let A = 1; A = 2; //変数Aに2が代入されたことにより1が解放される。 console.log(A); //2 これは関数でも起きます。解放されるのが先程の変数を中に入れたループ関数です。 ここで思うのは関数が終わったタイミング変数のデータは解放されると思いますが違っていて 次に解放されないパターンです function A() { let a = 0; return a; }; const B = A(); console.log(B); //0 やってることはリターンで返して変数に入れてるだけです。( )は関数の実行をします。 const B = A( );としているので関数自体は実行されてますが結果としてはコンソールに0と表示されます。 実際にデータが解放されるのはどこからも参照されなくなったときに解放されます。 この場合関数が終了してもconst Bに参照されてるため消えません。 静的スコープとはなんですか? 一言でいえば変数の参照は変わらないってだけです。 javascriptは静的スコープですが他言語では動的スコープもあるらしいです const a = 1; function A() { console.log(a); } function B() { const a = 2; A(); } B(); //1 loa(a)は最初に上の1を参照します。その後別の関数に値の変わった変数があるのに結果は1が出る クロージャー 片やデータの解放、片や参照元が変わらない。それで何が出来るんじゃいという話。クロージャーになります。 これも簡単にいうと関数にデータ保持させたろってことです。 function A() { let count = 0; function B() { count += 1; return count; } return B; } const C = A(); console.log(C()); //1 console.log(C()); //2 console.log(C()); //3 console.log(C()); //4 console.log(C()); //5 まぁこれだけ見るとショボって思うでしょう。私も思います。 グローバル変数が減るのと関数に状態を持たれるのがメリットとのことです。 試しに作ったけど、うん。何がすごいかわからない。入力値が5に対しての関数です。 function A(a) { return function B(b) { if(a > b){ console.log(a + "の方が大きい!"); } else if (a < b) { console.log(a + "より小さい!"); } else { console.log("値が同じ!"); } } } const A5 = A(5); A5(2); //5の方が大きい! A5(4); //5の方が大きい! A5(6); //5より小さい! A5(8); //5より小さい! A5(5); //値が同じ! おわり 軽い気持ちで調べたらえらくかかりました。クロージャーの凄さは分からなかったですがいつか使うでしょう。 何か個人的に画期的にものが思いついたらまた書きます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptから学ぶSwiftで新しく対応したasync、await

Swiftでasyncとawait機能が対応した。 自分自身Swift以外の言語の素養がなく、asyncとawaitとはなんぞやというところから勉強したのでその記録 async、awaitの学習教材としてJavaScriptの言語仕様を見ている 前提知識として、JavaScriptでのasync await Promise型  非同期処理の戻り値であり、非同期が完了するまで、その実態はundefinedになる。 戻り値が返ってきたら、その戻り値がラップされた型となる。戻り値が返ってきたタイミングで自身のthen()メソッドを呼ぶ getDate() .then(function(data) { return getYear(data) }) .then(function(year) { return getSomething(year) }) .then(function(item) { getAnotherThing(item) }) async 非同期の戻り値(Promise)が返ってくる (asyncで呼ばれるメソッドは基本バックグラウンドで実行される) async function(){ getDate() .then(function(data) { return getYear(data) }) .then(function(year) { return getSomething(year) }) .then(function(item) { getAnotherThing(item) }) }.then(function(data){ // 戻り値がPromiseなので更なるthenを実行することもできる }) await asyncな処理( Promiseが返ってくるような処理)において、Promiseの値が決定するまでその場で待機してくれる function myPromise(num) { return new Promise(function(resolve) { setTimeout(function() { resolve(num * num) }, 3000) }) } async function myAsync() { // ここで約3秒待機する const result = await myPromise(10); // ここは実行されない console.log(result); } myAsync(); awaitの使い所  then()で繋げなくて良くなる myPromise(10).then(function(data) { console.log(data); return myPromise(100) }).then(function(data) { console.log(data); return myPromise(1000) }).then(function(data) { console.log(data); }) // これをawaitを使うと下のようにかける! async function myAsyncAll() { console.log(await myPromise(10)); console.log(await myPromise(100)); console.log(await myPromise(1000)); } myAsyncAll(); Swiftで だいたい一緒 asyncのなかでUIを触りたいときはMainActor.runでメインスレッドでの実行を明示的にする enum CustomError:Error { case badURL case badImage } func fetchData(urlString:String) async -> Result<CustomModel,CustomError>{ let request = URLRequest(url: URL(string: urlString)!) guard let (data, response) = try? await URLSession.shared.data(for: request, delegate: nil),(response as? HTTPURLResponse)?.statusCode == 200 else { return .failure(.badURL) } let model = convertDataToModel(data: data) return .success(model) } struct CustomModel{ } func convertDataToModel(data:Data)->CustomModel{ return .init() } // 一回のみの実行 (fetchDataの処理が完了したら、switch文の中身を実行) func executeFetchData() async{ switch await fetchData(urlString: "http://example.com"){ case .success(let model): print(model) await MainActor.run{ [weak self] in self?.label = model.text } case .failure(let error): print(error) } } // 複数回の実行 func executeMultipleFetchData() async { switch await fetchData(urlString: "http://example.com"){ case .success(let model): print(model) await MainActor.run{ [weak self] in tableViewSectionTitle[0] = model.text } switch await fetchData(urlString: "http://example2.com"){ case .success(let model2): await MainActor.run{ [weak self] in tableViewSectionTitle[1] = model2.text } case .failure(let error): print(error) } case .failure(let error): print(error) } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Next.js+tailwindcssにgoogleFont読み込ませる!

googleFontをtailwindで使用する為の設定の仕方を紹介します。 こちら課題の一環でLGMTを一定数取らないといけない試験でぜひLGMTを押していただけるとありがたいです。 googlefontでフォントを選択して@importの方でコピーする! styles/globals.scssに読み込む @tailwind base; @tailwind components; @tailwind utilities; //読み込む @import url('https://fonts.googleapis.com/css2?family=Lato:wght@700&family=Noto+Sans+JP:wght@500&display=swap'); tailwind.config.jsに読み込む module.exports = { theme: { extend: { fontFamily: { roboto: ["Roboto"], }, }, }, } 使用する。 font-roboto font-(設定したやつ)で使える <div className="font-roboto"> テキスト </div>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Alpine.jsを始めよう!

はじめに みなさま、Alpine.jsをご存知でしょうか? まあ、ものすごく簡単に言うと かんたんなVue.js です。 ただでさえJSフレームワークの中では比較的簡単目なVue.jsですが、さらにかんたんです。 どんぐらいかんたんかというと jQueryと同じかそれ以上 ってレベルです。 しゅごい! 今回はこれを紹介していこうと思います。 JSフレームワークとは SPAとかJSでなんかすごいことやりたいときに入れるやつ 、くらいの雑な認識で大丈夫です。 いわゆる3大フレームワークと言われているのがお互い影響し合いつつ、競い合っている感じです。 概ねデータバインディング(JS内の変数の値をそのまま出したり、formから書き込んだり)がしたいときに使われることが多いかと思います。 Angular おそらく一番初めに出たJSフレームワーク Google製で、Google内で燃えに燃えている案件を鎮火させる過程で生まれたリアル銀の弾丸 ver1の頃は「AngularJS」だったが、2以降ほぼ別物になったので「JS」が名前から外れた React Facebook製 プログラマライクな作りなおかげか、おそらく最も人気がある ふだんJSを書かない人には死ぬほど敷居が高い Vue.js GoogleでAngularを使っていたエヴェン・ヨーによって開発された 感覚的にはAngularとReactのいいとこ取りって感じ .vueファイルにhtmlもjsもcssもまとめて書いちゃう Vue.jsと違うところ、同じところ v2の日本語版ドキュメントでも白状されていますが、 このツールのシンタックスは、ほぼ完全に Vue(それと、Angular による拡張)から借用しています。 ということで、結構シンタックスが似ています。 普段Vue.jsを使っている、あるいは挫折してしまったという人には朗報な気がします。 違うところ マスタッシュ記法 {{ }} でデータバインディングをしない Vue.jsでは hoge.vue <template> <div> <p>{{ hoge }}</p> </div> </template> <script> export default { data() { return {hoge: 'ほげ'}; } } </script> みたいに書くと ほげ って表示されます。 script の data のところで返している hoge を template の {{ hoge }} のところに当てはめています。 これがいわゆるマスタッシュ記法なんですが、これがAlpine.jsだとできません。 ちなみにAlpine.jsで同じことやると hoge.blade.php <div x-data="{hoge: 'ほげ'}"> <p x-text="hoge"></p> </div> だけでいいのです。すごくないですか? ディレクティブのprefixが違う 上の例でもチラチラ出てますが、 x-data とか x-text ってところですね。 Vue.jsに v-data はないのですが、 v-text はありますよね。 そう、Vue.jsで v- にしていたところが x- になっています。 Vue.js脳の人はそのままxにしていただければいいってことですね。 なんでXなのかは知りません。エェーックス!! .vueファイルを作らなくていい Vue.jsでも.vueファイル作ることが必須ではないのですが、作らずにコンポーネントを作ろうとすると大きな困難に立ち向かうことになるので、だいたい作ると思います。 Alpine.jsはhtmlソースに直接ガンガン書けるので大体のケースでは外部ファイルでわざわざJS書く必要すらありません。 同じところ シンタックスシュガーがほぼそのまま使える まあ、とくに on と bind のところですね。 こいつらは @ と : でいけます。おかげさまでVue.js書いてる感が出て楽しいです。 タブインターフェースを作ってみよう! Alpine.jsをつかってよくあるタブインターフェースを作ってみましょう! Alpine.jsは今流行りの tailwindcss とセットで語られることが多いので、それも使ってみましょう。 土台のHTMLをつくる tailwindcssのドキュメントに HTML starter template とかちょうど良さそうなのがあるので、これを引っ張って、そこにtailwindcssとAlpine.jsをCDNから引っ張ってくるコードを足してみました。 index.html <!doctype html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet"> <script defer src="https://unpkg.com/alpinejs@3.3.4/dist/cdn.min.js"></script> <title>Alpine tab sample</title> </head> <body> </body> </html> 次に tailwindcomponents というサイトに良さげなタブの作例があるのでこちらを参考にさせてもらいます。今回はこちらを使用させていただきました。 https://tailwindcomponents.com/component/simple-tab これらを使って桃太郎と浦島太郎を切り替えるタブを作ってみました。 htmlだけだとこんな感じです。 index.html <!doctype html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <script defer src="https://unpkg.com/alpinejs@3.3.4/dist/cdn.min.js"></script> <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet"> <title>Alpine tab sample</title> </head> <body> <div class="p-8"> <div style='border-bottom: 2px solid #eaeaea'> <ul class='flex cursor-pointer'> <li class='py-2 px-6 bg-white rounded-t-lg'>桃太郎</li> <li class='py-2 px-6 bg-white rounded-t-lg text-gray-500 bg-gray-200'>うらしまたろう</li> </ul> </div> <div> むかし、むかし、あるところに、おじいさんとおばあさんがありました。まいにち、おじいさんは山へしば刈かりに、おばあさんは川へ洗濯せんたくに行きました。  ある日、おばあさんが、川のそばで、せっせと洗濯せんたくをしていますと、川上かわかみから、大きな桃ももが一つ、 「ドンブラコッコ、スッコッコ。 ドンブラコッコ、スッコッコ。」  と流ながれて来きました。 </div> <div> むかし、むかし、あるところに浦島太郎という心やさしい漁師が住んでいました。 ある日のこと、浜辺を歩いていると一匹の亀が子供達にいじめられているのを見ました。 「これこれ、かめをいじめたらかわいそうだよ。はなしておやり」 そう言って浦島太郎は子供たちから亀を助けてやりました。 </div> </div> </body> </html> 現状話が混ざってしまってますね。ここにAlpine.jsのロジックを入れていきましょう。 Alpine.jsの仕掛けをいれる まずは x-data ディレクティブを入れます。 これは一番てっぺんのdivに入れてあげます。 x-data は とっておきたいデータを入れておく場所 です。 この辺に入れます <body> <div class="p-8" x-data="{open: 1}"> x-data の値のところはまんまjsのobjectですね。 次にイベントハンドラを入れていきましょう。 タブのところですね。 <div style='border-bottom: 2px solid #eaeaea'> <ul class='flex cursor-pointer'> <li class='py-2 px-6 bg-white rounded-t-lg' @click="open = 1">桃太郎</li> <li class='py-2 px-6 bg-white rounded-t-lg' @click="open = 2">うらしまたろう</li> </ul> </div> @click ってところがイベントハンドラです。clickって言っているくらいなので ここをクリックしたら ってところです。 値のところはどんな動作をさせるか、なんですが、ここでは x-data に入れている open の値を変えているよーっていう動作を入れています。 これでタブをクリックすれば内容が切り替わるようになったのですが、タブの色が切り替わらないので、切り替わるロジックを入れてやります。 <div style='border-bottom: 2px solid #eaeaea'> <ul class='flex cursor-pointer'> <li class='py-2 px-6 bg-white rounded-t-lg' @click="open = 1" :class="{'text-gray-500 bg-gray-200': open !== 1}">桃太郎</li> <li class='py-2 px-6 bg-white rounded-t-lg' @click="open = 2" :class="{'text-gray-500 bg-gray-200': open !== 2}">うらしまたろう</li> </ul> </div> :class ってところが ロジックで適用するクラスを切り替えているところ になります。 値のobjectのvalueは判定式になっていて、そこが true のときにkeyに書いてあるクラスが適用されます。 できあがり 最終的なソースはこんな感じになります。 index.php <!doctype html> <html> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <script defer src="https://unpkg.com/alpinejs@3.3.4/dist/cdn.min.js"></script> <link href="https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css" rel="stylesheet"> <title>Alpine tab sample</title> </head> <body> <div class="p-8" x-data="{open: 1}"> <div style='border-bottom: 2px solid #eaeaea'> <ul class='flex cursor-pointer'> <li class='py-2 px-6 bg-white rounded-t-lg' @click="open = 1" :class="{'text-gray-500 bg-gray-200': open !== 1}">桃太郎</li> <li class='py-2 px-6 bg-white rounded-t-lg' @click="open = 2" :class="{'text-gray-500 bg-gray-200': open !== 2}">うらしまたろう</li> </ul> </div> <div x-show="open === 1"> むかし、むかし、あるところに、おじいさんとおばあさんがありました。まいにち、おじいさんは山へしば刈かりに、おばあさんは川へ洗濯せんたくに行きました。  ある日、おばあさんが、川のそばで、せっせと洗濯せんたくをしていますと、川上かわかみから、大きな桃ももが一つ、 「ドンブラコッコ、スッコッコ。 ドンブラコッコ、スッコッコ。」  と流ながれて来きました。 </div> <div x-show="open === 2"> むかし、むかし、あるところに浦島太郎という心やさしい漁師が住んでいました。 ある日のこと、浜辺を歩いていると一匹の亀が子供達にいじめられているのを見ました。 「これこれ、かめをいじめたらかわいそうだよ。はなしておやり」 そう言って浦島太郎は子供たちから亀を助けてやりました。 </div> </div> </body> </html> 桃太郎時 うらしまたろう時 まとめ 以上、Alpine.jsのしょうかいでした! こんな恐ろしく簡単に、サクッととんでもないことできちゃうの、熱くないですか?
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

かんたんスムーススクロール TweenMax ScrollPlugin

TweenMaxとTweenMaxのScrollPluginを使ってページ全体を簡単に慣性スクロールさせる方法のメモです。 import gsap from "gsap"; import { ScrollToPlugin } from "gsap/all"; gsap.registerPlugin(ScrollToPlugin); function smoothScroll(toBottom) { let direction = "-=100"; if (toBottom) { direction = "+=100"; } gsap.to(window, { scrollTo: { y: direction, autoKill: true }, duration: 1, }); } let startY; function touchstart(e) { startY = e.changedTouches[0].pageY; } function touchmove(e) { e.preventDefault(); const moveY = e.changedTouches[0].pageY; if (moveY < startY) { smoothScroll(true); } else { smoothScroll(false); } } function mousemove(e) { e.preventDefault(); if (0 < e.deltaY) { smoothScroll(true); } else { smoothScroll(false); } } document.addEventListener("touchstart", touchstart, { passive: false }); document.addEventListener("touchmove", touchmove, { passive: false }); document.addEventListener("mousewheel", mousemove, { passive: false });
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

かんたん慣性スクロール TweenMax

TweenMaxと同ライブラリのScrollPluginを使ってページ全体を慣性スクロールさせる方法のメモです。 おしゃれサイトによくある、マウスホイールを動かすとゆっくり画面のスクロールが終わるやつの簡単な実装です。 import gsap from "gsap"; import { ScrollToPlugin } from "gsap/all"; gsap.registerPlugin(ScrollToPlugin); function smoothScroll(toBottom) { let direction = "-=100"; if (toBottom) { direction = "+=100"; } gsap.to(window, { scrollTo: { y: direction, autoKill: true }, duration: 1, }); } let startY; function touchstart(e) { startY = e.changedTouches[0].pageY; } function touchmove(e) { e.preventDefault(); const moveY = e.changedTouches[0].pageY; if (moveY < startY) { smoothScroll(true); } else { smoothScroll(false); } } function mousemove(e) { e.preventDefault(); if (0 < e.deltaY) { smoothScroll(true); } else { smoothScroll(false); } } document.addEventListener("touchstart", touchstart, { passive: false }); document.addEventListener("touchmove", touchmove, { passive: false }); document.addEventListener("mousewheel", mousemove, { passive: false });
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【エラー】TypeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D': Value is not of type 'long'.(執筆途中)

はじめに Dicomデータをsagittal, coronal表示させる時にタイトルのエラーが出たので記録する。 エラーについて :の右側を読むと、「long型じゃありません」とのこと。つまり、該当箇所の変数の型が本来ならlong型のところそうなってないみたい。 左側の”TypeError: Failed to execute 'getImageData' on 'CanvasRenderingContext2D'”については初めて見るエラーだったので詳しく調べてみることにする。 CanvasRenderingContext2D.getImageData() getImageDataというのは、Canvas2D APIのCanvasRenderingContext2Dというメソッドにある関数である。 この関数は、canvasで指定された部分の基礎となるピクセルデータを表すImageDataオブジェクトを返す。 この関数は引数に抽出するImageDataのx座標、y座標、幅、高さを持つことができます。 MDN Web Docs: CanvasRenderingContext2D.getImageData() この関数に表示させたいImageDataの各座標を渡して、ImageDataを出力するイメージになる。 エラー全体 上記のことを踏まえると今回出ているこのエラーは、getImageData()に渡している引数がlong型になっていないということになるのか...? 実際にこのエラー分をまるまるコピペしてググってみたところ、 ローカル環境で参照する場合はセキュリティ機構の使用によりエラーが発生する Webサーバーを配置してhttpでアクセスする必要がある。 後者の方は、実際にhttpアクセスで読み込んだデータを表示しているシステムを参考にしているの考えにくいと感じた。 最後に かなり雑な調べ方になってしまったが、エラーの概要は掴むことができた。 渡ってきたデータをlong型に変換する方法、実際にサーバーを立ててデータを読んでみる方法、両方とも試してみてどうだったのか、後日記載することにする。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScript(関数)

はじめに 基本に立ち戻りJavaScriptを深く理解しよう関数編 関数とは実行可能なオブジェクトである コールバック関数 他の関数に引数として渡される関数 function hello() { console.log('hello') } function fn(cb) { cb(); } //引数に関数helloを渡す fn(hello); 'hello' //setTimeoutもよく使うコールバック関数 //第一引数に実行する関数、第二引数に何ミリ秒待つかを指定 setTimeout(hello, 2000) this 呼び出し元のオブジェクトへの参照を保持するキーワード thisは オブジェクトのメソッドとして実行される場合→ 呼び出し元のオブジェクト 関数として実行される場合→ グローバルオブジェクト const name = 'Tim' const person = { name: 'Tom', hello: function() { console.log('Hello ' + this.name); } } //personオブジェクトのhello関数を実行 //thisは呼び出し元であるpersonを指す person.hello(); //Hello Tom //personオブジェクトのhello関数のみを取り出しコピー //定数ref->hello関数の状態 const ref = persion.hello //呼び出し元のオブジェクトは定数ref //hello関数のみを取り出しているのでnameプロパティは存在せずthis.nameはグローバルのTimを指す ref() //Hello Tim コールバック関数でのthis コールバック関数内でも同様に引数に関数を渡すのでpersonオブジェクトのnameは参照できない const name = 'Tim' const person = { name: 'Tom', hello: function() { console.log('Hello ' + this.name); } } function fn(ref){ ref() } fn(person.hello) //Hello tim 引数に関数ではなくオブジェクト全体を渡せば変数ref→personオブジェクトへの参照 ref.helloではオブジェクトのメソッドとして実行できるのでthisによりpersonオブジェクトのnameが参照できる const name = 'Tim' const person = { name: 'Tom', hello: function() { console.log('Hello ' + this.name); } } function fn(ref){ ref.hello() } fn(person) //Hello Tom bind, apply, call 少しややこしいthisの参照 これを簡単に記述することができるのがbind, apply, call bind bindによってthisの参照先を指定できる また第二引数を指定することでthisの参照先だけでなく引数を指定することもできる 後述するcall,applyとの違いとしてbind使用時点では実行はされないという点がある const name = 'Tim' const person = { name: 'Tom', hello: function() { console.log('Hello ' + this.name); } } //実行されるhello関数のthisの参照先をpersonオブジェクトと指定 const helloTom = person.hello.bind(person); function fn(ref){ ref.hello() } fn(helloTom); //Hello Tom //引数指定 function a(name) { console.log('hello' + name) } //定数bによって関数aを実行した時の引数はJohnに指定 const b = a.bind(null, 'John'); //実行時の引数よりbindが優先される b('Tim'); //hello John apply, call bindと同様にthisの参照先を指定できるが、違いとして2つは即時実行される またapplyは第二引数の配列を持たせられるという特徴もある const arry = [1,2,3,4,5] //即時実行 //Math.max()の引数にarryを渡すことでarryの中から一番大きい数字を返す const result = Math.max.apply(null,arry) //補足 //正直これでいい //const result = Math.max(...arry); console.log(result) //5 コンストラクター関数 新しくオブジェクトを生成するための雛形となる関数 new をつけて実行することでオブジェクトが生成される(インスタンス) //雛形 function Person(name,age){ this.name = name; this.age = age; } //インスタンス化 const bob = new Person('Bob',18) const jhon = new Person('Jhon',20) プロトタイプ コンストラクター関数にプロパティを追加する Preson.prototype.hello = function() { console.log('hello ' + this.name) } 雛形であるコンストラクター関数にhelloという無名関数の参照が渡ってくる 実は動作としては下記と同じである //コンストラクター関数にメソッドへの参照ではなくメソッド本体を待たせた場合(動作は同じ) function Person(name,age){ this.name = name; this.age = age; this.hello = function(){ console.log('hello ' + this.name) } } ではなぜprototypeでコンストラクター関数の外部からメソッドを定義するのか 答えはメモリの効率化である コンストラクター関数の内部でメソッドを定義するとインスタンス化ごとに同じ内容のメソッドが何度も生成されてしまう(無駄) prototypeにより外部でメソッドを定義するとメソッドは1つであり続け、インスタンスごとに生成されるのはその1つのメソッドへの参照である 結果メモリの効率化につながる コンストラクター関数の戻り値 コンストラクター関数の戻り値が設定されていない場合はthisの値とprototypeの参照をオブジェクトとして返す 戻り値returnにオブジェクトを指定した場合はインスタンス化時にはそのオブジェクトが返される このときprototypeの参照も反映されない function Person(name,age){ this.name = name; this.age = age; return{ neme: 'Jhon', age: 20 } } Person.prototype.hello = function(){ console.log('hello') } //Bob,18ではなくJhon,20が返される //prototypeの参照も反映されない const bob = new Person('Bob',18) instanceof どのコンストラクター関数から生成されたオブジェクトか確認できる instanceofの内部処理としてはオブジェクトのprototypeの等価性で判断する function F(a, b) { this.a = a; this.b = b; } F.prototype.c = function() {} const instance = new F(1,2); //instanceのprototypeとFのprototypeが同じだとtrueと判断する console.log(instance instanceof F) // true 実際は以下のようにinsstanceofによって条件分岐を行うことができる if文で引数が配列かオブジェクトか判断し処理を振り分ける function fn(arg) { if(arg instanceof Array) { arg.push('value'); } else { arg['key'] = 'value'; } } 関数コンストラクター 新しい関数オブジェクトを生成する const fn1 = new Function('a', 'b', 'return a + b'); console.log(sum(2, 6)); //8 普段よく使う関数宣言と同じではないか? (ほぼ)同じである function fn2(a,b) { return a + b } 普段よく使う関数宣言は、実は内部でnew Functionで関数が生成されている なので関数宣言で定義した関数は関数コンストラクターを継承していることがinstanceofで確認できる console.log(fn1 instanceof Function) //true new Functionから生成されているため、もちろんtrue console.log(fn2 instanceof Function) //true 関数宣言で生成されているがこれは内部でnew Functionによって生成されるためtrueになる プロトタイプチェーン プロトタイプが多重に存在している状態 function Person(name, age) { this.name = name; this.age = age; // this.hello = function() { // console.log('OwnProperty: hello ' + this.name); // } 1 } // Person.prototype.hello = function() { // console.log('Person: hello ' + this.name); // } 2 // Object.prototype.hello = function() { // console.log('Object: hello ' + this.name); // } 3 const bob = new Person('Bob', 18); bob.hello(); bob.hello()を実行した場合、bobインスタンスの中からhelloメソッドを探しに行くがその際優先順位がある インスタンス内->Personのプロトタイプ内->Objectのプロトタイプ内 つまり 上記コードで1,2,3が全て存在していた場合は一番上の階層である1が実行されconsole.log('OwnProperty: hello ' + this.name)が返される。 1がなく2,3のコードが存在していたら次に上の階層である2が実行されconsole.log('Person: hello ' + this.name);が返される 1,2,3全て存在していない時、初めてundifinedが返される hasOwnProperty( ), in 引数で与えられたプロパティが存在するかどうかを返す function Person(name,age) { this.name = name; this.age = age; } Object.prototype.hello = function() { console.log('Object: hello ' + this.name); } const bob = new Person('Bob', 18); //hasOwnProperty console.log(bob.hasOwnProperty('name')) //true console.log(bob.hasOwnProperty('hello')) //false あくまで自身のプロパティに存在するかなのでprototypeに存在しててもfalseになる //in console.log('hello' in bob) //true プロトタイプチェーンを遡り調べるので下の階層にhelloがありtrue プロトタイプ継承 別のコンストラクター関数のプロトタイプを継承し、コンストラクター間で機能を流用できるようにすること コンストラクター関数を作成する際、あるコンストラクター関数を継承することによりコードの冗長をなくし、機能拡張を容易に行えるようになる function Person(name, age) { this.name = name; this.age = age; } Person.prototype.hello = function() { console.log('hello ' + this.name); } // Personを継承し、またgenderプロパティを拡張 function Japanese(name, age, gender) { Person.call(this, name, age); this.gender = gender; } //PersonのプロトタイプをJapaneseのプロトタイプへ継承 Japanese.prototype = Object.create(Person.prototype); const taro = new Japanese('Taro', 23, 'Male'); クラス コンストラクター関数をクラス表記で書けるようにしたもの 今まで書いていたコンストラクター関数を //今まで function Person(name, age) { this.name = name; this.age = age; } Person.prototype.hello = function() { console.log('hello ' + this.name); } クラスで書き換えると以下のようになる ES6以降は基本的にはクラスによってコンストラクター関数を定義する class Person { constructor(name, age) { this.name = name; this.age = age; } hello() { console.log('hello ' + this.name); } } クラス継承 他のクラスのプロパティとメソッドを継承する プロトタイプ継承のクラス版 上のクラスで記述したPersonコンストラクター関数を継承したJapanese関数を定義 //extendsによってプロトタイプまで継承されるのでhelloメソッドは自動的に追加される class Japanese extends Person { constructor(name,age,gender){ super(name, age) this.gender = gender } //Personにはない新しいオブジェクトを追加 bye(){ console.log("Konnichiwa " + this.name); } } super クラス継承の際に用いたsuper 関数コンテキスト内に存在し、継承元の関数を呼び出す役割 上のクラス継承で見たextensdsによってクラスが継承されたコンテキスト内で継承元のコンストラクターを呼び出す場合 superの前でthisを使用することができない また継承元のメソッドを呼び出すことができる //Personのプロトタイプで設定したhelloメソッドを呼び出すことができる super.hello();] このように基本的にはクラスを継承したクラスのコンストラクター内やメソッド内で使用する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JSONで受け取ったtimestamp型の値をJavaScriptでサクッとDateに変換

概要 APIサイドからJSONを通じてフロント側(JavaScript)でデータを受け取るとき、日付を比較したい時がある。 そんなとき、JSONから受け取ったcreated_atなどの日付データ(timestamp)はそのままJavaScript側では使えない・・。 そこでJSONのtimestampをJavaScriptでDateとして使えるようにしていく。 やり方 hoge.js // 任意の方法でjsonからtimestamp型の値を受け取る // ここでは"timestamp"という変数として扱う console.log(timestamp); // 2021-09-17T06:21:00.101Z var date = new Date(timestamp); console.log(date); // Fri Sep 17 2021 15:21:00 GMT+0900 (日本標準時) サクッとできてしまいました。 hoge.js //2021年9月17日の0時0分0秒を取得して、先程のdateと比較してみる var start_of_today = new Date() start_of_today.setHours(0,0,0,0) console.log(start_of_today) // Fri Sep 17 2021 00:00:00 GMT+0900 (日本標準時) if (date > start_of_today) { console.log("今日の0時0分0秒から", date - start_of_today, "ミリ秒経ちました") // 今日の0時0分0秒から 55260101 ミリ秒経ちました } このようにDate同士の比較もできるようになりました 参考
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javascriptでイベントをキャンセルする方法

普段jQueryばかり書いている人間が、イベントキャンセル処理を通常のJavaScriptで書こうとしてハマったのでメモ。 概要 通常のJavaScriptでイベントをキャンセルしたい場合は、addEventLinstenerでpreventDefault()とstopPropagation()を呼び出そう。 問題 jQueryであれば以下のようにreturn falseすれば、バブリング(親要素のalert)およびデフォルトアクション(画面遷移)を停止できるが <div class="parent"> <a href="https://~~" class="child">テスト</a> </div> $('.parent').on('click' ,function(){ alert('parent'); }); $('.child').on('click' ,function(){ alert('child'); return false; }); 通常のJSのaddEventLinstenerで同じようreturn falseしてもデフォルトアクションをキャンセルできない。 以下の書き方だと親要素のalertも表示され、画面遷移もしてしまう。 const parent = document.querySelector('.parent'); const child = document.querySelector('a'); parent.addEventListener("click", function(){ alert("parent"); }); child.addEventListener("click", function(e){ alert("child"); return false; }); 解決策 js側でreturn falseの代わりにpreventDefault()とstopPropagation()を呼び出す。 child.addEventListener("click", function(e){ alert("child"); e.preventDefault(); //バブリングの停止 e.stopPropagation(); //イベントキャンセル }); ちなみにhtml側のonclickで以下のようにreturn falseを指定すれば画面遷移はキャンセルできるが親要素のイベントは走ってしまう。 <div class="parent"> <a href="https://~~" class="child" class="child" onclick="return false;">テスト</a> </div> こちらの記事によると、通常のJavaScriptでreturn falseした場合にはpreventDefault()のみが呼ばれるとのこと。 jQueryのreturn falseではreventDefault()とstopPropagation()の両方が呼ばれる。 まとめ コードの可読性を上げるためにも、通常のJavaScriptでもjQueryでもイベント伝播を停止する際はpreventDefault()とstopPropagation()を使用し、明確に動作の意図を伝えたほうが良さそう。 参考 JavaScriptでのイベントキャンセルの落とし穴 - Linkers Tech Blog addEventListener() のリスナーでreturn falseしてもイベントはキャンセルできない - いろいろ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptでイベントをキャンセルする方法

普段jQueryばかり書いている人間が、イベントキャンセル処理を通常のJavaScriptで書こうとしてハマったのでメモ。 概要 通常のJavaScriptでイベントをキャンセルしたい場合は、addEventLinstenerでpreventDefault()とstopPropagation()を呼び出そう。 問題 jQueryであれば以下のようにreturn falseすれば、バブリング(親要素のalert)およびデフォルトアクション(画面遷移)を停止できるが <div class="parent"> <a href="https://~~" class="child">テスト</a> </div> $('.parent').on('click' ,function(){ alert('parent'); }); $('.child').on('click' ,function(){ alert('child'); return false; }); 通常のJSのaddEventLinstenerで同じようreturn falseしてもデフォルトアクションをキャンセルできない。 以下の書き方だと親要素のalertも表示され、画面遷移もしてしまう。 const parent = document.querySelector('.parent'); const child = document.querySelector('a'); parent.addEventListener("click", function(){ alert("parent"); }); child.addEventListener("click", function(e){ alert("child"); return false; }); 解決策 js側でreturn falseの代わりにpreventDefault()とstopPropagation()を呼び出す。 child.addEventListener("click", function(e){ alert("child"); e.preventDefault(); //バブリングの停止 e.stopPropagation(); //イベントキャンセル }); ちなみにhtml側のonclickで以下のようにreturn falseを指定すれば画面遷移はキャンセルできるが親要素のイベントは走ってしまう。 <div class="parent"> <a href="https://~~" class="child" class="child" onclick="return false;">テスト</a> </div> こちらの記事によると、通常のJavaScriptでreturn falseした場合にはpreventDefault()のみが呼ばれるとのこと。 jQueryのreturn falseではreventDefault()とstopPropagation()の両方が呼ばれる。 まとめ コードの可読性を上げるためにも、通常のJavaScriptでもjQueryでもイベント伝播を停止する際はpreventDefault()とstopPropagation()を使用し、明確に動作の意図を伝えたほうが良さそう。 参考 JavaScriptでのイベントキャンセルの落とし穴 - Linkers Tech Blog addEventListener() のリスナーでreturn falseしてもイベントはキャンセルできない - いろいろ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【初心者向け】0から解説するAjax

ごあいさつ 「25歳文系未経験からエンジニア転職を目指す学習4ヶ月目の一般男性が、自分が過去につまづいたポイントをわかりやすく噛み砕いて書く!」をコンセプトに投稿しています。 LGTMしていただけると大変励みになります…!!! 概要 今回は「Ajaxとは?」という趣旨です。 私のようにフロントエンドからプログラミングを学び始めるとサーバ側のことがよくわからないまま言語の学習を進めてしまい「webアプリの全体像ってそもそもどんなものなの?」というところの理解を深める機会が少ないなあと思い、 過去にAjaxを学んでからそこの理解が深まったので取り上げます。 (+転職活動の面談で上手に説明できなかったのが悔しくて悔しくて復習したので…!笑) 解説 1.導入 まず、Ajaxとは Asynchronous JavaScript and XMLの略です。 Asynchronous(非同期) JavaScript and XML(XMLHttpRequest) 非同期でJavascriptとXML(XMLHttpRequest)を使ってサーバと通信をすることです。 ①非同期でサーバと通信 ②XML (過去の自分含め)初学者の方はこの3つの言葉が???になりがちだと思うので、順を追って簡単に解説します。 2.同期/非同期とは まず①の「サーバと通信」から説明します。 HPやwebサービスといったwebページは、私たちユーザーが操作するブラウザとデータが管理されているサーバ間での情報のやり取りによって表示されています。 例えば↓はQiitaホーム画面のURLですが、このURLをググるとQiitaのホーム画面が表示されますよね。 https://qiita.com/ これは、 ①私たちがブラウザが、サーバに「Qiitaのホーム画面を表示してくれ!」とリクエストを出して、 ②サーバがそのリクエストに反応して、指定されたデータを持ってきてブラウザ側に返す というやり取りが発生しています。 これが通信で、この通信にはざっくり同期と非同期の2パターンがあります。 以下、とっても噛み砕いた例を挙げて説明します。興味のある方はしっかりした一次情報に当たってみてください。 (例)Youtubeを開いているときに… 同期での通信… ホーム画面からログイン画面やライブラリ画面など、別のページに遷移する 非同期での通信…検索画面から検索したいワードを入れると、表示ページはそのままで検索結果部分だけ変わる となります。 つまり、非同期通信とは、表示画面はそのままで、ユーザがリクエストしたデータに応じて画面の一部が切り替わるというイメージで考えてもらえるといいのかな、と思います。 参考:公式ドキュメント https://developer.mozilla.org/ja/docs/Glossary/Asynchronous 参考:公式ドキュメント https://developer.mozilla.org/ja/docs/Web/Guide/AJAX 3. XML(XMLHttpRequest)とは 次に、Ajaxの「x」にあたる XML(XMLHttpRequest)についてです。 これは、非同期処理をするためのAPIのことで、JavaScript用の組み込みオブジェクトです。 しかし、実際にはXMLではなくJsonというデータ形式を使われることがほどんどのようなので、Jsonについても見てみましょう。 公式ドキュメント: https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest Jsonとは JavaScript Object Notation(表記) の略で、 データを人間と機械それぞれにとって扱いやすくするための形式です。 例えば、問い合わせフォームのお名前欄に田中、年齢欄に25と入力すると、サーバにデータが送られる際には { "name": "田中", "age": 25 } と変換される、といった具合です。(↑のコードがJson形式になっています。) 参考: https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON つまりAjaxとは、JavaScriptとXML(Json)で非同期でサーバと通信する手法と言えますね。 Ajaxのメリット/デメリット ざっくり、初学者の人にとってわかりやすいポイントをあげておきます。 メリット:処理が早い(=UX向上) →理由:ブラウザとサーバ間のデータのやり取りの負担を減らせるため デメリット:セキュリティの安全性 ⇨理由:オープンソースで処理を行うため、誰でもアクセスできてしまう 他にも色々とあるので、興味のある方は以下ご覧ください。 https://smartosc.jp/advantages-and-disadvantages-of-ajax/ まとめ Ajaxとは、JavaScriptとXML(実際は大体Json)を使用し、非同期で通信を行う手法のことで、これを用いるとUXの向上を始め、ユーザにとっても開発者にとっても色々メリットがあるよ!っていうお話でした。 所感 本記事を書く前に復習したつもりだったけれど、いざ言語化してみるとうまく言葉にできない部分が多くあり未熟さを痛感…。 あとは、言葉そのものの意味をググると理解が深まるなあと再認識しました。(ブラウザとは?サーバとは?Jsonってなんの略だっけ?など) ちなみに余談ですが、サーバの場所がどこにあるかググってみたところセキュリティ保護のため住所は公開されていないらしいです!笑
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ポリリズムを視覚的に理解できるメトロノームを作った!(JavaScript)

ポリリズムを視覚的に理解できるメトロノームを作りました! 実際に、自分がポリリズムを演奏したり考えたりするときのイメージに近いものになっています。 ポリリズムって何? “ポリ(poly)“は、”複数の“、”多数の“などを意味する言葉です。 あの「ポリゴン(多角形)」や「ポリマー(重合体)」の”ポリ“でもあります。 つまり、ポリリズムとは 複数の「リズムのまとまり」が重なって進行しているリズムを指します。 (詳しくはこちら↓) なぜ作ったのか 現在の記譜法の弱点 現在の楽譜は、旋律(メロディー)や和声(コード)を記述するのに適しています。 しかし、律動(リズム)に関しては…ぶっちゃけイマイチな部分もあります。 その中でも大きな問題点が、"対ポリリズム記述性能の低さ"です。 複雑なポリリズムを含む曲は少ないので、困っている人は少ないと思いますけど。笑 …ただ、逆の視点から見れば「楽譜に書きにくいからアイデアが抑圧されている」とも考えられます。 (実際に、旋律(メロディー)や和声(コード)は、現在の記譜法の発展とともに複雑化していった歴史もあります。) ポリリズムを分かりやすく説明したい この楽譜に表しにくいポリリズム。 「分かりやすく表せたらいいな~。でも、どうやってプログラム書いたら良いわからん…。」みたいな状態が続いていました。 しかし、独学で少しずつプログラミングの勉強を始めて約4年。 「あれ…今なら作れそうじゃね?」と思ったので、挑戦してみたら…なんとかできました!! 課題 ただ、課題もあります。 端末によっては、(処理が重たいせいか)ちゃんと動かない可能性があるところです。 手持ちのPC(WindowsとMac)から使う分には、ちゃんと動いてる気がします。 …ただ、スマホ(iPnone)から使うと、処理が重たいせいかちゃんと動きません。 (友達に試してもらったら、友達のスマホ(Android)は大丈夫っぽかったです。) あらゆる端末で安定的に動作させる方法を知っている方がいたら、教えていただけるとありがたいです。   ちなみに、現在はメトロノームの音や色付けの切り替えの実行はJavaScriptのsetIntervalを使っています。 main.js //以下のコードはイメージです。 //メトロノームの音を鳴らしたり色付けをする関数 function metronomePlay(){ //処理の中身 ホントは100行以上ある }; //指定した時間(intervalTime)ごとに、setIntervalで関数を実行する。 setInterval(metronomePlay() , intervalTime); おまけ このポリリズム対応メトロノームの仕組みを応用して 基本的なリズムを理解するのに役立つ教材と 変拍子対応のメトロノームを作りました。 多くの音楽をする方にとっては、こちらの方が便利かもしれません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Firebase V9におけるfirebase.apps.lengthの書き方

はじめに 初投稿になります。 自身の備忘録として、また、同症状を抱えている人の手助けになればと思い、ここに記します。 初回は「firebase.apps.length」にまつわるお話です。 (Firebase JavaScript SDK V9.0.2) 解決策 fb.ts import { getApps } from 'firebase/app' // import 要 getApps().length //使用例(before -> after) //before: Firebase V8 !firebase.apps.length //もしくは firebase.apps.length === 0 //after: Firebase V9 !getApps().length //もしくは getApps().length === 0 原因 FirebaseのV9へのバージョンアップに伴う破壊的変更が原因でした。 2021/8/25以降にアップデートorインストールした方は注意です。 リリースノート:https://firebase.google.com/support/release-notes/js 謝辞 Zennにて だら様 の 「Next.jsとFirebaseで質問箱のようなサービスを作る」というWeb本を購入させていただいました。 URL:https://zenn.dev/dala/books/nextjs-firebase-service ハンズオン形式で進めていく中、 Firebaseのバージョンを気にせずインストールしてしまったために、 エラー地獄にハマることとなりました。 結局、TwitterのDM上で だら様 に助けていただきながら、 ソースコードや公式docを見ながら今回の部分もなんとか解消しました。 その後、DM上でサンプルコードを送ってくださったり、 1日ちょっとでソースコードを更新いただいたりと、 手厚いサポートを賜りました。 だら様、その節はありがとうございました。 最後に ハンズオンで制作からデプロイまでを経験でき、 かつ、分かりやすくまとめられていて、買ってよかったなと思ってます。 何か作る経験をしたいという人や、Next.jsとFirebaseの連携、 それぞれの理解を深めるのにオススメなので、気になった方は読んでみてください。 追記 2021/09/17 現在、Firebaseのドキュメントでは V9の形式に変更されていましたので、詳しくはそちらを参照いただければ良いかと思います。 ・8/25以降アップデートした人 ・8/25以降インストールした人 ・8/25以降Firebaseを学び始めた人 は特に公式のドキュメントを見た方法がいいです。 間違っても 「Firebase Error: ~~ 直し方」検索 ⇒ 更新日時を確認せず記事を読む ということはしないほうが効率が良いかと思います。 急がば回れというやつですね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【技術書まとめ】ハンズオンJavaScript

「長い旅にはカバンより歌のほうがうれしいものだよ」 -- トーベ・ヤンソン:『さびしがりやのクニット』 読んだまとめ JSの全体像が見えた気がする。ハンズオンで実際にコードを書くので頭にも入りやすかった。ただ分厚いので時間はかかった。 1章 学び始める前に JavaScriptの基礎的な説明 2章 データを学ぶ JavaScriptの基礎的な説明 3章 処理を学ぶ アルゴリズムとは「何らかの解を得るための手順」のこと。 式は文の一種で値を返すが、文は必ずしも値を返さない let pi = 3.14 文 ブロック{} 変数や定数のスコープができる そのブロックのみで有効となる 4章 オブジェクトを学ぶ JSのオブジェクトは単なるキーバリューのペアではなくメソッドも定義できる 5章 モジュールを学ぶ true.toString()はプリミティブなのになぜできるのか 対応するオブジェクトに自動変換されるから ボックス化と呼ばれる 明示的に相互変換するには オブジェクトにする new Object(true) プリミティブにする Object(true).valueOf() 6基本的な標準オブジェクトを学ぶ falsyな値 false null undefined 0 0n '' NaN 数値のプロパティアクセス 42.toString()はエラーになる ドットを二つでアクセスできる 42..toString() Well-Known Symbol Symbol.hasInstance Symbol.toPrimitive Symbol.toStringTag Functionオブジェクト apply() は引数を配列で受け取る add3.apply(1, [16, 25]) call() は個別に受け取る add3.call(1, 16, 25) bind() はthisや引数の値を固定した関数を新たに作る bind(1)ならthisは1となる RegExp オプションフラグ g 一致した文字列を全て返す i 大文字小文字を無視する m 複数行検索する 文字列メソッドで正規表現を利用する search() 見つかったら位置を、見つからなかったら-1を返す match() 見つかったらその文字列を、見つからなかったらnullを返す matchAll() 見つかったらイテレータを返す split() 正規表現に一致する部分で分割して配列を返す replace() 置き換えて返す # 7章 コレクションを学ぶ Array Array.from(days, i => i * i) 二乗したものを配列にできる includes(3, 1) 第二引数の位置から確認を始める some(n => 4 < n) 条件式を満たす要素があるかどうか確認する every(n => 0 < n) 配列の全ての要素が条件式を満たすか確認する reverse() 破壊的メソッド sort() 破壊的メソッド デフォルトでは数値比較ではなく辞書順 entries() 要素とインデックスが両方必要な時に使う flat(2) 引数で平坦化する深さを指定する [1, 2, 3].reduce((sum, n) => sum += n, 0) 最後の引数は初期値 初期値は省略しない方がいい 空配列の場合 TypeError が発生する  要素が一つの場合コールバック関数が実行されない    配列をスタックのように扱う  stack.pop()  stack.push()  配列をキューのように扱う  queue.shift()  queue.pop()  Map  キーによって要素を管理するとき使う  オブジェクトではobj[1]とobj["1"]は区別されないが、マップでは区別される  MapやSetはブラケット記法やドット記法ではアクセスできない  ☠️ map.key  プロバティへのアクセスとなる  forEach()で回すときは値が先に渡される  map.forEach((v, k) => console.log(key: ${k}, value: ${v})) メモリ管理 JSが管理するメモリ スタック プリミティブを保持しているローカル変数が使用する 型ごとに必要なメモリ容量が決まっている オブジェクト どこに保存しているかの情報のみ これを参照と呼ぶ メモリ容量は固定 オブジェクトは容量固定ではないから 実際のデータはヒープに保存する ヒープ ガベージコレクションされる 例として参照カウント カウント0になったら利用なし 解放される 弱参照はカウントされない WeakMap 弱参照 元オブジェクトの生成や取得に時間がかかる場合の付随情報を管理する使い方など Mapだと元オブジェクトが消えても参照され続ける Set 値を一意に保持するだけの時に使う [...new Set(days)]で days の重複を取り除ける イテレータ next()メソッドを持ったオブジェクトの総称 戻り値はvalueとdoneを持つオブジェクト doneでまだ要素が残っているかどうかがわかる イテラブル 反復可能かどうか そのオブジェクトがSymbol.iteratorキーとするプロパティを持つかどうか for-ofは与えられたオブジェクトの[Symbol.iterator]メソッドを呼び出してイテレータを取得し、そのイテレータのnext()メソッドの呼び出し結果の done が true になるまで、next()を呼び出し value の値を変数に代入して、その変数を使用した処理を繰り返し実行している for-ofできるオブジェクトは全て[Symbol.iterator]メソッドを持つ 自分自身を返す[Symbol.iterator]メソッドがある for ( let iter = obj[Symbol.iterator](), rslt = iter.next(), item = rslt.value; !rslt.done; rslt = iter.next(), item = rslt.value ) { console.log(item) } ジェネレータ関数 イテレータかつイテラブル 関数実行するとジェネレータオブジェクトを生成して返す イテラブルなのでfor-of文で反復実行できる function*や*method(){}で作成する 関数定義の本文をnext()で実行する return に到達するとそれを{value: "1200kVA", done: true}オブジェクト戻り値として返す だがnext()が常にdone:trueだと繰り返せない yieldを処理を一時中断するreturnとして使う done:falseとなる メソッド next() 引数をひとつ取れる 再開された二度目以降の yield式の戻り値となる 最初に渡した引数は無視される return() 処理の再開と同時に繰り返しを終了する 与えた引数は戻り値の value の値に入る throw() 処理の再開と同時に例外を発生する 複雑なデータの扱いを学ぶ バイナリデータ 2進数で表現されたデータ まずデータをそのまま保持する ArrayBuffer オブジェクトを使う バッファのサイズ(byte)を引数にする ほとんど保持する機能だけ .byteLengthでバイト数を読み取れる slice(start, end)で切り取ったコピーを作れる 読み書きは別オブジェクトを使う ビュー 型付き配列(TypedArray) 特定の型を持つバイナリデータに配列形式でアクセスするオブジェクト群の総称 コンストラクタにArrayBufferオブジェクト以外の引数を与えると内部的に ArrayBufferオブジェクトを生成する DataView オブジェクト さまざまな型のデータにアクセスできる set<Type>() get<Type>() 明示的にエンディアンを指定できる リトルエンディアンはtrue JSON JSON.parse(42, reviver) 第二引数で変換処理をする関数を渡せる オブジェクトを文字列やバイト列に変換すること 直列化やシリアライズと呼ばれる JSON.stringify(obj)もその一つ 列挙可能(enumerable)でないプロバティはJSON文字列に含まれない toJSON()メソッドがあるとそれが使用される JSON.stringify(obj, replacer)でJSON文字列変換前に Array[0] だけを取得するなどの処理ができる 第3引数にはインデント指定できる let obj2 = JSON.parse(JSON.stringify(ko1))で1行でディープコピーできる 国際化を学ぶ i18n 言語や時間、数値の表記の違いを吸収する Date new Date(1868, 3, 4) 4月となる 月だけが0から始まる Intl.DateTimeFormat 非同期処理を学ぶ 処理の流れをスレッドと呼ぶ JSはシングルスレッド 非同期処理 コールバック関数 相手の都合のよいタイミングで電話を「かけ直して」もらう Buttonオブジェクト addEventListener()でコールパック関数を設定する 処理するのはイベントハンドラやイベントリスナ 何度も発生するイベントをその都度処理するのに適している 一般的な非同期通信に適した手法ではない コールバック地獄 Promise が解決してくれる Promise その処理が完了していなくても即座にPromiseオブジェクトを返してくれる 完了後の処理を then()メソッドの引数として与えられる Promiseは実行結果を保持している 実行完了後にthen()メソッドを使う 連結するとPromiseチェーンとなる function waitFor(msec) { return new Promise(resolve => { setTimeout(resolve, msec) }) } waitFor(Math.random() * 5000).then(() => { console.log("処理A") return waitFor(Math.random() * 5000) }).then(() => { console.log("処理B") return waitFor(Math.random() * 5000) }).then(() => { console.log("処理C") }) catch()メソッドを使うときは then()メソッドでは第二引数を使わない > Promise.resolve().then(() => console.log("Promise内")) console.log("Promise後") Promise後 Promise内 常に then()メソッドのコールバック関数があとに実行される 非同期処理はいつ完了するかわからない 完了タイミングで挙動が変わると動作が不安定になる 後実行の挙動が保証されている 複数の非同期処理をまとめて扱う Promise.all Promise.allSettled 一部失敗しても全体は失敗しない then() で結果を受け取ることができる Promise.race 最初に完了するPromiseだけが最終結果に影響を与える async関数 return文で値を返せば成功したPromiseが、throw文で例外を発生させれば棄却されるPromiseが返る 非同期イテレータ next()メソッドを持つが、その戻り値はPromiseとなる for-await-of文で作る メタプログラミングを学ぶ Proxy arrayProxy = new Proxy(array, {}) arrayProxyに対する操作はarrayに反映される arrayそのままの挙動となる ハンドラオブジェクトに{}ではなくメソッドを追加する トラップと呼ばれる 決められた処理の中継に割り込める プロパティアクセスをプロキシする get(), set(), has(), ownKeys() array = [3.14, 9.8, 2.718] arrayProxy = new Proxy(array, { get(target, prop) { return Math.round(target[prop]) // arrayProxy[0] が 3 となる }, set(target, prop, value) { if (!Number.isInteger(value)) { throw new Error("not Integer") } target[prop] = value }, has(target, prop) { return prop < 2 }, ownKeys(target) { return ["0", "1", "length"] } }) 関数やコンストラクタの呼び出しをプロキシする apply(), construct() 取り消し可能なProxyを作成する プロキシオブジェクトはターゲットの参照を保持しているためガベージコレクタに回収されない Proxy.revocable()で取り消す Webを学ぶ Web HTML文章の集合からJSで繋がれたコンテンツの集合になっていった グローバルオブジェクト 宣言していない変数や定数 globalThisオブジェクトのプロパティ globalThis === window同じ console location navigator ドキュメントオブジェクトモデル(DOM) DOMの構造 HTML, XML, SVG などを表現する 木構造 DOMツリー childNodes[0]で子ノードを辿っていける 主要オブジェクト Node 木構造の各ノードを表すオブジェクト Document DOMツリーのルートノード Element タグ要素 HTMLElement すべてのHTMLタグの継承元 要素への操作 document.body.childNodes Nodeオブジェクトのプロパティ Text整形のための改行なども含む 整形のための要素が必要になることはほとんどない document.body.children Elementオブジェクトのプロパティ HTML要素しか含まない idを持つ子要素に直接アクセスできる document.body.children.exampleId 要素を検索する getElementsByTagName() getElementById() getElementsByClassName() querySelector() querySelectorAll() 要素のコンテンツを操作する textContent すべてのテキストを返す innerText 実際に表示されているテキストだけを返す 要素を追加する 作る createElement() createNode() 追加する appendChild() insertBefore() prepend() append() 要素を入れ替える replaceChild() console上でそのまま編集する document.body.contentEditable = true CSSオブジェクトモデル document.styleSheets[0].cssRules すべてのルールを取得できる setProperty()で書き換えられる insertRule()で挿入する イベント 「何かの出来事」が生じたら「何かの処理」を行う イベント処理 addEventListener()とコールバック関数で実現する document.body.addEventListener("click", evt => { evt.target.style.backgroundColor = `#${Math.floor(Math.random() * 0xffffff).toString(16)}` }) removeEventListener() 無名関数は削除できない 名前をつけて渡しておく必要がある dispatchEvent() 任意のタイミングでイベント発火させる 代表的なイベント keydown キーが押された時 keyup 押されたキーが解放された時 イベントハンドラの探索順序 親をたどっていく bodyタグはすべての表示要素の親 イベントの流れ 親から子 キャプチャリング 子から親 バブリング HTMLタグにはデフォルトでイベントに反応するものがある チェックボックスやタグなど stopPropergation()では止められない preventDefault()で止める Web Components 独自の機能や見た目のタグを作成できる Custom Elements HTMLElementを継承したクラスを作る customElements.define()で登録する Shadow DOM Shadow DOM 外の描画に影響を与えないDOMツリー 通常のDOMツリーに追加できる HTML Template <template>タグ 画面には描画されないがJSから参照できるDOM要素 <template>とJSを組み合わせて実際のDOMに描画する HTMLとJSを分離できる attribute を引数のようにコンテンツの中身に使うなど // あっという間にお絵かき帳 document.styleSheets[0].insertRule(` .dot { position: absolute; width: 5px; height: 5px; background-color: black; } `) let clicking document.body.addEventListener("mouseup", () => clicking = false) document.body.addEventListener("mousedown", () => clicking = true) document.body.addEventListener("mousemove", evt => { if(!(clicking && evt.shiftKey)) return const dot = document.createElement("div") dot.className = "dot" dot.style.left = `${evt.clientX}px` dot.style.top = `${evt.clientY}px` document.body.append(dot) }) ネットワークを学ぶ URI(Uniform Resource Identifier) 「求めるコンテンツを示す手段」 電話番号のようなもの どうやってコンテンツを受け渡すかはそのあとの話 https://www.amazon.co.jp/s?k=javascript&ref=nb_sb_noss_2の構造 スキーム https デリミタ : オーソリティ //amazon.com プレフィックス // ホスト amazon.com パス /s クエリ k=javascript&ref=nb_sb_noss_2 包含 URI(Uniform Resource Locator) URN(Universal Resource Name) encodeURI() そのままURIとして使える encodeURIComponent() そのままURIとして使えないが、クエリパラメータとして使える HTTP 通信プロトコル 「もしもし〇〇ですが……」から始まる一連の儀礼や手順 リクエスト・レスポンス型 ステートレス WebAPI REST URIでリソースを一意に識別する GET, POST, PUT, PATCH, DELETE を使用する fetch 404エラーでもthen()が呼び出される then の中で status を確認する if (!response.ok) throw new Error(response.statusText) navigator.sendBeacon() ページナビゲーションに影響を与えずにビーコンを送信できる HTTP以外のプロトコル HTTP/2 バイナリベース リクエスト・レスポンスの多重化ができる WebSocket 双方向にデータを送信できる WebRTC ブラウザ同士のリアルタイム通信ができる ストレージを学ぶ Cookie DevToolsから確認する コンソールから確認する document.cookie HttpOnlyが設定されているとJSからはアクセスできない セッションIDをJSから読み込めるとセキュリティの問題になることがあるため 読取はまとめて得られるが代入は1エントリずつ document.cookie = "power=E" 内部的なフィールドに値を設定し、それを文字列形式で読み出すゲッターとセッター // JSでCookieを取得する let cookieMap = () => new Map(document.cookie.split(/;\s*/).map(kv => { const ms = kv.match(/([^=]+)=(.*)/) return [ms[1], ms[2].replace(/(^"|"$)/g, "")] })) cookies = cookieMap() cookies.get("lang") // Cookieの大まかな内部構造 let doc = { _cookie: new Map(), get cookie() { return [...this._cookie].map(kv => kv.join("=")).join(";") }, set cookie(val) { this._cookie.set(...val.split("=")) } } doc.cookie = "power=B" doc.cookie = "spec=C" doc.cookie // "power=B;spec=C" // 属性を指定する document.cookie = "power=B;max-age=1000" WebStorage サーバにデータが送信されない クライアント側でだけ利用できる Cookieは必ず送信されてしまう 5~10MB程度のデータ localStorage.getItem() localStorage.setItem() 文字列以外はJSONで入れる 容量制限を超えるとエラーが出る localStorage.removeItem() localStorage.clear() すべてのデータをまとめて削除する IndexedDB オブジェクト指向データベース キーバリューストア データベース作成やスキーマ定義が必要 データベースの構造 オブジェクトストア テーブルに対応するもの オブジェクト 行 プロパティ カラム 接続 indexedDB.open("jojodb", 1) 非同期で行われる オブジェクトストアを作成する db.createObjectStore("satnds", {keyPath: "id", autoIncrement: true}) インデックスを定義する standStore.createIndex("nameIndex", "name", {unique:true}) オブジェクトを追加する db.transaction(["stands"], "readwrite) トランザクションを開始する transaction.objectStore("stands") オブジェクトストアを取り出す standStore.add() 追加する 非同期で実行される 結果はIDBRequestオブジェクト オブジェクトを取得する standStore.get(1) マルチメディアを学ぶ グラフィック系APIの操作 センサーとデバイスを学ぶ モバイルデバイスのセンサー取得法など PWAを学ぶ ServiceWorker バックグラウンドで動作するスクリプト 登録 navigator.serviceWorker.register() ネイティブアプリを超える URIでアプリケーションを共有できる Web Share API 支払い情報やログイン情報をブラウザでまとめられる PaymentRequest API セキュリティを学ぶ サービスが家ならブラウザはサービスにつながるドアで、ログインは家の鍵 ユーザーが誰か確認する 認証 機能の利用を許可する 認可 JSが安全に利用できる理由 サンドボックスで動作するから 同一オリジンポリシー オリジン スキームとホストとポート番号の組み合わせ オリジンが異なる時に制限されるもの fetch() Cookieの読み書き WebStorageやIndexedDBへのアクセス CanvasのgetImageData() CORS(Cross-Origin Resource Sharing) リクエストのOriginヘッダにオリジンを設定して送信する サーバはそのオリジンを確認する 通信許可ならAccess-Control-Allow-Originヘッダを設定したレスポンスを返す 一定期間クロスオリジンの通信が許可される ローカルファイルアクセス クリップボードアクセス 代表的な攻撃 クロスサイトスクリプティング(XSS) ${name}部分に<script>alert(document.cookie)</script>などを入れられる セッションIDの漏洩 セッションハイジャック 対策 &lt;というようなHTMLエンティティに置換して埋め込む Cookieの値を信用しない 重要情報はサーバ上に保存する Cookieは言語やスタイルの設定などにする セッションIDはCookieをHttpOnlyにしてJSから読み取れないようにする クロスサイトリクエストフォージェリ(CSRF) ログイン済みのユーザに攻撃サイトを表示させてiframeでパスワードリセットさせるなど 対策 本来の<form>タグからしかリクエストできないようにする <form>に隠しパラメータとしてサーバで生成した乱数を設定する Credential Management API JSからブラウザの「バスワードを保存」機能を利用できる JSを通じて得られるハードウェアに関する情報 意図的に不正確な値が返されることがある 情報を集めてユーザーを特定するフィンガープリンティングを避けるため パフォーマンスを学ぶ 詳細な時間測定 performance.now() console.time()とconsole.timeEnd()で時間を測る リソースの取得を計測する performance.getEntriesByName(name) Webサイト表示のパフォーマンスを計測する performance.getEntriesByType("navigation")[0] パフォーマンスを改善する Web Worker worker1 = new Worker("js/worker1.js") やりとりできるデータ 関数オブジェクトとDOMノード以外 構造化クローンして受け渡されるから コピーが重すぎる Transferableオブジェクト 参照だけ受け渡す 高速になる WebAssembly 学び続けるために ECMAScript 標準化までの5ステージ 0: 藁人形(Strawperson) 「こういう仕様を考えた」と宣言した状態 1: 提案(Proposal) 課題と解決策とAPIの概要、代表者が決まる デモなどで実際の動作を確認する 2: 草案(Draft) 議論が深まり正式なフォーマットで仕様がまとめられる 公式のフォーマットで正確に記述することが目的 3: 候補(Candidate) 仕様書が完成して指名されたレビュアーとすべてのECMAScriptエディタが承認する 実際の利用からフィードバックを得て改善することが目的 4: 完了(Finished) 受け入れテストが作成される ECMA総会に提出されて批准されると標準化が完了となる Web API World Wide Web Consortium(W3C) Web Incubator Community Group(WICG) Web Hypertext Application Technology Working Group(WHATWG) Living Standard Internet Engineering Task Force(IETF) Khronos Group
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【React】コンポーネントのメモ化で怒られる / ESLint: Component definition is missing display name(react/display-name)

はじめに コンポーネントのメモ化を試みたところESLintで怒られた、のでその時の対処法。 メモ化 memo(コンポーネント); 「コンポーネントの定義に表示名がない」と言われている ESLint: Component definition is missing display name(react/display-name) 開発環境でのデバッグ時に、複数のコンポーネントが存在する場合エラーメッセージからのデバッグが難しくなってしまう。 ということがあってこのように怒られるらしい。 サンプルコード 怒られる // ESLint: Component definition is missing display name(react/display-name) export const Foo: React.VFC = memo(function foo() { return <div>memoサンプル</div>; }); 解決策 無名関数から普通の名前付き関数にする export const Foo: React.VFC = memo(function foo() { return <div>memoサンプル</div>; }); ESLintを部分的に disable にする // eslint-disable-next-line react/display-name export const Foo: React.VFC = memo(() => { return <div>memoサンプル</div>; }); 最後に ESLintの設定でそもそも回避できると思いますが、そこまで調べられておらず。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む