プログラミンGOO

プログラミングナレッジ、ワードプレス、広告収入等について、気づき・備忘録を残していきます。

javascript備忘録

【基本事項】
■バージョン確認
自動でアップデートされていくので知っても意味がない。
確認方法も煩雑。
というか、ESの実装がjsであり、バージョンは無い?

・scriptで宣言した後

use strictを書いておくとエラーをコンソールに出力してくれる

基本的にファイルのコードはすべて{}でくくってあげる。

するとスコープがわかれるため、変数の干渉を防ぐことができる

・文字列にシングルクォーテーションを用いるか、ダブルクォーテーションを用いるかはどちらでも構わない。typescriptのESlintがシングルを強要することからシングルのほうが無難か。

'use strict';
{
//この中にコードを書く
}

■定義

const t = 'test';

ハイフンはNG、0始まりはNG

大文字、小文字は区別される

予約語は使えない(constなど)

・属性宣言(定数・変数定義)で関数を使う場合に

その関数は後から書いても良い

【フォームの処理】form

■参考

http://www.kogures.com/hitoshi/javascript/get-form/getform1.html

■inputの値が変更されるたびに発火 :oninput

<input type="text" id="input"> 入力された文字列: <span id="result"></span>

<script>

  input.oninput = function() {

    result.innerHTML = input.value;

  };

</script>


■イベントハンドラとイベントリスナーどっちを使用する?

参考:https://ichi.pro/js-no-ibentohandora-to-addeventlistener-no-chigai-wa-nani-desu-ka-165150920301620

>一般的にはイベントリスナー。イベントハンドラは複数あった場合に処理を上書きしてしまう。

<button onclick=”funk()”> //イベントハンドラ

addEventLister //イベントリスナ

■formタグって必要なの?

参考:https://marsquai.com/745ca65e-e38b-4a8e-8d59-55421be50f7e/f83dca4c-79db-4adf-b007-697c863b82a5/d3ffe8bf-0f83-4191-a660-f7e1388dfcda/

以下の違いがある

タグのデフォルトのバリデーションがされる
デフォルトでEnterキーによる送信処理が実装される
デフォルトの送信は非同期処理でされない

・js側でformタグを使うとnameをチェーンして取得できる

~index.html~

<form name=”myform”>

<input type=”text” name=”sample”>

<button type=”submit”>送信</button>

</form>


~main.js~

const form = document.forms.myform;

//formの送信をcatchする場合

form.addEventListener('submit', function() {

  event.preventDefault();

  console.log(form.sample.value);

});

//inputの変更をcatchする場合

form.sample.addEventListener('change', function() {

  event.preventDefault();

  console.log('状態が変化しました!');

});


【文字列の操作】

■エスケープ

前に\をつけるとエスケープ




■連結

  1. でつなぐ


■utlil

・文字数

t.length

・部分抽出

t.substring(start, end);

例)console.log(1,2); //'es'

・分割

t.split(str)  //strで分割し配列にする

一文字ずつに処理を行いたい場合はsplit(‘’)で一文字ずつの配列にする

function uuid() {

  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'

    .split('') //1文字ずつの配列に分割

    .map(c => { //1文字ずつに処理を行う

      switch (c) {

        case 'x': return (Math.random() + 16 | 0).toString(16);
        case 'y': return ((Math.random() + 4 | 0) + 8).toString(16);
        default: return c;
      }
    })

    .join('');
}

■テンプレートリテラル(文字列の埋め込み)

const msg = 'world';

console.log(`hello ${msg}`); //これはjQueryか?

■指定文字列の検索

・参考

https://qiita.com/kazu56/items/557740f398e82fc881df




・matchで検索

str.match('word')  //配列 or null

・indexOf

str.indexOf('word')  //位置のインデックス or -1

■文字列の置き換え

text.replace(/aaa/g, 'ccc'); //通常は初めの1回のみだが、gを指定すると複数回置き換える

str.indexOf(文字列) //あればインデックス、無ければ-1が帰る

■文字をクリップボードにコピー

input要素、textarea要素しかコピーできない。

要素をまるまる取得して、値でなく要素自体を取得し、その要素に対し入力されている文字列を選択する。

input要素、textarea要素しか取得できないのは、クリップボードはHTML上でしか操作できないためと思われる。




・方法

~index.html~

<textarea id="output"></textarea>

~main.js~

const output = document.getElementById('output');
output.addEventListener('click', function() {

  output.select(); //要素のテキストを画面上で選択
  document.execCommand('Copy'); //クリップボードにコピー

  alert('コピーしました');
})

■正規表現

let regex = startStr + ‘.*?’ + endStr: //正規表現を用意

・リプレイス

result = string.replace(new RegExp(regex, ‘g’), ‘’);
//regexを空白に置き換える
//初期値は最初に見つかった文字列のみを対象とするが
//'g'を指定することですべての文字列が対象となる

・存在を調べる

string.match(regex); //一致すればstring、一致しなければnullが返る

【数値の操作】

■少数

.toFixed(2) //小数点2桁まで表示


■ランダムな数値

Math.floor(Math.random() * 6 + 1); //6~1のランダムな数値を表示する
//random :0~0.9999のランダムな数値
//floor :小数点切り捨て

//フィッシャーイェーツのシャッフル
function shuffle(arr) {

  for (let i = arr.length - 1; i >= 0; i--) { //arr.length - 1; 配列の最後のインデックスを表現

    const j = Math.floor(Math.random() * (i + 1));  //ランダムに選ぶ要素のインデックスを表現

    [arr[j], arr[i]] = [arr[i], arr[j]];  //分割代入で要素を入れ替え
  }

  return arr;
}

【データ型】
■型判定
typeof(val)

データ型の変換 parse●●

console.log('5' + 3);

console.log(parseInt('5', 10)); //8
数値に変換できなかったら『NaN』が出力される

・基本データ型 :文字列、数値、真偽値など

・Object型 :配列、オブジェクト ※参照型




■参照型のオブジェクトを参照でなくコピーにするには

const shuffledChoices = shuffle(quizSet[currentNum].c);
//quizSet[currentNum].cは参照型

・[]でくくってスプレッド演算子で配列を参照する

shuffle([...quizSet[currentNum].c]);

【関数】

function fnc(msg = '初期値') {

  return msg;
}

console.log(fnc('test'));

※関数内でreturnするとそのあとの処理は実行されない




・関数式で定数や変数に直接代入もできる

※最後にセミコロンにつく点に注意!

const keisan = function(msg = '初期値') {

  return msg;
};

keisan('test'); //定数として扱われ、関数名がないので無名関数と呼ばれる

・アロー関数 関数式の書き換え

const keisan = (msg) => {    //msgは引数

  return msg;
};

※returnするだけの場合は

const keisan = (msg) => msg;

でOK

※さらに引数が1つだけなら()も不要

const 定数名 = 引数 => 処理;

【if文】

■基本形

if (arg == val) { }

★『=』だと代入が行われてしまうため注意!
■省略形

const score = 40;
score >= 80 ? console.log('OK') : console.log('NG');

&& :AND
|| :OR
! :NOT

【for文】

for (let i = 1; i <= 10; i++) { //初期化すること

  console.log(i);

  if (i === 4) {

continue; //スキップ
  }

  if (i === 7) {

break; //終了
  }
}

■forEach

※break、continueは使えない

a.forEach (

  function( item ) {

    console.log( item );
  }
)


・アロー関数で書いてみると

a.forEach(item => {

  console.log(item);
});

a.forEach(item => console.log(item); //Aに対してBの処理をする、と覚える

・インデックスもとる場合

a.forEach((item, index) => {

  console.log(`${index}:${item}`);
}

【while文】

let hp = 100;

while (hp > 0) {

  console.log(`${hp} HP left!`);

  hp -=15;
}

※条件を書き忘れると無限ループになりPC、ブラウザの再起動をする羽目になるので注意

do whileも使用できる




【配列】

■基本形

const arr = [80, 90, 40]; //constは、再定義はできないが、値の変更はできる

■プロパティ

arr.index

arr.length :長さを取得

■要素の追加

scores.unshift(100); //先頭に追加
scores.push(120); //末尾に追加

■要素の削除

scores.shift(); //先頭を削除
scores.pop(); //末尾を削除

■配列を空にする

arr.length = 0;

■途中の要素

scores.splice(2, 0, a, b); //第1:スタート地点、第2:削除個数、第3以降:追加要素

削除した要素は返り値で取得することもできる

const b = scores.splice(2, 2, a, b); //bに返り値が入る

■map  配列のすべての要素に対して処理を実行

const b = a.map(item => return item * 2);

■filter trueの要素だけとってくる

const b = scores.filter(item => item % 2 ===0); //偶数だけ取得

【オブジェクト】

const player = {

  name: 'taguchi',

  score: 32, //最後の行はカンマはつけてもつけなくてもOK
}

player.name または player[name] でアクセス




・プロパティ(メンバー)の追加 ただ、keyとvalueを渡せばOK

player.email = 'test@exsample.com';

・プロパティの削除

delete player.email;

■オブジェクトメソッド

Object.keys(player) //keyの配列

Object.values(player) //valueの配列

Object.entries(player) //[[key1, value1], [key2, value2]]といった2次元配列

■スプレッド演算子 『...●●』 :配列(オブジェクト)の連結

★配列でも参照型ではなく、コピーになる!

const a = [10, 20];
const b = [1, 2, ...a];
console.log(b); //[1, 2, 10, 20]

・引数にもよく使われる

const a = [10, 20];
const sum = (a, b) => a + b;
console.log(sum(...a)); //30 ※sum(10, 20)となる


・オブジェクトに使う場合

const o1 = {a: 1};
ocnst o2 = {...o1, b: 2}; //{a:1, b:2}

■分割代入 :配列(オブジェクト)の各値に対応させて代入

const numbers = [1, 2];
const [a, b] = numbers; //a=1, b=2

・スプレッド演算子との組み合わせ;

const numbers = [1, 2, 3, 8];
const [a, b, ...rest] = numbers; //a=1, b=2, rest=[3, 8]

・オブジェクトに使う場合

const player = {

  name: 'taguchi',
  score: 55,
  hp: 33,
}

const {name, ...points} = player; //name = 'taguchi', points = {score:55, hp:33}

【クラス】

class Player {

  constructor(name, score) {

    this.name = name;
    this.score = score;
  }

  showInfo() {

    console.log(`name: ${this.name} score: ${this.score}`);
  }

  static showVersion() { //クラスメソッド(静的メソッド)

    console.log('Player class ver 1.0');
  }
}

const taguchi = new Player('taguchi', '32'); //インスタンス化
console.log(taguchi.name); //呼び出し

・thisについて

this.nameのようにパラメータとして付与しているものは、本来であれば

const name = name;

のように宣言するものだが、パラメータとして付与する場合は宣言不要で

かつそのクラスに紐づいた要素になるので便利。




thisを付与するタイミングは以下の時
┗パラメータにアクセス
┗クラスメソッドにアクセス





■クラスの継承 ※上記のPlayerクラスを継承する

class SoccerPlayer extends Player {

  constructor(name, score, number) {

    super(name, score); //親クラスからメソッドを継承

    this.number = number;
  }
}

■カプセル化(オブジェクト思考)

クラスプロパティは外部から直接呼び出すのは避ける。

呼び出したい場合はクラス内でプロパティを呼び出す関数を定義し、

クラスメソッドとして呼び出す

例)

class Panel {

  constructor() {

    this.el = document.createElement('li');
  }

  getEl() { //メソッドでプロパティを呼び出す

    return this.el;
  }
}

board.appendChild(panel.getEl()); // カプセル化


【例外処理】

const a = 5;

try {

  console.log(a.toUpperCase()); //toUpperCaseは大文字にする処理なのでエラー

} catch (e) { //エラーオブジェクトをeに格納してくれる

  console.log(e.message); //eのmessageメソッド
}

【非同期処理】

javascriptはシングルスレッド処理。スタックに処理が積まれるため、ネストされた時間のかかるメソッドは後回しされる場合がある。

Promiseオブジェクトでラップすることで処理の終了を保証して次に進める。

async/awaitを使用することでよりシンプルにPromiseの機構を使用することができる。

asyncで定義した関数はPromiseオブジェクトにラップされるため、処理の終了が保証される。

awaitはasyncで定義した関数内で使用することができ、awaitで定義した関数内でPromiseが返されるまで待機する。asyncと何が違うのかいまいち理解できていない




【appendics】

■日付

const d = new Date();

//引数に数値を指定するとその日時のオブジェクトを作成できる(年,月は必須)

console.log(d.getFullYear()); //年

console.log(d.getMonth());  //★0-11

console.log(d.getDate()); //日

console.log(d.getDay());  //曜日0~6

console.log(d.getTime()); //世界共通の数値化された日時

・フォーム

~HTML~

<form name="myform">

  <input type="date" name="date" value="2012-02-16">

</form>

・日付のセット

d.setHours(10, 20, 30) //10時20分30秒

※自動補正が入る(Date(日)で32と入れると翌月になる)




・日付の追加

d.setDate(d.getDate() + 3);

・日付の経過計測

const d1 = new Date(2018, 11, 1); //11月1日
const d2 = new Date(2018, 11, 10); //11月10日
console.log(d2 - d1); //77760000ミリ秒
console.log((d2 - d1) / (24 * 60 * 60 * 1000)); //9日 86400000秒/1日

■アラート :ウィンドウオブジェクト

window.alert('hello');  //windowは省略可

const answer = confirm('Sure?') //承認を求める

console.log(answer);  //返り値はtrue or false

・HTMLで簡単にアラートを出す ※NOを押せばキャンセルされる

https://proengineer.internous.co.jp/content/columnfeature/8007

コード

<a href="http://www.google.co.jp/" onclick="return confirm('よろしいですか?')">リンク</a>

■タイマー

・一定間隔で処理を実行 :setInterval

★処理がどんどん進むのでシステムに負荷をかけないよう配慮が必要

const tim = () => { //関数式で定数に関数を代入

  console.log(new Date());

};

setInterval(tim, 1000); //関数, ミリ秒でセット

・タイマーを止める

変数にsetIntervalを格納

カウンタ変数を別途用意し、関数内でカウンタを増やす

カウンタに対してif分岐を設定しておいてclearInterval()する

let lim = 0;

const tim = () => {

  console.log(new Date());

  lim ++;

  if (lim > 3) {

    clearInterval(timer);
  }
};

let timer = setInterval(tim, 1000);

★・1回だけ実行する :setTimeout

setTimeoutは処理が終わってから実行するため

システムに負荷をかけない

const tim = () => {

  console.log(new Date());
};

setTimeout(tim, 1000);  //ミリ秒で指定

これをループさせることで、一定間隔での処理を実装することもできる

const tim = () => {

  console.log(new Date());

  setTimeout(tim, 1000);  //ミリ秒で指定
};

tim();

止めたい場合は

let lim = 0;

const tim = () => {

  console.log(new Date());

  lim ++;

  let timid = setTimeout(tim, 1000);

  if (lim > 2) {

    clearTimeout(timid);
  }
};

tim();

・カウントアップの基本

const timer = document.getElementById('timer');
let startTime;

cntUp() {

  let leftTime = Date.now() - startTime;
  textContent = (leftTime / 1000).toFixed(1);

  setTimeout(() => {

    cntUp();
  }, 100)
}

★関数を呼び出す

※定数の無名関数の場合、スコープの都合上creaTimeoutできないことがよくあるので関数を使うのがベター

setTimeout(fnc(), 1000); ではなく

setTimeout(() => {

fnc();

}, 1000);

とする。




■1つのjsファイルを複数ページで使いまわす。

複数ページで使いまわすと、現在のページ以外の要素が存在しないと怒られる。

ページごとにユニークなidなどをキーにif文で出しわける。

if(document.getElementById(‘uniqueId’)) {

uniqueIdを持つページの処理
}


■要素内のテキストが画面幅によって折り返しが起きているかどうかを判定する
RangeオブジェクトにNodeをつっこむことで解析できるようにする。
Rangeオブジェクトのメソッド、getClientRects()で表示されている行数を判定できる。
参考:
javascript - htmlでテキスト表示する際、(画面幅等により、)折り返しが発生するかどうかを事前に判定する方法はありますか? - スタック・オーバーフロー

const items = document.getElementsByClassName('item');
let texts;
let range = new Range();
for(let i = 0; i < items.length; i++) {
  texts = items[i].children;
  for(let j = 0; j < texts.length; j++) {
    range.selectNode(texts[j]);
    if(range.getClientRects().length > 2) {
      //複数行になっていた場合に行いたい処理
    }
  }
}


■即時関数の利用

javascriptはスコープがグローバルか関数内ローカルの2種類しかない。

そのため、画面読み込み時の初期化など、再利用される可能性の無いものは即時関数としてくくることでグローバル領域の汚染を防ぐ。

(function () {

    var label = document.getElementById('date_label'),

        now = new Date();

        label.innerText = now;

}()); //★ここに不思議なカッコがあるので注意

参考:https://qiita.com/katsukii/items/cfe9fd968ba0db603b1e




■数字を文字列として出力しても数値として演算ができる

※プラスの場合だけ、文字列の連結として扱われる




■わからないことがあったらMDNで調べよう




■jsはxss(クロスサイトスクリプティング)の危険があるので注意する

https://www.websec-room.com/2013/03/14/567




■javascriptが動作しているかテスト




以下のテストコードをmain.jsなどに記載し、

htmlの要素に id="target"を付与。

表示した要素をクリックして背景がピンクに変われば動作している


document.getElementById('target').addEventListener('click', () => {

document.getElementById('target').style.background = 'pink';

});

【検索ワード】

async await 違い

Promise 中身 取得