【JavaScript】基本(備忘録)

プログラミング

JavaScriptの役割など

主にデータのやり取り(WebAPIからJSONの取得)とDOM操作(JSONをHTMLへとパース)が挙げられる。

JavaScriptの規格名は、ECMAScript(エクマスクリプト)と呼ばれる(略してES)。

2020年5月時点で最新バージョンはES2019(2020年6月頃にES2020が正式リリースの模様)だが、標準で使用されているのはES2015(ES6)。

データのやり取り

変数

ES6で変数を定義する際は、letかconstを使うのが無難。

let 変数名 = 数値、文字列等;
const 変数名 = 数値、文字列等;

let:再代入可能だが、再宣言不可。

let hoge = 10;
hoge = 20; // OK
let hoge = 20; // NG

const:再代入も再宣言も不可(もはや定数)。

const hoge = 10;
hoge = 20; // NG
const hoge = 20; // NG

また、constで定義した場合であっても、オブジェクト(以下の{…})のプロパティ(以下の’…’)の値は変更可能。

const hoge = { meat:'beef', fish:'tuna' };
const hoge = { meat:'pork', fish:'tuna' }; // NG
hoge.meat = 'pork'; // OK
console.log(hoge); // {meat: 'pork', fish: 'tuna'}

なお、ES5以前のJavaScriptでは、再宣言・再代入のどちらも可能なvarが用いられており、ES6でも使用可能。しかし、特に再宣言可能という性質上、プログラムが長くなった場合にはバグを誘発してしまうので、極力letかconstを用いる方が良さそう。

テンプレート文字列

ES6から新たに登場した表現方法で、バッククォート(`)で囲む。

変数を埋め込むことができるのが便利。

const name = 'KAZ';
const hello = `こんにちは、${name}さん`;
conloe.log(hello); // こんにちは、KAZさん

なお、テンプレート文字列を使わない場合は、下記のように書く。

const name = 'KAZ';
const hello = 'こんにちは、' + name + 'さん';
console.log(hello); // こんにちは、KAZさん

あまり差がないように見えるが、埋め込みたい変数が増えれば増える程、テンプレート文字列の方がベターと思う。

関数

関数の定義と呼び出しは、下記の通り。

// 関数の定義
function 関数名(第1引数, 第2引数, ...) {
  処理
  return 戻り値;
}

// 関数の呼び出し
関数名(第1引数, 第2引数, ...);

関数を定義するときの引数を仮引数、呼び出すときの引数を実引数とも言う。

具体例

// 関数の定義
function add(x, y) {
  const sum = x + y;
  return sum;
}

// 関数の呼び出し
add(2, 4); // 6

これくらいの処理なら、returnに直接処理を書いてもOK。

// 関数の定義
function add(x, y) {
  return x + y;
}

// 関数の呼び出し
add(2, 4); // 6

関数名をそのまま変数に代入することも可能。

// 関数の定義
function add(x, y) {
  const sum = x + y;
  return sum;
}

//変数に代入
const result = add(2, 4)
console.log(result) // 6

また、変数に直接代入する形で関数を定義することも可能(これを無名関数と呼ぶ)。

const add = function (x, y) {
  const sum = x + y;
  return sum;
}

const result = add(2, 4);
console.log(result); //6 

アロー関数

無名関数は、さらに下記のように書き換えられる。

アロー(=>)を使っているので、アロー関数と呼ぶ。

const add = (x, y) => {
  const sum = x + y;
  return sum;
};

const result = add(2, 4);
console.log(result); // 6

アロー関数を一般化すると、下記の通り。

const hoge = (第1引数, 第2引数, ...) => { // letでもOK
  処理
  return 戻り値;
}

アロー関数は、単に関数を短く書ける点以外にも違いがあり、その一つが、JavaScriptにデフォルトで用意されている特別な変数thisの扱い。

まず通常の関数での一例。最後の2行、gokuがgenkidama、gohanがmasenkouという出力。

waza = 'kamehameha';
function attack() { // 通常の関数
  console.log(this.waza)
}

const goku = {
  waza: 'genkidama',
  func: attack
}

const gohan = {
  waza: 'masenkou',
  func: attack
}

goku.func(); // genkidama
gohan.func(); // masenkou

関数部分をアロー関数にする場合は、下記の通り。

waza = 'kamehameha';
const attack = () => { // アロー関数
  console.log(this.waza)
}

const goku = {
  waza: 'genkidama',
  func: attack
}

const gohan = {
  waza: 'masenkou',
  func: attack
}

goku.func(); // kamehameha
gohan.func(); // kamehameha

最後の2行が、どちらもkamehamehaになっている。

これは、アロー関数で定義された関数には、定義された時点のthisをそのまま用いる(不変)という特徴のため。

従って、this.wazaは、アロー関数が定義された時点でのkamehamehaに固定されている。

ちなみに、最初の1行(waza = 'kamehameha';)を削除すると、通常の関数の場合、結果が変わらないのに対して、アロー関数の場合は、最後の2行の出力がundefinedとなる。

アロー関数が定義された時点で、this.wazaが何も定義できていないため。

高階関数・コールバック関数

高階関数とは、関数を引数にとる関数。そしてその引数となる関数をコールバック関数と呼ぶ。

function 高階関数 (コールバック関数) {
  処理
  コールバック関数();
}

例えば、特定の条件を満たしている場合にだけ、(コールバック関数の)処理をしたいとき等に用いると便利。

具体例

//zwarriorsという配列にオブジェクトを格納
const zwarriors = [
  {name: '孫悟空', type: 'サイヤ人'},
  {name: 'ピッコロ', type: 'ナメック星人'},
  {name: 'ベジータ', type: 'サイヤ人'},
];

//高階関数
function superSaiyan (member, fn) {
  for ( i = 0; i < member.length; i++ ) {
    if (member[i].type == 'サイヤ人') { //zwarriorsのtypeがサイヤ人か確認
      fn( member[i].name ); // コールバック関数の処理
    };
  };
}

//超サイヤ人に変身するコールバック関数
function transform (name) {
  console.log(`${name}は超サイヤ人に変身した`);
}

superSaiyan(zwarriors, transform);

//出力結果
孫悟空は超サイヤ人に変身した
ベジータは超サイヤ人に変身した

ES6から導入されたfor~of文で書くと下記の通り。

//zwarriorsという配列にオブジェクトを格納
const zwarriors = [
  {name: '孫悟空', type: 'サイヤ人'},
  {name: 'ピッコロ', type: 'ナメック星人'},
  {name: 'ベジータ', type: 'サイヤ人'},
];

//高階関数
function superSaiyan (member, fn) {
  for ( let mem of member ) {
    if (mem.type == 'サイヤ人') { //zwarriorsのtypeがサイヤ人か確認
      fn( mem.name ); // コールバック関数の処理
    };
  };
}

//超サイヤ人に変身するコールバック関数
function transform (name) {
  console.log(`${name}は超サイヤ人に変身した`);
}

superSaiyan(zwarriors, transform);

//出力結果
孫悟空は超サイヤ人に変身した
ベジータは超サイヤ人に変身した

ループ

繰り返し処理には、forを用いる。

for ( 初期化; 繰り返し回数の指定(条件); 変化式) {
  繰り返す処理
}

具体例(i++は、iを1ずつ増やす)

for ( let i = 1; i < 5; i++ ) {
  console.log(i)
} // 1, 2, 3, 4

既に述べたが、ES6からfor~of文が導入され、配列を順番に処理する場合に便利。

オブジェクト

オブジェクトとは、プロパティの集まり。プロパティとは、プロパティ名(キー)と値との組み合わせ。

下記の例で言うと、例えば{name: '孫悟空', type: 'サイヤ人'}が一つのオブジェクト。

name: '孫悟空' がプロパティ。nameがプロパティ名(キー)で、'孫悟空'が値。

一つのオブジェクトに2つのプロパティが入っており、zwarriorsという配列に3つのオブジェクトが入っている。

const zwarriors = [
  {name: '孫悟空', type: 'サイヤ人'},
  {name: 'ピッコロ', type: 'ナメック星人'},
  {name: 'ベジータ', type: 'サイヤ人'},
];

オブジェクトには、ArrayオブジェクトやObjectオブジェクト等の標準ビルトインオブジェクトがあり、それらに対して様々なメソッドやプロパティがあらかじめ用意されている。

lengthプロパティ

配列の要素数を取得するプロパティ。

const zwarriors = ['悟空', 'ピッコロ', 'クリリン'];
const result =  zwarriors.length;

console.log(result); // 3

sliceメソッド

配列を切り出して、新たな配列を戻り値として返す。

厳密にはArrayオブジェクトが参照するprototypeオブジェクトのメソッド。

const zwarriors = ['悟空', 'ピッコロ', 'クリリン'];
const result = zwarriors.slice(0, 2);

console.log(result); // ["悟空", "ピッコロ"]

pushメソッド

配列の要素を追加するメソッド。こちらもprototypeオブジェクトのメソッド。

const zwarriors = ['悟空', 'ピッコロ', 'クリリン'];
console.log(zwarriors.push('ヤムチャ')); // 4
console.log(zwarriors) // ["悟空", "ピッコロ", "クリリン", "ヤムチャ"]

forEachメソッド

配列の要素に対して関数で処理を行うメソッド。こちらもprototypeオブジェクトのメソッド。

高階関数でもある。配列としてではなく、要素ごとに処理されて返ってくる。

const sonfamily = ['悟空', '悟飯', '悟天'];
function addFamilyname(member) {
  console.log(`孫${member}`);
};
sonfamily.forEach(addFamilyname); // 孫悟空、孫悟飯、孫悟天

mapメソッド

forEachメソッドと似ているが、mapメソッドは処理した値を新しい配列として返してくれる。

こちらもprototypeオブジェクトのメソッドで、高階関数。

const sonfamily = ['悟空', '悟飯', '悟天'];
function addFamilyname(member) {
  return `孫${member}`;
}

result = sonfamily.map(addFamilyname);
console.log(result); // ["孫悟空", "孫悟飯", "孫悟天"]

concatメソッド

複数の配列を繋げて、1つの配列を返すメソッド。こちらもprototypeオブジェクトのメソッド。

const sonfamily = ['悟空', '悟飯', '悟天'];
const vegetafamily = ['ベジータ', 'トランクス'];

console.log(sonfamily.concat(vegetafamily)); // ["悟空", "悟飯", "悟天", "ベジータ", "トランクス"]

なお、スプレッド構文を用いると以下のようにも記載できる。

const sonfamily = ['悟空', '悟飯', '悟天'];
const vegetafamily = ['ベジータ', 'トランクス'];

console.log([...sonfamily, ...vegetafamily]); // ["悟空", "悟飯", "悟天", "ベジータ", "トランクス"]

popメソッド

配列の最後の要素を削除して、その削除された要素を返すメソッド。こちらもprototypeオブジェクトのメソッド。

const sonfamily = ['悟空', '悟飯', '悟天'];

console.log(sonfamily.pop()); // 悟天

joinメソッド

配列の全要素を順に連結した文字列を新たに作成して返すメソッド。こちらもprototypeオブジェクトのメソッド。

const saiya = ['超', 'サイヤ', '人'];

console.log(saiya.join()); // 超,サイヤ,人
console.log(saiya.join(', ')); // 超, サイヤ, 人
console.log(saiya.join('')); // 超サイヤ人
console.log(saiya.join('+')); // 超+サイヤ+人

Object.entries()メソッド

引数に与えたオブジェクトの「プロパティ名」および「値」を配列として返すメソッド。

「値」にオブジェクトが入っているオブジェクトがあったとして、「値」としてのオブジェクトの値を取り出す場合を下記に例示。

locDataというオブジェクトの中に2つのプロパティがあり、各プロパティの値がオブジェクト(緯度のプロパティと経度のプロパティ)。

//「値」にオブジェクトが入っているオブジェクト
const locData = {
  locA: { lat: 34.985, lng: 135.760}, // 京都駅の緯度・経度
  locB: { lat: 35.022, lng: 135.762}  // 京都御所の緯度・経度
};

//順番に取り出す
for (let [key, value] of Object.entries(locData)) {
  console.log(key, value.lat, value.lng);
}

//出力
locA 34.985 135.76
locB 35.022 135.762

DOM操作

DOMとは、Document Object Modelの略。

HTML文書の<body>や<div>のような各要素をDOM要素と呼び、Java Scriptを使ってこれらの要素からデータを取ってきたり、要素の内容を変更したりすることをDOM操作と呼ぶ。

要素のテキスト内容の取得・変更

HTMLにid=”hoge”のdiv要素があったとすると、getElementByIdメソッドを用いて下記のように要素を取得できる。

<div id="hoge">ほげ</div>
let el = document.getElementById('hoge');
console.log(el); // <div id="hoge">ほげ</div>

textContentプロパティを用いて書き換えられる。

el.textContent = 'HOGE'; // HTMLの表示がHOGEに変わる

innerTextプロパティでも同様の結果が得られる。innerTextプロパティなら、/nによる改行が反映される。

イベント

addEventListenerメソッドを用いることで、例えば、「要素がクリックされた」「ページが読み込まれた」「入力フォームが送信された」ときに通知をもらうことができる。

例えば、clickイベントの場合

<button id="btn">クリック</button>
let btn = document.getElementById('btn');

btn.addEventListener('click', function() {
  console.log('クリックしたよ'); // コンソールで'クリックしたよ'と表示
  alert('クリックしたよ'); // ポップアップで'クリックしたよ'と表示
});

アロー関数で書くと下記の通り。

let btn = document.getElementById('btn');

btn.addEventListener('click', (e) => { // 引数は何でもOK
  console.log('クリックしたよ'); // コンソールで'クリックしたよ'と表示
  alert('クリックしたよ'); // ポップアップで'クリックしたよ'と表示
});

他にも下記を含む様々なイベントがある。

  • マウスが乗ったときのmouseenterイベント
  • マウスが離れたときのmouseleaveイベント
  • ユーザがブラウザのUIからコピー操作したときのcopyイベント
  • ユーザがブラウザのUIにペーストしたときのpasteイベント
  • ユーザがブラウザのUIから切り取りしたときのcutイベント
  • ダブルクリックされたときのdbclickイベント
  • フォームが送信されたときのsubmitイベント
  • ページが読み込まれたときのloadイベント
  • <input>要素の値が変化したときのinputイベント
  • 要素の変更が終わったときのchangeイベント