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

モダンJavascript基礎 分割代入を学んでコードの可読性を上げよう!

はじめに

今回はES2015(ES6)で追加された分割代入について学んだことをまとめていこうと思います!
わかりにくいところや間違っているところがあったら、ご指摘お願いします!

分割代入とは

まず分割代入について説明していきます。分割代入を簡単に説明すると,

オブジェクトからプロパティを取り出して変数に代入するもの

です。

ちょっとイメージが湧きにくいですよね。コードで解説していきます。

const myProfile = {
  name: "田中",
  age: 20,
};

このようなオブジェクトがあるとします。そしてこのオブジェクトを使った変数を定義します。

const myProfile = {
  name: "田中",
  age: 20,
};

const message1 = `私の名前は${myProfile.name}です。年齢は${myProfile.age}です。`;

この変数message1の中身をconsole.logで見てみると
console.log
このようになります。

これでも別にいいのですが、もっとオブジェクトの変数名が長かったり、設定項目が多かったりすると、冗長で読みづらいコードになってしまいます。

そんな時こそ分割代入の出番です!!

const myProfile = {
  name: "田中",
  age: 20,
};
//分割代入構文↓
const {name,age} = myProfile;

この式で何をしているのかというとmyProfileというオブジェクトからname,ageというプロパティを取り出しています。左辺が取り出したプロパティで、右辺が取り出されたオブジェクトになります。

記述する順番に気をつけてください〜。

const myProfile = {
  name: "田中",
  age: 20,
};
const {name,age} = myProfile;
const message1 = `私の名前は${name}です。年齢は${age}です。`;

コードがすっきりしましたね。console.logで変数message1の中身も見てみましょう。
console.log
さっきと同じ結果になりました。このように分割代入を使えば、コードの可読性が上がるので、ぜひ使っていきましょう!

配列に分割代入を使う場合

オブジェクトだけでなく、配列にも分割代入は使うことができます。

const myProfile = ['田中', 20];
const message1 = `私の名前は${myProfile[0]}です。年齢は${myProfile[1]}です。`;

このようなコードに分割代入を利用すると

const myProfile = ['田中', 20];
const [name,age] = myProfile;
const message1 = `私の名前は${name}です。年齢は${age}です。`;

ここまで読みやすくなります!!
配列の場合、分割代入で最初に指定した変数に配列の0番目の要素が入り、2番目に指定した変数に配列の1番目の要素が入ります。配列は変数の順番が大事になってくるので気をつけてください。

最後に

分割代入はよく出てきますし、意味を知ってないと理解できないと思うので、しっかり勉強していきましょう!!!

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

【Rails】JSが読み込まれない時の対処法

railsアプリにて、JSの書き方は間違っていないはずなんだけど動かない!っていうことがありました。

原因

DOMが読み込まれる前に、JSが実行されて探しているDOMが見つからずにエラーとなっていた。

方法

実行したい処理を間に書いて下さい。
変数にDOMを指定する処理も全てこの中に書くようにして下さい。
そうすると、DOMが全て読み込まれてから実行されます。

document.addEventListener( 'DOMContentLoaded', function(){
    // 実行したい処理
}, false );
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Lodashを使って配列の差分を取得する

はじめに

開発しているアプリでGoogleカレンダーの予定を同期した際にデータベースに保存するようにしています。しかし、カレンダー側で削除した予定がデータベースには残っていて、表示されてしまっていました。
削除済みの予定をデータベースから削除する際に、データベースに保存している予定とGoogleカレンダーから取得した予定の差分を取得したいと思いました。
そこで、Lodashを利用すると配列の差分を簡単に取得することができます。

準備

インストール

npmの場合

$ npm i -g npm
$ npm i --save lodash

yarnの場合

$ yarn add lodash

インポート

import _ from "lodash";

使い方

_.differenceWithの第一引数に対象の配列、第二引数に比較対象の配列、第三引数にコンパレーターを指定します。

console.log(dbEvents)
// →[ { id: "idOfEvent1"}, { id: "idOfEvent2"} ]

console.log(calendarEvents)
// →[ { id: "idOfEvent1" }, ]

const diff = _.differenceWith(dbEvents, calendarEvent, (objValue, othValue) => {
  // 第一引数のidと第二引数のidが一致した場合はtrueを返す
  if (objValue.id === othValue.id) {
    return true;
  }
});

console.log("Diff is", diff);
// → Diff is [ { id: "idOfEvent2" } ]
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【monaca/iOS】<input type="file" accept="image/*">でカメラがクラッシュする原因



問題:input type="file" accept="image/*"で画像を取得するとき、カメラを起動しようとするとクラッシュする


状況:monacaでマークアップ言語とJavaScriptで開発 Cordovaバージョン10.0.0

結論:クラッシュするのは、monacaのカメラプラグインを有効にしていなかったから。


monacaでオナ禁アプリを作ったのですが、App Store Connectに申請したところ

Apple『カメラを起動した時にクラッシュするぞ。それ直してから出直してこい』

とリジェクトされてしまいました。該当箇所は

<input type="file" accept="image/*">

で画像を取得して表示、ローカルストレージに保存するという機能です。PCだとFinderが呼び出されますが、iOSだとこの画面が出て3つのオプションから選べるという仕様になっています。

IMG_6171.jpg

フォトライブラリから画像を選ぶという使い方を想定していたので実機確認でも「写真を撮る」についてはスルーしてしまっていました(アホ)

で、Appleに指摘されたのは、「写真を撮る」をタップするとクラッシュする、ということについて。

確かに、「写真をとる」を押した瞬間クラッシュします。「フォトライブラリ」と「ブラウズ」はちゃんと動くのに、なんでこれだけ?

目次

1.カメラ操作プラグインを有効にし忘れている
2.カメラ操作プラグインを使う際に気をつけること
3.まとめ

1. カメラ操作プラグインを有効にし忘れている

クラッシュの原因はシンプルかつ間抜けで、それは「カメラ操作のプラグインを有効にしていなかったから」でした。そりゃクラッシュします。monacaの「設定」=>「Cordovaプラグインの管理」=>「camera」を有効にすることで、カメラを使えるようになります。

2. カメラ操作プラグインを使う際に気をつけること

カメラプラグインをオンにしただけでは、別の問題で審査に通らなくなります。

Guideline 4.0 - DesignとGuideline 5.1.1 - Legal - Privacy - Data Collection and Storageに引っかかるためです。

どういうことかというと、カメラプラグインをONにしただけの状態だと、

attachment.Screenshot-0223-114855.png

こんな風に、モーダルの表示が「need camera access to take pictures」と、デフォルトの文章になっています。このモーダルの文章はユーザーがアクセスの許可を判断するにあたって非常に大切な情報でして、デフォルトのままだと、大事な情報を英語で書くなというのと、ユーザーがデータがどのように使用されるか知ることができないという理由で却下されます。

つまりこのモーダルの文章を書き換える必要があります。

どうやるかというと、config.xmlファイルの <edit-config>に以下のような記述があるので、これを書き換えます。

<edit-config target="NSCameraUsageDescription" file="*-Info.plist" mode="merge">
<string>need camera access to take pictures</string>
</edit-config>

この<string></string>の部分です。

ただし、文章はなんでもいいわけではなくて、カメラを必要とする機能を明記し、ユーザーのデータ(ここでは撮影した画像)をどのように使用するかの例を含める必要があります。

わかりにくいと思うので私のアプリの例を出すと、こんな感じに書いておけばOKです。

IMG_A60A7509C0A9-1.jpeg

もっと綺麗な書き方があるだろ!と思われるかもしれませんが、とりあえずこれで審査は通ります。

3. まとめ

・カメラを使おうとするとクラッシュするのは、カメラプラグインがOFFになっているから。
・カメラを使う場合はconfig.xmlにてデータの必要性とその使用目的を明記する必要がある。
・僕のアプリを見ていってくれると喜びます。



オナ禁アプリ↓
kinyoku-100px-icon.png
禁欲エボリューション



初めて作ったアプリ↓
mem-100px-icon.png
文字数制限メモ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Node.js】promiseの非同期処理について

プログラミング勉強日記

2021年2月27日
昨日の記事でJavaScriptの非同期処理について扱ったが、今回はNode.jsのpromiseの使い方をまとめる。

promiseとは

 Node.jsのpromiseは、非同期処理を読みやすいコードで実装できる。
 Node.jsでも使用されるJavaScriptでは、非同期処理のときにコールバック関数を使用する。だが、処理が複雑になるほどコールバック関数が入れ子になってしまい、コードの内容がわかりにくくなる。

Node.jsでpromiseを使う方法

 まず、promiseをインストールする。

$ npm install promise

 promiseの書き方は以下のようになる。

文法
// promiseパッケージを読み込む
var 変数 = require('promise');

変数(function (fulfilled, rejected) {
  処理内容
}

参考文献

非同期処理を覚える!Node.jsのpromiseの使い方【初心者向け】

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

Reactの公式チュートリアルを進化させる(2)

はじめに

Reactの公式チュートリアルを進化させる(1)の続きです.
React公式から与えられた課題はこれでした.

まだ時間がある場合や、今回身につけた新しいスキルを練習してみたい場合に、あなたが挑戦できる改良のアイデアを以下にリストアップしています。後ろの方ほど難易度が上がります:
1. 履歴内のそれぞれの着手の位置を (col, row) というフォーマットで表示する。
2. 着手履歴のリスト中で現在選択されているアイテムをボールドにする。
3. Board でマス目を並べる部分を、ハードコーディングではなく 2 つのループを使用するように書き換える。
4. 着手履歴のリストを昇順・降順いずれでも並べかえられるよう、トグルボタンを追加する。
5. どちらかが勝利した際に、勝利につながった 3 つのマス目をハイライトする。
6. どちらも勝利しなかった場合、結果が引き分けになったというメッセージを表示する。

今回は課題2に取り組みます.

課題内容

課題2の内容はこちら

  1. 着手履歴のリスト中で現在選択されているアイテムをボールドにする。

実装済みのやり直しボタンのうち,表示されている盤面の状態を表しているものを太字にしろということでしょうか.

つまり,これ↓を
after1.png

こうして↓
after2.png

戻ったりしてもこうなるよ↓
after2-2.png

ということでしょう.

実装

CSSで太字用クラスを用意して,太字にしたいときにそのクラスを割り当てるという方針でいきます.

まずは,index.cssに太字用クラスを追記します.

index.css
/* 太字クラスを追加 */
.bold {
  font-weight: bold;
}

あとは,「現在選択されているアイテム」にだけこれを割り当てれば良いだけです.
stepNumberは現在のターンを表しているので,ボタンのうち上からstepNumber番目を太字にすれば良さそうです.

index.jsを開いて,Gameコンポーネントのrenderメソッドのmovesの部分を以下のように書き換えましょう.

index.js
    const moves = history.map((value, index) => {
      const desc = index ?
        `Go to move #${index} (${(value.position % 3) + 1},${Math.floor(value.position / 3) + 1})`:
        'Go to game start';
      return (
        <li key={index}>
          <button onClick={() => this.jumpTo(index)} 
           className={index == this.state.stepNumber ? 'bold' : ''}> // [追加行] indexとstepNumberが等しいときboldを割り当てる
        {desc}
      </button>
        </li>
      );
    });

実装例

課題2終了時点のコードです.

index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

// Square関数コンポーネント
function Square(props) {
  return (
    <button className="square" onClick={props.onClick}>
      {props.value}
    </button>
  );
}


// Boardクラスコンポーネント
class Board extends React.Component {
  renderSquare(i) {
    return <Square value={this.props.squares[i]} onClick={() => this.props.onClick(i)} />;
  }

  render() {
    return (
      <div>
        <div className="board-row">
          {this.renderSquare(0)}
          {this.renderSquare(1)}
          {this.renderSquare(2)}
        </div>
        <div className="board-row">
          {this.renderSquare(3)}
          {this.renderSquare(4)}
          {this.renderSquare(5)}
        </div>
        <div className="board-row">
          {this.renderSquare(6)}
          {this.renderSquare(7)}
          {this.renderSquare(8)}
        </div>
      </div>
    );
  }
}


// Gameクラスコンポーネント
class Game extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      history: [{
        squares: Array(9).fill(null),
        position: null,
      }],
      stepNumber: 0,
      xIsNext: true,
    };
  }

  handleClick(i) {
    const history = this.state.history.slice(0, this.state.stepNumber + 1);
    const current = history[history.length - 1];
    const squares = current.squares.slice();
    if (calculateWinner(squares) || squares[i]) {
      return;
    }
    squares[i] = this.state.xIsNext ? 'X' : 'O';
    this.setState({
      history: history.concat([{
        squares: squares,
        position: i,
      }]),
      stepNumber: history.length,
      xIsNext: !this.state.xIsNext,
    });
  }

  jumpTo(step) {
    this.setState({
      stepNumber: step,
      xIsNext: (step % 2) === 0,
    });
  }

  render() {
    const history = this.state.history;
    const current = history[this.state.stepNumber];
    const winner = calculateWinner(current.squares);

    const moves = history.map((value, index) => {
      const desc = index ?
        `Go to move #${index} (${(value.position % 3) + 1},${Math.floor(value.position / 3) + 1})`:
        'Go to game start';
      return (
        <li key={index}>
          <button onClick={() => this.jumpTo(index)} className={index == this.state.stepNumber ? 'bold' : ''}>{desc}</button>
        </li>
      );
    });

    let status;
    if (winner) {
      status = 'Winner: ' + winner;
    } else {
      status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
    }

    return (
      <div className="game">
        <div className="game-board">
          <Board squares={current.squares} onClick={(i) => this.handleClick(i)}/>
        </div>
        <div className="game-info">
          <div>{status}</div>
          <ol>{moves}</ol>
        </div>
      </div>
    );
  }
}


// calculateWinner関数コンポーネント
function calculateWinner(squares) {
  const lines = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];
  for (let i = 0; i < lines.length; i++) {
    const [a, b, c] = lines[i];
    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
      return squares[a];
    }
  }
  return null;
}

// ========================================

ReactDOM.render(
  <Game />,
  document.getElementById('root')
);

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

モダンJavaScript基礎 Constの深掘り

はじめに

はじめまして!今現在、プログラミングを学習中のタイソンです。今回はjavascriptの基礎中の基礎であり、最も頻出する「const」についてまとめていこうと思います。

Constの基礎of基礎

constとは値の書き換え、または変数の再宣言ができない変数を宣言する方法です。書き方は以下の通りです。

const 変数名 = 変数に入れる値;

値の書き換えや再宣言ができないので、以下のように使うとエラーが出てしまいます。

値の書き換えはできない

const str = 'aiueo'
str = 'kakikukeko'
変数の再宣言はできない

const str = 'aiueo'
const str = 'kakikukeko'

オブジェクトをconstで定義する場合

前のチャプターで述べた通り、constで定義した変数は書き換えることはできません。
しかしconstで定義したオブジェクトは値を変えることができてしまうのです!!

const man = {
  name: '田中',
  age: 20,
};

man.name = '鈴木'

こう記述し、console.log(man)で変数manの中身を確認してみると、このようになっています。
console.logの中身
オブジェクトのプロパティの値はconstで定義していても、中身を変えることができるということです。もちろんconstで定義したオブジェクトに値を追加することも可能です。

const man = {
  name: '田中',
  age: 20,
};

man.address = '東京'

配列をconstで定義する場合

配列をconstで定義する場合はどうでしょう。
配列もオブジェクトの場合と同様でconstで定義していても要素の変更はできます!

const animal = ['dog', 'cat']
animal[0] = "bird"

このように配列の要素を書き換えて、console.log(animal)で配列を出力してみます。
animal.png

このようにconstで定義していても変更が可能なわけです。もちろん要素の追加もできます。ちなみに配列に追加する際、javascriptではpushを使います。

const animal = ['dog', 'cat']
animal.push("monkey")

最後に

いかがだったでしょうか。これからもこういったモダンjavascriptの文法について書いていこうと思います。読んでいただきありがとうございました。

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

Reactの公式チュートリアルを進化させる(1)

はじめに

Reactの公式チュートリアルでは,三目並べゲームの実装方法が紹介されていますが,このページの最後にこんな記述があります.

まだ時間がある場合や、今回身につけた新しいスキルを練習してみたい場合に、あなたが挑戦できる改良のアイデアを以下にリストアップしています。後ろの方ほど難易度が上がります:
1. 履歴内のそれぞれの着手の位置を (col, row) というフォーマットで表示する。
2. 着手履歴のリスト中で現在選択されているアイテムをボールドにする。
3. Board でマス目を並べる部分を、ハードコーディングではなく 2 つのループを使用するように書き換える。
4. 着手履歴のリストを昇順・降順いずれでも並べかえられるよう、トグルボタンを追加する。
5. どちらかが勝利した際に、勝利につながった 3 つのマス目をハイライトする。
6. どちらも勝利しなかった場合、結果が引き分けになったというメッセージを表示する。

やるしかないですね.

てことで,実装したので課題ごとに載せていこうと思います.
本記事では課題1のみ記載します.
当方React初心者ですので,何かあればアドバイスいただけると幸いです.

なお,この記事はReactの公式チュートリアルを終えていることを前提に書いています.
公式チュートリアルで解説されていることについては詳しく触れないのでご承知おきください.

課題内容

最初の課題内容はこちらです.

  1. 履歴内のそれぞれの着手の位置を (col, row) というフォーマットで表示する。

公式チュートリアルでは,着手の履歴を保存しておくことにより,過去のターンに戻ってやり直せるタイムトラベル機能を実装しています.

チュートリアルでは,下画像のように「Go to move #(ターン)」という形式で表示されたボタンをクリックすることで戻ることができるのですが,
before.png
下画像のように,そのターンで選択したマスを(列,行)という形式で表示することで分かりやすくしなさい,という主旨の課題のようです.
after.png

実装

チュートリアルでは,着手の履歴として盤面の状態のみを保存していましたが,選択したマスの位置も保存することにします.

Gameコンポーネントのstate
  this.state = {
    history: [{ // 着手の履歴を保存
      squares: Array(9).fill(null), // 盤面の状態
      position: null,  // [追加行] 選択したマスの位置(squaresのindex)
    }],
    stepNumber: 0, // ターン数
    xIsNext: true, // 手番
  };

これに伴い,stateの更新を行うhandleClickメソッドも以下のように変更します.
handleClickメソッドは,盤面のマスがクリック(選択)された際の処理です.

GameコンポーネントのhandleCkick
  handleClick(i) {
    const history = this.state.history.slice(0, this.state.stepNumber + 1); // 着手の履歴
    const current = history[history.length - 1]; // 現在の状態
    const squares = current.squares.slice(); // 現在の盤面
    if (calculateWinner(squares) || squares[i]) { // 決着がついている or 既に選択されたマス だったら
      return;
    }
    squares[i] = this.state.xIsNext ? 'X' : 'O'; // 手番でXかOか決める
    this.setState({ // stateの更新
      history: history.concat([{
        squares: squares,
        position: i, // [追加行]
      }]),
      stepNumber: history.length,
      xIsNext: !this.state.xIsNext,
    });
  }

JSXの生成を行っているmovesの内容も変更します.

Gameコンポーネントrenderメソッドのmoves
    const moves = history.map((value, index) => {
      const desc = index ?
        `Go to move #${index} 
         (${(value.position % 3) + 1},${Math.floor(value.position / 3) + 1})`: // [変更行] (列,行)
        'Go to game start';
      return (
        <li key={index}>
          <button onClick={() => this.jumpTo(index)}>{desc}</button>
        </li>
      );
    });

positionは,9個のマスに対して0~8の通し番号を左上から振った場合の位置を表しているため,
列番号はvalue.position % 3) + 1
行番号はMath.floor(value.position / 3) + 1
とすることで表せます.

チュートリアルでは,mapのコールバック関数の引数として,(step, move)を使用していましたが,個人的に分かりづらかったので(value, index)に変更しています.(step, move)のままでも構いません.

実装例

課題1終了時点のコードを載せておきます.

index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';

// Square関数コンポーネント
function Square(props) {
  return (
    <button className="square" onClick={props.onClick}>
      {props.value}
    </button>
  );
}


// Boardクラスコンポーネント
class Board extends React.Component {
  renderSquare(i) {
    return <Square value={this.props.squares[i]} onClick={() => this.props.onClick(i)} />;
  }

  render() {
    return (
      <div>
        <div className="board-row">
          {this.renderSquare(0)}
          {this.renderSquare(1)}
          {this.renderSquare(2)}
        </div>
        <div className="board-row">
          {this.renderSquare(3)}
          {this.renderSquare(4)}
          {this.renderSquare(5)}
        </div>
        <div className="board-row">
          {this.renderSquare(6)}
          {this.renderSquare(7)}
          {this.renderSquare(8)}
        </div>
      </div>
    );
  }
}


// Gameクラスコンポーネント
class Game extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      history: [{
        squares: Array(9).fill(null),
        position: null,
      }],
      stepNumber: 0,
      xIsNext: true,
    };
  }

  handleClick(i) {
    const history = this.state.history.slice(0, this.state.stepNumber + 1);
    const current = history[history.length - 1];
    const squares = current.squares.slice();
    if (calculateWinner(squares) || squares[i]) {
      return;
    }
    squares[i] = this.state.xIsNext ? 'X' : 'O';
    this.setState({
      history: history.concat([{
        squares: squares,
        position: i,
      }]),
      stepNumber: history.length,
      xIsNext: !this.state.xIsNext,
    });
  }

  jumpTo(step) {
    this.setState({
      stepNumber: step,
      xIsNext: (step % 2) === 0,
    });
  }

  render() {
    const history = this.state.history;
    const current = history[this.state.stepNumber];
    const winner = calculateWinner(current.squares);

    const moves = history.map((value, index) => {
      const desc = index ?
        `Go to move #${index} (${(value.position % 3) + 1},${Math.floor(value.position / 3) + 1})`:
        'Go to game start';
      return (
        <li key={index}>
          <button onClick={() => this.jumpTo(index)}>{desc}</button>
        </li>
      );
    });

    let status;
    if (winner) {
      status = 'Winner: ' + winner;
    } else {
      status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
    }

    return (
      <div className="game">
        <div className="game-board">
          <Board squares={current.squares} onClick={(i) => this.handleClick(i)}/>
        </div>
        <div className="game-info">
          <div>{status}</div>
          <ol>{moves}</ol>
        </div>
      </div>
    );
  }
}


// calculateWinner関数コンポーネント
function calculateWinner(squares) {
  const lines = [
    [0, 1, 2],
    [3, 4, 5],
    [6, 7, 8],
    [0, 3, 6],
    [1, 4, 7],
    [2, 5, 8],
    [0, 4, 8],
    [2, 4, 6],
  ];
  for (let i = 0; i < lines.length; i++) {
    const [a, b, c] = lines[i];
    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
      return squares[a];
    }
  }
  return null;
}

// ========================================

ReactDOM.render(
  <Game />,
  document.getElementById('root')
);


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

完全未経験の学生がvue.jsでポートフォリオ作成した

Portfolio

トップページ
無題.png

まず最初に,この記事では技術的な部分にはあまり触れないです.単純に初学者が作成に至るまでに参考にしたリファレンスや方法をまとめるだけです.したがって当たり前ですが,ほとんどの方にとっては何の価値もない記事となっています.

フロント未学習の大学生が1週間でVue.jsを使ったポートフォリオを作った話

この記事に触発されて,自分もvue.jsでポートフォリオを作成しました.
他の動機として,普段の研究やバイトではpythonばかり使ってるので,web系の言語も習得したいなと思って始めました.ただ最初はDjangoを使ってなにかバックエンドのものを作ろうとしたのですが,思ったよりも時間がかかりそうなので,先にvue.jsでフロントエンドを経験してみました.

完成度低いですが,最近忙しくて作業する時間がなく,どうやって作成したのかを忘れてしまいそうなので,いま記事を書いてます(本当に完成度低い).

上記の記事では1週間で仕上げていますが,自分の経験値のなさからかそれとも自頭の違いからか,理解に時間がかかり,1か月ぐらいグダグダ勉強してた気がします.作り始めてからは1週間ぐらいだったと思います.

よく初学者にある"何がわからないのかわからない"っていう状況が非常に多くてそれを打開するために,いろいろな本や動画,記事を参照しました.

中身はよくあるVue.jsでSPAを実現したってだけの簡単なウェブサイトです.なんの新規性も技術的な深化もありません.

あとはGithubでissue管理して,作業を行いました.
以下の記事の手順で行うとチームでの作業を疑似体験できるため非常にいい経験になると思います.
Githubでissue管理して開発しよう

学習編

pythonとCとC++への理解があるだけで,フロントエンドに関しては完全未経験でした.HTMLもCSSもJavascriptも未経験でしたので1から勉強しました.

HTML, CSS, JavaScript

Progate

progate

たくさんの方が薦めていますが,私は合いませんでした.
習うより慣れよ方式なので,定義や枠組みをしっかり理解してから使いたい私のスタイルとは合わなかったです.

結局以下の本を使用しました.この本は最近読んだ技術系の本でも一番好きです.レイアウト,色使い全ていいです.おしゃれなベジタリアン向けレシピ本を読んでる感じで,一日で読み終わってしまいました.値段高めで英語ですけど,家に置いておいてもオシャレだなと思います.

HTML and CSS: Design and Build Websites

JavaScriptに関しては,あまり勉強しませんでした.理由としてはもともとpythonができるってことで,コードをみても理解不能になることなどはなかったからです.つまり何がわからないのかわからない状況にはならずに,わからない箇所があっても調べればどうにかなるって感じでした.他の言語の経験がなくてもjavascriptに関してはprogateでサラッとどんな仕様なのか見ておくだけでいいのかなと思います.

Vue.js

公式リファレンス

これもいろんな方が薦めていますが,私には難しかったです.そもそも他のweb系の技術を学んだことがなかったので,言葉の意図がわからなかったりそもそも意味がわからないってことばかりでした.

結局いろいろ本や記事を読んでみて,なんとなくわかってきたところで,以下のビデオに沿ってたくさんアプリを作りました.単純にSPA仕様のポートフォリオを作りたいだけなら必要ないですが,実際ポートフォリオ作成はコードを書く練習にはならなくて,ただ技術をなんとなく使って終わりになってしまいました.なので実際にゴリゴリコード(javascript)を書いて成長って意味でオススメです.英語で10時間ありますが,かなり初歩からの説明となっており,わかりやすいです.

Vue 3 Tutorial - Full Course 10 Hours 10 apps

もし本を読みたかったらなんでもいいと思います.数冊読んでみたのですが,全部書いてあることは同じでした.

以下の記事も参考に読みました.
Vue.js + Bootstrap4でポートフォリオサイトの雛形を作ろう!
【超簡単】Vue.jsを使って3時間で自分のホームページを作成&公開する
Vueを学び、SPA対応のポートフォリオサイトを自作するまでの道のり
Vue.jsまとめ【初心者】
vue.js+Vuexチュートリアル

実装編

使用したツール

HTML, CSS, JavaScript, Vue.js, Bootstrap(いらない)

Vuetifyも入れようと思ったんですが,最初にnpm run devした後に入れることがうまくいかなくてやめました(Bootstrap同様にポートフォリオ作成の必要条件ではないですし…)

仕様

未完成の仕様もありますが,以下のことを試みました.

・SPA
・GitHub pagesでのdeploy
・Google font
・レスポンシブ対応(まだ微妙)
・多言語対応(まだ途中で放置)

コンテンツ

自分は完全未経験なので全然書くことがありませんが,とりあえず

・自己紹介
・スキル
・作成したもの
・投稿(Qiitaへの投稿)

にしました.

レイアウト

ここはなんのリファレンスにも頼らずに自分で適当にやってので流し読みしてください.

ワイヤーフレーム

ワイヤーフレームというWebページのレイアウトを定める設計図を作成するのが当たり前らしいです.
自分は見様見真似の自己流でやりました.
以下のサイトが無料で,デフォルトのデザインもたくさん入っていて使いやすかったです.

Figma

こんな感じで適当に,いろいろいじって遊んでました.
先にこれでデザインを決めると,HTMLとCSSを書くときに非常に楽でした.

image.png

配色

これは普段の研究室やバイトのパワポ作成で学んだ処世術ですが,基本的には三色ぐらいでまとめると見やすいです.(Webサイトにも当てはまるのか?)
その三色(もしくは四色)の決め方としては,パレットがあります.
Color paletteとググれば無限に出てきますので,その中で気に入った配色のものを使用しました.
具体的には以下のサイトを使用しました.

Color Hunt

アバター

別に必要ないですが,この機会にWebエンジニアっぽいのを作ってみました.

画像

なんでもいいと思います.
私は好きなアニメのSouth parkのアバター作成を用いました.

South Park Avatar Creator

加工

よくある丸型のアイコンの作製.
ただの画像の切り抜きなので,何のソフトでも可能ですが,私は以下のサイトを利用しました.
背景とかいろいろいじれます.

Free Profile Picture Maker

完成したアバターが以下のものになります.

SPA

詳しい技術的な仕様は,もっと詳しい方々の記事を読んでください.Single Page Applicationとあるように,ページ全体を先にロードして,ボタンぽちぽちしてもいちいちサーバ側と通信しないで済む技術です.

これはVue-routerというプラグインを導入することで,実現することができるようになります.
最初はよくわからなかったのですが,以下の記事を参考にとりあえず導入してゴチャゴチャいじってたら理解できました.

今さら聞けない?Vue Router
Vue-routerを使って、SPAをシンプルにはじめてみる

Google Fonts

フォントをこちら側で提供しないと,ブラウザによって異なるフォントになってしまいます.
なので,Google Fontを使って特定のフォントが表示されるようにしました.
なぜか?(簡単すぎるからか)リファレンスがなかったので以下の記事にしました.
Google FontsをVue.jsで使用する

GitHub pagesへのdeploy

この記事を参考にさせていただきました.
vue-cliで作ったアプリをGithub Pagesにデプロイ
しかし,うまくいかずにstackover flowで調べたところ,vue-cli3では以下のファイルが必要みたいでした.
以下のvue.config.jsを作成してconfig内に置いてやる必要があります.

vue.congig.js
module.exports = {
  outputDir: 'docs',
  assetsDir: './',
  publicPath: './'
}

これを置いたあとにbuildすれば大丈夫です.

作ってみて

思ったよりも時間がかかって大変でした.
わからないことがわからないという最悪の状況を久々に経験して,辛かったというのが率直な感想ではありますが,この経験はあくまでも登竜門というか,必ず最初には経験しないといけないことだと思います.
逆にこれを経験したからこそ今ならばvue.js以外のフレームワークにもすんなりと対応できる力が養われたと思います.

あとは,web系の技術の習得には,調べる能力?というのが結構問われてるのかなあって感じました.
大学院の研究活動やバイトでの開発業務をしているとリファレンスをたくさん探したりすることは当たり前の行為ですが,web業界も日々バージョンであったり技術の衰退が激しいので,vue.jsに限ってもバージョンやプラグインなどの違いから一つのリファレンスだけではどうにもならないっていうことが多いです.なので調べる能力?が大事なのかなあと感じました.

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

JavaScript中級者がChrome拡張を作る実況

はじめに

本記事は,自称JavaScript中級者の私が初めてのChrome拡張を作る模様を実況したものとなります.実況なので,細かい解説は割と省いています.JavaScriptの基本的な文法を抑えてる人が「大体こんな流れでChrome拡張を作るんだ〜」ってわかるような,一歩踏み出すきっかけになればいいなと思います.
なお,本記事は実際に自分が作りながら平行して執筆しているため,話し言葉多め,リアリティが増し増しになっているかもシレマセン.ご容赦を.

Step0. 何を作るか決める

当然,何を作るかはっきりしなければ作るものも作れません.先へ進めません.
ここでは,「最近マーケティング等の分野の記事で多用乱用されているカタカナ言葉(横文字)をどうにかする拡張機能」を作ろうと思います.
イケてる感を出したいのか,「日本語でええやんけ!」って単語までカタカナになっていると,まぁ読みにくいこと.それか素直に全部英語で書いてくれ.「エビデンス」とか「根拠」でええやん.おっと愚痴がすべりました.
以前から構想はあったのですが,友人からも「それ欲しい」と言われたので重い腰を上げて作ることにしました.

Step1. 作り方の概要を知る

いざ「よっしゃ拡張機能作るぞ!」となっても,作り方など一切知りません.そこで「chrome 拡張機能 作り方」とググって一番上に出てきた記事を読みます.私の場合は↓コチラが出てきました.先人の知恵はすばらしい.ありがたく読ませて頂きます.
https://qiita.com/RyBB/items/32b2a7b879f21b3edefc
こちらによれば,今回必要なものは

  • JavaScriptファイル(実際に動作するプログラムを書く)
  • manifest.json(拡張機能全般に関する情報を書く)
  • 拡張機能のアイコン画像

の3つになりそうです.(他にもHTML,CSSなど,Webページの表示で一般的に使われているファイルも使えるようですが,今回は不要と判断しました.)
JavaScriptファイルは,今あるプログラミングの知識を総動員すれば多分作れるし,manifest.jsonは https://qiita.com/mdstoy/items/9866544e37987337dc79 を読んでなんとなくわかった気がしたし.あれ…?思ってたより簡単じゃね…?

Step2. JavaScriptファイルを作る

manifest.jsonは後回しにして,とりあえず動作する部分を作ろうと思います.

Step2-1 動作を設計する

まずはどういう仕組みでカタカナ言葉を変換するか考えます.パッと思いついたのは,以下のような実装です.

  1. カタカナ言葉を変換する辞書(連想配列)を作っておく.
  2. 読み込んだhtmlの中からカタカナの単語を見つける.ここで,カタカナの単語とは「カタカナで始まり,カタカナ以外の文字が現れるまでの文字列」とします.正規表現が使えそうですね.2つ以上のカタカナの単語が連続していたりすると取り逃しが出そうですが,まあそれくらいは許容範囲としましょう.
  3. 2.で見つけたカタカナの単語が辞書内にあれば置き換える.

もうちょっと高速で,良い実装もありそうですが,とりあえずこれを採用しようと思います.辞書作りが大変そうだな〜と思いましたが,後押ししてくれた友人がノリノリで協力してくれるようなので,ありがたく力を借りることにします.

Step2-2 設計通りにJavaScriptを書く

まず,変換用の辞書について.これはjsにベタ書きでいいでしょう.

const katakanaEliminateDictionary = {
    "エビデンス": "根拠",
    "サクセス": "成功",
    ...
}

うんうん,カタカナ言葉を撲滅しようという意気が伝わってくる命名ですね.

次に,「カタカナの単語を全て見つけ,辞書内にあれば置き換える」という部分ですね.html内のタグを再帰的に探索し,innerTextに正規表現やString.replace(target, alternative)を用いることで実装しようと思います.
ここの実装でちょっと躓いて,1時間くらいかかってしまいましたが,無事に動作するようになって安心しました.ポイントは,再帰探索&置換で帰りがけ探索を用いることで,葉要素から置換を行うことのようです.

ともあれ,書いたコードをブラウザのコンソールに貼り付けることで,辞書内の単語を撲滅することに成功しました.本当は適当なカタカナ言葉乱用サイトでの動作例を載せたいところですが,サイト作成者さんに怒られそうなので自重しておきます.

Step3 manifest.jsonを作る

基本的な事項はStep1でも紹介したhttps://qiita.com/mdstoy/items/9866544e37987337dc79 を参考に.
ブラウザ上で右クリックした時のメニューからカタカナ言葉撲滅関数を実行できるといいなと思い調べてみたところ,↓のサイトが参考になったので,こちらの記述も参考にJSファイルを書き直しつつ,manifest.jsonを書き進めます.
https://karupoimou.hatenablog.com/entry/2019/04/22/040546

しかし,これだと現在開いているタブのページのDOMの書き換えができない模様.どうやら,Content Scriptsというものが関わっているらしく,↓の記事を参考に無理やりDOMの書き換えをするようにしました.
https://mem-archive.com/2019/12/09/post-2164/

これで,「ページ上で右クリックすると,メニュー内でカタカナ言葉撲滅関数を実行できる」という挙動を実現できました.

完成形

結果,出来上がったファイルたちがコレ.chromeで拡張機能の設定 を開き,パッケージ化されていない拡張機能を読み込むから,下の例のextensionフォルダを開くことで導入できました.
多くの記事を横断して読みながら作ったため,もしかしたら無駄な部分があるかもしれません.

extension/
|
├ manifest.json
├ app.js
└ wrapper.js
manifest.json
{
    "manifest_version": 2,
    "name": "カタカナ言葉撲滅Chrome拡張",
    "version": "1.0.0.0",

    "description": "カタカナ言葉が乱用されているサイトが読みにくかったので,撲滅してくれる拡張をつくりました.",
    "icons": {
        "128": "icon128.png"
    }, 

    "author": "AuthorName",
    "background": {
      "scripts": ["app.js"]
    },
    "content_scripts":[
        {
          "matches":[
            "http://*/*",
            "https://*/*"
          ],
          "js":[
            "app.js"
          ]
        }
      ],
    "permissions" : [
        "contextMenus",
        "http://*/*",
        "https://*/*",
        "tabs"
    ],

    "homepage_url": "http://path/to/homepage",
    "offline_enabled": true
  }
app.js
const katakanaEliminatorDictionary = {
    "エビデンス": "根拠",
    "サクセス": "成功",
    ...
}
const katakanaEliminatorKeys = Object.keys(katakanaEliminatorDictionary);
const targetPattern = "[\u30A1-\u30F6ー]+"; //全角カタカナと"ー"の正規表現
let htmlElement = document.documentElement;

function replacePattern(element){
    //子要素に対して帰りがけ探索的に再帰呼び出し
    for(let i = 0; i < element.children.length; i++){
        replacePattern(element.children[i]);
    }

    //innerText内のカタカナの単語をすべて検索
    //カタカナがなくなるまで繰り返す

    //辞書内に無い単語で無限ループしないために,どこまで見たのか記憶する
    let searchedIndex = 0;
    console.log("replacing...");
    while (true) {
        let katakanaWords = element.innerText.substr(searchedIndex).match(targetPattern);
        if(katakanaWords){
            console.log(katakanaWords[0]);
            if (katakanaEliminatorKeys.includes(katakanaWords[0])){
                element.innerText = element.innerText.replace(
                    katakanaWords[0],
                    katakanaEliminatorDictionary[katakanaWords[0]]);
            }
            searchedIndex += katakanaWords.index + katakanaWords[0].length
        } else {
            break;
        }
    }
    return;
}

function funcWrapper(){
    replacePattern(htmlElement);
}
chrome.contextMenus.create({
    "title": "カタカナ言葉を撲滅する",
    "type": "normal",
    "onclick": function(){
        chrome.tabs.executeScript(null, { file: './wrapper.js' }, () => {});
    }
});
wrapper.js
funcWrapper(); //コレだけでOK

あとがたり

ここまでおつきあいくださりありがとうございました.Step2で1時間半,Step3では結構苦戦して2時間半くらいかかってしましましたが,どうにか休日の半日で完成させることができてホッとしております.
JavaScriptを知っていたので実装自体はあまり苦労しませんでしたが,これを拡張機能として動かすところではやはり分からないことが多くて苦労しました.
これで,意味わからないカタカナ言葉ばかりのサイトにというイシューに対するソリューションをドラスティックにリリースできてサティスファイドになりました.

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

オンプレ環境で使えるDiscordの読み上げBotを作りました

事の発端

知り合いとDiscordサーバーでは土日に通話しながらゲームをするときに、通話の際テキストチャンネルで発言するのみで喋らない"聞き専"が結構います。
そこでチャットを読み上げてくれる「Shovel」というBotを導入しました。
キャプチャ.PNG
しかし、土日の夜は非常に人が多いのか、ボイスチャットに呼ぼうとしても呼べない時が何度かあり、そこで自分たち専用のサーバーを用意する案が上がります。

Raspberry Piを入手

秋葉原に行って、Raspberry Pi4と電源などの一式を入手。
早速、以下の条件を満たす読み上げDiscord Botを探し始めます。

  • ラズパイ上で動く
  • Dockerでいける(環境を汚したくないため)
  • オンプレ環境で使える
  • 完結している、クラウドサービスを使っていない(Cloud Text-to-Speechなど)

しかし案外見つからず1、結局自分で作る事にしました。

成果物

よみのん
上の四つの条件を満たしたDiscord用読み上げBotです。
Discord.js+Open Jtalk+Dockerで作成しています。
Discord用のBOT KEYを発行した後に、適当にVPSや自前のラズパイによみのんをデプロイしてもらえば動きます。
詳しくはのよみのんのReadme.mdを見て下さい。

Issue、Starは大歓迎です。


  1. 単純に僕の検索能力不足...? 

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

ruby on rails 非同期いいね(編集中)

アプリケーションの立ち上げ

% rails new favorite-app -d mysql
% cd favorite-app
% rails db:create
% rails g scaffold post title:string user_id:integer   #postコントローラ作成
% rails g controller likes                             #likesコントローラ作成
% rails g model Like user_id:integer post_id:integer

Gemfileの下部に以下を追記

gem 'devise'
gem 'font-awesome-sass'

Gemfile編集後に実行

% bundle install
% rails g devise:install
% rails g devise user
% rails db:migrate

「application.css」を「application.scss」に変更

その後以下のコードを追記。

// application.scssの下部に以下を追記(既存のコードは消さない)
```ruby
/*
* This is a manifest file that'll be compiled into application.css
* vendor/assets/stylesheets directory can be referenced here using a relative path.
* 省略
*= require_tree .
*= require_self
*/

------------この部分を追記-----------------
@import "font-awesome-sprockets";
@import "font-awesome";
------------この部分----------------------
```

favorite-app/app/javascript/packs/application.jsを編集

require("@rails/ujs").start()
// require("turbolinks").start()   ⇐この行を削除
require("@rails/activestorage").start()
require("channels")
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ruby on rails 非同期いいね

アプリケーションの立ち上げ

% rails new favorite-app -d mysql
% cd favorite-app
% rails db:create
% rails g scaffold post title:string user_id:integer   #postコントローラ作成
% rails g controller likes                             #likesコントローラ作成
% rails g model Like user_id:integer post_id:integer

Gemfileの下部に以下を追記

gem 'devise'
gem 'font-awesome-sass'

Gemfile編集後に実行

% bundle install
% rails g devise:install
% rails g devise user
% rails db:migrate

「application.css」を「application.scss」に変更

その後以下のコードを追記。

// application.scssの下部に以下を追記(既存のコードは消さない)
```ruby
/*
* This is a manifest file that'll be compiled into application.css
* vendor/assets/stylesheets directory can be referenced here using a relative path.
* 省略
*= require_tree .
*= require_self
*/

------------この部分を追記-----------------
@import "font-awesome-sprockets";
@import "font-awesome";
------------この部分----------------------
```

favorite-app/app/javascript/packs/application.jsを編集

require("@rails/ujs").start()
// require("turbolinks").start()   ⇐この行を削除
require("@rails/activestorage").start()
require("channels")
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ruby on rails 非同期いいね (編集中)

アプリケーションの立ち上げ

% rails new favorite-app -d mysql
% cd favorite-app
% rails db:create
% rails g controller home                              #homeコントローラ作成
% rails g scaffold post title:string user_id:integer   #postコントローラ作成
% rails g controller likes                             #likesコントローラ作成
% rails g model Like user_id:integer post_id:integer

Gemfileの下部に以下を追記

gem 'devise'
gem 'font-awesome-sass'

Gemfile編集後に実行

% bundle install
% rails g devise:install
% rails g devise user
% rails db:migrate

「application.css」を「application.scss」に変更

その後以下のコードを追記。

// application.scssの下部に以下を追記(既存のコードは消さない)

/*
 * This is a manifest file that'll be compiled into application.css
 * vendor/assets/stylesheets directory can be referenced here using a relative path.
 * 省略
 *= require_tree .
 *= require_self
 */
------------この部分を追記-----------------
@import "font-awesome-sprockets";
@import "font-awesome";
------------この部分----------------------

favorite-app/app/javascript/packs/application.jsを編集

require("@rails/ujs").start()
// require("turbolinks").start()   ⇐この行を削除
require("@rails/activestorage").start()
require("channels")

favorite-app/config/routes.rb

Rails.application.routes.draw do
  devise_for :users
  root 'home#index'
  resources :posts
  post 'like/:id' => 'likes#create', as: 'create_like'
  delete 'like/:id' => 'likes#destroy', as: 'destroy_like'
end

favorite-app/app/controllers/posts_controller.rb

class PostsController < ApplicationController
  before_action :authenticate_user!
  before_action :set_post, only: %i[ show edit update destroy ]

  def index
    @posts = Post.all
  end

  def show
  end

  def new
    @post = Post.new
  end

  def edit
  end

  def create
    @post = Post.new(post_params)
    @post.user_id = current_user.id

    respond_to do |format|
      if @post.save
        format.html { redirect_to @post, notice: "Post was successfully created." }
        format.json { render :show, status: :created, location: @post }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    respond_to do |format|
      if @post.update(post_params)
        format.html { redirect_to @post, notice: "Post was successfully updated." }
        format.json { render :show, status: :ok, location: @post }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: @post.errors, status: :unprocessable_entity }
      end
    end
  end

  def destroy
    @post.destroy
    respond_to do |format|
      format.html { redirect_to posts_url, notice: "Post was successfully destroyed." }
      format.json { head :no_content }
    end
  end

  private
    def set_post
      @post = Post.find(params[:id])
    end

    def post_params
      params.require(:post).permit(:title)
    end
end

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

WordPressで資産運用シミュレーションツールを作った

はじめに

WordPressで作ったブログの投稿に、資産運用のシミュレーションツールを簡単なJavaScriptで作りました。(ツール)

この記事では、WordPressの投稿を自分独自に作り変えてツールのようにする方法について解説します。

ツール自体のソースの中身については解説しません。githubにソースがありますので気になる方は御覧ください。(github)
スクリーンショット 2021-02-25 21.51.42.png

ブログについて

お金のことを勉強するついでにブログを書いています。(ブログ)

勉強してて思うのですが、お金は知ってるか知らないかだけでめちゃくちゃ得したり損したりします。なのに学校では教えてくれない。
この記事を見たあなたもお金の勉強をしていないならしたほうが良いです。若ければ若いほどいい!

画面を作る

インプットの場所とボタンを作りましょう。

インプット

基本的には以下のカスタムHTMLを使って作ります。
スクリーンショット 2021-02-25 22.24.16.png

ポイントは、パーツごとにカスタムHTMLを使うことですね。
カスタムHTMLは他のブロックと組み合わせて使うことが出来ますので、レスポンシブにしたければ以下のように3カラムのブロックの中に各パーツを配置します。(3カラムは使用してるテーマによってはないかもしれません。自分はCocoonというテーマを使用しています。)
スクリーンショット 2021-02-25 22.29.41.png

スクリーンショット 2021-02-25 22.30.01.png
スクリーンショット 2021-02-25 22.31.15.png

あとは各パーツにid属性を付与してJavaScriptから使えるようにするだけです。

ボタン

インプットと同様にカスタムHTMLだけでやると味気ない感じになってしまいます。
inputはカスタムHTMLに入力しただけでいい感じになりましたが、ボタンはなりませんでした。
自分が使っているテーマのCocoonはinputにはCSSを用意してくれているけど、ボタンには用意がないみたいです。
スクリーンショット 2021-02-25 23.03.46.png
スクリーンショット 2021-02-25 23.04.03.png
そういうときは、一度ブロックエディタでボタンを作ってから「HTMLとして編集する」からHTMLに変換したものをカスタムHTMLにコピペしましょう。
そのまま編集してもいいですが、ページを離れるたびにHTMLに変換する必要があるので面倒くさいです。
スクリーンショット 2021-02-25 23.14.30.png
あとはボタンを押した時にJavaScriptの関数を呼び出すようにするだけです。(onclick属性)

処理を作る

処理は投稿ページ下のカスタムJavaScriptのところに記述します。
CSSがほしければカスタムCSSに記述します。
これらはこのページのみにのみ適用されます。
スクリーンショット 2021-02-25 22.08.22.png

ボタンを押されたときに呼び出されるメソッドを作り、その中でインプットの値を取得して計算して答えとグラフを出すというコードを書くだけです。
最初に書いた通りコードの詳細はgithubで確認してください。(github)

ちなみに、グラフの描画はChart.jsを利用しています。まあまあ使いやすいです。

作成中は

WordPressの投稿ページでコード書くのはやりにくすぎるので
vsコードなどでページを作ってからコピペするのがいいと思います。
スクリーンショット 2021-02-25 23.46.19.png

おわりに

なかなか雑な説明でしたね。ご質問あればコメントまでお願いします。
もう一個「将来価値-現在価値変換ツール」というのも作ってます。(ツール)

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

Amazonの商品ページから、「人気のインディーズマンガ」を消したい(chrome)

モチベーション

Amazonでマンガのページを見ていると、人気のインディーズマンガというカルーセルが出てくる。
スクリーンショット 2021-02-27 1.34.13.jpg
↑こういうやつ。
作品を読んでいないので、内容をどうこう言うつもりはないんですが、一度も買ったことないし、無闇に肌色が多かったりして邪魔だなと思ったのだが・・・非表示にする方法が公式の設定から見つけられなかった。
と言うわけで、放置し続けるストレスより作業するストレスの方が少ないと思って、DOMから強制的に排除することにしました。

拡張機能の導入

今回はscriptAutoRunnerを使いました。
scriptAutoRunner
サイトにアクセスするたびに、自動でjavascriptを走らせてくれるお方です。

javascriptを準備する

「人気のインディーズマンガ」をタイトルにもつdivを取得し、その上の階層を削除するjavascriptを書きます。

const deleteIndiesMangaCarousel = () => {
  const targetTitleList = [
    "人気のインディーズマンガ",
    "高評価のインディーズマンガ",
  ];
  const widgetHeadDivList = document.querySelectorAll(".dbs-widget-head");
  const targetTitleDiv = Array.from(widgetHeadDivList).find((div) => {
    const textContent = div.querySelector(".dbs-widget-head-title").textContent;
    return targetTitleList.find((title) => {
      return textContent.includes(title);
    });
  });
  if (!targetTitleDiv) {
    return;
  }
  const targetNode = targetTitleDiv.parentNode;
  targetNode.remove();
};

deleteIndiesMangaCarousel();

拡張機能を設定する

chromeのアドレスバーに
chrome://extensions/
と入力
scriptAutoRunnerが表示されるので、詳細をクリック。

スクリーンショット 2021-02-27 11.10.17.png

拡張機能のオプションをクリック
スクリーンショット 2021-02-27 11.10.47.png

GUIが表示されるので、先程のjavascriptをコピペ

スクリーンショット 2021-02-27 11.42.07.png

プラグを繋ぐ

スクリーンショット 2021-02-27 11.42.02.png

これで表示されなくなりました。カルーセルがあった位置でリロードすると一瞬チラッと見えたりしますが、まぁいいでしょう。
ここまで書いた時点で、「人気のインディーズマンガ」以外にも「高評価のインディーズマンガ」というタイトルが出てきてコード書き直しとSS撮り直しになったのが、ちょっとイラッとしました。

めでたしめでたし

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

「あなたの過去を表示します」JavaScriptでWebカメラの画像を遅延表示してみた

なぜ、過去を表示したいのか

 カメラで撮影した画像を遅れて表示させる方法を「タイム シフト」「追いかけ再生」と言います。遅延表示により、再生を戻すことなく数秒前の過去の画像を連続して表示し続けます。この機能を使い、例えば保健体育では、跳び箱を跳ぶす様子を撮影しながら遅延再生して自分の動きを確認させることができます。過去に、Windows用ソフトを開発し公開していました。
 しかし、GIGAスクールの時代、学校に導入されるのは、Windows、iOS、chromebookと多種多様です。そこで、どの機種にも対応できるよう、ブラウザ上で作動する「タイムシフトカメラ」を作ってみました。
作動例→ https://kaihatuiinkai.jp/time_shift/in_camera.html

 それでは、作成ステップを説明します。データの流れとプログラム作動を確認してもらうため、ソースコードを全て貼り付けしました。長くなってしまうことをご了承願います。

カメラ画像を表示

参照:[HTML5] カメラをJSで操作し写真を撮影する
https://blog.katsubemakito.net/html5/camera1
こちらのソースをほぼそのまま利用しています。

カメラ画像を映像要素<video>に表示します。
作動例→ https://kaihatuiinkai.jp/time_shift/camera1.html
なお、カメラ画像を表示させるためには https であることが必要です。

camera1.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Camera1</title>
  <style>
  canvas, video{ border: 1px solid gray; }
  </style>
</head>
<body>
<h1>カメラ画像を映像要素&lt;video&gt;に表示</h1>
video<br>
<video id="video" width="300" height="200"></video>
<script>
window.onload = () => {
  const video   = document.querySelector("#video");
  // カメラ設定  //
  const constraints = {
    audio: false,
    video: {
      width:  300,
      height: 200,
      facingMode: "user"   // フロントカメラを利用
      // facingMode: { exact: "environment" }  // リアカメラを利用
    }
  };
  // カメラを<video>と同期 //
  navigator.mediaDevices.getUserMedia(constraints)
  .then( (stream) => {
    video.srcObject = stream;
    video.onloadedmetadata = (e) => {
      video.play();
    };
  })
  .catch( (err) => {
    console.log(err.name + ": " + err.message);
  });
};
</script>
</body>
</html>

映像要素の画像を<canvas>に表示

画像を<canvas>に1秒ごとに貼り付けて表示します。
作動例→ https://kaihatuiinkai.jp/time_shift/camera2.html

「1秒前の過去の画像」が表示されます。インターバル処理の数値で、画像書き換えの時間を変更します。100にすると、<video>動画と同様に見えます。

camera2.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Camera2</title>
  <style>
  canvas, video{ border: 1px solid gray; }
  </style>
</head>
<body>
<h1>映像要素の画像を&lt;canvas&gt;に表示</h1>
1秒のインターバル処理でcanvasに表示<br>
video                 canvas1<br>
<video  id="video"   width="300" height="200"></video>
<canvas id="canvas1" width="300" height="200"></canvas>
<script>
window.onload = () => {
  const video   = document.querySelector("#video");
  const canvas1 = document.querySelector("#canvas1");
  // カメラ設定  //
  const constraints = {
    audio: false,
    video: {
      width:  300,
      height: 200,
      facingMode: "user"   // フロントカメラを利用する
      // facingMode: { exact: "environment" }  // リアカメラを利用する場合
    }
  };
  // カメラを<video>と同期 //
  navigator.mediaDevices.getUserMedia(constraints)
  .then( (stream) => {
    video.srcObject = stream;
    video.onloadedmetadata = (e) => {
      video.play();
    };
  })
  .catch( (err) => {
    console.log(err.name + ": " + err.message);
  });
  // インターバル処理
  var intervalID = setInterval(function(){
    // canvas の準備
    picture = canvas1.getContext("2d");
    // video画像を canvas1に貼り付ける
    picture.drawImage(video, 0, 0, canvas1.width, canvas1.height);
  }, 1000);
};
</script>
</body>
</html>

<canvas1>の画像を<canvas2>に表示

<canvas1>の画像を変数に入れて、その変数で<canvas2>に画像を表示します。
作動例→ https://kaihatuiinkai.jp/time_shift/camera3.html

camera3.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Camera3</title>
  <style>
  canvas, video{ border: 1px solid gray; }
  </style>
</head>
<body>
<h2>映像要素の画像を&lt;canvas1&gt;に表示、&lt;canvas1&gt;の画像を&lt;canvas2&gt;に表示</h2>
video                 canvas1                 canvas2<br>
<video  id="video"   width="300" height="200"></video>
<canvas id="canvas1" width="300" height="200"></canvas>
<canvas id="canvas2" width="300" height="200"></canvas>
<script>
window.onload = () => {
  const video   = document.querySelector("#video");
  const canvas1 = document.querySelector("#canvas1");
  const canvas2 = document.querySelector("#canvas2");
  // カメラ設定  //
  const constraints = {
    audio: false,
    video: {
      width:  300,
      height: 200,
      facingMode: "user"   // フロントカメラを利用する
      // facingMode: { exact: "environment" }  // リアカメラを利用する場合
    }
  };
  // カメラを<video>と同期 //
  navigator.mediaDevices.getUserMedia(constraints)
  .then( (stream) => {
    video.srcObject = stream;
    video.onloadedmetadata = (e) => {
      video.play();
    };
  })
  .catch( (err) => {
    console.log(err.name + ": " + err.message);
  });
  // インターバル処理
  var intervalID = setInterval(function(){
    // canvas1 の準備
    picture = canvas1.getContext("2d");
    // canvas1に画像を貼り付ける
    picture.drawImage(video, 0, 0, canvas1.width, canvas1.height);
    // canvas1から画像を取得して変数に入れる
    var image = picture.getImageData(0, 0, canvas1.width, canvas1.height);
    // canvas2 に変数の画像を貼り付ける
    document.getElementById("canvas2").getContext('2d').putImageData(image, 0, 0);
  }, 1000);
};
</script>
</body>
</html>

<canvas1>の画像を配列に入れて、<canvas2>に遅延表示

 配列変数を使って、<canvas2>に遅延表示します。初めは配列に画像がないため起動時にエラーが出るので、これを回避処理します。
作動例→ https://kaihatuiinkai.jp/time_shift/camera4.html

camera4.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>Time Shift Camera</title>
  <style>
  canvas, video{ border: 1px solid gray; }
  </style>
</head>
<body>
<h2>&lt;canvas1&gt;の画像を配列に入れて、&lt;canvas2&gt;に遅延表示</h2>
video                 canvas1                 canvas2<br>
<video id="video" width="300" height="200"></video>
<canvas id="canvas1" width="300" height="200"></canvas>
<canvas id="canvas2" width="300" height="200"></canvas>
<script>
var imageMax = 110;   // 遅延最大時間 最大10秒
var imageArray = new Array(imageMax); // 画像保存用
var imageNumber = 0;  // 現在の画像番号
var imageDisplay = 0; // 表示番号
var imageDelay = 10;  // 表示遅延  1秒
window.onload = () => {
  const video  = document.querySelector("#video");
  const canvas1 = document.querySelector("#canvas1");
  const canvas2 = document.querySelector("#canvas2");
  // カメラ設定  //
  const constraints = {
    audio: false,
    video: {
      width: 300,
      height: 200,
      facingMode: "user"   // フロントカメラを利用する
      // facingMode: { exact: "environment" }  // リアカメラを利用する場合
    }
  };
  // カメラを<video>と同期 //
  navigator.mediaDevices.getUserMedia(constraints)
  .then( (stream) => {
    video.srcObject = stream;
    video.onloadedmetadata = (e) => {
      video.play();
    };
  })
  .catch( (err) => {
    console.log(err.name + ": " + err.message);
  });

    // canvas1 の準備
    picture = canvas1.getContext("2d");
    // canvas1に画像を貼り付ける
    picture.drawImage(video, 0, 0, canvas1.width, canvas1.height);

  // インターバル処理
  var intervalID = setInterval(function(){
    // canvas1 の準備
    picture = canvas1.getContext("2d");
    // canvas1に画像を貼り付ける
    picture.drawImage(video, 0, 0, canvas1.width, canvas1.height);
    // 画像記録番号
    imageNumber = imageNumber + 1;
    if(imageNumber >= imageMax){
      imageNumber =0;
    };
    // canvas1から画像を取得して変数に入れる
    imageArray[imageNumber]= picture.getImageData(0, 0, canvas1.width, canvas1.height);
    // 遅延画像番号
    imageDisplay = imageNumber - imageDelay;
    if(imageDisplay <0 ){
      imageDisplay = imageDisplay + imageMax; // マイナスの処理
    }
    // エラー回避処理
    try {
    // canvas2 に変数の画像を貼り付ける
      document.getElementById("canvas2").getContext('2d').putImageData(imageArray[imageDisplay], 0, 0);
    }catch(e){
      // エラー時には何もしない
    };
  }, 100);
};
</script>
</body>
</html>

iPhoneエラー対応

 Windowsのchrome、Macのsafari、iPadのsafariで動きます。でも、iPhoneで作動しません。対応策として

  const video  = document.querySelector("#video");
  video.setAttribute('autoplay', '');
  video.setAttribute('muted', '');
  video.setAttribute('playsinline', '');

としてください。
参照: iPhone の場合 video が止まってしまうことへの対処
https://otiai10.hatenablog.com/entry/2019/11/11/090124

 30秒間 × 10画像 = 300画像 を配列に入れると、600~800MBのメモリーを消費します。どこまで配列を大きくできるか? 挑戦してみてください。
 ブラウザで画像処理ができること、プログラムが短いことに技術の進歩を感じます。

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

JavaScript sort()って何してるの?備忘録

JavaScriptの案件に配属された当初、比較関数を用いた配列のソートの記述がすぐ理解できなかったので、備忘録としてメモ。

sort()とは

  • 並び替えをしてくれる便利なメソッド
  • 元の配列データを変更してしまう点には注意

単純な文字列のソート

文字列が格納された配列に対してsort()を実行すると、アルファベット順にソートされる。

const strs = ['c', 'b', 'a', 'd'];
strs.sort();
console.log(strs); // 出力結果:['a', 'b', 'c', 'd']

比較関数を用いたソート

ソートしたい対象が数値やオブジェクトなどの場合は、sort()メソッドと比較関数を使用。

例: 文字数でソートしてみる

今回は['abc', '', 'aaa', 'zz']という配列を
文字数を比較する比較関数を用いて
['', 'zz', 'abc', 'aaa']の少→多の順になるようにソートしてみます。

const strs = ['abc', '', 'aaa', 'zz'];

strs.sort((a, b) => a.length - b.length);
console.log(strs); // 出力結果:['', 'zz', 'abc', 'aaa']

慣れないうちは、下記の方がわかりやすいかもです。

const strs = ['abc', '', 'aaa', 'zz'];

// 比較関数
const compare = (a, b) => {
 return a.length - b.length;
}

strs.sort(compare);
console.log(strs); // 出力結果:['', 'zz', 'abc', 'aaa']

理解に苦しんだ箇所

案件の中でstrs.sort((a, b) => a.length - b.length);が出てきた時の私の心情は
下記の通りです。

  • いきなり引数2つ出てきた...
  • a,bってなに...
  • もはやここで何が起きてるか謎...

どんな処理がされているのか

strs.sort((a, b) => a.length - b.length);
ここで何が起きているのか、私なりに理解した内容をまとめます。

上記のコードでは、配列strsの値を2ずつ取り出して文字数で比較し、
1つずつ順番を入れ替えています。具体的な処理を書くと

1. 'abc' と ''    を比較 -> 'abc'の方が文字数が多いため入れ替え ['', 'abc', 'aaa', 'zz']
2. 'abc' と 'aaa' を比較 -> 文字数が同じためそのまま           ['', 'abc', 'aaa', 'zz']
3. 'aaa' と 'zz'  を比較 -> 'aaa'の方が文字数が多いため入れ替え ['', 'abc', 'zz', 'aaa']
4. 'abc' と 'zz'  を比較 -> 'abc'の方が文字数が多いため入れ替え ['', 'zz', 'abc', 'aaa']
5. ''    と 'zz'  を比較 -> ''の方が文字数が少ないためそのまま  ['', 'zz', 'abc', 'aaa']

つまり、
引数a、bの正体は、['abc', '', 'aaa', 'zz']の中の比較する2つの値であり、
比較関数ではa.length - b.lengthでどちらの文字列が大きいかを比較し、
a.length - b.length > 0ならa bの順を入れ替える
という処理がされている。と理解。

引数の名って大事

sort()が何をしてくれるかを理解し、ありがたみを感じられるようになった時に、改めて思ったこと。
今回理解に苦しんだ最大の理由は引数a、bが何かわからなかったから。
引数でどんな値が渡されるのか、少しでもわかりやすく命名するように心がけようと思います...!

const strs = ['abc', '', 'aaa', 'zz'];

strs.sort((str1, str2) => str1.length - str2.length);
console.log(strs); // 出力結果:['', 'zz', 'abc', 'aaa']
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【jquery,js】表示する時間によって画像を変更する[switch,Date,append,html] [js09_20210227]

処理の概要

ブラウザを開いた時、時間帯によって表示する画像を変えます。
index.htmlと同じ階層にimgフォルダを用意し、任意の画像を格納して下さい。

処理のフロー:

 (1)dateオブジェクトで時間を取得
 (2)ケース分岐して表示するためのファイルを指定する
 (3)jsで要素を追加し、画像を表示する

画面イメージ

画像1


時間帯によって表示される画像が変わります。今は、7時なのでこの画像が表示されます。他の画像を貼り付けるのが面倒なので、今回はこれだけです。

ソースコード

index.html
<head>
<link rel="stylesheet" href="./css/default.css">
</head>
<body>
<div id="timeBackImage"></div>
</body>
main.js
// DOMの準備後に実行する内容
$(function() {
    var ldateObj = new Date();
    var currentTime = ldateObj.getHours();
    var lfileName = "";

    switch(true){
        case (0 <= currentTime && currentTime < 5):
            lfileName = 'night.png';
            break;
        case (5 <= currentTime && currentTime < 12):
            lfileName = 'morning.png';
            break;
        case (12 <= currentTime && currentTime < 18):
            lfileName = 'daytime.png';
            break;
        case (18 <= currentTime && currentTime < 24):
            lfileName = 'night.png';
            break;
    }

//   // 時間による分岐
//   if (0 <= h && h < 7) {
//     fileName = "night.png";   // 夜  0~ 6時 night.png
//   } else if (7 <= h && h < 12) {
//     fileName = "morning.png"; // 朝  7~11時 morning.png
//   } else if (12 <= h && h < 19) {
//     fileName = "daytime.png"; // 昼 12~18時 daytime.png
//   } else if (19 <= h && h < 24) {
//     fileName = "night.png";   // 夜 19~23時 night.png
//   }

    var addImageTag = $("<img>");
    addImageTag.attr("src","img/" + lfileName);
    $("#timeBackImage").append(addImageTag);
});
default.css
img {
    width: 300px;
    height: 200px;
}

ポイント

html:
(1)なし
js:
(1)Dateオブジェクトを作成し、現在時刻を取得する準備をする
(2)※switchメソッドはこの使い方は可読性を下げます。ifとelseifで分けた方がいいです。
(3)htmlメソッドではなく、appendで子要素として

参考資料

JavaScript(仕事の現場でサッと使える!デザイン教科書) p130

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

ナウキャストの画像取得(20210224版)

これは何ですか?

気象庁の降水レーダー画像を取得するスクリプトです。2021年02月24日の更新に伴って書き直しました。

画像取得ソースは:point_down:

コードはgistに収めています。

ナウキャストの画像取得(20210224版) by puppeteer/node.js

相変わらず習作ですが、画像取得リトライ工作をなんぼかいたしました。Slackによるエラー通知もさせてみました。ユーザ依存な部分を伏せ書きにしていますのでご注意ください。

お役に立てれば幸いです。

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

YouTube は《学びの宝庫》 HTML/CSS and JavaScript編 2021(随時更新)

1,私が思う一番のプログラミング学習法は... 

YouTubeを利用して学習を進めることだと思います!

その理由は、

まず
1,無料であること!
2,情報が最新であること!
3,好きな技術を学べること!
4,海外の技術を習得できること!
5,いつでもどこでもそして実践的に学習できる!
6,通常の2倍の学習スピードで進めることができる!

要は、低コスト・ハイパフォーマンスだからです:bangbang:

ところで、プログラミング学習には、様々な方法があると思います!

例えば、

・プログラミングスクールに通う
・技術書を買って独学
・メンターさんに教えてもらう
・UdemyやSkillShareを利用する

など、たくさんあります:books:

しかし、

YouTubeも同等の情報量、もしかしたらそれ以上の学びに出会えるチャンスがあります!

理由の1~6まで述べた通り、メリットがたくさんあります!

その一つ、6について説明すると、
ご存知の通り、YouTubeには倍速再生というものがあり、
Max2倍まで設定することができます!
なので、2倍の学習スピードで進めることが出来ます!

この記事は、私が学習をする上で特に参考になった動画をロードマップ形式で随時更新していきます!

一つの意見として、ご参考にして頂けたら幸いです:bangbang:

2,学習ロードマップ(実際に参考にした動画のみ掲載)

【ステップ1:HTML/CSSの基礎】

(随時掲載)

【ステップ2:JavaScriptの基礎】

(随時掲載)

【ステップ3:JavaScriptでToDoListを作ってみよう】

さっそく、基礎知識を使ってToDoListを作ってみましょう???

(動画のアップロード日:2020/04/11)

実際に作ってみました➡こちら

2021-02-27_04h35_48.png

【ステップ4:JavaScriptの基礎が終わったら】

JavaScriptの基礎が一通り終わって、なにか物足りないと感じなたら、これがオススメです!???

(動画のアップロード日:2021/01/28)

コメントからもわかるように、超わかりやすかったです:sparkles:

2021-02-27_04h05_50.png

コンテンツ

2021-02-27_04h10_40.png

【ステップ5:React js でプロジェクトを作ってみよう!】

(随時掲載)

3,最後に

プログラミング学習は、短期決戦だと思います!
学ばないといけないことは、膨大であり常に進化しています!
効率を考えたら、学習した直後からもう作成に取り掛かったほうが、より理解と習得に結びつくのかなと感じています!

また、意見や要望などがあればコメントでいただけたらと思います!

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

YouTube は学びの宝庫:gift:

:gift:

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

YouTube は《学びの宝庫》 HTML/CSS and JavaScript編 (随時更新)

1,私が思う一番のプログラミング学習法は... 

YouTubeを利用して学習を進めることだと思います!

その理由は、

まず
1,無料であること!
2,情報が最新であること!
3,好きな技術を学べること!
4,海外の技術を習得できること!
5,いつでもどこでもそして実践的に学習できる!
6,通常の2倍の学習スピードで進めることができる!

要は、低コスト・ハイパフォーマンスだからです:bangbang:

ところで、プログラミング学習には、様々な方法があると思います!

例えば、

・プログラミングスクールに通う
・技術書を買って独学
・メンターさんに教えてもらう
・UdemyやSkillShareを利用する

など、たくさんあります:books:

しかし、

YouTubeも同等の情報量、もしかしたらそれ以上の学びに出会えるチャンスがあります!

理由の1~6まで述べた通り、メリットがたくさんあります!

その一つ、6について説明すると、
ご存知の通り、YouTubeには倍速再生というものがあり、
Max2倍まで設定することができます!
なので、2倍の学習スピードで進めることが出来ます!

この記事は、私が学習をする上で特に参考になった動画をロードマップ形式で随時更新していきます!

一つの意見として、ご参考にして頂けたら幸いです:bangbang:

2,学習ロードマップ(実際に参考にした動画のみ掲載)

【ステップ1:HTML/CSSの基礎】

(随時掲載)

【ステップ2:JavaScriptの基礎】

(随時掲載)

【ステップ3:JavaScriptでToDoListを作ってみよう】

さっそく、基礎知識を使ってToDoListを作ってみましょう???

(動画のアップロード日:2020/04/11)

実際に作ってみました➡こちら

2021-02-27_04h35_48.png

【ステップ4:JavaScriptの基礎が終わったら】

JavaScriptの基礎が一通り終わって、なにか物足りないと感じなたら、これがオススメです!???

(動画のアップロード日:2021/01/28)

コメントからもわかるように、超わかりやすかったです:sparkles:

2021-02-27_04h05_50.png

コンテンツ

2021-02-27_04h10_40.png

【ステップ5:React js でプロジェクトを作ってみよう!】

(随時掲載)

3,最後に

プログラミング学習は、短期決戦だと思います!
学ばないといけないことは、膨大であり常に進化しています!
効率を考えたら、学習した直後からもう作成に取り掛かったほうが、より理解と習得に結びつくのかなと感じています!

また、意見や要望などがあればコメントでいただけたらと思います!

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

JavaScriptで連番:range関数コードゴルフ

はじめに

この間友人たちとPythonでコードゴルフに興じる機会があった。
それでおもしろくなったので、今回JavaScriptでPythonのrange関数の実装をコードゴルフしてみることにした。

※ひとりコードゴルフ。

2021/02/27 修正

まともな動作検証をやっていなかったため見事にバグのご指摘をいただき、急遽簡単にテストしました。
ただ手を抜いているので、まだバグはあると思います。ご了承の上、発見の際はぜひご報告ください。

修正に伴い、記事の一部を書き直しました

修正点

  • バグの発見された5つの関数(解説欄に修正と記してあります)
  • 記法のおすすめ
  • 負の値に関する暗黙のレギュレーションの明文化

以下は修正されていません

  • パフォーマンスの計測値

レギュレーション

  • 最短コードでrange(start,stop,step)を実装する。
  • 出力はリスト・イテレータを問わない
  • 負の値は考慮しない(start, stop, step, 出力する連番すべて0より大きいとする)

というわけで書いてみました。いろんなサイト様を参考にさせていただきましたが、もっといろんな方法で書けるやろ!と思ったのでやってみました。結果としては7+1通り。

コード内のa,b,cは順にstart, stop, stepです。stopは含みません。

f(a,b,c)の形で頻出します。

ex: f(1,7,3) -> start 1, stop 7, step 3, -> [1, 4]

パフォーマンス計測

jsbench.meにベンチマークとコードあります。

今回の本題ではなかったですが、実用を見据えて一応計測しておきました。

計測

  • 乱数は最初に一気に100回分生成。それぞれの関数に100回ずつ計測。この100回を1試行とする。
  • 7関数あるので7試行。試行間での乱数セットは共通。
  • あとはjsbench.meにお任せ。

乱数の値域は以下

  • start 0~49
  • stop 51~100
  • step 0~10

結論

以下作品集をつらつらしゃべる前に、簡潔にthe bestを知りたい人へ。僕から言いたいこと。

連番リスト


2021/02/27 追記

修正により評価が変わりました。連番リストは以下もおすすめしておきます。

[...Array(b-a)].flatMap((_,i)=>i%c?[]:i+a)

以下の記法よりも可読性が高く、長さも1字しか変わらないです。ただしパフォーマンスは低いので、小規模なリストのみの利用に向きます。


連番リストおすすめは

[...Array((b-a)/c+1|0)].map((_,k)=>a+k*c)

理由は、パフォーマンスがそこそこある、短くて書きやすい、アレンジがきく、ってこと。
Array(~)で個数を指定して、mapで中身をいじってる。ちょっと可読性が低いけど、まぁこれが無難な選択。

range関数

range関数でいうと、

function*f(a,b,c){do{yield a}while((a+=c)<b)}

もうまちがいなくこれ。なんならこの記事の中で一番自慢したいとこ。パフォーマンスも可読性も最強だからほんとにこれは言うことがない。強いて言えば取り回しが上の連番リストよりは多少劣ることぐらい。判定をちょっと変更すれば負のstepにも対応できる。

結構いろいろ見たけど、この簡潔な関数をなぜか誰も書いてない。みんな似たり寄ったりの連番リストばっかり。ぜひ使ってほしい。もちろん俺も使う。

やってることは、ほんとに単純なジェネレータ。それだけ。

優秀作品集

var f=(a,b,c)=>[...Array((b-a)/c+1|0)].map((_,k)=>a+k*c)

var f = (a, b, c) => [...Array(((b - a + c) / c) | 0)].map((_, k) => a + k * c);

2021/02/27修正
// 56字(出力部分だけなら41字)
// 安直な作り。出力部のみの利用が良さそう。
// ビット演算は少数部分のカットをしている。可読性がやや低いのが難点。
// この呼び方だとArrayの初期化に展開子...が必要
// 必要最小限だけのリストを用意し、中身を調整する仕組み。
// パフォーマンスもかなり高い。しかし修正により価値を落とした。

// 31224.07 ops/s ± 3.34%
// 65.69 % slower

var f=(a,b,c)=>[...Array(b).keys()].filter(x=>!(x<a|(x-a)%c))

var f = (a, b, c) =>
  [...Array(b).keys()].filter((x) => !((x < a) | (x - a) % c));

// 61字(出力部分46字)
// 大量に確保して一気に間引く方式。filter関数のビット演算は論理ORの代わり。

// 1813.2 ops/s ± 4.02%
// 98.01 % slower

var f=(a,b,c)=>[...Array(b-a)].flatMap((_,i)=>i%c?[]:i+a)

var f = (a, b, c) => [...Array(b - a)].flatMap((_, i) => (i % c ? [] : i + a));

2021/02/27 修正
// 57字(出力部分41字)
// 上2つの中間。ある程度搾っておいて、flatmapで間引きと調整を同時に行う。
// flatmapで空リストを返すと、その要素の消去と同じ挙動になる。

ロジックの見直しにより、可読性と短さを両立した便利な記法であることが判明。パフォーマンスは低い。

// 924.95 ops/s ± 3.88%
// 98.98 % slower

var f=(a,b,c)=>({[Symbol.iterator]:_=>({next:_=>({value:a,done:(a+=c)-c>b})})})

var f = (a, b, c) => ({
  [Symbol.iterator]: (_) => ({
    next: (_) => ({ value: a, done: (a += c) - c > b }),
  }),
});

2021/02/27 修正
// 79字(出力部分のみでの利用不可)
// イテレータでも作ってみたかった。結果としては、イテレータ仕様に制約が多く、長くなった。

// 7922.87 ops/s ± 7.94%
// 91.29 % slower

function*f(a,b,c){do{yield a}while((a+=c)<b)}

function* f(a, b, c) {
  do {
    yield a;
  } while ((a += c) < b);
}

// 45字(出力部なし)
// まさかの最小コード部門優勝はジェネレータ。可読性もめちゃくちゃ高く、芸術賞も同時受賞。
// さらにはパフォーマンス最速も叩き出し、最速部門賞まで受賞。まさかまさかの3冠達成。
// ただし実用面では、リスト方式の出力部のみの利用に取り回しの面で劣る。

ちなみにwhile判定を<bから!==bに変更すれば、「b-aがcで割り切れないと無限ループする」という制約のもと負のstepをとれるようになります。

// 90999.3 ops/s ± 5.87%
// Fastest

var f=(a,b,c)=>[..."".padEnd(b-a,10**c/10)].flatMap((v,i)=>-v?i+a:[])

var f = (a, b, c) =>
  [..."".padEnd(b - a, 10 ** c / 10)].flatMap((v, i) => (-v ? i + a : []));

// 69字(54字)
// テキストメソッドをコンセプトに作ってみたもの。padEndの機能がおあつらえ向き。
// テキストの0,1を並べてstepを表現するアイデアはお気に入り。
// ただしパフォーマンスは最悪。

// 780.48 ops/s ± 9.71%
// 99.14 % slower

var f=(a,b,c)=>eval(`[${"".padEnd(b-a+c,0+",".repeat(c))}]`).flatMap((_,i)=>i+a)

var f = (a, b, c) =>
  eval(`[${"".padEnd(b - a, 0 + ",".repeat(c))}]`).flatMap((_, i) => i + a);

2021/02/27 修正
// 80字(65字)
// テキストでarrayを構成してevalに突っ込む。リストのempty(!=undefined,!=null)のmapで参照されない特性を
// 生かしてstepを表現するという問題作。セキュリティ的にも脆弱?パフォーマンスは意外に悪くない

// 2160.94 ops/s ± 4.69%
// 97.63 % slower

番外

var f={a:2,b:10,c:3,next:_=>({value:f.a,done:(f.a+=f.c)-f.c>f.b}),[Symbol.iterator]:_=>f}

var f = {
  a: 2,
  b: 10,
  c: 3,
  next: (_) => ({ value: f.a, done: (f.a += f.c) - f.c > f.b }),
  [Symbol.iterator]: (_) => f,
};

2021/02/27修正
// 89字(-)
// 自己参照イテレータによる実装。データ内蔵でイテレート機構まで完結する。
// 構造としては面白いが、名前と密結合しており、扱いづらさが目立つ。

// Out of memoryにより、ベンチマークができなかった。ランタイムを破壊するな。。。

参考リンク集

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

あなたのWebページを測定するツール!!『 Chrome Lighthouse 』測定基準をメモしておく

◇「 Webサイト点数 」の仕組みをメモ

今回は「LighthouseのPerformance 」は「 どの点を測定して、私たちのサイトを評価しているのか? 」調べてみました。
※分かりにくいので動画も最後に用意しています

◇Chromeブラウザ搭載の「 Lighthouse 」とは?

近年、「 Google ウエブマスター向け公式ブログ 」でも紹介されているとおり、
Webのページパフォーマンス・UXもSEOに重要な部分になります。
その重要になってきている「 Webページの読み込みパフォーマンスを測定」するツールがLighthouse / PageSpeed Insightsです。

  • Chromeに実装されている機能で確認できるのが「Lighthouse」
  • Googleのサイトで確認するのが「PageSpeed Insights」

Webページパフォーマンスだけでなく「SEO」「Accessibility」「Best Practices」も
測定(チェック)できるのがChromeブラウザ搭載の「 Lighthouse 」です!!

なぜ?あなたが?

個人的にWebサービスを作っていて、SEO等に興味をもったのがきっかけでした。

◇Lighthouseの使い方

1. [デベロッパーツール] → [Lighthouse] → [Generate report]

2.測定結果:かなり良い方でしょう。

この点数はどういう基準で測定されてるのでしょうか?
と疑問に思ったので調べてみました。

◇「6つのメトリクス(測定基準)」今回はPerformanceのみ

以下「6つのメトリクスを解説」
「Lighthouse:Performance == PageSpeed Insights」として解説を進めていきます。
image.png

First Contentful Paint(FCP)メトリック

ページの読み込みが開始されてから、ページのコンテンツのいずれかの部分が画面にレンダリングされるまでの時間を測定します。
https://web.dev/lcp/

Speed Index

スピードインデックスは、ページ読み込み中にコンテンツがどれだけ早く視覚的に表示されるかを測定します。
https://web.dev/speed-index/

Largest Contentful Paint(LCP)メトリック

ユーザーがページで最も有意義なコンテンツをどのくらい早く見ることができるかを表します。感覚的な読み込みスピードを測定し、ページ読み込みタイムラインにおいてページの主要コンテンツが読み込まれたと思われるタイミングを指します。
https://web.dev/lcp

Time to Interactive(TTI) メトリック

Webサイトによっては、インタラクティブ性を犠牲にしてまで、コンテンツの可視性を最適化している場合があるので、TTIの測定が重要になってきます。サイトは準備ができているように見えますが、ユーザーが操作可能になるタイミングを測定しています。
https://web.dev/tti/

Total Blocking Time(TBT) メトリック

Total Blocking Timeは「First Contentful Paint からTime to Interactive」までの間で、
メインスレッドが入力の応答性を妨げた長くブロックされていた時間の合計を測定します。
https://web.dev/tbt/

Cumulative Layout Shift (CLS)メトリック

Cumulative Layout Shift(キュームレイティブ・レイアウト・シフト)は、ページの存続期間全体で発生するすべての予期しないレイアウトシフトについて、すべての個々のレイアウトシフトスコアの合計を測定します。
https://web.dev/cls/

【参考サイト】
Web.dev( https://web.dev

6つのメトリクス測定基準の割合

image.png
※こちらもご参考まで。

「6つのメトリクス」全てグリーンを目指す!!

6つのメトリクス全てグリーンになればGoogleが定義する良いサイトと判断されると思いますので、
上記測定基準が見えてきたと思いますので、AllGreenを目指しましょう!

以下のように黄色とか赤色のヒントが出てくるので、ヒントをクリックして内容を確認して解消していくと
必然とgreenになっていきます!!
※「解消しやすそうなものから」やるのがコツです!!
image.png

◇Lighthouse 関連の重要な記事

▼Google ウエブマスター向け 公式ブログ(ページエクスペリエンスについて)
https://webmaster-ja.googleblog.com/2020/06/evaluating-page-experience.html

▼ PageSpeed Insights(Lighthouse:Performance測定と同様)
https://developers.google.com/speed/pagespeed/insights/?hl=ja-JP

◇補足動画

記事では分からんって人はこちら
https://youtu.be/srayKfhg5Ho
IMAGE ALT TEXT HERE

以上

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

あなたの「Webページを測定」!!『 Chrome Lighthouse 』測定基準をメモしておく

◇「 Webサイト点数 」の仕組みをメモ

今回は「LighthouseのPerformance 」は「 どの点を測定して、私たちのサイトを評価しているのか? 」調べてみました。
※分かりにくいので動画も最後に用意しています

◇Chromeブラウザ搭載の「 Lighthouse 」とは?

近年、「 Google ウエブマスター向け公式ブログ 」でも紹介されているとおり、
Webのページパフォーマンス・UXもSEOに重要な部分になります。
その重要になってきている「 Webページの読み込みパフォーマンスを測定」するツールがLighthouse / PageSpeed Insightsです。

  • Chromeに実装されている機能で確認できるのが「Lighthouse」
  • Googleのサイトで確認するのが「PageSpeed Insights」

Webページパフォーマンスだけでなく「SEO」「Accessibility」「Best Practices」も
測定(チェック)できるのがChromeブラウザ搭載の「 Lighthouse 」です!!

なぜ?あなたが?

個人的にWebサービスを作っていて、SEO等に興味をもったのがきっかけでした。

◇Lighthouseの使い方

1. [デベロッパーツール] → [Lighthouse] → [Generate report]

2.測定結果:かなり良い方でしょう。

この点数はどういう基準で測定されてるのでしょうか?
と疑問に思ったので調べてみました。

◇「6つのメトリクス(測定基準)」今回はPerformanceのみ

以下「6つのメトリクスを解説」
「Lighthouse:Performance == PageSpeed Insights」として解説を進めていきます。
image.png

First Contentful Paint(FCP)メトリック

ページの読み込みが開始されてから、ページのコンテンツのいずれかの部分が画面にレンダリングされるまでの時間を測定します。
https://web.dev/lcp/

Speed Index

スピードインデックスは、ページ読み込み中にコンテンツがどれだけ早く視覚的に表示されるかを測定します。
https://web.dev/speed-index/

Largest Contentful Paint(LCP)メトリック

ユーザーがページで最も有意義なコンテンツをどのくらい早く見ることができるかを表します。感覚的な読み込みスピードを測定し、ページ読み込みタイムラインにおいてページの主要コンテンツが読み込まれたと思われるタイミングを指します。
https://web.dev/lcp

Time to Interactive(TTI) メトリック

Webサイトによっては、インタラクティブ性を犠牲にしてまで、コンテンツの可視性を最適化している場合があるので、TTIの測定が重要になってきます。サイトは準備ができているように見えますが、ユーザーが操作可能になるタイミングを測定しています。
https://web.dev/tti/

Total Blocking Time(TBT) メトリック

Total Blocking Timeは「First Contentful Paint からTime to Interactive」までの間で、
メインスレッドが入力の応答性を妨げた長くブロックされていた時間の合計を測定します。
https://web.dev/tbt/

Cumulative Layout Shift (CLS)メトリック

Cumulative Layout Shift(キュームレイティブ・レイアウト・シフト)は、ページの存続期間全体で発生するすべての予期しないレイアウトシフトについて、すべての個々のレイアウトシフトスコアの合計を測定します。
https://web.dev/cls/

【参考サイト】
Web.dev( https://web.dev

6つのメトリクス測定基準の割合

image.png
※こちらもご参考まで。

「6つのメトリクス」全てグリーンを目指す!!

6つのメトリクス全てグリーンになればGoogleが定義する良いサイトと判断されると思いますので、
上記測定基準が見えてきたと思いますので、AllGreenを目指しましょう!

以下のように黄色とか赤色のヒントが出てくるので、ヒントをクリックして内容を確認して解消していくと
必然とgreenになっていきます!!
※「解消しやすそうなものから」やるのがコツです!!
image.png

◇Lighthouse 関連の重要な記事

▼Google ウエブマスター向け 公式ブログ(ページエクスペリエンスについて)
https://webmaster-ja.googleblog.com/2020/06/evaluating-page-experience.html

▼ PageSpeed Insights(Lighthouse:Performance測定と同様)
https://developers.google.com/speed/pagespeed/insights/?hl=ja-JP

◇補足動画

記事では分からんって人はこちら
https://youtu.be/srayKfhg5Ho
IMAGE ALT TEXT HERE

以上

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

Chrome デベロッパーツール「 Webサイト点数 」の仕組みをメモ「LighthouseのPerformance」

◇「 Webサイト点数 」の仕組みをメモ

今回は「LighthouseのPerformance 」をどうやって測定してるのか?調べてみました。

◇補足の動画も用意しました

記事では難しい箇所もあったので、30分ほどの動画に収録しましたので、
もう少し詳しく知りたい人は見てくださいね。
https://youtu.be/srayKfhg5Ho
IMAGE ALT TEXT HERE

◇Chromeブラウザ搭載の「 Lighthouse 」とは?

近年、「 Google ウエブマスター向け公式ブログ 」でも紹介されているとおり、
Webのページパフォーマンス・UXもSEOに重要な部分になります。
その重要になってきている「 Webページの読み込みパフォーマンスを測定」するツールがLighthouse / PageSpeed Insightsです。

  • Chromeに実装されている機能で確認できるのが「Lighthouse」
  • Googleのサイトで確認するのが「PageSpeed Insights」

Webページパフォーマンスだけでなく「SEO」「Accessibility」「Best Practices」も
測定(チェック)できるのがChromeブラウザ搭載の「 Lighthouse 」です!!

◇Lighthouseの使い方

1. [デベロッパーツール] → [Lighthouse] → [Generate report]

2.測定結果:かなり良い方でしょう。

この点数はどういう基準で測定されてるのでしょうか?
と疑問に思ったので調べてみました。

◇「6つのメトリクス(測定基準)」今回はPerformanceのみ

以下「6つのメトリクスを解説」
「Lighthouse:Performance == PageSpeed Insights」として解説を進めていきます。
image.png

First Contentful Paint(FCP)メトリック

ページの読み込みが開始されてから、ページのコンテンツのいずれかの部分が画面にレンダリングされるまでの時間を測定します。
https://web.dev/lcp/

Speed Index

スピードインデックスは、ページ読み込み中にコンテンツがどれだけ早く視覚的に表示されるかを測定します。
https://web.dev/speed-index/

Largest Contentful Paint(LCP)メトリック

ユーザーがページで最も有意義なコンテンツをどのくらい早く見ることができるかを表します。感覚的な読み込みスピードを測定し、ページ読み込みタイムラインにおいてページの主要コンテンツが読み込まれたと思われるタイミングを指します。
https://web.dev/lcp

Time to Interactive(TTI) メトリック

Webサイトによっては、インタラクティブ性を犠牲にしてまで、コンテンツの可視性を最適化している場合があるので、TTIの測定が重要になってきます。サイトは準備ができているように見えますが、ユーザーが操作可能になるタイミングを測定しています。
https://web.dev/tti/

Total Blocking Time(TBT) メトリック

Total Blocking Timeは「First Contentful Paint からTime to Interactive」までの間で、
メインスレッドが入力の応答性を妨げた長くブロックされていた時間の合計を測定します。
https://web.dev/tbt/

Cumulative Layout Shift (CLS)メトリック

Cumulative Layout Shift(キュームレイティブ・レイアウト・シフト)は、ページの存続期間全体で発生するすべての予期しないレイアウトシフトについて、すべての個々のレイアウトシフトスコアの合計を測定します。
https://web.dev/cls/

【参考サイト】
Web.dev( https://web.dev

6つのメトリクス測定基準の割合

image.png
※こちらもご参考まで。

「6つのメトリクス」全てグリーンを目指す!!

6つのメトリクス全てグリーンになればGoogleが定義する良いサイトと判断されると思いますので、
上記測定基準が見えてきたと思いますので、AllGreenを目指しましょう!

以下のように黄色とか赤色のヒントが出てくるので、ヒントをクリックして内容を確認して解消していくと
必然とgreenになっていきます!!
※「解消しやすそうなものから」やるのがコツです!!
image.png

◇Lighthouse 関連の重要な記事

▼Google ウエブマスター向け 公式ブログ(ページエクスペリエンスについて)
https://webmaster-ja.googleblog.com/2020/06/evaluating-page-experience.html

▼ PageSpeed Insights(Lighthouse:Performance測定と同様)
https://developers.google.com/speed/pagespeed/insights/?hl=ja-JP

以上

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

Chromeデベロッパーツール「 Webサイト測定値(点数 )」の仕組みをメモ ”Lighthouse:Performance”

◇「 Webサイト点数 」の仕組みをメモ

今回は「LighthouseのPerformance 」は「 どの点を測定して、私たちのサイトを評価しているのか? 」調べてみました。
※分かりにくいので動画も最後に用意しています

◇Chromeブラウザ搭載の「 Lighthouse 」とは?

近年、「 Google ウエブマスター向け公式ブログ 」でも紹介されているとおり、
Webのページパフォーマンス・UXもSEOに重要な部分になります。
その重要になってきている「 Webページの読み込みパフォーマンスを測定」するツールがLighthouse / PageSpeed Insightsです。

  • Chromeに実装されている機能で確認できるのが「Lighthouse」
  • Googleのサイトで確認するのが「PageSpeed Insights」

Webページパフォーマンスだけでなく「SEO」「Accessibility」「Best Practices」も
測定(チェック)できるのがChromeブラウザ搭載の「 Lighthouse 」です!!

なぜ?あなたが?

個人的にWebサービスを作っていて、SEO等に興味をもったのがきっかけでした。

◇Lighthouseの使い方

1. [デベロッパーツール] → [Lighthouse] → [Generate report]

2.測定結果:かなり良い方でしょう。

この点数はどういう基準で測定されてるのでしょうか?
と疑問に思ったので調べてみました。

◇「6つのメトリクス(測定基準)」今回はPerformanceのみ

以下「6つのメトリクスを解説」
「Lighthouse:Performance == PageSpeed Insights」として解説を進めていきます。
image.png

First Contentful Paint(FCP)メトリック

ページの読み込みが開始されてから、ページのコンテンツのいずれかの部分が画面にレンダリングされるまでの時間を測定します。
https://web.dev/lcp/

Speed Index

スピードインデックスは、ページ読み込み中にコンテンツがどれだけ早く視覚的に表示されるかを測定します。
https://web.dev/speed-index/

Largest Contentful Paint(LCP)メトリック

ユーザーがページで最も有意義なコンテンツをどのくらい早く見ることができるかを表します。感覚的な読み込みスピードを測定し、ページ読み込みタイムラインにおいてページの主要コンテンツが読み込まれたと思われるタイミングを指します。
https://web.dev/lcp

Time to Interactive(TTI) メトリック

Webサイトによっては、インタラクティブ性を犠牲にしてまで、コンテンツの可視性を最適化している場合があるので、TTIの測定が重要になってきます。サイトは準備ができているように見えますが、ユーザーが操作可能になるタイミングを測定しています。
https://web.dev/tti/

Total Blocking Time(TBT) メトリック

Total Blocking Timeは「First Contentful Paint からTime to Interactive」までの間で、
メインスレッドが入力の応答性を妨げた長くブロックされていた時間の合計を測定します。
https://web.dev/tbt/

Cumulative Layout Shift (CLS)メトリック

Cumulative Layout Shift(キュームレイティブ・レイアウト・シフト)は、ページの存続期間全体で発生するすべての予期しないレイアウトシフトについて、すべての個々のレイアウトシフトスコアの合計を測定します。
https://web.dev/cls/

【参考サイト】
Web.dev( https://web.dev

6つのメトリクス測定基準の割合

image.png
※こちらもご参考まで。

「6つのメトリクス」全てグリーンを目指す!!

6つのメトリクス全てグリーンになればGoogleが定義する良いサイトと判断されると思いますので、
上記測定基準が見えてきたと思いますので、AllGreenを目指しましょう!

以下のように黄色とか赤色のヒントが出てくるので、ヒントをクリックして内容を確認して解消していくと
必然とgreenになっていきます!!
※「解消しやすそうなものから」やるのがコツです!!
image.png

◇Lighthouse 関連の重要な記事

▼Google ウエブマスター向け 公式ブログ(ページエクスペリエンスについて)
https://webmaster-ja.googleblog.com/2020/06/evaluating-page-experience.html

▼ PageSpeed Insights(Lighthouse:Performance測定と同様)
https://developers.google.com/speed/pagespeed/insights/?hl=ja-JP

◇補足動画

記事では分からんって人はこちら
https://youtu.be/srayKfhg5Ho
IMAGE ALT TEXT HERE

以上

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

もちろんバックエンドとのやり取りはCORS対策を行っていますよね???

皆さんバックエンドとのやり取りでCORS対策は行っていますか?

今回はLaravelでCORS対策を行うやり方を書いていこうかなと思います。

既にLaravelに触れたことのある方はconfig\cors.phpを見たことがあるかと思います。

config/cors.php
<?php
return [
    'paths' => ['*'],

    'allowed_methods' => ['*'],

    'allowed_origins' => ['*'],

    'allowed_origins_patterns' => [],

    'allowed_headers' => ['*'],

    'exposed_headers' => [],

    'max_age' => 0,

    'supports_credentials' => true,
];

実際はこんな感じに書いてあります。

ただ、これ注目し欲しいのがallowed_originsです。

この中身を*(アスタリスク)にしてしまうと、全てのドメインから通信を行うことができてしまいます。

便利かもしれませんが、本番環境でどのドメインからも通信を行うことができたら個人情報だだもれですね。

じゃあ対策をしてあげましょう!

ミドルウェアの作成

以下のコマンドを入力してミドルウェアを作成します。名前は適当に変えて下さい。今回はAPI通信用のCORS対策を行うのでApiCorsとしています。

php artisan make:middleware ApiCors

そしたらapp\Http\Middleware\ApiCors(自分で決めた名前)を開いてください。

Middleware\ApiCors.php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class ApiCors
{
    public function handle(Request $request, Closure $next)
    {
        if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
            return $next($request)
                ->header('Access-Control-Allow-Origin', config('cors.allowed_origins'))
                ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
                ->header('Access-Control-Allow-Headers', ['X-Requested-With', 'Content-Type', 'Origin', 'Cache-Control', 'Authorization', 'Accept', 'Accept-Encoding'])
                ->header('Access-Control-Allow-Credentials', true);
        } else {
            return $next($request)
                ->header('Access-Control-Allow-Origin', config('cors.allowed_origins'))
                ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
                ->header('Access-Control-Allow-Headers', ['X-Requested-With', 'Content-Type', 'Origin', 'Cache-Control', 'Authorization', 'Accept', 'Accept-Encoding']);
        }
    }
}

Access-Control-Allow-Originで通信を行うドメインを入力します。

config('cors.allowed_origins')としているのは、環境変数としてローカルで開発をしている時と本番環境用に分けるためです。

なんたって本番環境用にローカルホストのドメイン入力したら一発アウト。

Karnel.php

次にMiddleware\Kernel.phpに今作成したミドルウェアを登録します。

Middleware\Karnel.php
    protected $routeMiddleware = [
        'apicors' => \App\Http\Middleware\ApiCors::class,
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
        'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
    ];

'apicors' => \App\Http\Middleware\ApiCors::classのようにします。

apicorsの部分はお好きな名前で。

CORS対策の適用

routes\api.phpにCORS対策のミドルウェアを適用させます。

routes\api.php
<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ApisController;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::middleware('apicors')->group(function() {
  Route::apiResource('/apis', ApisController::class);
});

こんな感じでCORS対策を行うことができます!

これでもまだセキュリティ対策は甘い方だと思います。

まぁでも一歩前進ということで。

以上、「もちろんバックエンドとのやり取りはCORS対策を行っていますよね???」でした!

良ければ、LGTM、コメントお願いします。

また、何か間違っていることがあればご指摘頂けると幸いです。

他にも初心者さん向けに記事を投稿しているので、時間があれば他の記事も見て下さい!!

あと、最近「ココナラ」で環境構築のお手伝いをするサービスを始めました。

気になる方はぜひ一度ご相談ください!

Thank you for reading

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

JavaScriptのオブジェクトについてまとめてみた

オブジェクトとは

オブジェクトとは「関連のあるデータと機能の集合」と定義されます。

簡単に言うならば、
オブジェクトを使うと「データをまとめて扱える」というだけの話です。
オブジェクトの宣言方法は下記です。

{}

オブジェクトは変数に格納できます

// 例1
var obj = {}
// 例2
var person = {}

中身が同じオブジェクトでも、比較すると false になリます。

var obj1 = {}
var obj2 = {}

if(obj1 === obj2){
  console.log("同じ?")
}else{
  console.log("同じではない")
}

このようにコンソールで記載すると、同じではないと出力されます。

プロパティ

「プロパティ」とはオブジェクトが持つデータのことです。
オブジェクトには「プロパティ」をセットできます。

プロパティのセット方法 1

宣言時に指定する方法

var obj = { name: "yamada taro", age: 33 }

obj // {name: "yamada taro", age: 33}

プロパティのセット方法 2

. (ドット) を使用してプロパティに値をセットする

var obj = {}
obj.name = "yamada taro"
obj.age = 33

obj // {name: "yamada taro", age: 33}

プロパティのセット方法 3

ハッシュ(連想配列)を使用してプロパティに値をセットする

var obj = {}
obj['name'] = "佐藤健"
obj['age'] = 31
obj['profile'] = 'He is an actor.'

obj // { name: "佐藤健", age: 31, profile: 'He is an actor.' }

プロパティのセット方法 4

ES2015からの機能。プロパティ名と値に指定する変数名が同じ場合、省略して書ける。

var name = "yamada taro"
var age = 33
// var obj = { name: name, age: age } 
var obj = { name, age }

obj // {name: "yamada taro", age: 33}

プロパティとは、オブジェクトが持つ「名前付きのデータ」のことです。要するに、オブジェクトに含まれる「変数」のことを「プロパティ」と名前を付けていると考えます。
変数とは異なる概念です。

JavaScript のオブジェクトは、自身に関連付けられたプロパティを持ちます。オブジェクトのプロパティは、オブジェクトに関連付けられている変数と捉えることができます。オブジェクトのプロパティは、オブジェクトに属するものという点を除けば、基本的に通常の JavaScript 変数と同じようなものです。

オブジェクトのプロパティを取り出す

オブジェクトのプロパティを取り出す時は、. (ドット) を使います。

プロパティの中身をプログラム内で使用することを「取り出す」「アクセスする」「参照する」などと表現しますが意味はだいたい同じです。

// obj が持つ name という プロパティ を取り出す(アクセスする、参照する)
obj.name

var name = obj.name // 変数に格納
obj.name = "アイウエオ" // 書き換える


var obj = { 
  name: "山田太郎", 
  age: 33, 
}

console.log(obj.name) // 山田太郎
console.log(obj.age) // 33

連想配列のkeyを指定して取り出すこともできます

var obj = { 
  name: "佐藤健", 
  age: 31
}

console.log(obj['name']) // 佐藤健
console.log(obj['age']) // 31

プロパティの中身にアクセスするには、どのオブジェクトが持つプロパティかを指定する必要があります。

var obj = { name: "山田太郎" }
console.log(name) // undefined
console.log(obj.name) // 山田太郎


var obj1 = { name: "山田太郎" }
var obj2 = { name: "織田信長" }
console.log(obj1.name) // 山田太郎
console.log(obj2.name) // 織田信長

オブジェクトを宣言する際のルール

1. 宣言

中括弧 (or 波括弧、or カーリーブラケット)

{} // 中括弧を使う

2. プロパティが一つの場合の書き方

key と value は : (コロン) で繋ぎます.

// データの名前: 実際のデータ 
// key: value 形式と表現することもあります
{ name: "山田太郎" }

3. プロパティが複数ある場合

カンマで区切ります.

// 複数ある場合はカンマで区切ります
// key: value, key: value, ...
{ name: "山田太郎", age: 33 }

// 改行してもOK その場合もカンマで区切る
{
  name: "山田太郎",
  age: 33
}

オブジェクトのプロパティには関数もセットできる

オブジェクトには関数もセットできます。そして関数もオブジェクトです。
オブジェクトのプロパティに関数(正確には関数オブジェクト)をセットできると考える事ができます。

// obj が sayHello という プロパティ を持つ
var obj = { 
  sayHello: ...
}

// sayHello という key に対応する value が functionオブジェクト
var obj = { 
  sayHello: function() {
    console.log("こんにちは")
  }
}

// 関数を「参照」する
obj.sayHello
// 関数を実行する
obj.sayHello()

プロパティ内の関数から同じオブジェクトのプロパティにアクセスするにはthisを使う

// name と sayHello プロパティ を持つオブジェクト
var obj = { 
  name: "山田太郎",
  sayHello: function() {
    console.log("こんにちは、" + this.name + "と申します")
  }
}

obj.sayHello() // こんにちは、山田太郎と申します

consoleオブジェクトについて

console.log("HELLO")

console は オブジェクト そして log はconsoleオブジェクトが持つプロパティについてです。

グローバルオブジェクト

thisはオブジェクト。そして、グローバルオブジェクトです。

変数をvarで宣言した時、グローバルオブジェクトに登録される(グローバフオブジェクトのプロパティになる)
consoleもグローバルオブジェクトのプロパティ

なのでthisを使って参照できます。

これでも可能。

これも可能。

全て同じ動きをします。

// 全部同じ意味

console.log("hello")
this.console.log("hello")
window.console.log("hello")
this.window.console.log("hello")

しかし下記のように書くと、

var obj = {
  test_a: function() {
    // thisなし
    console.log("hello")
  },
  test_b: function() {
    // thisあり
    this.console.log("hello")
  }
}

test_a() は問題なし、test_b() はエラーになります。thisが何を指すか変わるからです。
エラーメッセージに Cannot read property と出力されています。

これならOK

// Chrome: Consoleタブで実行してみよう

var obj = {
  test_a: function() {
    // tihsなし
    console.log("hello")
  },
  test_b: function() {
    // this ではなく window を使う
    window.console.log("hello")
  }
}

thisは、どこで呼び出されるかによってどのオブジェクトを指すかが変わる

まとめ
- いつも使っている console は オブジェクト だった
- console.log は console オブジェクトが持つ log という名前のプロパティ(メソッド)
- console.log("hello") 以外にも console.clear() などがある
- console 自体も window というグローバルオブジェクトのプロパティなので window.console.log("hello") と呼び出せる
- グローバルオブジェクトのプロパティにthisを使ってアクセスする際は、スコープ を意識する必要がある

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