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

簡単レシート印刷 receiptline の API を調べてみた

日本発のオープンソース receiptline でレシート印刷に少しずつトライしています。
何と超速でマクドナルドのレシートを再現している方を発見!びっくりこ!

落札したレシートプリンターは無事届きました。
しかしまだ準備ができていないので、前回利用した開発ツールを引き続き使います。
今回は receiptline の API です。

01.png

開発ツールは何をしている?

開発ツールの左側の編集エリアに文字を入力すると、右側のレシート用紙にプレビューが表示されます。
Web ブラウザーのデベロッパーツールを使って、開発ツールの内部を解析してみました。

02.png

入力データ

ReceiptLine
^^領収書|
2019/07/20 01:23|
#NGC17TH|

缶ビール | ¥211~
シュークリーム | ¥129*

出力データ

見やすいように整形して、   に置換しておきました。

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="576px" height="168px" viewBox="0 0 576 168" preserveAspectRatio="xMinYMin meet" version="1.1">
    <defs>
        <filter id="receiptlineinvert" x="0" y="0" width="100%" height="100%">
            <feFlood flood-color="#000"></feFlood>
            <feComposite in="SourceGraphic" operator="xor"></feComposite>
        </filter>
    </defs>
    <g font-family="'MS Gothic', 'San Francisco', 'Osaka-Mono', 'Courier New', 'Courier', monospace" fill="#000" font-size="24" dominant-baseline="text-after-edge">
        <g transform="translate(0,48)">
            <text transform="scale(1,2)" x="504,528,552">領収書</text>
        </g>
        <g transform="translate(0,72)">
            <text x="384,396,408,420,432,444,456,468,480,492,504,516,528,540,552,564">2019/07/20&#xa0;01:23</text>
        </g>
        <g transform="translate(0,96)">
            <text x="480,492,504,516,528,540,552,564">#NGC17TH</text>
        </g>
        <g transform="translate(0,120)">
            <text x="0">&#xa0;</text>
        </g>
        <g transform="translate(0,144)">
            <text x="0,24,48,72">缶ビール</text>
            <text x="516,528,540,552,564">¥211&#xa0;</text>
        </g>
        <g transform="translate(0,168)">
            <text x="0,24,48,72,96,120,144">シュークリーム</text>
            <text x="516,528,540,552,564">¥129*</text>
        </g>
    </g>
</svg>

ソースコード

開発ツールの内部で、入力データを出力データに変換しているはずです。
ソースコードを解読して、該当部分を探し出しました。

designer/script/receiptline-designer.js
const printer = {
    cpl: Number(cpl.textContent),
    encoding: /^ja/.test(window.navigator.language) ? 'cp932' : 'cp437'
};
const svg = receiptline.transform(edit.value, printer);

ありました。transform メソッドです。
引数は、編集エリアの文字列と、オプション (レシート用紙の桁数、日本語 or 英語)。
戻り値は SVG の文字列です。これを DOM に変換して表示しています。

アプリ開発では、このメソッドに渡す文字列の組み立て処理がメインになりますね。

サンプルプログラム

receiptline パッケージには、コピーして使えるサンプルプログラムが添付されています。
・・・はじめからこちらをチェックすべきでしたね。

Web ブラウザー用

example/js/ja.html
// for SVG output
const printer = {
    // cpl: characters per line (required)
    cpl: 48,
    // font: Japanese, encoding: utf-8 (required)
    encoding: 'cp932',
    // upsideDown: ignored (optional)
    upsideDown: false,
    // gamma: ignored (optional)
    gamma: 1.0,
    // command: SVG (optional)
    command: 'svg'
};
const svg = receiptline.transform(reader.result, printer);

テキストファイルを読み込んで、変換して、表示しています。
中身は開発ツールのソースコードとほとんど一緒です。

Node.js 用

example/nodejs/start.js
sock.on('connect', () => {
    const command = receiptline.transform(text, printer);
    sock.write(command, /^<svg/.test(command) ? 'utf8' : 'binary');
});

テキストデータを HTTP で受信して、変換して、仮想プリンターへ送信しています。
開発ツールを起動する designer.js のソースコードと全く同じでした。

変換 API を使ったプログラミングは後日トライすることにします。
次回は仮想プリンターを試してみようと思います。

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

データベースを使わずにToDoアプリ作成してみた

本稿について

  • JavaScript
  • HTML
  • CSS

のみを使ってTodoアプリを作っていきたいと思い、その開発の記録となります。
要所要所で詰まったところなどを備忘録的に書いていってます。
今回は、DBに関する知見を使わずに 実装していきたいと考えております。

この記事が参考になりそうな方

初学者の方(初心者ではなく、学習を始めたばかりの方)となります。
フレームワークや、データベースなどのバックエンドの知見を用いずに、
JavaScript、HTML、CSSのみで実装を目指します。
(ほぼほぼJavaScriptっす)

最終形のイメージ(参考)

こちらのような、GoogleのTodoアプリを参考にしていきたいと思います。

724fa2b381849fa16992412f02161d46.gif

ファイル構成(超簡易)

.
├── README.md
├── css
│   ├── sanitize.css
│   └── style.css
├── js
│   └── main.js
└── todo.html

ひな形

ざっくりと、下記の雛形を用意しました。最初の取っ掛かりのために、Todoのli要素を数個、HTML固定で記載してます

<!doctype html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <title>Document</title>
      <script type="text/javascript" src="js/main.js"></script>
    <link rel="stylesheet" href="css/style.css">
    <link rel="stylesheet" href="css/sanitize.css">
  </head>
  <body>
    <h1>My Tasks</h1>
    <form>
      <input type="text" name="" id="new_todo"/>
      <input type="button" value="追加" id="btn" onclick="appendTodo()"/>
    </form>
    <ul id="lists">
      <li>Todo 1 <button onclick="changeDone()">done</button></li>
      <li>Todo 2 <button onclick="changeDone()">done</button></li>
      <li>Todo 3 <button onclick="changeDone()">done</button></li>
      <li>Todo 4 <button onclick="changeDone()">done</button></li>
      <li>Todo 5 <button onclick="changeDone()">done</button></li>
      <li>Todo 6 <button onclick="changeDone()">done</button></li>
    </ul>
    <button id="btnexp" onclick="exportTodolist()">ファイル出力</button>
    <input type="file" id="importTodo" />
    <pre id="pre1"></pre>
  </body>
</html>

データベースを使わずにどうやってTodoを記憶させる?

今回はデータベースを使わずに行うため、一度作成したTodoリストを出力させる形式で作ることを目指しました。
下記の記事を参考にBLOBを使っています
https://javascript.keicode.com/newjs/download-files.php

BLOBを使ってファイル出力する機能のソースコード

  const blob = new Blob([nodeItem.value],{type:"text/plan"});
  const link = document.createElement('a');
  link.href = URL.createObjectURL(blob);
  link.download = '作ったファイル.txt';
  link.click();

ファイル出力ボタンを押して確認してみると、出力はされました。が...
62e40fb5898dded99611795fed28b81f.gif

ファイル出力された際、HTMLLIElementの中身をどのように出力する?

ファイル出力 ボタンを押してファイル出力はできましたが、
出力された中身をみると下記のようになってしまいました。。
スクリーンショット 2020-07-19 15.58.42.png
li要素自体をそのまま出力しようとすればそりゃ当然で、
中身を取得するためにtextContentを使い、
doneボタンを押したli要素については✅マーク付き、そのほかはただの四角?で出力されるようにしてみました。
最終的に下記のようにli要素の中身を出力できるようにできました。

スクリーンショット 2020-07-21 19.24.03.png

doneボタンまで出力されててじゃまなので、下記のような書き方をして必ず後ろについてくるdoneの4文字を削るようにしました。

  for(i=0;i < Todolist.length; i++){
    const todolist = Todolist[i];
    if (todolist.className === 'done'){
      nodeItem.value += `☑︎ ${todolist.textContent.slice(0,-4)}\n`;
    }else {
      nodeItem.value += `□ ${todolist.textContent.slice(0,-4)}\n`;
    }

※innerTextやinnerHTMLとtextContentの違いについて、こちらのMDNリファレンスわかりやすいです。
HTML要素や子要素を取り除くことができるか、といった点や、処理が重くならないよう再フローがかからないようにできる点から、今回textContent採用しています

constしか使いたくない

とりあえずファイル出力できた時点でのソースはこんな感じでした。

function exportTodolist(){

  const Todolist = document.querySelectorAll('li');
  let nodeItem = "";

  for(let i=0;i < Todolist.length; i++){
   nodeItem += Todolist[i].textContent;
  }

  // ファイル出力の実装
  let blob = new Blob([nodeItem],{type:"text/plan"});
  let link = document.createElement('a');
  link.href = URL.createObjectURL(blob);
  link.download = '作ったファイル.txt';
  link.click();
}

下記の記事が有名ですが、
https://qiita.com/taiju_suzuki/items/49ed558bd837452353b8
varやletは再代入や再宣言で値を書き換えるリスクがあるため、
constだけ使うようにしたいので下記の感じで書き換えます。

function exportTodolist(){

  const Todolist = document.querySelectorAll('li');
  const nodeItem = {value:""};
  for(let i=0;i < Todolist.length; i++){
    nodeItem.value += (Todolist[i].textContent + `\n`)
  }

  // ファイル出力の実装
  const blob = new Blob([nodeItem.value],{type:"text/plan"});
  const link = document.createElement('a');
  link.href = URL.createObjectURL(blob);
  link.download = '作ったファイル.txt';
  link.click();
}

ファイルインポート機能の実装

DBを使わない為一度作成したTodoはファイルに出力するが、
逆にファイルを読み込む機能も実装しておいた方が都合が良い。
↓のように実装してみました。ソースコードとてもきちゃない。

//ファイルインポート機能
window.addEventListener('load', () => {
  const f = document.getElementById('importTodo');
  f.addEventListener('change', evt => {
    const input = evt.target;
    if (input.files.length == 0) {
      console.log('No file selected');
      return;
    }
    const file = input.files[0];
    const reader = new FileReader();
    reader.onload = () => {
      const pre = document.getElementById('pre1');
      const result = reader.result.split("\n");
      for(i=0;i < result.length - 1; i++){
        const li = document.createElement('li');
        const button = document.createElement('button');
        button.innerText = 'done';
        button.onclick = "changeDone()";
        li.innerHTML = result[i];
        li.appendChild(button);
        console.log(li.innerHTML.charAt(0));
        if (li.innerHTML.charAt(0) !== `□`){
          li.className = "done";
        }
        li.innerHTML = li.innerHTML.slice(2);
        const ul = document.querySelector('ul');
        ul.appendChild(li);
      }
    };
    reader.readAsText(file);
  });
});

こちらの日本語版スタックオーバーフローの記事を参考にしています。
https://ja.stackoverflow.com/questions/36426/javascript%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89%E4%BB%B6%E6%95%B0%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E5%87%A6%E7%90%86%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6

無事、ファイルimport機能も実装できました。
0d9330344dc72a3670ca1faadd60b30b.gif

まだまだ実装する機能は残っていますし、(タスクのグループ化、サイドバーでの選択、作業済みのタスクを移動させる 等)当初の再集計イメージにはまだ遠いですが、
続きはまた別途書いていこうと思いますー

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

データベースを使わずにToDoアプリ作成してみる

本稿について

  • JavaScript
  • HTML
  • CSS

のみを使ってTodoアプリを作っていきたいと思い、その開発の記録となります。(※未完です)
要所要所で詰まったところなどを備忘録的に書いていってます。
今回は、DBに関する知見を使わずに 実装していきたいと考えております。

この記事が参考になりそうな方

初学者の方(初心者ではなく、学習を始めたばかりの方)となります。
フレームワークや、データベースなどのバックエンドの知見を用いずに、
JavaScript、HTML、CSSのみで実装を目指します。
(ほぼほぼJavaScriptっす)

最終形のイメージ(参考)

こちらのような、GoogleのTodoアプリを参考にしていきたいと思います。

724fa2b381849fa16992412f02161d46.gif

ファイル構成(超簡易)

.
├── README.md
├── css
│   ├── sanitize.css
│   └── style.css
├── js
│   └── main.js
└── todo.html

ひな形

ざっくりと、下記の雛形を用意しました。最初の取っ掛かりのために、Todoのli要素を数個、HTML固定で記載してます

<!doctype html>
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width">
    <title>Document</title>
      <script type="text/javascript" src="js/main.js"></script>
    <link rel="stylesheet" href="css/style.css">
    <link rel="stylesheet" href="css/sanitize.css">
  </head>
  <body>
    <h1>My Tasks</h1>
    <form>
      <input type="text" name="" id="new_todo"/>
      <input type="button" value="追加" id="btn" onclick="appendTodo()"/>
    </form>
    <ul id="lists">
      <li>Todo 1 <button onclick="changeDone()">done</button></li>
      <li>Todo 2 <button onclick="changeDone()">done</button></li>
      <li>Todo 3 <button onclick="changeDone()">done</button></li>
      <li>Todo 4 <button onclick="changeDone()">done</button></li>
      <li>Todo 5 <button onclick="changeDone()">done</button></li>
      <li>Todo 6 <button onclick="changeDone()">done</button></li>
    </ul>
    <button id="btnexp" onclick="exportTodolist()">ファイル出力</button>
    <input type="file" id="importTodo" />
    <pre id="pre1"></pre>
  </body>
</html>

データベースを使わずにどうやってTodoを記憶させる?

今回はデータベースを使わずに行うため、一度作成したTodoリストを出力させる形式で作ることを目指しました。
下記の記事を参考にBLOBを使っています
https://javascript.keicode.com/newjs/download-files.php

BLOBを使ってファイル出力する機能のソースコード

  const blob = new Blob([nodeItem.value],{type:"text/plan"});
  const link = document.createElement('a');
  link.href = URL.createObjectURL(blob);
  link.download = '作ったファイル.txt';
  link.click();

ファイル出力ボタンを押して確認してみると、出力はされました。が...
62e40fb5898dded99611795fed28b81f.gif

ファイル出力された際、HTMLLIElementの中身をどのように出力する?

ファイル出力 ボタンを押してファイル出力はできましたが、
出力された中身をみると下記のようになってしまいました。。
スクリーンショット 2020-07-19 15.58.42.png
li要素自体をそのまま出力しようとすればそりゃ当然で、
中身を取得するためにtextContentを使い、
doneボタンを押したli要素については✅マーク付き、そのほかはただの四角?で出力されるようにしてみました。
最終的に下記のようにli要素の中身を出力できるようにできました。

スクリーンショット 2020-07-21 19.24.03.png

doneボタンまで出力されててじゃまなので、下記のような書き方をして必ず後ろについてくるdoneの4文字を削るようにしました。

  for(i=0;i < Todolist.length; i++){
    const todolist = Todolist[i];
    if (todolist.className === 'done'){
      nodeItem.value += `☑︎ ${todolist.textContent.slice(0,-4)}\n`;
    }else {
      nodeItem.value += `□ ${todolist.textContent.slice(0,-4)}\n`;
    }

※innerTextやinnerHTMLとtextContentの違いについて、こちらのMDNリファレンスわかりやすいです。
HTML要素や子要素を取り除くことができるか、といった点や、処理が重くならないよう再フローがかからないようにできる点から、今回textContent採用しています

constしか使いたくない

とりあえずファイル出力できた時点でのソースはこんな感じでした。

function exportTodolist(){

  const Todolist = document.querySelectorAll('li');
  let nodeItem = "";

  for(let i=0;i < Todolist.length; i++){
   nodeItem += Todolist[i].textContent;
  }

  // ファイル出力の実装
  let blob = new Blob([nodeItem],{type:"text/plan"});
  let link = document.createElement('a');
  link.href = URL.createObjectURL(blob);
  link.download = '作ったファイル.txt';
  link.click();
}

下記の記事が有名ですが、
https://qiita.com/taiju_suzuki/items/49ed558bd837452353b8
varやletは再代入や再宣言で値を書き換えるリスクがあるため、
constだけ使うようにしたいので下記の感じで書き換えます。

function exportTodolist(){

  const Todolist = document.querySelectorAll('li');
  const nodeItem = {value:""};
  for(let i=0;i < Todolist.length; i++){
    nodeItem.value += (Todolist[i].textContent + `\n`)
  }

  // ファイル出力の実装
  const blob = new Blob([nodeItem.value],{type:"text/plan"});
  const link = document.createElement('a');
  link.href = URL.createObjectURL(blob);
  link.download = '作ったファイル.txt';
  link.click();
}

ファイルインポート機能の実装

DBを使わない為一度作成したTodoはファイルに出力するが、
逆にファイルを読み込む機能も実装しておいた方が都合が良い。
↓のように実装してみました。ソースコードとてもきちゃない。

//ファイルインポート機能
window.addEventListener('load', () => {
  const f = document.getElementById('importTodo');
  f.addEventListener('change', evt => {
    const input = evt.target;
    if (input.files.length == 0) {
      console.log('No file selected');
      return;
    }
    const file = input.files[0];
    const reader = new FileReader();
    reader.onload = () => {
      const pre = document.getElementById('pre1');
      const result = reader.result.split("\n");
      for(i=0;i < result.length - 1; i++){
        const li = document.createElement('li');
        const button = document.createElement('button');
        button.innerText = 'done';
        button.onclick = "changeDone()";
        li.innerHTML = result[i];
        li.appendChild(button);
        console.log(li.innerHTML.charAt(0));
        if (li.innerHTML.charAt(0) !== `□`){
          li.className = "done";
        }
        li.innerHTML = li.innerHTML.slice(2);
        const ul = document.querySelector('ul');
        ul.appendChild(li);
      }
    };
    reader.readAsText(file);
  });
});

こちらの日本語版スタックオーバーフローの記事を参考にしています。
https://ja.stackoverflow.com/questions/36426/javascript%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%81%AE%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89%E4%BB%B6%E6%95%B0%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF%E5%87%A6%E7%90%86%E3%81%AB%E3%81%A4%E3%81%84%E3%81%A6

無事、ファイルimport機能も実装できました。
0d9330344dc72a3670ca1faadd60b30b.gif

まだまだ実装する機能は残っていますし、(タスクのグループ化、サイドバーでの選択、作業済みのタスクを移動させる 等)当初の再集計イメージにはまだ遠いですが、
続きはまた別途書いていこうと思いますー

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

ESLint 7.5.0

v7.4.0 | 次 (2020-08-01 JST)

ESLint 7.5.0 がリリースされました。小さな機能追加とバグ修正が含まれています。

質問やバグ報告等ありましたら、お気軽にこちらまでお寄せください。

? 日本語 Issue 管理リポジトリ
? 日本語サポート チャット (招待リンク)
? 本家リポジトリ
? 本家サポート チャット (招待リンク)


[PR] ESLint は開発リソースを確保するための寄付を募っています。
応援してくださると嬉しいです。


✨ 本体への機能追加

Optional Chaining 構文をサポートしました

? #13416

Optional Chaining 構文をサポートしました。新しい構文を利用するには、parserOptions.ecmaVersion2020に設定する必要があります。

.eslintrc.json (例)
{
    "parserOptions": {
        "ecmaVersion": 2020
    }
}

id-blacklist ルールが非推奨になりました

? #13465

前回のリリースで id-blacklist ルールは id-denylist に名称変更され、既存の id-blacklistid-denylist の別名になりました。

しかし、同じルールが複数の名称で存在するのは関連ツールにとって不便だったため、id-blacklist は非推奨としてマークされることになりました。今後は id-denylist をご利用ください。

? 新しいルール

特になし

? オプションが追加されたルール

sort-imports allowSeparatedGroups

? #13455

他の文、または空行やコメントによって分離されたimport文について、それぞれ別個に並び順を矯正するためのオプションが追加されました。

/*eslint sort-imports: [error, { allowSeparatedGroups: true }]*/

//✔ GOOD
import b from 'b.js';
import c from 'c.js';
// 空行やコメント行などで分離されているので、`import a` は `import b` より下にあっても良い
import a from 'a.js';

//✘ BAD
import b2 from 'b.js';
import c2 from 'c.js';
import a2 from 'a.js'; // 空行やコメント行などで分離されていないので、`import a2` は `import b2` より上にないとダメ

Open Online Demo

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

ESLintで特定のjsをignoreしてreviewdogでエラーになったら

結論

ESLintのWarningを全て出力対象外として構わなければ、ESLint実行時に--quietオプションを付ける

reviewdogがエラーになる理由とその対処方法

ESLintでは、.eslintignoreに記述したファイルをチェック対象外にします。

.eslintignore
foo.js

この時、ESLintを実行するとfoo.jsに対して、以下のようなWarningが出力されます。

(下記フォーマットは、-f checkstyleを付けた場合。なお、わかりやすく改行とインデントを入れています)

<?xml version="1.0" encoding="utf-8"?>
<checkstyle version="4.3">
  <file name="/home/runner/work/foo.js">
    <error line="undefined" column="undefined" severity="warning" message="File ignored because of a matching ignore pattern. Use &quot;--no-ignore&quot; to override." source="" />
  </file>
</checkstyle>

File ignored because of a matching ignore pattern

ignoreしたからといって何も出力されないわけではなく、ignoreしたことを警告してくれているわけですね。

このESLintの出力内容ですが、通常、linecolumnには数値が入り、ソースコード中のチェックにかかった位置がわかります。

しかし、ignoreの場合は、どちらもundefinedとなります。

<error line="undefined" column="undefined" severity="warning" message="File ignored because of a matching ignore pattern. Use &quot;--no-ignore&quot; to override." source="" />

このESLintの出力をそのままreviewdogに入力すると、内容を解析できずにparse errorとなってしまいます。

reviewdog: parse error: strconv.ParseInt: parsing "undefined": invalid syntax

reviewdogは、lineの値を元にGitHubのPR上にコメントしてくれます。

ですのでlineの値がundefinedでは困ってしまうのだと思われます。

これを回避する手段として、ESLintのWarningをignore対象に限らず、全て出力対象外として良いということであれば、--quietオプションを付ける方法があります。

--quietオプションを付けるとESLintのWarinigレベルは出力されなくなり、結果reviewdogのparse errorは発生しなくなります。

参考

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

JavaScriptで設定したCookieはLaravelで単純にRequestから取れないので注意

概要

JavaScriptで設定したCookieはLaravelで単純にRequestから取れない。$request->cookie('flag')などするとnullが帰ってきてしまう。

詳細

JavaScriptで以下のように設定したCookie。

Cookie.set('flag', 'true');

LaravelでCookieの中身を見た場合。

Controller.php
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class IndexController extends Controller
{
    public function index(Request $request)
    {
        dd($request->cookie());
    }
}

出力は以下のようになる。

array [▼
  "flag" => null
  ~略~
]

なぜ起こるか

Laravelは自分で設定したCookieについては暗号化している。
なので仮に暗号化していなかった場合には、Cookieを復号しようとして失敗する。失敗するとnullが返る。

該当の処理は以下のところ。
Laravelバージョンはv6.9.0のコード。

image.png

対処法

MiddlewareのEncryptCookiesにおいて、暗号化されていないと期待するリストをかけるので追加する。

EncryptCookies.php
use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;

class EncryptCookies extends Middleware
{
    protected $except = [
        'flag'
    ];
}

おまけ

$_COOKIE を取得すれば生のものが取れるよ、という情報もstackoverflowなどでちらほら見られます。
確かに $_COOKIE はPHPの組み込み変数なので、確かに復号の仕組みが入っていないので生のCookieを取得できますが、Laravelを使っているのであればLaravelの仕組みの上に乗ったほうが良さそうです。

参考: https://www.php.net/manual/ja/reserved.variables.cookies.php

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

ウェブカツ!!が業界初のプログラミング漫画「はたらくプログラミング」を作ってしまった話

まえおき

どうも、最近運営しているプログラミングスクール「ウェブカツ!!」を売却しようとして「40億で売れる?」ってIT業界で有名なM&Aエージェントに相談してみたら「25億が現実的な落とし所ですねー。。」と渋い顔で言われてしまった、かずきちです。

一時、ベンチャー経営者やアンチがうちの生徒雇わない発言して物議を醸しましたが、一向にうちの生徒の内定報告いただいている状態で何よりです。
今年の秋口からは、うちの本が続々と出ます。
SNSマーケの口コミのみで、広告やSEOすらやってなかったので、もう
伸び代しかないですね。(ケイスケホンダ選手風)

アクティブで一時期1500人超える勢いだったんですが、安っぽいアフィリエイターみたいな副業気分で学ぼうとしてる甘っちょろい人間も増えてたので、僕が相当生徒数削りました。事業やってて思うのは、やっぱ費用が安いと意識の安い人間が入りますね。
(安くしちゃえば1万人は超えるし、売り上げも上がるのは分かってますが、その分しょうもないエンジニア増やしてもなという。)

因みにうちで身に付くレベルがどれかというと卒業したばかりの生徒達が作ったものを一部お見せするとこんな感じです。

https://itengineer-scouter.com/
※このサービスは、今は余力がないので運営ほったらかしてますが、スクールや教育が増えれば今後確実に定量評価出来るものが必要になるんでコンテンツちゃんと考えれば伸ばせるやつ。
競合ではpaizaとかあって僕もやりましたが、あれってエンジニアとしてのお仕事で使う技術能力とはかなりかけ離れちゃってるんですよね。技術というより数学テストだし。

うちは他スクールと違って、生徒に「作品」を作らせることはしてません。
だって、仕事としてお金もらってやってるのって
「商品」を作ること
ですから。

趣味レベルのものを作ってもしょうがないんですよね。
「商品」として成り立つレベルが作れなきゃ。

うちの生徒には元医師やらBIG4税理士法人、大手金融機関、大手メーカー勤めの高学歴な人〜中卒、40代主婦まで、地域は北海道から沖縄果てはフィリピン、マレーシア、インド、デンマークといったバリエーション豊かな人達が学んでいます。
(中卒も40代主婦もきちんと内定もらって今はエンジニアとしてバリバリやっているので、これからフリーランスで稼いでくれるのが楽しみです)

余談ですが、最近テック〇〇の面談受けた人がまた入ってきたんですが、営業に
「都内に出てこれない人は本気度が低いから無理だよ」
と言われたそうです。(うちは地方でも内定決まっているというのに。。)
都内が案件多いとはいえ、斡旋して自分らの利益にしたいからとはいえ。ね。
まぁ、正社員の斡旋するだけで、年収の3割もらえるんで、一人100万以上入ってくるものね。
そりゃ、売り上げ主義でいけば都内就職者だけ扱いたいよね。

「はたらくプログラミング」を作りたい!

前置き長くなりましたが、そんな中で今回うちの生徒(今は卒業生)で「ちょっと昔趣味で漫画描いてた」という人に

「はたらく細胞」みたいにプログラミング版を作りたいんだけど出来ない?

とお願いし、それがようやく完成。反響も上々なようで今回その製作の裏側をご紹介したいと思います。

amazonとboothで現在発売中です。
https://www.amazon.co.jp/dp/B087Z6J1RZ/ref=cm_sw_r_tw_dp_x_-qQfFbBE70Y32

「はたらくプログラミング」を作ろうと思った経緯

僕はいわゆる「ガチエンジニア」じゃ決してありません。
技術自体が全く好きではありません。
異業種の営業マンからエンジニアに転向する際の独学で、このITエンジニア業界の
「教育能力なさすぎ」
「伝えるスキルなさすぎ」
「ビジネス、マーケティング能力なさすぎ」
の3拍子にイラッとし、その改革のためにスクールを立ち上げた(昔はただの動画サービスだったけど)わけですが、そんな中でずっと

漫画で学べりゃ楽なのになぁ

と思っていました。
僕は漫画大好きなんですもの。字とか嫌い。
スクールも全て動画で教えているくらいですしね。

が、漫画を書くスキルはもちろんないですし、そもそもどんな漫画にすりゃいいのか思いつかなかったんですね。
そんなある時、出会っちゃったわけですよ、あれに。

「はたらく細胞」

ですよ。
これを読んだ瞬間、降りてきちゃったわけです。

神が。

これだ!って感覚です。

「はたらく細胞」をインスパイアしよう!

そう思ったわけです。
神の命です。

「はたらく細胞」をパクインスパイアしちゃいなさい。

そういう神の命を頂いたわけです。

何をどういう順序でどういう世界観で伝えるか。それが重要だ。

とはいえ、「プログラミングを擬人化する」というところまではきたんですが(まぁ、調べたらそういう擬人化した漫画ちっくなものはありましたが)、それぞれをどう伝えるか悩みました。
実際、わかばちゃんシリーズであったりコード学園ってのがありましたが、どっちも僕が求めるものとは違ったんです。

スクリーンショット 2020-03-12 05.11.19のコピー.png

ちなみに僕はいわゆる「オタク」が好きそうな萌え系キャラが大嫌いです。
エンジニア界隈では好かれるでしょうが、僕のような一般人からしたら気持ち悪さしかないんですね。(申し訳ないけどそれが本音だよ)
だから、そんな擬人化キャラにはしたくなかったですし、わかばちゃんのような4コマ漫画では、はたらく細胞のように

難解な専門知識を漫画としてストーリー仕立てで各キャラの個性や世界観も感じながら楽しみながら学習したい

という僕の堕落し甘えきった目的には到達できなかったんです。
だって、あれは漫画部分が一部あるだけの「解説本」ですし。
初心者の頃の僕はコードが出てきた段階で拒絶反応ですしね。
一番の初心者ってそっからなわけで。

僕はエンジニアが大嫌いだ

そもそも、僕は異業種の人をエンジニアとして育ててこの業界に送り込みたいんです。
だって僕は

エンジニア大嫌いなんですもの。

でも、

エンジニアは大好きなんです。

言ってること分かります?

営業やってた僕からすれば、エンジニアという職業は指動かしてるだけで金もらえるわ、
リモートも出来るわ、
ヘッドフォンしながら仕事出来るわ、
スマホいじりながら仕事出来るわ、
短期間で一気に報酬上げられるわ、
自動化して自分で金稼げるわ
で「天国」なんですよ。
エンジニアで月100万稼ぐのと営業で月100万稼ぐのじゃ天と地ほどの差な労力です。
女性ならライフステージによっても他の仕事より融通効きやすいだろうしね。
(女っ気なくてむさ苦しい現場が多いのが残念だけども。うちのスクールの女性比率はかなり高いので女性生徒からすると現場出てみて女性が少なすぎる現状にびっくりするみたいです。)

でも、僕のQiitaやらTwitterやらにウジのように湧いてくるキモいエンジニアは嫌いなんですよ。
教え方下手くそなエンジニアも、ビジネスもわからない子供エンジニアも嫌いなんですよ。
商品より作品作りたがったり、顧客課題をすっぽかして技術情報だけで鼻息荒くしてるエンジニアも大嫌いなんですよ。

だから、もうこの業界変えるには既存エンジニアより異業種のコミュケーション能力高い人や素養ある人に営業もビジネスも税務も法務も教えてエンジニアも並より上のスキル教える方が大事だと思っているわけです。
(最近、SNS訴訟に強い弁護士が教えてくれる法務部がうちのスクールに出来ました。営業部も日本で唯一大学で営業を学問として教えている生保で元億プレーヤーの花田敬さんに見てもらってます。)

なので、そもそも

プログラミングって何それ?聞いたことあるくらいだけど

な人たちでも読みたくなるようなものを作りたかったんですね。
売れない営業マンが漫画喫茶で手にとって読めるレベルのやつが。
そんで、あわよくば

「あ、プログラミングって面白そうかも」

と思ってくれりゃあ御の字っていう。

まぁ、とは言え、結構細かな技術部分の違いも入れて作ってるので、プログラミング学習中の人でもためになる内容になってます。
なので、各スクールさんで補助教材の1つとして使えたり、プログラミングが小学校必修となって親御さんなり教師がプログラミングがどんなものか学ぶ第一歩としても役立つと思います。
(実際に今有名な出版社さんから、うちの持ち出しなしで出版依頼も来てます)
image.png

世界観どうしよう

ターゲットも定まったところで世界観どうしようか悩みました。
ちなみにこの漫画は「漫画を読みながらWEBプログラミングの世界を学べる」ようにしたかったので、擬人化は
・HTML言語
・CSS言語
・JavaScript言語
・PHP言語
・SQL言語
を出そうと思ってました。
それぞれの言語の役割がざっくりイメージ出来て、自分たちが普段見ているHPが表示される中ではこんなやり取りが行われているんだという通信の流れもイメージできればいいなと。
(あとあとでRubyも出すことにしました。どんな登場でどんなキャラかは漫画でのお楽しみで)
スクリーンショット 2020-03-12 05.12.03.png
まぁ、キャラの動かし方としては、二郎系インスパイアの感じにしかならんだろうなとは思っていたので、
あとは色々とやり取りを重ねていくうちに世界観が見えてくるようになりました。
スクリーンショット 2020-03-12 05.12.34.png
スクリーンショット 2020-03-12 05.12.45.png
スクリーンショット 2020-03-12 05.13.13.png

HTML言語のキャラをざっくりどうするか

キャラ設定的なのどうするか考えていったんですが、
htmlはwebの根幹みたいなもんでしょう。
建築で言えば「基礎工事」や「家の骨組み」を作る人なわけなので、

熱血漢なてやんでぇ大工職人

という感じになりました
まぁ、ベタですが変に凝ると初心者がそもそも入っていけない世界になっていっちゃうので、ベタな王道で行くことにしました。

css言語のキャラをざっくりどうするか

cssは骨組みだけの簡素な家に外観つけて華やかにしていく美術さん的な感じですね。
ここらへんもベタに行きたかったので、お色気担当を入れることになり、

お色気のある大人な美術担当の女性

にすることになりました。
ストーリー内でも、htmlが土台を作り、cssが装飾を行う。という実際のweb制作の仕組みと同じにしています。
(こんな女性が実際の現場にいて欲しいと切に願ってます)

js言語のキャラをざっくりどうするか

これは、はたプロ(はたらくプログラミング)作りたい!ってちょろってツイートした時に
「言語を女性に全て擬人化したらこんなんだよね」
ってのが生徒からもらってたんで、それが採用されました。

jsはまぁフロントやってる人なら分かりますが、javaなりphpなりといった言語と違って標準のオブジェクトをぶっ壊す事も出来てしまうし、型とか関係なく放り込めるし、

ある意味柔軟で自由奔放、ある意味で大雑把

みたいな言語なので、そのまま
自由奔放でガサツで未熟感のある女性
になりました。
たぶん、B型女性かO型でしょうね。
僕はA型なんで、たぶん合わないです。
(振り回されてみたい願望もあるけど)

また、このjsちゃんをメインキャラに据える事にしました。
まぁ、うちのスクールがそもそも
バックも分かるフロントエンドエンジニア
を創出してるので、自然とjsメインになった感じです。
今後のテクノロジー成長の事も考えるとnodeもあるし、業務システムなどにある様な無機質な「システム」ではなく「サービス」としての価値勝負になっていき、UIリッチ、UXリッチでSPA化が当たり前になり、バックはAPIのみで簡素化されていく事を考えるとフロントエンド案件が今後どんどん増えていくのは必死ですしね。

つづく

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

【Nuxt.js】Nuxt文法編:$attrs

? この記事はWP専用です
https://wp.me/pc9NHC-li

前置き

属性の受け継ぎに関する
$attrsをまとめました!

inheritAttrsと
v-bind="$attrs"の2種類があります?

inheritAttrs とは

inherit
英語で「受け継ぐ」

親で与えられた属性を受け継ぐか
真偽値で決めることができます。

inheritAttrs: true

picture_pc_48118aa444ea32334dbe1db1befa80bc.gif

リンク先が '/' で
新しいタブで開かれていますね!

これだけ見ると普通のリンクなのですが
解説・コードを見ると
奇妙に感じるかもしれません?笑

【解説】

挙動を確認するために親子どちらでも
nuxt-linkタグのto属性でリンク先を指定しています?

to属性は子が優先されているのに
target属性は親のを引き継いでます。

もちろんtarget属性を子で指定すれば
子が優先されます!

が!

そもそも通常は親から子に何も使わず
何かを渡すことはできません。
属性に限らず、
テキストであれば
propsなりslotなり、何かを使います。
とっても変な感じがしますね?

ちなみに属性を渡す場合は、
この後に解説するv-bind="$attrs"を使います?

うっかり何も使わず親で属性を渡しちゃってた!
ということは防ぎたいです。。。

Link.vue
<template>
 <nuxt-link to="/">
   リンク!
 </nuxt-link>
</template>

<script lang="ts">
export default {
 inheritAttrs: true,
}
</script>
index.vue
<template>
<div class="page">
  <Link
    to="/sample"
    target="_blank"
  />
</div>
</template>

<script>
import Link from '~/components/Link.vue'

export default {
components: {
  Link,
},
}
</script>

inheritAttrs: false

attrs.gif

inheritAttrs: true
この奇妙な状態を解決するために
falseにしておくのが無難です?

今度は親の属性を引き継がず、
子の属性のみが反映されていますね!

【コード】

inheritAttrs: trueのコードをfalseに変えるだけ

v-bind="$attrs" とは

? 続きはWPでご覧ください?
https://wp.me/pc9NHC-li

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

Koa.js 3つのポイント。

Koa について

Nodeには Koa というフレームワークがあります。

人気の度合いについては Deno に Koaに触発されたプロジェクトOakが立ち上がるぐらいには人気があるようです。
ただし、日本語の記事は 2016-2017の v2のリリース以降は言及された記事がそれほど無く人気が盛り上がっている感じはありません。

Koaの特徴

ざっくり

全部入りのフレームワークとは異なり、リクエストやレスポンスの処理の限定的な処理しか持ちません。ちなみにルーティングすら用意されていません。

アプリケーションを拡張する方法は基本的にミドルウェアと呼ばれる関数を定義する方法しかなく、ある意味覚える事が少ないです。

コードを読んでいく上では高階関数の読み慣れが必要な印象ですが、全部入りのフレームワークに比べ、アプリケーションを拡張する際に 基底クラスやインターフェイスの理解(あるいは罠の熟知)が不要な点は気に入っています。

3つポイントを抑える

本体は覚える事が少ないです、以下の3つが主要な概念です。

  • context
  • middleware
  • next

context について

new koa() で新しいアプリケーションを作成した場合、そのアプリケーションの独立した環境(=コンテキスト)オブジェクトが作成されます。
このコンテキストオブジェクトはNodeのリクエストとレスポンスがうまくラップされています。また、状況に応じて拡張することも可能です。

https://github.com/koajs/koa/blob/master/docs/api/context.md

※ グローバルな状態が管理されているオブジェクトとして理解すれば大体あっていそうです。

単純なWebサーバの例です。

const Koa = require("koa");

const app = new Koa();

app.use((ctx /*<- これがコンテキスト*/) => {
    //この関数をミドルウェアと呼ぶ
    ctx.body = "koa app.";
})

app.listen(3000);

このコンテキストを経由して、リクエストの内容を取得したり、クライアントに情報を渡したりする事が出来ます。

middleware について

ミドルウェアは context を 第一引数、nextを第2引数に持つ関数です。ただそれだけです。
そのため、関数中で何をするか何をするべきで無いかは実装者に委ねられます。
contextの拡張(機能の追加)を行う際もこのミドルウェアを利用します。

Koa はそのミドルウェアを重ねて処理をすると良く説明されますが、複数の関数をうまく合成(compose)する仕組みと言い換えることも出来ます。

単純化してミドルウェアの仕組みを説明します。

const ctx = {state:""}
// ものすごく単純化したミドルウェアを重ねるイメージ
const middlewares = [
    (ctx,next) => {
        ctx.state = ctx.state + "1"; 
        next();
        },
    (ctx,next) => {
        ctx.state = ctx.state + "2";
        next();
        },
    (ctx,next) => {
        ctx.state = ctx.state + "3";
        next();
        }
    ]

const dispatch = (i) => {
    if(middlewares[i+1]){
        middlewares[i]( ctx , () => dispatch(i+1) );
        return;
    }
    middlewares[i](ctx,() => {});
}

dispatch(0);
console.log(ctx.state);
//123

サンプルでは ctx.state に3つのミドルウェアで1文字ずつ足していき最終的に123の文字列が出力されます。 dispatch は nextを通じて 再帰的に処理されます。

つまり next をコールすることで、次に登録されたミドルウェアに処理を移します。

このようにミドルウェアの層を重ねていく事でアプリケーションを開発します。

※シェルでテキストをコマンドとパイプで処理するイメージに近いと思えば近い。

※ 実際にはayncに対応しているため もう少し複雑です。この部分は koa-compose というライブラリが担っています。

https://github.com/koajs/compose

next について

前項で説明した通り、nextは次のミドルウェアを呼び出し、後続のミドルウェアでnextが呼ばれる限り再帰的に処理を行います。つまり ミドルウェア中ではnextが呼び出されたあとは自身よりあとのミドルウェアが実行済(解決済)の状態で自身に制御が戻ってきます。

これを公式では ダウンストリーム/アップストリームと表現しているようです。

※ コードではnextより上がダウンストリームでnextより下がアップストリーム。(合ってるか不安

先程の疑似ミドルウェアにコードを追加します。

const ctx = {state:""} // アプリケーションの環境

// ものすごく単純化したミドルウェアのイメージ
const middlewares = [
    (ctx,next) => {
        ctx.state = ctx.state + "1"; 
        console.log( "pre next" , ctx.state); // 1  が出力される
        next();
        console.log( "after next" ,ctx.state); // 123 が出力される
        // つまり 自分よりあとの2つのミドルウェアが実行された後 この関数に制御が戻ってきている
        },
    (ctx,next) => {
        ctx.state = ctx.state + "2";
        next();
        },
    (ctx,next) => {
        ctx.state = ctx.state + "3";
        next();
        }
    ];

const dispatch = (i) => {
    if(middlewares[i+1]){
        middlewares[i]( ctx , () => dispatch(i+1) );
        return;
    }
    middlewares[i](ctx,() => {});
}

dispatch(0);

上の仕組みにより、nextは単純に次に処理を移す事だけでは無くミドルウェアで表現できることの幅を広げてくれる事が理解できるかと思います。

私の脳ではこれを最大限活用するとコード追い辛いように思うんですが

実行される順番がわかりやすいように、もう少し書き加えています。

const ctx = {state:""} // アプリケーションの環境
let i = 1
// ものすごく単純化したミドルウェアのイメージ
const middlewares = [
    (ctx,next) => {
        ctx.state = ctx.state + "1"; 
        console.log( "down mw#1" ,  i++ ); //1
        next();
        console.log( "up mw#1" ,  i++ ); //6
        },
    (ctx,next) => {
        ctx.state = ctx.state + "2";
        console.log( "down mw#2" ,  i++ ); //2
        next();
        console.log( "up mw#2" ,  i++ ); //5
        },
    (ctx,next) => {
        ctx.state = ctx.state + "3";
        console.log( "down mw#3" ,  i++ ); //3
        //next();
        console.log( "up mw#3" ,  i++ ); //4
        }
    ]

const dispatch = (i) => {
    if(middlewares[i+1]){
        middlewares[i]( ctx , () => dispatch(i+1) )
        return
    }
    middlewares[i](ctx,() => {})
}
dispatch(0)
/**
down mw#1 1
down mw#2 1
down mw#3 1
up mw#3 1
up mw#2 1
up mw#1 1
**/

実行順を確認してみると、上から処理が降りていき終端に達すると、今度は上方向に処理が移っていくのがわかりやすくなると思います。

まとめ

ほとんど、ミドルウェアの説明になってしまった。

koa API ドキュメント(3つしかない

https://github.com/koajs/koa/tree/master/docs/api

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

Xilinx Zynqのブートシーケンスを、USBロジックアナライザとジャバスクリプトを使って確認する

新しいXilinx Zynq SoCシステムの開発過程では、ハードウェアの仕様を理解し、シグナルのタイミングをみることが重要である。残念ながら、ブートシーケンス内のQSPIのトランザクション速度の仕様は、明らかでない場合もある。Digilent Digital DiscoveryとHigh Speed Adapterシステムでは、100 MHz以上のはるかに速いクロック速度で起こるQSPI伝送を可視化できる。Digital Discoveryは512 MB DDRを搭載しているため、非常に大規模な収集を実行することが可能だ。そのため、エンジニアや開発者はブートシーケンスを可視化し、タイミングを特定することができる。

Digital Discoveryは、USBロジックアナライザ(USB Logic Analyzer)であり、プロトコルアナライザ(Protocol Analyzer)であり、またパターンジェネレーター(Pattern Generator)でもある。デジタル入力と出力は、単純なワイヤプローブまたはブレッドボードワイヤを使えば回路に接続することができる。あるいは、より高度なプロジェクト向けに、Digital Discovery High Speed Adapterとインピーダンス整合されたプローブを使い、入力と出力をつなげて利用することも可能だ。

Digilent ZYBO Zynq SoCプラットフォームのフラッシュメモリのブートシーケンスを見てみる。まず初めに、SOICクリップを使ってQSPIシグナルを取り出し、Digital Discoveryのロジックアナライザに取り込む必要がある。

digitaldiscovery_zyboz7-demo-2000.png

次に、ジャバスクリプトを使ってデバッグテストを作成し、WaveFormsで信号をデータに変換する。これを行うには、Click to Add Channels -> Custom in the Logic Analyzerを選択する。

WaveForms.png

WaveForms Logic Analyzer.png

WavForms Logic Analyzer Add Custom.png

Digilent ZYBOをオンにすると、指示がZynqからフラッシュメモリに送られる。その後、ロジックアナライザでブートシーケンスを可視化できる。アプリケーションノートは、Digilent Wikiで入手が可能だ。(https://reference.digilentinc.com/learn/instrumentation/tutorials/zynq-qspi-boot/start)

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

CocosCreator の Lifecycle Callback

CocosCreator の Lifecycle Callback

CocosCreatorでスクリプト書いた時の勉強メモ。意外とこの手の記事少ない気がしたので

参考 : Lifecycle Callback・Cocos Creator / 公式のドキュメント

  • onLoad() : 初期化時、シーン作成時など、scriptが初期化されるタイミング
  • start() : 最初のupdate()が実行される前
  • update() : フレームごと
  • lateUpdate() : 全部のupdateが終わった最後に
  • onEnable() : falseからtrueになったとき
  • onDisable() : trueからfalseになった時
  • onDestroy() : destroy()が呼び出された時

Tips (参考URLのTipsをDeepLに投げただけ。実行順序について)

コンポーネントの初期化から活性化、最終的な破棄までのライフサイクル関数の実行順序は、onLoad -> onEnable -> start -> update -> lateUpdate -> onDisable -> onDestroyとなります。

ここで、onLoadとstartはコンポーネントの初期化に使われることが多く、ノードがactiveInHierarchyになったときに一度だけ実行されます。上記の内容と実行順序の違いに加えて、以下のような違いがあります。
(参考URLのTipsをDeepLに投げただけ。実行順序について)

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

typescript 基本的な型付け

基本的な型付け

TypeScriptはJavaScriptに対して型をつけるという方向で仕様が作られています。 JavaScriptは動的言語の中でも、いろいろ制約がゆるく、無名関数とオブジェクトを使ってかなり柔軟なプログラミングの手法を提供してきました。 そのため、オブジェクトに対して型をつける方法についても、他のJavaなどの静的型付け言語よりもかなり複雑な機能を持っています。

スクリーンショット 2020-07-21 10.35.31.png

一番コスパのいい(手抜きな)型付け: any型

スクリーンショット 2020-07-21 10.43.22 1.png

最初に、一番費用が少ない方法を紹介します。 それが any です。 any と書けば、TypeScriptのコンパイラは、その変数のチェックをすべて放棄します。
まずはコンパイルだけは通したい、というときに使うと良さそうです。

: unknown型

anyと似ていますがタイプセーフな型です。型を特定するまであらゆる操作が制限されるみたいな型です。unknownは存在しうるすべての型の Union のようなものです。unknown型には任意の値を代入できる点はany型と同一ですが、型アサーション等が無いと利用できません。スクリーンショット 2020-07-21 11.04.20 1.png

まとめ

1:96スコープの中で最初からあるわけではないデータ

2:API をinterfaceで定義していく時に後回しにしたいプロパティの型

3:関数のオーバーロード定義時ただ引数の数を合わせたいだけの時の型

4:型の種類が多い(そして数が不明かつ API ドキュメントの無いプロジェクト)

みたいな所とかは一旦unknownで置いておいて、使う時になってから実際の型に置き換えたり、キャストしたりすると良い。

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

[Javascript] Arrayメソッドチート表 [非破壊・破壊・return・MDNリンク]

目的

  • メソッド利用時に、splitにarray渡してしまったり、spliceが非破壊破壊的か忘れるのでここらでまとめて、is not functionを撲滅したい。

今日やること

  • メソッドを安全に使えるような表をつくる。

そもそも非破壊的、破壊的ってなによ?

非破壊とは、渡した値を変換せずに処理をすること。

非破壊的なもの
let array = [1,2,3]
let newarray = array.forEach(e=>e+1)

console.log(array) //[1,2,3]
console.log(array) //[2,3,4]

破壊的とは、渡した値を変換すること

破壊的なもの
let array = [1,2,3]
let newarray = array.pop()

console.log(array) //[2,3,4]
console.log(array) //[2,3,4]

値を返すかどうかは非破壊的、破壊的によらずメソッド次第。

非破壊的と破壊的をどう使い分ければよいの?

上のとおり破壊的であると元の値が、処理後の値になってしまいます。
これは、同じ配列に対し繰り返し処理をしたい場合に元の配列を起点に繰り返し処理がしづらいので、使い回しがしづらくなることを示しています。

なので、繰り返し処理をしたい場合は非破壊を使うべし。です。

でも、だったら、なんで破壊的メソッドがあるの?

これについてはわかりませんでした。
一度しか使わない限定的な条件かでなら安全かつ早いのでしょうか?

よければこっそりコメントください。

メソッドチート表

参照しやすいようにメソッド名にはMDNリンクを貼りました。

メソッド名 渡す型 非破壊  破壊  return 使用例
forEach() Array なし 配列の各要素に対して、コールバック関数で処理をしたい。
map() Array 新配列 配列の各要素に対して、コールバック関数の処理を実行した新しい配列を返したい
filter() Array 新配列 配列の各要素に対して、コールバック関数でtrueになる要素のみで構成される新しい配列を返したい
reduce() Array 単一の値(acc) 配列の各要素に対して、コールバック関数の処理を実行した単一の値にして返したい第二引数の初期値は設定しておくべき
reduceRight() 単一の値(acc) reduceの処理を右から左へしたもの
splice() Array     新配列 配列から配列の一部を抽出、削除、追加し、新しい配列を返したい
slice() Array     新配列 配列から配列の一部を取り出し、新しい配列を返したい引数はインデックス番号 第一引数<=x<=第二引数
concat() Array/String 新配列/文字列 配列に他の配列や値をつないでできた新しい配列を返したい(文字列の場合も同様)
join() Array 新配列 配列の各要素を第一引数の区切り文字で区切った新しい配列を返した。区切り文字のデフォルトは,
push() Array 新配列の要素数 配列の末尾に要素を追加し、新たな配列の長さを返したい。
unshift() Array 新配列の要素数 配列の先頭に要素を追加し、新たな配列の長さを返したい。
pop() Array 取り除いた値 配列の最後の要素を取り除き、その値を返す
shift() Array 取り除いた値 配列の先頭の要素を取り除き、その値を返す
includes() Array/String true/false 配列に引数の値が含まれているかどうかを true か false で返したい
find() Array 最初の要素 コールバック関数を満たす配列内の最初の要素の値を返したい
findIndex() Array 最初のインデックス コールバック関数を満たす場合、配列内の 最初のインデックス を返したい
indexOf() Array/String 最初のインデックス/-1 引数に与えられた値と合致する最初の要素のインデックスを返したい。存在しなければ-1を返す
sort() Array なし 配列の要素をソートしたい新しい配列は用意されない                   
reverse() 新配列 配列の要素を反転させ、配列を書き換えたい 
fill() Array 新配列 配列中の開始インデックスから終了インデックスまで固定値に変更したい
copyWithin() Array 新配列 サイズを変更せずに、配列の一部を同じ配列内の別の場所にシャローコピーして返したい
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JS 配列の後ろからN個返す

LodashのtakeRight関数を作成してみた

メソッド使用せずに作成した場合

const takeRight = (array = [], takeRightNum) => {
  const reverseArray = array.reverse()
  const newArray = []
  let setNum = 1

  if (array.length < takeRightNum) {
    setNum = array.length
  } else {
    setNum = takeRightNum
  }

  for (let i = 0; i < setNum; i++) {
    newArray.push(reverseArray[i])
  }
  return newArray
}

console.log(takeRight([1, 2, 3]))
// => [3]

console.log(takeRight([1, 2, 3], 2))
// => [2, 3]

console.log(takeRight([1, 2, 3], 0))
// => []

console.log(takeRight([1, 2, 3], 5))
// => [1, 2, 3]

sliceメソッドで作成した場合

sliceメソッドとは

  • の引数に抜き出す範囲を指定すると、新しい配列オブジェクトとして返します
  • マイナス数字だと後ろから順に選択する

▼以下の記事を参考にさせて頂きました
suin: JavaScriptで配列の後ろからN個の要素を取り出す

const takeRight = (array = [], takeRight = 1) => {
  if (takeRight === 0) {
    return []
  }
  return array.slice(-takeRight)
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaScriptで経過時間を取得する

経過時間を知りたい

どれくらい時間が経過したのか知りたいときに便利です。

const startTime = Date.now();
let nowTime = 0;

nowTime = (Date.now() - startTime) / 1000;

Date.now()

UTC (協定世界時) での 1970 年 1 月 1 日 0 時 0 分 0 秒 から現在までの経過時間をミリ秒単位で返します。

参考
Date.now()

なので、1563292043074 みたいな数字が返ってきます。

startTimeDate.now() が格納された時間から、今この瞬間のDate.now() を引くと経過時間のミリ秒がわかります。

求められたミリ秒を1000で割ると秒数を求めることができます。

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

store の初期化方法

概要

以下のような初期化ではなく、あらかじめ初期値を宣言することで初期化する方法の紹介です

export const state = {
    text: '',
    arr: [],
    obj: {}
}

export mutations = {
    resetState(state) {
        state.text = ''
        state.arr = []
        state.obj = {}
    }
}

コード(例)

// 今回 deep copy するために使用
import { cloneDeep } from 'lodash'

// state の初期値を宣言
const initialState = {
    text: '',
    arr: [],
    obj: {}
}

// 初期値を deep copy 
export const state = cloneDeep(initialState)

export const mutations = {
    resetState(state) {
        Object.keys(state).forEach(key => {
            // state のキー毎に initialState で定義した初期値を deep copy して代入
            state[key] = cloneDeep(initialState[key])
        })
    }
}

注意点

  • 最初のstateの宣言、resetStateでの代入はdeep copyで行わなければならない
  • shallow copyで行うとinitialStateの値自体が書き換わってしまい正常に初期化できない場合がある
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Angularのテンプレート内にテンプレートを作る

ng-template, ng-container, *ngTemplateOutlet を使う

<div *ngFor="let item of list">
  <ng-container *ngTemplateOutlet="group; context: { item: item }"></ng-container>
</div>

<ng-template #group let-item="item">
  <span>{{item.a}}</span>
  <span>{{item.b}}</span>
  <span>{{item.c}}</span>
</ng-template>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む