JavaScript で基本となる値です。

数値

数字な値(number)は単に数値を記述するだけです。

const one = 1;
const eleven = 11;
const pi = 3.14;

真偽値

truefalseからなる値です。ある条件が正しければtrue、正しくなければfalseを使います。頭に!を付けるとそれぞれ逆の意味になります。

if (true) {
  console.log('正しい');
}

if (!false) {
  console.log('正しくない');
}

null

今は何もないを表す値ですが、使わなくていいです。
使う場合はそのままnullと書きます。

const nil = null;

undefined

こちらも何もないを表す値です。変数初期化時に値を入れない場合勝手にundeifnedになります。

const undefinedValue;
console.log(undefinedValue); // undefined

文字列

上記は、すべてそのまま書くだけで使えるものでしたが、これは'"(または、バッククオート)で囲む必要があります。これで文字列(string)になります。個人的には'を使うのが好きです。

const hello = 'hello';
const world = "world";

const name = 'nju33';
const helloName = `hello ${name}`;
console.log(helloName); // hello nju33
関連

Undefined は対象に値が何も入っていない状態を表します。

変数定義時に値を指定しない場合や、

let foo;
// foo === undefined

引数を要求する関数で引数を渡さなかった場合、

const fn = str => { /* ... */ };
fn(); // str === undefined

などによく見られます。

安全な undefined 確認

実を言うと undefined は予約語として扱われていないので、コードを書く人が好きに値を設定できてしまいます。もしも、誰かが変な値を指定してしまうと今書いているコード部分の=== undefinedで比較している箇所がうまく動かなくなるかもしれません。

そのようにならないようにundefinedの代わりにvoid 式を使うと良いです。void 式は式に関係なく必ずundefinedを返す式です。

// どこか遠い所
const undefined = 'foo';

// ---

const myFunction = () => {
  console.log(undefined); // 'foo' 😱
  // 以下の式が`false`に
  console.log(undefined === void 0);
}

myFunction();
関連

forEach

単にすべての配列の要素を回したい時に使います。
戻り値はundefinedです。

const result = [1, 2, 3, 4].forEach(num => {
  console.log(num);
});
// 1
// 2
// 3
// 4
console.log(result) // undefined;

map

配列のある要素を、同じ位置で別の値に変換したい時などに使います。
戻り値はなんでもありで、具体的には配列に存在するすべての型の配列です。

const result = [1, 2, 3, 4].map(num => {
  if (num % 2 === 0) {
    return String(100 - num);
  }
  
  return num;
});
// 1
// '98'
// 3
// '96'
console.log(result) // [1, '98', 3, '96']

reduce

配列の値を使って、1つの値を導き出したい時などに使います。
戻り値はなんでもありで、具体的にはハンドラーが受け取る第1引数の型です。

ハンドラーの中でreturnした値が、次のハンドラーの第1引数に来ます。reduceの第2引数に値を渡すと、それが1周目のaccの値になります。

// 0 + 1 + 2 + 3 + 4
const result = [1, 2, 3, 4].reduce((acc, num) => {
  acc = acc + num
  return acc;
}, 0);

console.log(result); // 10;

some

「1つでもそういう条件の要素があるか?」を調べる時に使います。
戻り値は、1つでも当てはまればtrue、1つも当てはまらなければfalseです。

const result1 = [1, 2, 3, 4].some(num => {
  return num === 2;
});
console.log(result1); // true

const result2 = [1, 2, 3, 4].some(num => {
  return num === 5;
});
console.log(result2); // false

every

「すべての要素でそんお条件が当てはまるか?」を調べる時に使います。
戻り値は、すべて当てはまればtrue、1つでも違うならfalseです。

const result1 = [1, 2, 3, 4].every(num => {
  return num < 10;
});
console.log(result1); // true

const result2 = [1, 2, 3, 4].every(num => {
  return num < 3;
});
console.log(result2); // false

push

配列の最後に値を追加します。
戻り値は「いくつ追加したか」の数値です。

破壊的メソッドで、元の配列を書き換えます。

const arr1 = [1, 2, 3, 4];
const result1 = arr1.push(5);
console.log(result1); // 1
console.log(arr1); // [1, 2, 3, 4, 5]

const arr2 = [1, 2, 3, 4];
const result2 = arr2.push(5, 6);
console.log(result2); // 2
console.log(arr2); // [1, 2, 3, 4, 5, 6]

pop

配列の一番最後の値を取り出します。
戻り値は取り出した値です。

const result = [1, 2, 3, 4].pop();
console.log(result); // 4

unshift

配列の最初に値を追加します。
戻り値は「いくつ追加したか」の数値です。

破壊的メソッドで、元の配列を書き換えます。

const arr1 = [1, 2, 3, 4];
const result1 = arr1.unshift(0);
console.log(result1); // 1
console.log(arr1); // [0, 1, 2, 3, 4]

const arr2 = [1, 2, 3, 4];
const result2 = arr2.unshift(-1, 0);
console.log(result2); // 2
console.log(arr2); // [-1, 0, 1, 2, 3, 4]

shift

配列の一番最初の値を取り出します。
戻り値は取り出した値です。

破壊的メソッドで、元の配列を書き換えます。

const result = [1, 2, 3, 4].shift();
console.log(result); // 1

splice

pushpop,unshift,shift的に使うこともできますが、基本的に、

  • 配列から中間地点にある要素を削除する

  • 配列の中間地点にある要素を追加する

のに使います。戻り値は削除した要素の配列です。

破壊的メソッドで、元の配列を書き換えます。

要素の削除

第1引数は中間地点を表していて、第2引数は「いくつ削除するか」を渡します。以下の場合、インデックス1(2)の位置から要素を1つ削除するという意味になり、2が削除されます。

const arr = [1, 2, 3, 4];
const result = arr.splice(1, 1);
console.log(result); // [2]
console.log(arr); // [1, 3, 4]

要素の追加

第3引数以降には追加したい要素をただ順番に書いていくだけです。以下では第2引数を0にしているので、何も削除せず、インデックス1の位置から101102を追加するという意味になります。

const arr = [1, 2, 3, 4];
const result = arr.splice(1, 0, 101, 102);
console.log(result); // []
console.log(arr); // [1, 101, 102, 2, 3, 4]

要素の削除と追加

もちろんこの2つを組み合わせて使うこともできます。

const arr = [1, 2, 3, 4];
const result = arr.splice(1, 1, 101, 102);
console.log(result); // [2]
console.log(arr); // [1, 101, 102, 3, 4]

find

IEでは使えません。

配列から条件にある要素を見つけて要素を返します。
戻り値は要素があれば要素の型、なければundefinedです。

const result = [1, 2, 3, 4].find(num => {
  return num % 2 === 0;
});
console.log(result); // 2

const result2 = [1, 2, 3, 4].find(num => {
  return num % 5 === 0;
});
console.log(result2); // undefined

findIndex

IEでは使えません。

配列から条件にある要素を見つけて要素のインデックス値を返します。
戻り値は要素があれば要素インデックス値(number)、なければ-1です。

const result = [1, 2, 3, 4].findIndex(num => {
  return num % 2 === 0;
});
console.log(result); // 1

const result2 = [1, 2, 3, 4].findIndex(num => {
  return num % 5 === 0;
});
console.log(result2); // -1

flat

IEEdgeNodeJSでは使えません。

1階層までの配列をトップレベルの配列の要素とすることができます。
戻り値は処理後の配列です。

const result = [1, [2, 3], [[4]]].flat();
console.log(result); // [1, 2, 3, [4]]

flatMap

IEEdgeでは使えません。

mapの結果の後、さらにflatするような処理をします。
戻り値は処理後の配列です。

以下はmap[[1, 99], [2, 98], [3, 97], [4, 96]]となった後にflat[1, 99, 2, 98, 3, 97, 4, 96]となる感じです。

const result = [1, 2, 3, 4].flatMap(num => {
  return [num, 100 - num];
});
console.log(result); // [1, 99, 2, 98, 3, 97, 4, 96]
関連

いつ完了するか分からない処理を順番に実行するのに使います。例えば、

  • API のレスポンスが返ってきた時

  • 指定秒スリープした時

  • DOM が出来上がった時

など。そして、そのような処理を行えるようにPromiseクラスがあります。
Promiseインスタンスはresolverejectコールバック関数を引数として受け取れる関数を渡して作ります。 resolveは処理が成功した時に呼ぶもので、rejectは処理が失敗した時に呼ぶものです。

インスタンスメソッド

Promise#then

resolveコールバック関数が呼ばれるとPromise#thenメソッドが呼ばれます。このメソッドはresolve(arg)が実行された直後に実行されます。resolveに渡した第一引数がPromise#thenの第一引数の値になります。

const processing = new Promise(resolve => {
  resolve({value: 1});
});

processing.then(obj => {
  console.log(obj); // {value: 1}
});

Promise#catch

reject(arg)が実行された時に呼ばれるのがPromise#catchです。

const processing = new Promise((_, reject) => {
  reject({value: 1});
});

processing.catch(obj => {
  console.log(obj); // {value: 1}
});

実はthrowでも同じようにPromise#catchが呼ばれます。

const processing = new Promise((_, reject) => {
  throw {value: 1};
});

processing.catch(obj => {
  console.log(obj); // {value: 1}
});

注意する点として、catchできるのは「rejectまたはthrowされた非同期関数で終わっている場合」に限ります。なので、以下のように何も返さないPromise#catchなどで握り潰してしまうと、その部分のキャッチした値は完全に捨ててしまうことになります。

const processing = new Promise((_, reject) => {
  throw {value: 1};
})
  .catch(() => undefined);

processing.catch(obj => {
  // 呼ばれない
  console.log(obj); // {value: 1}
});

連続した処理

最初に書いたとおりこれの使う理由には処理を連続で書けるようにする点があります。では、どうするのがいいかという事の個人的な話です。

まず、常にPromise#catchをチェーン毎に1つにします。
処理を連続で書けると言っても、throwするかもしれない処理をそのまま渡すと、Promise#catchが難しくなっていきやすいと感じます。それはPromise#catchからPromise#catch間や親との間の伝達の問題です。
ちゃんとエラー処理を施した非同期関数を別に作り渡すようにすると良いと思います。

別の非同期関数にしてチェインに渡すことで次の非同期関数には、自分自身のPromise#thenの結果だけを渡すことができ、同様に自分へはPromise#thenの結果が渡ってくるようにできます。つまり、自分自身のPromise#catchが後のチェイン上の非同期関数へ影響を与えることがなくなります。

例えばこんな感じです。(new Promise(resolve => resolve())() => Promise.resolve()new Promise((_, reject) => reject())() => Promise.reject()のように置き換えれます)

const childAsyncFn1 = () => Promise.reject("...");
const childAsyncFn2 = () => Promise.reject("...");
const childAsyncFn3 = () => Promise.reject("...");

const mainAsyncFn1 = () => {
  return childAsyncFn1()
    .then(childAsyncFn2);
};

const mainAsyncFn2 = () => {
  return Promise.resolve()
    .then(childAsyncFn3);
};

await mainAsyncFn1()
  .then(mainAsyncFn2)
  .catch(err => {
    // childAsyncFn1 のエラー処理
  });

そしてPromise#catchではできるだけPromise#thenと抽象的に同じ意味の値を返すようにすると良いと思います。最終手段のエラー処理と頭に置いておくと良いんじゃないかなと思います。

const childAsyncFn1 = () => Promise.reject("...");
const childAsyncFn2 = () => Promise.reject("...");
const childAsyncFn3 = () => Promise.reject("...");

const mainAsyncFn1 = () => {
  return childAsyncFn1()
    .then(childAsyncFn2)
    .catch(() => {
      // 後が問題なく動くような抽象的な値を返す
      // これにより必ず `Promise#then` が返される
      return {/*...*/}
    });
};

const mainAsyncFn2 = something => {
  return Promise.resolve(something)
    .then(childAsyncFn3);
};

// mainAsyncFn2 へ渡るようになる
await mainAsyncFn1()
  .then(mainAsyncFn2)
  .catch(err => {
    // もしかしたら childAsyncFn2 のエラー処理
  });

async-awaitは、「いつ完了するか分からない処理」だけど「順番に実行したい」な事をするために使います。「コールバック地獄」と呼ばれていたような読みづらいコードをシンプルに書けます。

構文

functionの前、アロー関数なら()の前にasyncと書きます。

async function foo() {
  /* ... */
}
const bar = async () => {
  /* ... */
};

そして、中でPromiseを返す関数の実行前にawaitと書けば、処理が終わるまでその場で待ってくれます。これはPromise#thenを使う方法と比べて構文を反対に書いたような形になります。つまり「関数→then→変数」から「変数→await→関数」といった具合です。

// Promise#then
asyncFn1().then(data => {/*...*/});
asyncFn2().then(() => {/*...*/});

// await
const data = await asyncFn1();
await asyncFn2();

以下は1毎にコンソールにテキストを出力する例です。

/**
 * 1秒待つ
 * (
 *    `async`と書くと`Promise`だなとわかるのでオススメしたいです
 *    TypeScript 除く
 *  )
 */
const delay = async () => new Promise(r => setTimeout(r, 1000));

(async () => {
  console.log('すぐ表示');
  await delay();
  console.log('1秒後表示');
  await delay();
  console.log('さらに1秒後');
})();

エラー処理

await文の例外はtry-catchでキャッチすることができます。(エラーでやっているけど単に勉強の為でPromise#rejectでも良い)

class OversleepError extends Error {
  constructor() {
    super('寝坊した');
    Error.captureStackTrace(this, OversleepError);
  }
}

/**
 * 寝る
 */
const sleep = async () => {
  throw new OversleepError();
};

(async () => {
  try {
    await sleep();
  } catch (err) {
    console.log(err instanceof OversleepError); // true
  }
})();

扱うのはPromiseなのでcatchで一旦受け取ってできるだけ処理することももちろんできます。

/* 上の関数定義そのまま */

const eatBreakfast = async () => {
  /* 食べる */
};

(async () => {
  const task = {
    breakfast: true
  };

  await sleep().catch(err => {
    if (err instanceof OversleepError) {
      task.breakfast = false;
      return;
    }
  });

  // 遅刻してない場合、
  // 朝食を食べる
  if (task.breakfast) {
    await eatBreakfast();
  }
})();
関連

起こす

throwを使うと、その部分で「何かしら変な事が起きた」ことが返せます。

throw new Error('エラーメッセージ');

コメント

JDOC コメントを残すと他の人の助けになるかもです。

/**
 * @throws {Error} こんなの時
 */
function foo() {
  /* ... */
}

起こったエラーを扱う

try-catchを使います。
tryブロックにはエラーが起こりそうな処理を書きます。もし起きた時、throwされたErrorcatchブロックの引数で受け取れます。

try {
  foo();
} catch (err) {
  console.log(err);
  // Error: エラーメッセージ
  //   at Object.

  // ここで扱えないなら再度 throw したり
  // throw err;
}

よく使うエラー

最低限Errorにだけはして返すといいと思います。

TypeError

TypeError オブジェクトは、値が期待される型でない場合のエラーを表します。 TypeError - JavaScript | MDN

引数の型などに想定外の型を渡された時などに使います。

/**
 * @throws {TypeError} num が数値じゃない時
 */
const plusOne = num => {
  if (typeof num !== 'number') {
    throw new TypeError('数値を渡してください');
  }

  return num + 1;
};

SyntaxError

構文的に不正なコードを解釈しようとした場合のエラーを表します。 SyntaxError - JavaScript | MDN

渡された文字列をパースする関数などで、想定外の形の文字列を渡された時などに使います。

const parse = str => {
  const re = /* 正規表現 */;
  if (!re.test(str)) {
    throw new SyntaxError('文字列の形が不正です')
  }

  return Foo.parse(str);
}

自分で作る

Errorクラスを継承して自分のErrorクラスを作ることができます。
Error.captureStackTraceはスタックトレースから無駄を減らしてくれます。

class MyError extends Error {
  constructor(message) {
    super(message);
    Error.captureStackTrace(this, MyError);
  }
}

const foo = () => {
  /* ... */
  throw new MyError('エラー!!');
  /* ... */
};

try {
  foo();
} catch (err) {
  console.log(err instanceof MyError); // true
}
関連

「ある配列やオブジェクトの1部だけを使うからそれだけ取り出して使いたい」ような時に使えます。

Object

const {取り出したいプロパティ名} = ...とするだけです。

const {a, c} = {a: 1, b: 2, c: 3};
console.log(a); // 1
console.log(c); // 3

万が一同じ名前の変数がスコープ上にあるなら:で別名をつけることができます。

const {a: alias} = {a: 1};
console.log(alias); // 1

また=を使うことで、その値がundefinedの時にデフォルト値が入るようにできます。

const {c = 3} = {a: 1};
console.log(c); // 3

組み合わせると。

const {d: aliasOfD = 4} = {a: 1};
console.log(aliasOfD); // 4

Array

最初の要素だけ取りたい場合は、

const [first] = [1, 2, 3];
console.log(first); // 1

最後だけならカンマで頭の要素を飛び越えて取得します。

const [,,first] = [1, 2, 3];
console.log(first); // 1

またそれ以降の要素をすべて取得したいなら...を使います。

const [,...tail] = [1, 2, 3];
console.log(tail); // [2, 3]

ただ、これは最後の変数値にしか使えません。

const [...head,] = [1, 2, 3];
// これは駄目!

また配列も=でデフォルト値を設定できます。

const [first = 1] = [];
console.log(first); // 1

...の方には設定できません。

const [, ...tail = [2, 3]] = [1];
// SyntaxError: Invalid destructuring assignment target
関連

EventTarget#addEventListener

EventTarget#addEventListenerは特定のイベントが起きた時に、それに連動する形である処理を実行したい時に使います。よくあるのが要素をクリックしたら「ほげほげ」するというような処理です。それはこのように書かれます。

document.getElementById('button').addEventListener(
  'click',
  () => {
    console.log('clicked');
  }
);

1番目がイベントの名前、そして2番目に連動して実行したい処理(関数)です。ちなみに、addEventListenerには3番目の引数も設定できます。これは仮引数falseが渡っているのでデフォルトでは有効ではない形でイベントが設定されます。

3番目の引数はuseCaptureと書かれたりしていて、子要素で同名のイベントが起きた時に親から連動処理を実行するかを定めるものです。例を用意しました。

useCapturetrueuseCapturefalse

EventTarget#removeEventListeneraddEventListener

document.getElementById('button').removeEventListener(
  'click',
  () => {
    console.log('clicked');
  }
);


const onClick = () => {
  console.log('clicked');
};

addEventListenerremoveEventListener

const button = document.getElementById('button');
button.addEventListener('click', onClick);
button.removeEventListener('click', onClick);

Object#hasOwnProperty

プロトタイプオブジェクトを辿らずにそのオブジェクトがプロパティを持っているか調べれます。これはオブジェクトのメソッドですが、対象のオブジェクトがhasOwnPropertyを持っている可能性などが可能性は低いですがある為メソッドでの呼び出しは良くありません。以下のようにcallから呼び出すとほぼ確実にメソッドのhasOwnPropertyが呼び出せてより安全です。

Object.prototype.hasOwnProperty.call({foo: 'foo'}, 'foo');
// true
({foo: 'foo', hasOwnProperty: () => false}).hasOwnProperty('foo');
// false

in

プロパティ名 in オブジェクトでも調べることができます。こちらはプロトタイプを遡り調べることができます。

'hasOwnProperty' in Object
// true

もちろん、ただのプロパティの有無も調べられますよ。

'foo' in {foo: 'foo'}
// true
関連

権限などの管理はビットフラグを使うと楽そうです。

const EXECUTABLE = 1 << 2;
const WRITABLE = 1 << 1;
const READABLE = 1;

const executes = user => {
  return Boolean(EXECUTABLE & user.permission);
};

const writes = user => {
  return Boolean(WRITABLE & user.permission);
};

const reads = user => {
  return Boolean(READABLE & user.permission);
};

const executableUser = {permission: 0b111};
const writableUser = {permission: 0b011};
const readableUser = {permission: 0b001};

const process = user => {
  switch (true) {
    case executes(user): {
      console.log('execute!');
      break;
    }
    case writes(user): {
      console.log('write!');
      break;
    }
    case reads(user): {
      console.log('read!');
      break;
    }
    default: {
      throw new Error('');
    }
  }
};

[executableUser, writableUser, readableUser].forEach(process);
// execute!\nwrite!\nread!\n

AND

両方が1の場合のみ1になります。0b101 & 0b1000b100(4)です。
上記コードでEXECUTABLE0b100で判断しようとしていて、executableUserpermission: 0b111を持っているのでBoolean(0b100 & 0b111)trueとなります。readableUserでは0b100 & 0b001 === 0b000falseとなるので権限を持っていないことがわかります。

OR

片方が1なら1になります。権限を付与する時などに。0b100 | 0b001 === 0b101

JavaScript で飯食べたい歴約 5 年、 純( nju33 ) によるノートサイトです。

このサイトではドリンク代や奨学金返済の為、広告などを貼らせて頂いてますがご了承ください。

Change Log