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

JavaScriptでコントラストのアクセシビリティ適合レベルを求める

アクセシビリティの記事やツールで良く見かける『AA』や『AAA』を自分で求める方法です。 TL;DR 一応クラス使ってそれっぽく書いてみました。 a11y.js class PartOfRGB { constructor (param) { this.param = param } // 16進数 toHex () { return this.param.toString(16) } // 8bitをsRGBに変換する toSRGB () { return this.param / 255 } // 相対輝度計算に使うためのRGB getRGBForRelativeLuminance () { const sRGB = this.toSRGB() if (sRGB <= 0.03928){ return sRGB / 12.92; } return Math.pow(((sRGB + 0.055) / 1.055), 2.4); } } class RGB { constructor (strRGB) { const rgb = this.convStrToRGB(strRGB) this.R = new PartOfRGB(rgb[0]) this.G = new PartOfRGB(rgb[1]) this.B = new PartOfRGB(rgb[2]) } // 16進数の文字列 toStr () { return `#${this.R.toHex()}${this.G.toHex()}${this.B.toHex()}` } // #fffff → [255, 255, 255] convStrToRGB (strRGB) { return strRGB.match(/[^#]{2}/g).map(rgb => parseInt(rgb, 16)) } // 相対輝度 getRelativeLuminance () { const R = this.R.getRGBForRelativeLuminance(); const G = this.G.getRGBForRelativeLuminance(); const B = this.B.getRGBForRelativeLuminance(); return 0.2126 * R + 0.7152 * G + 0.0722 * B; } } class ColorContrast { constructor (strC1, strC2) { this.c1 = new RGB(strC1) this.c2 = new RGB(strC2) } // コントラスト比 getContrastRatio () { const l1 = this.c1.getRelativeLuminance() const l2 = this.c2.getRelativeLuminance() const bright = Math.max(l1, l2) const dark = Math.min(l1, l2) return Math.round((bright + 0.05) / (dark + 0.05) * 100) / 100 } // コントラスト比がアクセシブルかを判定する judgeA11y () { const contrastRatio = this.getContrastRatio() if (contrastRatio >= 7) { return 'AAA' } else if (contrastRatio >= 4.5) { return 'AA' } return 'NG' } } const CC1 = new ColorContrast('#FFE6E6', '#ffffff') const CC2 = new ColorContrast('#c7a999', '#1d1616') console.log(`${CC1.c1.toStr()}, ${CC1.c2.toStr()}`) console.log(`コントラスト比: ${CC1.getContrastRatio()}`) console.log(`アクセシビリティ: ${CC1.judgeA11y()}`) console.log() console.log(`${CC2.c1.toStr()}, ${CC2.c2.toStr()}`) console.log(`コントラスト比: ${CC2.getContrastRatio()}`) console.log(`アクセシビリティ: ${CC2.judgeA11y()}`) 出力 出力 #ffe6e6, #ffffff コントラスト比: 1.19 アクセシビリティ: NG #c7a999, #1d1616 コントラスト比: 8.11 アクセシビリティ: AAA 簡単な説明 2つの色それぞれの相対輝度を求める 2つの色のコントラスト比を求める コントラスト比によって適合レベルを判別する コントラスト比 >= 7.0 : AAA コントラスト比 >= 4.5 : AA 相対輝度を求める過程がちょっと複雑ですが、それ以外は分かりやすいと思います。 応用 これを応用して、3色のアクセシビリティをチェックするツールをReactで作ってみました。 https://a11y-contrast-tool.vercel.app/ 参考 https://waic.jp/docs/WCAG20/Overview.html W3C勧告のWCAG公式ドキュメントです。 https://lifehackdev.com/ZakkiBlog/articles/detail/web15 コードはここを参考にしました。 https://ja.wikipedia.org/wiki/Help:%E9%85%8D%E8%89%B2%E3%81%AE%E3%82%B3%E3%83%B3%E3%83%88%E3%83%A9%E3%82%B9%E3%83%88%E6%AF%94 Wikipediaのa11yヘルプです。かなり分かりやすくまとまっています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Node.js基本編 Express+SQLiteで超定番のTo Doメモアプリを作る

本編はNode.js+Express+SQLiteを使って、DataBaseにCRUDできるアプリを作る工程を紹介をします。実際に作るのは定番中の定番、To Doメモアプリですので難しい事は一切しない初学者向けです。 掌田津耶乃 著のNode.js超入門がベースです。 一応念のため、CRUDとは Create(登録) 新しいデータを登録する。 Read(参照) レコードをテーブルから取り出す。 Update(更新) レコードの内容を更新する。 Delete(削除) レコードを削除する。 一応念のため、Webアプリケーションとは(サイトとの違い) Webサイト=情報を提供 静的ファイルをホスティングしてるだけで、誰が見ても同じ情報を表示する。 Webアプリケーション=情報のやり取り ユーザーがフォーム入力、送信、など様々な行動をアプリケーション上で行える。ユーザーが送信したデータを処理して結果を表示する。 では実際にやっていきましょう。大きく分けて4ステップで説明していきます。 Step1:Node.jsアプリ基盤構築 Step2:DataBase構築 Step3:ページを用意 Step4:CRUD処理を実装 前提条件:Node.jsはインストールしておいてください。インストールの仕方はこちらを参考 Step1:Node.jsアプリ基盤構築 入門編でも紹介したアプリケーションのひな形を生成してくれる便利なツールのExpress-Generatorをインストールしましょう。 npm install -g express-generator これでグローバルにインストールされてシステム全体でExpress-Generatorが使えます。 ではアプリを作っていきます。 express -e アプリ名 express -e todo-app これで「todo-app」という名前のディレクトリができ、各種フォルダも自動で作られます。 Express-Generatorはデフォルトで各種パッケージを入れておいてくれるので、プロジェクトディレクトリに入り、npm installをして全部インストールしましょう。 cd todo-app npm install そして、今回DataBaseを扱う為に必要なSQLite3は、別途インストールが必要です。 npm install --save sqlite3 各ディレクトリの説明をざっくりと、 bin/ アプリを実行する為のコマンドとなるファイルが保管されてます。基本的に触りません。 public/ CSSや画像などをこの中に置きます。 routes/ このディレクトリではルート(URL)ごとの処理がまとめらています。 用意するページのアドレスごとにここにファイルを追加します。 views/ 画面側を作る上で必要なViewファイルを置きます。サーバーサイドからこのファイルに対して値を渡すことが出来ます。 node_modules/ npm installするとパッケージ類はこのディレクトリに入ってきます。基本的に触りません。 app.js これがメインプログラムです。Expressの設定周りを担っています。 これでアプリの基盤はひとまず完成です。Express-Generatorを使うとすごい楽ですね。 Step2:DataBase構築 続いてDataBaseの構築です。DB Browser for SQLiteを使います。 *DB Browser for SQLiteはSQLiteのデータベースをGUIで管理することができるツールです。 導入方法はこちらを参考にしてください、簡単です。 まずDataBaseファイルを作ります。 「新しいデータベース」をクリックします ファイル名は「memo_data」として、保存先はtodo-appフォルダ直下です。これでmemo_data.db / memo_data.sqlite3というファイルが作られます。 次にテーブルを作ります。 今回は超シンプルなメモアプリなので、メモを格納するテーブル(テーブル名:memos)を一つだけ用意ます。 次にカラムを作ります カラムは以下2点に留めておきます。 ・id -これは編集、削除するのに指定する為に必須 ・text (もっとあっていいですが今回はミニマムな実装に留めます) 最初に何個かダミーデータを登録しておきましょう。 普通のアプリ開発では必要なデータを洗い出して、テーブル、カラムをどう分けるかなどをこんな風に図に起こして 設計 するのが当たり前ですが、 今回は超絶シンプルなメモアプリなので設計なんて大そうな作業は不要です。 ちなみにテーブル、カラムなど超基本のデータベース用語ですが、カラムが列(項目)で、テーブルがそれをまとめる表のイメージです。 データベース構築はこれで完了です。 Step3:ページを用意 続いてクライアント側の画面であるページを作っていきます。 Node.jsではテンプレートエンジンというクライアント側の画面が簡単に作成できるパッケージがあります。Express-Generatorで既にejsというテンプレートエンジンがインストール済みなので、これを使ってページを作っていきます。 今回必要なページは4つです。views配下にmemoという名前でフォルダを作り、 メモ一覧表示ページ: index.ejs 新規メモ追加ページ: add.ejs メモ編集ページ: edit.ejs メモ削除ページ: delete.ejs を作成してください、中身のコードは以下になります。 index.ejs <!DOCTYPE html> <html> <head> <title><%= title %></title> </head> <body> <h3><%= title %></h3> <div> <table> <% for(var i in content) { %> <tr> <% var obj = content[i]; %> <th><%= obj.id %></th> <td><%= obj.text %></td> </tr> <% } %> </table> </div> </body> </html> add.ejs(index.ejsとbodyタグ以外は同じ) <body> <h3><%= title %></h3> <p><%= content %></p> <div> <form action="/memo/add" method="post"> <p>メモ内容:<input type="text" name="text"></p> <input type="submit" value="追加"> </form> </div> </body> edit.ejs(index.ejsとbodyタグ以外は同じ) <body> <h3><%= title %></h3> <p><%= content %></p> <div> <form action="/memo/edit" method="post"> <p>メモ内容:<input type="text" name="text" value="<%= memoData.text %>"></p> <input type="hidden" name="id" value="<%= memoData.id %>"> <p><input type="submit" value="更新"></p> </form> </div> </body> delete.ejs(index.ejsとbodyタグ以外は同じ) <body> <h3><%= title %></h3> <p><%= content %></p> <div> <p>メモ内容:<%= memoData.text %></p> <form action="/memo/delete" method="post"> <input type="hidden" name="id" value="<%= memoData.id %>"> <p><input type="submit" value="削除"></p> </form> </div> </body> 見ての通り基本はHTMLファイルで、値を受け取ってそれを表示したり、値を送ったりしているだけです。 title, content, memoDataという名前で値を送る処理はroutes(サーバー側)から行ってます。 Step4:CRUD処理を実装 最後に肝心のCRUD処理を実装していきます。 routes配下にmemo.jsというファイルを作り、以下の処理を書いていきます。 各所にコメントを入れてあります。 var express = require('express'); var router = express.Router(); var sqlite3 = require('sqlite3'); //データベースオブジェクトの取得 const db = new sqlite3.Database('memo_data.sqlite3'); router.get('/', function(req, res, next) { db.serialize(() => { //SQL文, memosテーブルから全てのレコードを取得する(* は全て) db.all("select * from memos", (err, rows) => { if (!err) { const data = { title: 'To Do メモ 一覧表示', content: rows //DataBaseから返された全レコードがrowsに配列で入ります } //viewファイルのmemo/indexにdataオブジェクトが渡されます //res.render(テンプレートファイル名, { 渡す値をオブジェクトで }) → テンプレートファイルを描画する res.render('memo/index', data); } }) }) }); router.get('/add', function(req, res, next) { const data = { title: '追加', content: '新しいデータを入力してください' } res.render('memo/add', data); }); router.post('/add', function(req, res, next) { const tx = req.body.text; //SQL文, DataBaseのレコード作成 db.run('insert into memos (text) values (?)', tx) //res.redirect() 引数に指定したアドレスにリダイレクト res.redirect('/memo'); }); router.get('/edit', function(req, res, next) { const id = req.query.id; db.serialize(() => { const q = "select * from memos where id = ?"; db.get(q, [id], (err, row) => { if (!err) { const data = { title: '更新', content: 'id = ' + id + 'のレコードを更新', memoData: row } res.render('memo/edit', data); } }) }) }); router.post('/edit', function(req, res, next) { //POST送信された値はreq.body内にまとまられている const id = req.body.id; const tx = req.body.text; const q = "update memos set text = ? where id = ?"; db.run(q, tx, id); res.redirect('/memo'); }); router.get('/delete', function(req, res, next) { const id = req.query.id; db.serialize(() => { const q = "select * from memos where id = ?"; db.get(q, [id], (err, row) => { if (!err) { const data = { title: '削除', content: 'id = ' + id + 'のメモを削除しますか?', memoData: row } res.render('memo/delete', data); } }) }) }); router.post('/delete', function(req, res, next) { const id = req.body.id; const q = "delete from memos where id = ?"; db.run(q, id); res.redirect('/memo'); }); module.exports = router; そして、app.jsに以下を追記してください var memoRouter = require('./routes/memo'); app.use('/memo', memoRouter); ここまでできたらnpm startを実行して、http://localhost:3000/memoを開いてください。 最初に登録したダミーデータが表示されていればうまくいってます。 では新規登録をしてみましょう。 http://localhost:3000/memo/add 更新してみましょう (id=7を指定) http://localhost:3000/memo/edit?id=7 削除してみましょう (id=7を指定) http://localhost:3000/memo/delete?id=7 今回は最低限の実装だけを紹介したので、追加、更新、削除への導線は上記のURLから直接アクセスでしたが、一覧ページにボタンを配置してそこから操作させるのが一般的だと思います。またエラーハンドリングなども含めてないので、存在しないidを編集、削除しようとすると落ちます。 まとめ テーブル1個のアプリなんて現場ではまずあり得ないと思います(せめて複数テーブルの結合innerjoin, outerjoinくらいはやっておくべきでしょうか)が、Node.js、サーバーサイドに徐々に慣れてきました。 次はREST APIに関しての記事を書こうと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptのイベントドリブン

イベント イベント:Userが何かすること イベントドリブン:イベントに対するJavaScriptの動作 イベントの書き方↓ document.getElementById('ID名').addEventListener('click',function(){ .. }); 解説 document.getElementById('ID名') //まずはIDでエレメントを取得する .addEventListener('click',function(){ .. }); //addEventListenerでイベントを発火 addEventListenerには2つパラメーターが必要 ①イベントの種類(今回はクリックしたとき) ②動かすプログラム ②に関しては無名関数やらなんやらとあるみたいですが、 ひとまず、function(){}と書き方を覚えておけば良い。 以上
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptの関数

関数の定義 JavaScriptの関数(Function)を定義する const addZero = function(value){ if (value > 10) { value = '0' + value ; return value; } let now = new.Date(); let seconds = now.getSeconds(); seconds = addZero(seconds); 解説します↓ const addZero = function(value){ // 定数の定義 =functionで関数として扱われる // ()は関数を適用する対象 if (value > 10) { value = '0' + value ; return value; //returnの記述は必ずする(=戻り値、返り値) } let now = new.Date(); //オブジェクトのインスタンス化 let seconds = now.getSeconds(); //それに対して秒を取得するメソッド seconds = addZero(seconds); //secondsを持たせたaddZeroを呼び出し、戻り値をsecondsに代入 という感じ。 戻り値は1つだけしか指定できないので、 複数戻り値が欲しい場合はオブジェクトを作る形で対応するらしい(やり方はまだ知らない) それから、関数の定義の仕方は funciton addZero (value){ } でもいいらしい。 (どちらかというと先述した方が一般的っぽい) ふむ〜。 戻り値の考え方と、最後の関数呼び出しで代入らへんが なんかモヤモヤとしちゃう。 以上
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptで数値を操作する

本記事の内容 本記事ではJavaScriptを用いて数値に対して手を加えます。 間違い等ある場合、お手数ですがご連絡いただけますと幸いです。 Math.floor/Math.ceil/Math.round/toFixed/Math.random Math.floorは小数点以下を切り捨てるメソッド。 Math.ceilは小数点以下を切り上げるメソッド。 Math.roundは四捨五入するメソッド。 num.toFixedは指定した小数点まで表示するメソッド。 以下で実際に確認していきます。 以下コード デベロッパーツールにて表示確認 (option + command + I で表示可能。Chromeを使用していることとする。) index.html const num = 9.333333 console.log(Math.floor(num)); #9と表示される console.log(Math.ceil(num)); #10と表示される console.log(Math.round(num)); #9と表示される console.log(num.toFixed(5)); #9.33333と表示される Math.randomメソッド Math.random()*Xは指定した範囲内で数値をランダムに得るメソッド。 例えばデベロッパーツールにてconsole.log(Math.random()*3)と記述すると、0~2までの範囲で数値をランダムに表示する。では、指定した範囲で整数値を取得するにはどの様にすれば良いのか? 範囲をmin~maxの範囲で整数値を取得するとするならば、以下の式が成り立つ。 index.html Math.floor(Math.random(max+1-min))+min 順序立てて考えていく ~範囲~ 5(min)~10(max)までの範囲で整数値を取得するとする。 ・Math.random(11)で0~10までの数値をランダムに取得する。 ・しかし、今回は5~10までの範囲で考えているため、このままでは0~4までの整数値が含まれてしまう。 ・一度0~6((10+1)-5)の範囲で整数値を取得し、後からminとなる整数値を足せば良い! ・よって上記に記述した式が成り立つ(ただし、上記の式はMath.floorと記述していることから整数値を求めていることに注意)。 ※わかりにくければ、定規の様なものを意識するといいかもしれない。 最後に 最後までお付き合いいただきありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptのメソッドとプロパティ

Javascriptの基礎知識 オブジェクトとメソッドとプロパティ document.write 意)画面に表示する(documentオブジェクトにwriteメソッド) JavaScriptは「.」を使って、 オブジェクトとメソッドを数珠繋ぎのように表記していく document.getElementById('ID名').innerHTML = 'あいうえお'; 意)ID名のエレメントを取得して、HTMLの内容を あいうえお に書き換える ひとつずつ解説↓ document.getElementById('ID名') documentオブジェクトに.getElementById(IDでエレメントを取得する)メソッド getElementById('ID名').innerHTML = 'あいうえお';  getElementByIdはエレメントオブジェクトというオブジェクトになり、そこに.innnerHTMLというプロパティを繋いでいる メソッドとプロパティの考え方 動きを表す → メソッド 見た目を表す → プロパティ というイメージでとりあえずOK innerHTMLはHTMLのinner、つまりHTMLの中身(内容)を表すプロパティ 以上
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javascript  else if  私初心者なので 復習

ifとelseだけじゃ足りない!!!さらに条件を追加したい時 const number = 6; 定数numberの値が10より大きい (YES)"10より大きいです" (NO)定数numberが5より大きい?                (YES)"5より大きいです" (NO)"5以下です" ifとelseの間に else if(条件)を追加することで、if文に条件を追加できるよ if(条件式1) { 条件式1が「true」の時の処理 } else if (条件式2) { 条件式1が「false」、条件式2が「true」 の時の処理 } else { どちらの条件式も「false」の時の処理,当てはまんない時 } const number = 6; if(number > 10) {//false console.log("numberは10より大きいです"); } else if (number > 5) {//true console.log("numberは5より大きいです"); } else { console.log("numberは5以下です"); } //コンソール表示には numberは5より大きいです と出るよ。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javascript  else 条件成り立ちません  私初心者なので 復習

if文の条件が満たない場合に、別の処理を行いたい場合がある 例えば、numberの値が10より大きくない場合には 10以下です と出力してみる。 const number = 6; //定数numberの値が10より大きい??? //YES "10より大きいです" //NO "10以下です" elseの書き方 if文に elseを組み合わせると 「もし・・・なら・・を行います、そうじゃなかったら・・を行います」 という処理ができるようになるよ if文の条件がfalseの場合、elseの処理が実行されるよ if(条件式) { 条件が true の時の処理 } else { 条件が false の時の処理 } 実際に書いてみる //else使わない時は、いっぱいif文が必要になる const number = 6; if (number > 10) { console.log("numberは10より大きいです"); } if (number <= 10) { console.log("numberは10以下です"); } //一つの式にまとめよう const number = 6; if (number > 10) { console.log("numberは10より大きいです"); } else { console.log("numberは10以下です"); }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

nuxtにcomposition-apiを導入する

インストール $ yarn add @nuxtjs/composition-api nuxt.config.jsonに加筆 { buildModules: [ '@nuxtjs/composition-api/module' ] }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javascript  比較演算子  私初心者なので 復習

比較演算子 左と右の値が等しいか調べるよ a === b aとbが等しければtrue 等しくなければfalseになる a !== b aとbが異なる const number = 17; console.log(number === 17);//true const name = "qiiko"; console.log(name !== "qiiko");//false
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javascript  if文 と 真偽値  私初心者なので 復習

true false(フォルス) if文は条件式がtrueであれば実行され、falseであれば実行されない。 const number = 17; if(number > 10){//条件式が成り立つ  console.log("numberが10より大きいです"); } //上に書いたやつを真偽値使って書いてみる const number = 17; if(true){//trueに置き換えて console.log("numberが10より大きいです"); } 条件に使った>は、比較演算子と呼ばれる、大小比較の記号。 a<b ・・・aはbより小さい a<=b ・・・aの方が小さい、または等しい a>b ・・・aはbより大きい a>=b ・・・aの方が大きいまたは等しい const number = 17; console.log(number< 50);//true console.log(number<= 17);//true console.log(number> 17);//false
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Safariで見ているページを Chromeで開くブックマークレット【iPhone】

はじめに いまSafariで見ているページをGoogle Chromeで開くブックマークレットです。iPhone Safariで動作確認しました。 コード javascript:location.protocol='googlechrome:'; 解説 ChromeのURLスキームはgooglechrome: です。表示しているページの通信プロトコル(URLの先頭)をこれに置き換えます。それ以外の部分は変更しません。Qiitaを例に取るとこうなります。 使用前 https://qiita.com 使用後 googlechrome://qiita.com この時スマホはSafariでhttpsによる通信を行わず、Chromeを起動してQiitaを開きます。 その他のブラウザ Firefoxで開くためのコードほかを挙げておきます。 Firefox javascript:location.href='firefox://open-url?url='+location.href; Firefox Focus javascript:location.href='firefox-focus://open-url?url='+location.href; DuckDuckGo javascript:location.protocol='ddgQuickLink:'; あとがき HTMLのaタグでmailto:と指定すればメールソフトが立ち上がるリンクとなる、というのはよく知られていると思います。あれもURLスキームの1つを利用したもの。アプリの切り替わり方は似たような感じになります。 本日もありがとうございました。 参考 URLスキームについては、こちらが詳しいです。 https://ios.gadgethacks.com/how-to/always-updated-list-ios-app-url-scheme-names-paths-for-shortcuts-0184033/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptでオブジェクトを使う

JavaScriptの基礎知識 HTMLでJavaScriptを読み込む方法 scriptタグを使う <script> この中にプログラムを書いていく </script> 例として日付を表示させるには <script> document.write('<p class="days">2020/01/01</p>'); //末尾にセミコロンをつけるのはJavaScriptの決まり </script> JavaScript部分の解説↓ document.write( ) document→オブジェクト(対象) write→メソッド(命令) ( )→パラメーター(設定) ↓ 訳:「オブジェクトに対してパラメーターの内容をメソッドしてね」 オブジェクトの考え方 オブジェクトのみだと実体がない!(設計図のみの状態) なので、 オブジェクトを使うときは実体化=インスタンス化してから使う インスタンスにするには newメソッドを使って変数に代入する let today = new Date(); インスタンスにしたところで、 <script> let today = new Date(); document.write('<p>今日は'+ today.getDate() '日です</p>'); </script> まず、new Dateでオブジェクトをインスタンス化し、 設計図のみだったものから、todayという実体を作る。 作った実体に対して .getDateメソッド で日付を取得する。 (document.writeのdocumentも実はブラウザが用意していたインスタンス) 引数に値を入力することも可能↓ <script> let newYear = new Date(2021/1/1); document.write('<p>元旦は'+ newYear.getDate() '日です</p>'); </script> //元旦は2021/1/1日です こんな感じでオブジェクトはインスタンス化して使う。 ※ただし一部例外もあり(Mathオブジェクトとか) 以上
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javascript  if文 条件分岐 私初心者なので 復習

ある条件が成り立つときだけある処理を行う・・・ //イメージ const number = 17; //定数numberの値が10より大きいかい??? YES!!!! console.log("numberは10より大きいです");//条件に当てはまるか考えて、こんなふうに答えてくれる if文 if文を使うと「もし・・・ならば・・を行います。」という条件分岐が可能になる。 if文の後ろに条件式を書いて、 それが  成り立つ 場合の処理を{}波括弧の中に書きます。 最後}の後ろは セミコロンはいらないです; const number = 17; if(numberが10より大きい場合){ console.log("numberは10より大きいです");//条件式が成立すれば実行される } 実際にコードを入れてみます。 const number = 17; if(number > 10){//()内 numberの値が10より大きいという条件 console.log("numberは10より大きいです"); } //コンソール表示 numberは10より大きいです console.logの前にインデントをTABキーで開けるとコードが見やすくなります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

backgroundをif文で使うときに気をつけたいこと

想定する読者 javascriptのコードを書いていて、ある要素のbackgroundの値を分岐判定に使おうと思った人。(例えばすごろくゲームを作っていて、赤色マス、青色マスの判定を画面の色に頼っていたとか) きっかけ 私は背景の色を#を使って指定してしまう癖があるのですが、backgroundの色に応じて処理を変えたいときにif(node.style.background="#~~~")という感じでかいても絶対にtrueの処理に入ってくれなっかのです。これの解決にはだいぶ頭を悩ませてしまったので、備忘録として記録しておきます。  結論からいうとこれにはブラウザがbackgroundの値をどのような形で保持しているか、が原因でした。ブラウザが保存する形式に合わせないと==でも===でもfalseになってしまします。以下の実験では、プロパティの設定時ではいずれも有効と判断される記入例を並べ、if文にかけた時の判定を比べてみました。 実験コード <body> <div id="box" style="width:300px;height: 300px;background: #f55;"></div> <script type=text/javascript > window.onload=function(){ const box=document.getElementById("box"); console.log(box.style.background); console.log(box.style.background=="#f55"); console.log(box.style.background=="rgb(255,85,85)"); console.log(box.style.background=="rgb(255, 85, 85)"); console.log(box.style.background=="rgb(255, 85, 85) none repeat scroll 0% 0%"); //以下省略 実験結果 chromeの場合 rgb(255, 85, 85) ⇐ブラウザが保存している色情報の形式 false ⇐16進数表記  false ⇐rgb表記(スペース無し) true  ⇐rgb表記  false ⇐色以外のrepeat設定などを含めた文 firefoxの場合 rgb(255, 85, 85) none repeat scroll 0% 0%  ⇐ブラウザが保存している色情報の形式 false ⇐16進数表記  false ⇐rgb表記(スペース無し) false ⇐rgb表記   true  ⇐色以外のrepeat設定などを含めた文 #ではじめる16進数表記での色指定(2行目)はif文では意図した処理になりません。rgbで指定するにも","の後にしっかりスペースを開けて合わせないといけないようですね(3,4行目参考)。しかしもっと気をつけるべきこととがありました。私の環境では2つしか比べられませんでしたが、ブラウザによってbackgroundの保存形式が違うではないですか。  jQuery等を使っていれば問題ないのかも知れませんが、もしネイティブjsでかつ.backgroundをif文で使いたいときは if(box.style.background.indexOf("rgb(255, 85, 85)")>=0) のようにすればchromeとfirefoxでは対応できます。(edgeとかではだめかもしれないけど。。)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javascript  テンプレート 連結方法 私初心者なので 復習

文字列と定数の連結は、+記号だけかと思っていました。 テンプレートリテラル・・・名前長い。 っていう連結方法があります。 確かコードを書くときに+で書くよりも短くまとまるだからそうです const name = "qiita"; console.log(`こんにちは、${name}さん`); //コンソール表示   こんにちは、qiitaさん 文字列の中で ${定数} とすることで、文字列の中に定数や変数を含めることができます。 この時に、文字列全体をバッククォーテーションで(`)囲むこと。場所はjis(日本のキーボード)キーだと @マークのところにあります もう一回書いてってみます const name = "qiita"; const age = 17; console.log(`${name} は ${age}歳です`); //コンソール表示  qiitaは17歳です
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Deno・VSCode】Deno拡張機能が有効な環境でdocumentの補完を有効にする

こんにちは。すずともです。 Deno拡張機能を有効にすると、.js、.tsなどのファイルでDenoのLangage Serverが働くようになります。 Denoのプログラムを書く上でこれは便利な機能なのですが、ホームページを構築しようと埋め込み用のJavascriptファイルを作ると、そのファイルでもDenoの拡張機能が働いてしまいます。 Denoが働いてる環境でホームページ書くことなんてあるの?と思うかもしれませんが、サーバを立ててホームページを公開するときにDenoを使うと便利なんです。 今回の実験に使ったファイルはGithubにあげてありますので、作るのめんどくさい人はcloneしてくださいな。 kamekyame/serve-static-deno - Github ホームページを公開するだけのサーバを立てる servestと呼ばれるモジュールを使うと簡単に作れます。 以下のコードをコピペして実行するだけです。ちなみにこのコードはservestの公式HPから持ってきたものです。 Host static files main.ts import { createApp, serveStatic } from "https://deno.land/x/servest@v1.3.1/mod.ts"; const app = createApp(); app.use(serveStatic("./public")); app.listen({ port: 8899 }); 上記のコードでは、serveStatic関数に./publicと入れることで、publicフォルダ内のファイルを静的ファイルとして提供します。つまり、publicフォルダ内にindex.htmlやjs、cssなどをまとめておけば、http://localhost:8899 でホームページを公開するサーバとなるわけです。 公開するホームページでDOM操作をしてみる。 index.htmlは適当に作るとして、そのなかでmain.jsを読み込み、titleというIDのついたH1タグの中身を変更するとしましょう。ファイル構成はこんな感じですかね。 serve-static-deno ├ .vscode │ └ settings.json ├ main.ts └ public ├ index.html └ main.js 一応index.htmlも載せておきます。 index.html <!DOCTYPE html> <html lang="jp"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1 id="title"></h1> <script type="module" src="main.js"></script> </body> </html> main.jsは main.js const title = document.getElementById("title"); title.textContent = "Hello!"; 単純なやつですね。 実際に上記のファイル構成で作ってみると、たぶん、main.jsのdocumentの所がこんな感じになっていると思います。 ※マウスカーソルが見えてませんが、documentの文字の上に載せてます。 documentがanyになっていますね。つまり、documentの補完をしてくれません。これだと、getElementbyIDみたいな打ち間違えも多くなっちゃいます。(特にdom関係の関数名は長いですからね笑) ちなみに、HTML内にscriptタグを作ってjsを書くと、Document型と判断してくれていることが分かります。htmlファイルはDenoの監視下ではないので、補完してくれるというわけですね。 documentの補完のおまじない なぜdocumentがanyになるか。それは、Denoのプログラムではdocumentが使えないからです。だってDOM操作をする先がないんですからね笑 DenoにはTypescriptのコンパイラがついているのですが、そこでdocumentの補完を無効にしています。 無効にしているだけで、有効にすれば補完ができるというわけです! ってことで、補完を有効にしたいファイルの先頭に以下のおまじないを付けてください! /// <reference lib="dom"/> ただのコメント分じゃん!って思うかもしれませんが、Typescriptのコンパイラは3つスラッシュのコメントを読んでくれるようです。 おまじないによって、補完が効きましたね! おまじないの意味 ここからはおまじないの意味までちゃんと知っておきたい!っていうコアな人?(最近使えればいいやって人多くない?)向けの情報です。 Typescriptの公式リファレンスにちゃんと載ってます。 Triple-Slash Directicves typescriptでは、コンパイラオプションにlibってのを渡すことで、どの型定義、構文を使うかを指定しています。 ってことで、documentを補完してほしかったらlib="dom"を追加しているってわけです。 ちなみに、Deno内部では独自ライブラリdeno.windowっていうのを使用しているらしく、これでdocumentの部分などDenoに関係ない部分を消しているんですね。 不安定だから気を付けてね main.jsに先ほどのおまじないを追加すればいいわけですが、vscodeの拡張機能はそこまで賢くないらしく、関係ないファイルにまでdocumentの補完をしてくれちゃってますw まぁ、リアルタイムでチェックしてくれてるのに1ファイルだけ使うライブラリが違うって無茶苦茶ですからね笑 ↑サーバ側のmain.tsファイル、documentを補完してしまっている。 なので、誤ってdocument.~を使わないように! とはいっても、実行時に走るちゃんとした?コンパイラにはエラー吐かれる(tsファイルなら)のでまぁ安心ですね。 ↓エラー文 error: TS2584 [ERROR]: Cannot find name 'document'. Do you need to change your target library? Try changing the lib compiler option to include 'dom'. document.body; コンパイラのlibオプションにdomがないから入れたらどう?(意訳) 終わりに 最後まで記事を読んでくださりありがとうございました? Denoはまだまだ奥が深く、僕はtypescriptもDenoから学んだので、知識も浅いです。 浅いなりにoutputしていこうかなということで記事を書いています! 言い回しが分かりにくかったり、間違った意味で言葉を使ったりしていたら教えてくれるとありがたいです。 これからもDeno、バンバンつかっていろんな記事書いていきますので、よろしくお願いします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

useEffect 第二引数について

投票アプリ作成中、よくわからない警告に遭遇(Part2) 投票アプリ以外でも、時々、今回の警告は見たことがあった。。。 React Hook useEffect has a missing dependency: 'email'. Either include it or remove the dependency array react-hooks/exhaustive-deps (日本語)React Hook useEffectに依存関係がありません: 'email'。それを含めるか、依存関係配列react-hooks / exhaustive-depsを削除します 大前提として、useEffectについて 第一引数には、副作用として実行する関数を与える。 useEffectに指定することで、副作用は、コンポーネントの描写が終わった後に実行される。 第二引数によって、副作用を実行する頻度を設定できる。 第二引数を与えなかった場合、コンポーネントの描写後、毎回実行。 ?第二引数に空の配列を与えた場合には、初回描写時にのみ実行。 ?第二引数に配列を与え、要素として変数を指定すると、指定した変数に変更があった場合のみ実行。 警告が出る理由 第2引数を指定していないから。 今回、以下のコードのように、 ?第二引数に空の配列を与えた場合には、初回描写時にのみ実行。 としていた。 // ユーザー情報を取得 useEffect(() => { firebase .firestore() .collection("users") .where("email", "==", email) .onSnapshot((snapshot) => { const getUsers = snapshot.docs.map((doc) => { return { ...doc.data(), docid: doc.id, }; }); setUsers(getUsers); }); }, []); 対処法 以下のコードのように、 ?第二引数に配列を与え、要素として変数を指定すると、指定した変数に変更があった場合のみ実行。 とすることで、警告は消えた。 }, [email]); その他の警告と対処 ① React Hook useEffect has missing dependencies: 'history.location.state.birthday', 'history.location.state.email', 'history.location.state.gender', 'history.location.state.password', and 'history.location.state.username'. Either include them or remove the dependency array react-hooks/exhaustive-deps (対処) こちらも ?第二引数を空の配列 としていたため、 以下のように、 ?変数を指定した ことで、警告は消えた。 }, [history]); ② React Hook useEffect has missing dependencies: 'email', 'question.answer1Id', 'question.answer2Id', and 'question.docid'. Either include them or remove the dependency array react-hooks/exhaustive-deps (対処) こちらも ?第二引数を空の配列 としていたため、 以下のように、 ?変数を指定した ことで、警告は消えた。 }, [email, question]); 今後は、、、 第二引数が、 ⭐空の配列が適している場合、変数を指定する場合⭐ これらを適切に使い分けれるように、まだまだ勉強が必要だ。。。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【javascript】まだよくわかってないClassを使って日付操作【勉強】

前回の記事で日付の続きでもあります。 日付処理は有用なライブラリがありますが、経験値積むためなのでお許しを。 目的 Dateを継承して以下のようなメソッドチェーンにしたかった。 const time = new Time(1999,7,7,16,30,30,500); const f = 'YYYY/MM/DD H:mm:ss.fff(DDD)'; console.log( time.term(1990, 2, 3) ); // -297621030500 console.log( time.getWeekday() ); // Sat console.log( time.getWeekday('ja') ); // 土 console.log( time.format(f) ); // 1999/08/07 16:30:30.500(Sat) console.log( time.advance(1).format(f) ); // 2000/08/07 16:30:30.500(Mon) console.log( time.advanceDays(-3,5).format(f) ); // 2000/08/04 21:30:30.500(Fri) console.log( time.reset().format(f) ); // 1999/08/07 16:30:30.500(Sat) コード 追記1:time.term()のミリ秒以外で出力するメソッドを追加。 追記2:time.reset()関連の修正。引数nowを追加。 class Time extends Date { constructor(...args) { super(...args); this.default = super.toISOString(); } reset(now) { const d = now===true ? new Date() : new Date(this.default); super.setFullYear(d.getFullYear()); super.setMonth(d.getMonth()); super.setDate(d.getDate()); super.setHours(d.getHours()); super.setMinutes(d.getMinutes()); super.setSeconds(d.getSeconds()); super.setMilliseconds(d.getMilliseconds()); return this } advance() { if (arguments[0]) super.setFullYear(super.getFullYear() + arguments[0]); if (arguments[1]) super.setMonth(super.getMonth() + arguments[1]); if (arguments[2]) super.setDate(super.getDate() + arguments[2]); if (arguments[3]) super.setHours(super.getHours() + arguments[3]); if (arguments[4]) super.setMinutes(super.getMinutes() + arguments[4]); if (arguments[5]) super.setSeconds(super.getSeconds() + arguments[5]); if (arguments[6]) super.setMilliseconds(super.getMilliseconds() + arguments[6]); return this } advanceDays() { if (arguments[0]) super.setDate(super.getDate() + arguments[0]); if (arguments[1]) super.setHours(super.getHours() + arguments[1]); if (arguments[2]) super.setMinutes(super.getMinutes() + arguments[2]); if (arguments[3]) super.setSeconds(super.getSeconds() + arguments[3]); if (arguments[4]) super.setMilliseconds(super.getMilliseconds() + arguments[4]); return this } term() { return new Date(...arguments) - this; } termSeconds() { return Math.round((new Date(...arguments) - this) / 1000); } termMinuts() { return Math.round((new Date(...arguments) - this) / 60000); } termHours() { return Math.round((new Date(...arguments) - this) / 3600000); } termDays() { return Math.round((new Date(...arguments) - this) / 86400000); } getWeekday(langStr) { const n = super.getDay(); switch (langStr){ case 'ja': return '日月火水木金土'.charAt(n); default: return ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'][n]; } } format(formatStr) { const weekdays = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']; const pad = (num, dig) => ('000' + num).slice(-dig); return formatStr.replace(/([YMDHhmsf])\1*/g, match => { switch (match) { case 'YYYY':return super.getFullYear(); case 'YY': return pad(super.getFullYear(), 2); case 'M': return super.getMonth()+1; case 'MM': return pad(super.getMonth()+1, 2); case 'D': return super.getDate(); case 'DD': return pad(super.getDate(), 2); case 'H': return super.getHours(); case 'HH': return pad(super.getHours(), 2); case 'm': return super.getMinutes(); case 'mm': return pad(super.getMinutes(), 2); case 's': return super.getSeconds(); case 'ss': return pad(super.getSeconds(), 2); case 'fff': return pad(super.getMilliseconds(), 3); case 'DDD': return weekdays[super.getDay()]; default: return match; } }) } } メソッド解説 reset time.reset( boolean now ) 引数 true or other 返値 date date 説明 後述のadvance/advanceDayの処理で変化した日付をインスタンス生成時のものに戻す。引数をtrueにした場合のみ、このメソッドを実行した時間に上書きする。 advance time.advance( number [y,[m,[d,[h,[mm,[s,[ms]]]]]]]] ) 引数 number 第一引数を年、月,日,時,分,秒,ミリ秒と続く 返値 date date 説明 time.advance(0,1,1)で一月一日分加算され、time.advance(-1)で1年戻る advanceDays time.advanceDays( number [d,[mm,[s,[ms]]]] ) 引数 number 第一引数を日、時,分,秒,ミリ秒と続く 返値 date date 説明 advance()の年月を省いたもの term time.term() 引数 new Date()に指定する引数と同じもの 返値 number milliseconds 説明 インスタンス生成した日付と、ここで指定した日付の差が何ミリ秒かを出力 termSeconds... time.termSeconds() / time.termMinutes() / time.termHours() / time.termDays() 引数 new Date()に指定する引数と同じもの 返値 number seconds/minutes/hours/days 説明 各単位の対応版 getWeekday time.getWeekday( string lang ) 引数 string 言語指定 返値 string weekday 説明 'ja'を指定すれば日本の曜日、それ以外は英語の曜日 format time.format( string format ) 引数 string 出力形式 返値 string date 説明 詳細は前回の記事。'YYYY/MM/DD'と指定すれば2000/08/04のように返す。 私感 superの使い方これでいいのかとか、他のメソッドでも使いたいweekdaysのような曜日の配列をconstructorに置いても良いのか(外から書き換えられそう)とか、他にも多分色々おかしいところがあるかもしれない。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vuexについてざっくりまとめてみた

Vuexとは? JavascriptのフレームワークであるVue.jsを使ったアプリケーションで用いられる状態管理ライブラリ。 つまり、Vueのプロジェクト内で使われているデータをより扱いやすくするためのの管理システム。 なんのためにある? アプリケーション内にあるデータのやりとりの利便性や可読性を上げるため。 アプリケーション全体で使用するデータをコンポーネント毎ではなく、一つの場所でまとめて管理するという考え方。 Vuexを使用せずに、図内左端のコンポーネントにあるデータを右端のコンポーネントで使用する場合、propsや$emitが繰り返され、コードの可読性が低下する(データが追いにくくなる)。 Vuex内でのデータの動き
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Javascript】非同期通信のfetchを使ってサーバーからjsonファイルの情報をブラウザーに表示してみた

初めに 非同期通信にはXMLHttpRequest(XHR)とfetch APIがあります。今回はfetchによる非同期通信を学習し、試してみることに。やることは至ってシンプル。契約中のレンタルサーバーに自作のjsonファイルをアップロードし、そのjsonファイルに記載されているある情報を取得してブラウザに表示してみました。 ※内容に間違いなどがある場合はご指摘をよろしくお願いします。 前回の記事:https://qiita.com/redrabbit1104/items/1ce9f665a0fcd1d99bb2 https://qiita.com/redrabbit1104/items/b8b61a72f849fa3e8881 https://qiita.com/redrabbit1104/items/02bc16cf5abd4ed10ec1 https://qiita.com/redrabbit1104/items/c131c46897bfdf86e08b やりたいこと 個人で契約中のレンタルサーバーにjsonファイルをアップロードし、javascriptの非同期通信fetch APIを利用してサーバーに接続。jsonファイルをhttp通信のGETメソッドで特定の情報を取得してブラウザに表示させる。 作業手順 ①test.jsonファイルを作成します。 ②CORSを設定(.htaccessファイルを作成しサーバーにアップロード) ③作成したtest.jsonファイル、.htaccessファイルをサーバーにアップロードします。 ④local上でhtmlファイルを作成 ⑤関数の実行 test.jsonファイルを作成 データ通信でjson形式のファイルがよく使われるため、test.jsonというファイルを作りました。 { "name": "hogehoge", "description": "Hello, World", "countries": { "USA": "hello", "UK": "hello", "CHINA": "hello", "JAPAN": "hello" }, "email": "hogehoge@abc.com" } この中で、"description"という項目の情報を取得します。 CORSの設定 契約中のレンタルサーバーはCORS(Cross-Origin Resource Sharing)の設定が必要です。何故ならOriginが異なるサイトに接続するにはサーバーに接続するための許可が要るからです。その許可を得るためのファイルを作成します。 CORSについての関連記事 :https://qiita.com/att55/items/2154a8aad8bf1409db2b  https://javascript.keicode.com/newjs/what-is-cors.php .htacessの作成 Header set Access-Control-Allow-Origin: "*" //ファイル名は「.htaccess」 test.json、.htaccessをサーバーにアップロード レンタルサーバーにtest.jsonと.htaccessをアップロードします。接続したいurl(トップページ)の直下にアップロードしました。(.htaccessは隠しファイルなので、macの場合「shift + command + .」で隠しファイルを表示させてからアップロードします) local上でhtmlファイルを作成 ご自身のパソコンのどのフォルダーでもいいですが、簡単なhtmlファイルを作成しscriptタグを使ってjavascriptを記述しました。 ❶fetch_test.htmlを作成 fetchAPIで取得したデータを表示させるためのHTMLファイルを作成します。 <body> <div id="text"></div> </body> 中身はとてもシンプルです。divタグを用意し、id名をtextにしました。 ❷fetch関数の作成 非同期通信のgetメソッドで先ほどアップロードしたjsonファイルに接続するための関数を作成します。 function fetchGet(url, options) { return fetch(url, options) .then(response => { if (response.ok) { //接続に成功した場合 return response.json();  //結果の値(response)をjson形式で取得 } throw new Error('エラーです'); //失敗した場合にエラーメッセージを表示 }).catch(e => console.log(e.message)); } ❸async関数を作成(awaitを使うため) 上記で宣言したfetch関数をawaitを使って処理が完了するまで、内容を画面に表示しないようにします。 const url = 'http://hogehoge.com/test.json'; // 接続したurl名 const options = { method: 'GET', // GETメソッドを指定 }; async function fetchText(url, options) { const response = await fetchGet(url, options); //fetchGet関数にawaitを指定し、fetchGet関数が完了するまで以下の処理が走らないようにする const targetDiv = document.getElementById('text'); //text要素を取得 const textElement = document.createElement('div'); //divタグを生成 textElement.innerText = response.description; //divタグのテキストにfetchで取得したdescriptionの値を代入 targetDiv.appendChild(textElement); //text要素の子要素に作成したtextElementを挿入 } fetchText(url, options); //関数を実行 ブラウザから"hello world"が表示される Get通信が成功しjsonファイルの"description"に該当する値"hello world"がブラウザに表示されました。fetch apiを使った非同期通信が成功しました。 参考サイト https://blog.e2info.co.jp/2020/03/08/corscross-origin-resource-sharing/ https://qiita.com/api/v2/docs https://qiita.com/mikan3rd/items/ba4737023f08bb2ca161
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JSテンプレートリテラル ${ }

はじめに 業務で使用したプロジェクトの中に、このような書き方があり、「バッククオートで囲む?」「${}って書き方あるん?」と思ったので簡単に調べました。 { //略 href: `${process.env.BASE_URL}/sample/sample.html`, //略 } テンプレートリテラル 結論から言うと、ECMAScript 6 (2015年)から導入された構文で、テンプレートリテラルといいます。バッククオートで囲みます。 改行がそのまま反映される const sentence = `むかーしむかし あるところに おじいさんとおばあさんがいました` これと const sentence = "むかーしむかし\nあるところに\nおじいさんとおばあさんがいました" これは一緒ということです。 文字列の中に式を埋め込める console.log(`500円の商品の税込価格は${500*1.1}円です。`) // 結果: 500円の商品の税込価格は550円です ${ func() } このようにテンプレートリテラル内で、メソッドを呼び出すこともできます。 さいごに 記事を読んでいただきありがとうございました。ほかにもテンプレートリテラルを使って、色々できそうです。 参照記事 テンプレートリテラル(MDN)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Warning: Can't perform a React state update on an unmounted component.

投票アプリ作成中、よくわからない警告に遭遇 投票作成ページにて、投票を作成すると、投票を表示させるメインページに戻るが、その際に毎回、以下のような警告が出ていた。 Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function. (日本語)警告:マウントされていないコンポーネントでReact状態の更新を実行することはできません。 これは何もしませんが、アプリケーションのメモリリークを示しています。 修正するには、useEffectクリーンアップ関数のすべてのサブスクリプションと非同期タスクをキャンセルします。 警告が出る理由 useEffet内で、まだ、firebaseからすべて読み込まれていないのに、setQuestionsを実行しようとするから警告が出る。 const VotesList = () => { const [questions, setQuestions] = useState(null); useEffect(() => { firebase .firestore() .collection("questions") .orderBy("timestamp", "desc") .onSnapshot((snapshot) => { const questions = snapshot.docs.map((doc) => { return { username: doc.data().username, question: doc.data().question, answer1: doc.data().answer1, answer1Id: doc.data().answer1Id, answer2: doc.data().answer2, answer2Id: doc.data().answer2Id, docid: doc.id, //<- keyを設定するためにidを取得、あとで削除機能等をつける }; }); setQuestions(questions); }); }, []); return ( <> <ul> {questions?.map((question) => { return <CountVotes question={question} key={question.docid} />; })} </ul> </> ); }; 対処法 下記のように書き直すことで、警告は出なくなった。 アンマウント時にはsetQuestionsは実行せず、 マウント時のみsetQuestionsが実行するようにする。 まだDOMに無い時には return dispose で一度回避するイメージ。 useEffect(() => { let disposed = false; const dispose = () => { disposed = true; }; firebase .firestore() .collection("questions") .orderBy("timestamp", "desc") .onSnapshot((snapshot) => { const questions = snapshot.docs.map((doc) => { return { username: doc.data().username, question: doc.data().question, answer1: doc.data().answer1, answer1Id: doc.data().answer1Id, answer2: doc.data().answer2, answer2Id: doc.data().answer2Id, docid: doc.id, //<- keyを設定するためにidを取得、あとで削除機能等をつける }; }); !disposed && setQuestions(questions); }); return dispose; }, []);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ピラミッドの作成

4段のピラミッドを作成する //4段繰り返す処理を実行 for (i = 1; i <= 4; i++) { const array = []; //*各段の左側の空有白部分を表現 for (j = 1; j <= 4 - i; j++) { array.push(" "); } //各段の*部分を表現 for (j = 1; j <= 2 * i - 1; j++) { array.push("*"); } const result = array.join(""); console.log(result); } // 出力結果 // * // *** // ***** // *******
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Node.js】Express.js / MySQL / ejs / を使ったCRUDアプリ

目的 現在、MySQLに保管した店舗データを編集できるアプリケーションを作成しています。Node.jsのexpress.jsを使用し、viewにはejsを利用しています。この記事では、初学者の私がつまずいた、パラメータの受け渡しについて記述します。 ずばり「企業一覧画面から、企業に属した店舗の一覧を表示させる」処理についてです。 一連の処理は、こんな感じです 企業+店舗一覧を取得(MySQL) → 企業一覧画面で企業名をクリック(ejs) → 店舗一覧画面(ejs) → 店舗名のリンクをクリック (ejs) → ★ express.js(app.js)でデータを加工(MySQL) → ★ 加工したデータをejsに渡す(express.js) → ★ ejsで加工したデータを表示させる 対象読者 ・Express初心者 ・アプリ作成初心者 ・MySQL初心者 環境と周辺構造 ・local (mac Big Sur) ・AWS MySQL 基本となるデータベースとの接続やCRUD処理の基礎的な書き方等については、主にリンク先の記事を参考に作成しました。 参照:Express.js(node.js)からMySQLへの接続とCRUD操作 テーブル構造 テーブルの相関関係は以下の通りです。 account_masterが企業、shop_masterが企業が運営する店舗と仮定し作成しています。 テーブルの関係性を簡単に表すと、 account_master.account_id = shop_master.shop_account_idです。 企業側のaccount_idは店舗側のshop_account_idと同じことを意味しています。 画面イメージ 少し雑ですが、画面のイメージは以下の通りです。 ・企業 一覧画面(account_master_index.ejs) ・店舗一覧画面(shop_index) 企業名リンクをクリックすると、店舗一覧画面に遷移します。 ディレクトリ構造 ※現在、未完成のため一部のみ記載 account_app/ ├── node_modules ├── views │ ├── account_master_index.ejs │ ├── edit.ejs │ └── shop_index.ejs ├── .env ├── .gitignore ├── app.js ├── package.json └── README.md app.jsにexpress.jsやMySQLの処理を記述し、viewsの中でテンプレートを作成しています。 前提 参考サイトでは、簡易なテーブルのデータで作成されていたため、企業の一覧や、店舗の一覧は簡単に表示まで出来ました。しかし、企業に基づく店舗など関係性がちょっと複雑な場合、どう表示させればよいかが全く分かりませんでした。 先に企業一覧について、次に店舗一覧について記述します。 企業一覧画面 app.js 企業一覧画面は参考サイトを元に、テーブル名、select文を変えるだけでOKでした。※記述外の設定は参考サイトを参照ください。 //app.jsの企業一覧に関する部分 app.get('/', (req, res) => { const sql = "select * from account_master where is_deleted = 0; con.query(sql, function (err, result, fields) { if (err) throw err; res.render('account_master_index',{account_master : result}); }); }); app.getは 第一引数に指定したURLに対応しており、express.js のアプリケーションのルート( 今回は、localhost:3000 )へのGETメソッドに対応します。con.queryでselect * from account_master where is_deleted = 0"を取得。 例外処理を記述した後、res.renderの第一引数にデータを表示させたいテンプレートを設定し、第二引数に .ejs に渡す名前を指定します。この命名により、ejs側ではresultではなくaccount_masterを使って取得したデータを利用できます。 account_master_indx.ejs 一部抜粋した記述です。 //account_master_indx.ejsの中身 <% account_master.forEach(function (value) { %> <tr> <td><%= account_id %></td> ★ <td><a href="/shop_index/<%= value.account_id %>"><%= value.account_name %></a></td> <td><%= value.account_email.split('*') %></td> <td><%= value.mail_requested %></td> <td><%= value.is_deleted %></td> <td><%= value.updated_at %></td> <td><%= value.account_form_url %></td> <td><a href="/edit/<%= value.ue_account_id %>">up</a></td> </tr> <% }); %> 参考サイトはforEachを使っていたため、そのまま使っています。<% %>や、<%= %>で処理を書くのか、 HTML として表示させるかを書きます。 ★ここで4行目に注目 <a href="/shop_index/<%= value.account_id %>"><%= value.account_name %></a>で企業 id のパラメータをURLに指定しています。後にこれと同じURLのパラメータとして表示させる処理をreq.paramsを使い app.js 内に で記述します。 ここからが今回の記事の本題です ポイントとしては以下のとおりです。 ・個別に呼び出すのではなく、まず店舗の全データを取得する ・配列を新たに作成する ・for文、if文で条件指定する ・加工した「会社一覧に紐づく店舗一覧の配列を作成するデータ」をejs側で表示する app.jsでデータを加工する 失敗した考え方 店舗一覧画面を出そうした際に、まず企業一覧画面と企業の編集画面を参考にしました。というのも、編集画面は企業のaccount_idを自然に渡せていたからです。そのため、店舗一覧画面も企業一覧と編集画面のようにaccount_idを受け渡せないかと考えました。 そもそも、この↑部分の認識が間違っており、正しくはexpress.js側で処理したデータをejsで表示させる。つまり、ejsからgetメソッドで表示させる場合はejsから値を受け渡すなどは行わないです。 成功した考え方 いきなり企業に紐づく店舗一覧を、expressで記述しそれをejs側で表示させるのではなく、まずapp.js内で先に店舗の全データを出します。そのデータを使って、必要な情報だけを載せた配列を新たに作成します。作成した配列をejs側で呼び出し、表示させます。 店舗一覧画面 店舗一覧画面に関する記述は以下のとおりです。 app.js //店舗データを取得するための変数を定義 var shopDat; //店舗の全データを取得 con.query('select * from shop_master where is_deleted = 0;', function (error, results, fields) { if (error) throw error; shopDat = results; //shopDatに代入 }); ~~(中略)~~ //企業ごとの店舗一覧を取得しshop_index.ejsで表示させるためのデータ加工 app.get('/shop_index/:shop_account_id', (req, res) => { let shops = []; //新たな配列を作成 for(let i = 0; i < shopDat.length; i++){ if (req.params.shop_account_id == shopDat[i].shop_account_id) { //表示するパラメータを指定 var target_shop = { //配列に入れるオブジェクトデータを定義 "shop_id": shopDat[i].shop_id, "shop_name_jp": shopDat[i].shop_name_jp, "shop_name_en": shopDat[i].shop_name_en, "shop_account_id": shopDat[i].shop_account_id, "is_deleted": shopDat[i].is_deleted, "updated_at": shopDat[i].updated_at }; shops.push(target_shop) //空の配列shopsに.pushで追加 } }; res.render('shop_index',{shop_data :shops}); //shop_dataとしてshop_index.ejsに渡す }); 先に shopDat を宣言し、そこにMySQLから店舗の全データを代入します。店舗一覧画面を表示させる箇所に、 shops という新たな空の配列を作成します。更にi番目の shopDat のデータを保持させる target_shop というオブジェクトを作成します。shops.push(target_shop)を shops という空の配列に、 for 文で作成されたオブジェクトを追加して、加工データを作成します。 この時req.params.shop_account_id == shopDat[i].shop_account_idではURLに渡すパラメータと企業に紐づく店舗の情報を一致させるために記述しています。※shop_account_idは企業のアカウント id と同じです。 req.params はリクエストされたパスからパラメータを取得するに使う文字列です。 [Node.js][Express]リクエストからパラメータを取得する・POSTされたデータを取得する shop_index.ejs //店舗一覧画面に関係する部分 <% for (let i = 0; i < shop_data.length; i++) { %> <tr> <td><%= shop_data[i].shop_id %></td> <td><%= shop_data[i].shop_name_jp %></td> <td><%= shop_data[i].shop_name_en %></td> <td><%= shop_data[i].shop_account_id %></td> <td><%= shop_data[i].updated_at %></td> <td><a href="/edit/<%= shop_data[i].shop_id %>">更新する</a></td> </tr> <% }; %> 企業一覧画面ではforEachを使いましたが、こちらは for 文で表記しました。これで、企業に属する店舗の一覧を表示させることができました。 小技とつまずいたポイント ・出力したいデータが正しいかどうかをHTML(.ejs)でみたい → <%- JSON.stringify(shop_data) %>と記述することで見られます! ・JavaScriptのデータは配列[ ]の中にオブジェクト{ }をもつことができる。 → JavaScriptは [{ name:aaa, email:xxx@yyyy}, { name:bbb, email:yyy@xxxx}, { }....]とできるようです。 ・forとif文を一気に記述するのではなく、一つづつ書くこと → 処理を一気に書こうとして、ほしいデータをなかなか出すことが出来ませんでした。落ち着いて出力されたデータを見ながら、一つづつ解決するほうが結果早いですね。 ・配列から要素を取り出す方法 → iをつけることに、なかなか気がつけませんでした。 まとめ JavaScriptを勉強しはじめて3週間ほどですが、MySQLのデータを加工を実施しました!空の配列を作って、ほしいデータを作成をすることは初めての作業でしたが、なんとかうまく出来たので良かったです。途中で、配列なのか連想配列なのか迷ったりしたため中々答えにたどり着けませんでした。これが初学者の方のためになればと思います。 また、一部未完成・不十分な記述がありますので、ご教示いただけると幸いです! 以上 参照 ・Express.js(node.js)からMySQLへの接続とCRUD操作 ・[Node.js][Express]リクエストからパラメータを取得する・POSTされたデータを取得する ・for 文と push メソッドを使って配列要素を複数生成
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Node.js】Express.js / MySQL / ejs / を使ったDBのCRUDアプリ

目的 現在、MySQLに保管した店舗データを編集できるアプリケーションを作成しています。Node.jsのexpress.jsを使用し、viewにはejsを利用しています。この記事では、初学者の私がつまずいた、パラメータの受け渡しについて記述します。 ずばり「企業一覧画面から、企業に属した店舗の一覧を表示させる」処理についてです。 一連の処理は、こんな感じです 企業+店舗一覧を取得(MySQL) → 企業一覧画面で企業名をクリック(ejs) → 店舗一覧画面(ejs) → 店舗名のリンクをクリック (ejs) → ★ express.js(app.js)でデータを加工(MySQL) → ★ 加工したデータをejsに渡す(express.js) → ★ ejsで加工したデータを表示させる 対象読者 ・Express初心者 ・アプリ作成初心者 ・MySQL初心者 環境と周辺構造 ・local (mac Big Sur) ・AWS MySQL 基本となるデータベースとの接続やCRUD処理の基礎的な書き方等については、主にリンク先の記事を参考に作成しました。 参照:Express.js(node.js)からMySQLへの接続とCRUD操作 テーブル構造 テーブルの相関関係は以下の通りです。 account_masterが企業、shop_masterが企業が運営する店舗と仮定し作成しています。 テーブルの関係性を簡単に表すと、 account_master.account_id = shop_master.shop_account_idです。 企業側のaccount_idは店舗側のshop_account_idと同じことを意味しています。 画面イメージ 少し雑ですが、画面のイメージは以下の通りです。 ・企業 一覧画面(account_master_index.ejs) ・店舗一覧画面(shop_index) 企業名リンクをクリックすると、店舗一覧画面に遷移します。 ディレクトリ構造 ※現在、未完成のため一部のみ記載 account_app/ ├── node_modules ├── views │ ├── account_master_index.ejs │ ├── edit.ejs │ └── shop_index.ejs ├── .env ├── .gitignore ├── app.js ├── package.json └── README.md app.jsにexpress.jsやMySQLの処理を記述し、viewsの中でテンプレートを作成しています。 前提 参考サイトでは、簡易なテーブルのデータで作成されていたため、企業の一覧や、店舗の一覧は簡単に表示まで出来ました。しかし、企業に基づく店舗など関係性がちょっと複雑な場合、どう表示させればよいかが全く分かりませんでした。 先に企業一覧について、次に店舗一覧について記述します。 企業一覧画面 app.js 企業一覧画面は参考サイトを元に、テーブル名、select文を変えるだけでOKでした。※記述外の設定は参考サイトを参照ください。 //app.jsの企業一覧に関する部分 app.get('/', (req, res) => { const sql = "select * from account_master where is_deleted = 0; con.query(sql, function (err, result, fields) { if (err) throw err; res.render('account_master_index',{account_master : result}); }); }); app.getは 第一引数に指定したURLに対応しており、express.js のアプリケーションのルート( 今回は、localhost:3000 )へのGETメソッドに対応します。con.queryでselect * from account_master where is_deleted = 0"を取得。 例外処理を記述した後、res.renderの第一引数にデータを表示させたいテンプレートを設定し、第二引数に .ejs に渡す名前を指定します。この命名により、ejs側ではresultではなくaccount_masterを使って取得したデータを利用できます。 account_master_indx.ejs 一部抜粋した記述です。 //account_master_indx.ejsの中身 <% account_master.forEach(function (value) { %> <tr> <td><%= account_id %></td> ★ <td><a href="/shop_index/<%= value.account_id %>"><%= value.account_name %></a></td> <td><%= value.account_email.split('*') %></td> <td><%= value.mail_requested %></td> <td><%= value.is_deleted %></td> <td><%= value.updated_at %></td> <td><%= value.account_form_url %></td> <td><a href="/edit/<%= value.ue_account_id %>">up</a></td> </tr> <% }); %> 参考サイトはforEachを使っていたため、そのまま使っています。<% %>や、<%= %>で処理を書くのか、 HTML として表示させるかを書きます。 ★ここで4行目に注目 <a href="/shop_index/<%= value.account_id %>"><%= value.account_name %></a>で企業 id のパラメータをURLに指定しています。後にこれと同じURLのパラメータとして表示させる処理をreq.paramsを使い app.js 内に で記述します。 ここからが今回の記事の本題です ポイントとしては以下のとおりです。 ・個別に呼び出すのではなく、まず店舗の全データを取得する ・配列を新たに作成する ・for文、if文で条件指定する ・加工した「会社一覧に紐づく店舗一覧の配列を作成するデータ」をejs側で表示する app.jsでデータを加工する 失敗した考え方 店舗一覧画面を出そうした際に、まず企業一覧画面と企業の編集画面を参考にしました。というのも、編集画面は企業のaccount_idを自然に渡せていたからです。そのため、店舗一覧画面も企業一覧と編集画面のようにaccount_idを受け渡せないかと考えました。 そもそも、この↑部分の認識が間違っており、正しくはexpress.js側で処理したデータをejsで表示させる。つまり、ejsからgetメソッドで表示させる場合はejsから値を受け渡すなどは行わないです。 成功した考え方 いきなり企業に紐づく店舗一覧を、expressで記述しそれをejs側で表示させるのではなく、まずapp.js内で先に店舗の全データを出します。そのデータを使って、必要な情報だけを載せた配列を新たに作成します。作成した配列をejs側で呼び出し、表示させます。 店舗一覧画面 店舗一覧画面に関する記述は以下のとおりです。 app.js //店舗データを取得するための変数を定義 var shopDat; //店舗の全データを取得 con.query('select * from shop_master where is_deleted = 0;', function (error, results, fields) { if (error) throw error; shopDat = results; //shopDatに代入 }); ~~(中略)~~ //企業ごとの店舗一覧を取得しshop_index.ejsで表示させるためのデータ加工 app.get('/shop_index/:shop_account_id', (req, res) => { let shops = []; //新たな配列を作成 for(let i = 0; i < shopDat.length; i++){ if (req.params.shop_account_id == shopDat[i].shop_account_id) { //表示するパラメータを指定 var target_shop = { //配列に入れるオブジェクトデータを定義 "shop_id": shopDat[i].shop_id, "shop_name_jp": shopDat[i].shop_name_jp, "shop_name_en": shopDat[i].shop_name_en, "shop_account_id": shopDat[i].shop_account_id, "is_deleted": shopDat[i].is_deleted, "updated_at": shopDat[i].updated_at }; shops.push(target_shop) //空の配列shopsに.pushで追加 } }; res.render('shop_index',{shop_data :shops}); //shop_dataとしてshop_index.ejsに渡す }); 先に shopDat を宣言し、そこにMySQLから店舗の全データを代入します。店舗一覧画面を表示させる箇所に、 shops という新たな空の配列を作成します。更にi番目の shopDat のデータを保持させる target_shop というオブジェクトを作成します。shops.push(target_shop)を shops という空の配列に、 for 文で作成されたオブジェクトを追加して、加工データを作成します。 この時req.params.shop_account_id == shopDat[i].shop_account_idではURLに渡すパラメータと企業に紐づく店舗の情報を一致させるために記述しています。※shop_account_idは企業のアカウント id と同じです。 req.params はリクエストされたパスからパラメータを取得するに使う文字列です。 [Node.js][Express]リクエストからパラメータを取得する・POSTされたデータを取得する shop_index.ejs //店舗一覧画面に関係する部分 <% for (let i = 0; i < shop_data.length; i++) { %> <tr> <td><%= shop_data[i].shop_id %></td> <td><%= shop_data[i].shop_name_jp %></td> <td><%= shop_data[i].shop_name_en %></td> <td><%= shop_data[i].shop_account_id %></td> <td><%= shop_data[i].updated_at %></td> <td><a href="/edit/<%= shop_data[i].shop_id %>">更新する</a></td> </tr> <% }; %> 企業一覧画面ではforEachを使いましたが、こちらは for 文で表記しました。これで、企業に属する店舗の一覧を表示させることができました。 小技とつまずいたポイント ・出力したいデータが正しいかどうかをHTML(.ejs)でみたい → <%- JSON.stringify(shop_data) %>と記述することで見られます! ・JavaScriptのデータは配列[ ]の中にオブジェクト{ }をもつことができる。 → JavaScriptは [{ name:aaa, email:xxx@yyyy}, { name:bbb, email:yyy@xxxx}, { }....]とできるようです。 ・forとif文を一気に記述するのではなく、一つづつ書くこと → 処理を一気に書こうとして、ほしいデータをなかなか出すことが出来ませんでした。落ち着いて出力されたデータを見ながら、一つづつ解決するほうが結果早いですね。 ・配列から要素を取り出す方法 → iをつけることに、なかなか気がつけませんでした。 まとめ JavaScriptを勉強しはじめて3週間ほどですが、MySQLのデータを加工を実施しました!空の配列を作って、ほしいデータを作成をすることは初めての作業でしたが、なんとかうまく出来たので良かったです。途中で、配列なのか連想配列なのか迷ったりしたため中々答えにたどり着けませんでした。これが初学者の方のためになればと思います。 また、一部未完成・不十分な記述がありますので、ご教示いただけると幸いです! 以上 参照 ・Express.js(node.js)からMySQLへの接続とCRUD操作 ・[Node.js][Express]リクエストからパラメータを取得する・POSTされたデータを取得する ・for 文と push メソッドを使って配列要素を複数生成
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JS~DOM概要~

概要 JavascriptではDOMの操作が必須になります。 DOMとは何かについての記事になります。 JS復習 JSはどのように動くのかについて復習します。 詳しくはこちらの記事を参照していただけると幸いです。 ①HTML/CSSの情報を読み取る ②その情報をもとに加工 ③HTML/CSSを書き換える 上記の引用がざっくりとした流れです。 DOM操作とは、③に当たります。 またJSでJSでDOMの中身を書き換えたとしてもHTMLを書き換えているわけではないことを覚えておきましょう。 DOM ブラウザが読み込まれるとDocument Object Model もしくは DOM と呼ばれるデータ構造が読み込まれます。 index.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <div class="header"> <h1 class="title">JavaScript</h1> <p class="sub-title">DOM操作について</p> </div> </body> </html> DOMはWebページをツリー状に構造化したものです。そして、このツリーにある要素をNode(ノード)と言います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JS~オブジェクトと参照~

概要 JSには8つのデータ型があります。 7つのデータ型(プリミティブ型)これは、Number,string,Boolean,Null,Undefined,BigInt,Symbolがあります。 そしてもう1つはオブジェクトです。 プリミティブ型では、変数を直接代入しました。これに対しオブジェクトでは参照と言います。 この記事では参照について触れていきます。 参照とは index.js const menu = { name :'パンケーキ', price : '580円', set : '1000円' }; console.log(menu); このmenuの中は1つの箱になります。箱の中には、一つ一つ名前が付けられた値が保存されています。 上記の例でいうと、nameと名前のついたパンケーキ。priceと名前のついた580円、setと名前がついた1000円です。 オブジェクトは内部にプロパティを持つデータの集合です。 変数に入れるのはデータの集合ではありません。 menuという内部データを見るためのパスワードです。これを参照と言います。 参照を代入する値をconstで宣言しているので書き換えはできないのではと考えます。 しかし、変数に代入するのはmenu(パスワード)であり、そこから先の{オブジェクト内}は定数では無いからです。 したがって、constで宣言しているにも関わらず値の書き換えができるということです。 コード 上記の内容をコードにすると以下のようになります。 index.js console.log(menu); //{name: "パンケーキ", price: "580円", set: "1000円"} const menu2 = menu; //参照の複製 menu2.price = '400円'; //複製でプロパティを書き換える console.log(menu); //{name: "パンケーキ", price: "400円", set: "1000円"} まとめ(擬人化) 独自の解釈でまとめます。 menuという家があります。 const = menu これはmenu家の鍵になります。 この鍵を使用してmenuという家に入ります。 menuという家には複数の人が出入りします。そこで、鍵の複製が必要になリます。その鍵を元にアクセスして値を書き換えることができるというわけです。 menuもmenu2も複製した鍵なので無効になることはなく、アクセスすることができます。 index.js const menu = { name :'パンケーキ', price : '580円', set : '1000円' }; console.log(menu); //{name: "パンケーキ", price: "580円", set: "1000円"} const menu2 = menu; //複製 menu2.price = '400円'; //書き換え console.log(menu2); //{name: "パンケーキ", price: "400円", set: "1000円" console.log(menu); //{name: "パンケーキ", price: "400円", set: "1000円"}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

nodenvでインストールしたバージョンがなかったときの対応

nodenvでバージョンインストールしたくてコマンド実行 $ nodenv install 14.16.1 そんなバージョンないよと言われた。インストールできるバージョンリストを最新にする必要があるようだ。 コマンド実行時に表示されるコマンドを実行してみる。 $ git -C /Users/kawamurakenji/.anyenv/envs/nodenv/plugins/node-build pull share/node-build/15.8.0 | 14 ++++++++++++++ share/node-build/15.9.0 | 14 ++++++++++++++ share/node-build/16.0.0 | 10 ++++++++++ test/fetch.bats | 1 + 35 files changed, 304 insertions(+), 5 deletions(-) create mode 100644 share/node-build/10.23.3 create mode 100644 share/node-build/10.24.0 create mode 100644 share/node-build/10.24.1 create mode 100644 share/node-build/12.20.2 . . . どうやらリストが最新になったぽいので、インストールできるバージョンを確認する。 $nodenv install --list お目当てのバージョンをみつけた。 14.15.4 14.15.5 14.16.0 14.16.1 15.0.0 15.0.1 15.1.0 . . . これでインストールできた。 $ nodenv install 14.16.1 nodenvを使って、特定のプロジェクトでバージョンを適用する。適用したいディレクトリに移動してからコマンド実行。 ディレクトリ別でnodeバージョンを設定すれば、ディレクトリ移動しただけで自動切り替えされるので便利らしい。 $ nodenv local (バージョン) $ node -v デフォルトのバージョンをしたい場合はこれらしい。 nodenv global (バージョン)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Dogelog Runtime, Prolog to the Moon

We got recently interested in the JIT-ing capabilities of JavaScript. So we set sail to write a take on the Albuferia Prolog Interpreter. The result is a first cross compiler, that compiles Prolog with Cut into JavaScript arrays that can then be executed by the Dogelog runtime. The point of departure was the following paper: A portable Prolog compiler Conference: Logic Programming WorkshopAt: Albufeira, Portugal William Clocksin - January 1983 https://www.researchgate.net/publication/273888197 The above compiler suggests an instruction set that is based on a register window. The instruction set is flexible, in that it can build fresh Prolog terms and/or perform unification. During unification it can avoid building unnecessary fresh Prolog terms. The compiler goes also into length to compile tail recursion in a smart way. We didn't implement this part. But we provide a already the cut and a primitive trail garbage collection. Built-ins on the other hand are not yet provided. Cross Compiling The compiler is currently a cross compiler. One needs to use another Prolog system and run the Prolog program through it. In the future we might let the browser do that, but currently there are the following files that perform the cross compilation: Term Compiler term: Here we are close to the Albufeira compiler in that we also use the instructions var(N), functor(F,N), atom(C) and the characteristic pop instruction. Since we do not have memory pointers in Java Script we use an index into an array to create terms. Clause Compiler solve2: Here we divert from the Albufeira compiler in that we chop up the instruction stream in a Prolog clause head and body part, which sit itself in a list. This will later simplify the Dogelog runtime. File Compiler dogelog: This is a very rudimentary utility that can produce JavaScript array statements that can then be embedded in a HTML page. The utility makes use of Jekejeke Prolog strings which are coded as '$STR'(atom). Other Prolog systems might need something else. From within Jekejeke Prolog the cross compiler can be invoked as follows: ?- set_prolog_flag(double_quotes, string). ?- doge('examples.pl', 'examples.js'). Dogelog Runtime The Dogelog runtime needs a full fledged unification. Although the Albufeira instruction stream can build and unify Prolog terms, it falls back to a unification routine in case two instantiated variables meet. The Dogelog runtime consists of: Term Handling unify2.js: Can perform unification. During unification variables that get instantiated get recorded on the trail. The JavaScript file also provides routines to mark and sweep the trail, which is later used in garbage collection. Clause Handling executor2.js: Can solve Prolog goals. We use a solver that works on goal list. Clauses heads and bodies are difference lists, so that the modify the goal list like in resolution. When the trail gets too large garbage collection is performed. When implementing the solver we replicated the Jekejeke Prolog engine with its two modes "call" and "redo". This is a loop that fetches goals from the goal list during when in "call" mode and jumps to choice points when in "redo" mode. TauProlog Comparison We were currious how Dogelog compares to TauProlog. So we were running Peano factorials which stretches the tail recursion and garbage collection of any Prolog system. The test files were: TauProlog Benchmark: We made ourselfs comfortable with the TauProlog API. They required us to code a lot of call backs. We realized a logic that did try to execute Peano factorials up to 10. But somehow TauProlog gave silently up at 7. TauProlog Benchmark results are here. Dogelog GC Demo: The Dogelog API doesn't use inverted programming. The Prolog interpreter is viewed as an iterator that can be asked for a next solution. The Dogelog runtime is able to reach Prolog factorial 10 in a Chrome browser. Dogelog GC Demo results are here. We take performance figures of this test as a judgement whether the Dogelog runtime is a total disaster or not. So we did also some measurement via JavaScript Date.now(). It turns out that the Dogelog runtime fares quite well compared to TauProlog: Future Outlook We are mostly interested in the JIT-ing capabilities of JavaScript. So we will need a future version of Dogelog that compiles closer to the metal, either JavaScript code or even maybe Webassembly code. For this project we will have to look again at the many ideas from the Albufeira instruction set.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む