Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
24
Help us understand the problem. What are the problem?

イマドキな JavaScript で書かない・使わないもの: var, function, then, jQuery

お仕事などでは使わざるをえない場合もあるかもしれませんが、少なくとも理想的には使わない方が良いものを書きます。

  • var を書かない
    • let もなるべく書かない
    • なるべく const を使う
  • function をなるべく書かない
    • アロー関数またはクラスやオブジェクトのメソッド定義を使う
    • 理論上どうしても必要な場合のみ function
  • then() を書かない
    • await を使う
  • jQuery を使わない
    • 純粋な WEB API を使用して DOM を走査する
    • fetch() で通信する
  • XMLHttpRequest を使わない
    • fetch() で通信する

1. 対象環境

本記事では、IE 以外の主要ブラウザおよび Deno での JavaScript を想定しています。

Node.js は一部異なる場合があります。

IE 対応が必要な場合は、Babel 等のトランスコンパイラの使用を検討してください。

2. var を書かない

const, let は IE 11 ですら使用できます ※ 。

for 文内での let の挙動が異なるようです。

参考「let - JavaScript | MDN

2.1. なるべく const を使う

(JavaScript は関数型言語ではありませんが) 関数型言語の概念から、変数を使わずになるべく定数だけを使用することでバグの発生リスクを抑えることができることが分かるため、なるべく const を使用してください。

なるべく const で書くためのいくつかのテクニックがあります。

  • 値を書き換えないものは const
  • if 文の代わりに三項演算子等の使用を検討する
    • 三項演算子 (c ? t : f)
    • 論理和 ||
      • const z = x || y; (Falsy な値の注意が必要)
    • Null 合体演算子 ??
    • Optional Chaining 演算子 ?.
  • 配列などのコレクションの操作は map()reduce() 等の反復メソッドをなるべく利用する
  • 別関数に分離して直接 return する

2.1.1. 値を書き換えないものはとにかく const

MDN や Google の開発者向けの一部のヘルプページなどでも、サンプルコードで let が多用されている場合がありますが、値を書き換えないものは全て const にします。

良くない例
let response = await fetch(url);
let json = await response.json();
let message = json.message;
良い例
const response = await fetch(url);
const json = await response.json();
const message = json.message;

2.1.2. 同じ変数を使いまわさず、別名の定数を作る

例えば、変数の値の形式を変換するような処理をしたいとき、意味的には中身が同じなため同じ変数名を使いたくなりますが、以下を参考にして別名の定数を作ってください。

  • 英語の過去分詞や形容詞を付ける
  • 変換後の型名を付ける

(※臨機応変に名前を使用してください。)

良くない例
let html = '<div>nya</div>';

html = html.replace(/</g, '&lt;').replace(/>/g, '&gt;');
heml = new TextEncoder().encode(html);
良い例
const html = '<div>nya</div>';
const escapedHtml = html.replace(/</g, '&lt;').replace(/>/g, '&gt;');
const htmlUint8Array = new TextEncoder().encode(escapedHtml);

2.1.3. if 文の代わりに三項演算子等の使用を検討する

  • 三項演算子 (c ? t : f)
  • Null 合体演算子 ??
  • Optional Chaining 演算子 ?.
良くない例
const options = {};

let isYes = true;
if ( 'something' in options && 'isYes' in options.something ) {
    isYes = options.something.isYes;
} else {
    isYes = true;
}

let ynStr;
if ( isYes ) {
    ynStr = 'Yes';
} else {
    ynStr = 'No';
}
良い例
const options = {};
const isYes = options.something?.isYes ?? true;
const ynStr = (isYes ? 'Yes' : 'No');

三項演算子は本来括弧 () を必要としませんが、演算子の優先順位が分かりにくくなることがあるため、括弧 () を付けた方が良いと思います。

参考「条件 (三項) 演算子 - JavaScript | MDN
参考「Null合体演算子 - JavaScript | MDN
参考「Optional chaining - JavaScript | MDN

Null 合体演算子 ?? の代わりに論理和 || を使用する場合は、Falsy な値の注意が必要です。

// 
const size = 0;

console.log(size ?? 1024); // 出力: 0
console.log(size || 1024); // 出力: 1024

// 
const text = '';

console.log(text ?? '(default)'); // 出力: ''
console.log(text || '(default)'); // 出力: '(default)'

参考「論理和 (||) - JavaScript | MDN

2.1.4. コレクションの操作は反復メソッドをなるべく利用する

例:

  • map(): 配列を同じ length のまま変換する
  • reduce(): 配列から 1 つの値に変換する
    • 文字列にしたい場合は map()join() を使用したほうが便利
  • filter(): 配列の一部を取り出して新しい配列を返す

※他にも便利なメソッドがあります。

良くない例
const dataArray = [{ id: 58 }, { id: 25 }, { id: 67 }, { id: 10 }];

let maxId = 0;
for (const data of dataArray) {
    maxId = Math.max(maxId, data.id);
}
良い例
const dataArray = [{ id: 58 }, { id: 25 }, { id: 67 }, { id: 10 }];
const maxId = dataArray.map(data => data.id).reduce((acc, id) => Math.max(acc, id), 0);

参考「反復メソッド - Array.prototype - JavaScript | MDN

2.1.5. NodeListHTMLCollection はスプレッド構文 [...obj] で簡単に配列 Array に変換できる

NodeListHTMLCollectionmap()reduce() 等の反復メソッドがありませんが、スプレッド構文を用いて簡単に配列に展開できます。

HTMLCollection から Array に変換
const imgSrcArray = [...document.getElementsByClassName('image')].map(node => node.src);
NodeList から Array に変換
const favImgSrcArray = [...document.querySelectorAll('img.favorite')].map(node => node.src);

参考「スプレッド構文 - JavaScript | MDN

2.1.6. 別関数に分離して直接 return する

const を使用するかどうかに関わらず、機能を適切に別関数やメソッドに分割することはソースコードの品質を向上させ、バグの削減など保守性も良くなります。

良くない例
const profiles = [{ id: 22, name: 'kitty' }, { id: 1, name: 'puppy' }, { id: 33, name: 'bunny' }];

let profilesHtml;
if ( profiles.length !== 0 ) {
    profilesHtml = '<div>' + profiles.map(profile => '<span>ID: ' + profile.id + ', Name: ' + profile.name + '</span>').join('<br>') + '</div>';
} else {
    profilesHtml = '<div>No Profile</div>';
}
良い例
// 
const getProfilesHtml = profiles => {
    if ( profiles.length !== 0 ) {
        return '<div>' + profiles.map(profile => '<span>ID: ' + profile.id + ', Name: ' + profile.name + '</span>').join('<br>') + '</div>';
    } else {
        return '<div>No Profile</div>';
    }
};

// 
const profiles = [{ id: 22, name: 'kitty' }, { id: 1, name: 'puppy' }, { id: 33, name: 'bunny' }];

const profilesHtml = getProfilesHtml(profiles);

2.2. const が使えないと勘違いされがちなもの

2.2.1. 配列は const でも中身を書き換えられる

配列の中身を操作したいために let にしているコードを見かけますが、配列の宣言は const でも中身を書き換えられます。

配列をまるごと書き換えることはできなくなります。

const array = [2, 5, 8];

array.push(15); // array: [2, 5, 8, 15]

array = [3, 6, 9, 18]; // TypeError

2.2.2. for...infor...ofconst を使える

for...infor...ofconst を使用すると、ループのたびに別の定数として扱われます。

for (const property in object) {
  console.log(property);
}

for (const value of array) {
  console.log(value);
}

2.3. for (;;)let を使用する

当たり前に見えますが、経験上、そもそも for (;;) で書きたくなる処理は反復メソッド等で処理することがむずかしい場合が多いです。

for (;;) で書きたい処理に関しては無理に const で実現しようと思わず、let を使用していいと思います。

3. function をなるべく書かない

functionthis の挙動が特殊なため、特別な理由がない限りは使用しない方が混乱を避けられます。

3.1. コールバック関数はアロー関数を使用する

単にコールバック関数を生成したい場合はアロー関数を使用してください。

参考「アロー関数 - JavaScript | MDN

良くない例
// 
const profiles = {
    _profiles: [{ id: 22, name: 'kitty' }, { id: 1, name: 'puppy' }, { id: 33, name: 'bunny' }],
    _defaultId: 22,
    getDefaultProfile() {
        return this._profiles.find(function (profile) { return profile.id === this._defaultId; });
    }
};

// 
console.log(profiles.getDefaultProfile()); // 出力: undefined
良い例
// 
const profiles = {
    _profiles: [{ id: 22, name: 'kitty' }, { id: 1, name: 'puppy' }, { id: 33, name: 'bunny' }],
    _defaultId: 22,
    getDefaultProfile() {
        return this._profiles.find(profile => profile.id === this._defaultId);
    }
};

// 
console.log(profiles.getDefaultProfile()); // 出力: {id: 22, name: "kitty"}

addEventListener() では this を使用せず、コールバック関数の引数 event から event.currentTarget でイベントがアタッチされた要素を取得できます。

参考「Event - Web API | MDN

3.2. クラスやオブジェクトのメソッド定義を使う

クラスやオブジェクトのメソッドの定義では function を表記せずに定義でき、this に関する混乱は起きにくいです。

(※メソッド単体を取り出すような処理をすると混乱が起きます。)

以前はオブジェクトでのメソッド定義で function が必要でしたが、今では不要です。

参考「クラス - JavaScript | MDN
参考「メソッドの定義 - オブジェクト初期化子 - JavaScript | MDN

3.3. 理論上どうしても必要な場合のみ function

関数を生成したいプログラムで、どうしても function でないと実現不可能な場合もあります。

参考「JavaScript の デコレータ の使い方 - Qiita

3.4. ジェネレータ関数 function* は別物

ジェネレータ関数 function* は見た目は似ていますが、全く別物なので使用して良いです。

参考「function* - JavaScript | MDN

4. then() を書かない

IE 以外の主要ブラウザでは Promise に対応しており、そのいずれもが async, await をサポートしています。

then() は使用せずに await を使用してください。

参考「Promise - JavaScript | MDN
参考「await - JavaScript | MDN

5. jQuery を使わない

jQuery は昔は便利なライブラリでしたが、今では使用するメリットがあまりありません。

jQuery のごく一部の機能を利用するためだけに、WEB ページの読み込み時間を長くするよりも、純粋な Web API を使用するか、より複雑な WEB ページに向いているライブラリの React 等を使用してください。

ソースコードの意味的な構造を小さくできることは可読性が上がり、保守性などの点から見ても良いことですが、jQuery というサイズの大きなライブラリを読み込んだうえで、WEB API の長いメソッド名を $ 1 文字に置き換えることは意味的には規模が変わらず、メリットになりません。

ID やクラス名で要素を取得したいということが分かっているなら、getElementById()getElementsByClassName() を使用したほうが高速に動作します。

jQuery のように複雑なセレクタを用いて要素を取得したい場合は、querySelector()querySelectorAll() を使用してください。

参考「Document.querySelector() - Web API | MDN
参考「Document.querySelectorAll() - Web API | MDN

jQuery.ajax() を使わなくても fetch() で簡単に通信できます。

参考「WindowOrWorkerGlobalScope.fetch() - Web API | MDN

6. XMLHttpRequest を使わない

fetch() で簡単に通信できます。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
24
Help us understand the problem. What are the problem?