153
134

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

「可読性を上げる」ために敢えてショートハンドを使う

Last updated at Posted at 2019-04-04

この記事はちょこちょこ修正しているため、「この記事は最終更新日からn年以上が経過しています。」の警告が出ませんし、いまでもLGTMをいただきますが、内容は2019年4月のものとなっています。JavaScriptの機能もそれから多く追加・修正されていることにご留意ください。

対象

  • JavaScript 初心者
  • キーを叩きすぎて手が痛くなってしまった人
  • めんどくさがりの人

tl;dr

  • コードゴルフにおいてショートハンドがよくつかわれますが、
    ここでは可読性が高く、かつ文字数を少なくすることができるショートハンドを紹介します。
  • もちろん可読性が高いというのは、人によって基準が異なるので、ここで紹介するのはあくまでも個人的なものです。
  • 使いすぎてはいけません。コーディング規約があればそれを遵守しましょう。

条件分岐

ifの省略 (三項演算子)

before
const month = 5;

if (month >= 5) {
	console.log("令和で、あります。");
} else {
	console.log("平成で、あります。");
}
after
console.log(`${ month >= 5 ? "令和" : "平成" }で、あります。`);

ifの省略 (And演算子)

before
const isReiwa = true;

if (isReiwa) {
	console.log("令和で、あります");
}
after
const isReiwa = true;

isReiwa && console.log("令和で、あります");

&& の左側が truthy と判定されるときに右側が実行される。

エルビス演算子やNull合体演算子の代わり

let v1 = "yeah!!!"
let v2;
console.log(v1 || "default"); //> "yeah!!!"
console.log(v2 || "default"); //> "default"

※注: 厳密には左側が falsy に判定される場合に右側が返される。

falsy と判定される

  • false
  • ""
  • NaN
  • 0
  • undefined
  • null

(truthy については上記以外)

そのため、次のような場合正常な動作が見込めない:

function rotate180(angle) {
	// デフォルトで 90 をセット…???
	angle = angle || 90;

	const rotatedAngle = angle + 180;

	if(rotatedAngle <= 360) {
		return rotatedAngle;
	} else {
		return rotatedAngle - 360;
	}
}

寒気がしますね(これは書かないと思いますが)。
このコードでの問題点は、angle0 が渡されたとき、
次のように解釈されるからです。

/* 1 */ angle = angle || 90
/* 2 */ angle =   0   || 90 // 右側から評価を始める
/* 3 */ angle = false || 90 // `0` は `falsy`
/* 4 */ angle =          90 // 評価が右側に移る

つまり、 0 がセットできない ということです!!!
このような場合は、 パラメータの初期値 のセットを使いましょう。

ループ ※追記

@pxfnc さんより追記

for文で配列の全ての要素にアクセスして何かするパターンにおいて、for(~ of ~)forEachメソッドを使うと漏れがなくループさせることができます。

before
const items = ["foo", "bar", "baz"];

for(let i = 0; i < items.length; ++i) {
    console.log(items[i]);
}

これは以下のように変更できます

after(for~of)
const items = ["foo", "bar", "baz"];

for(const item of items) {
    console.log(item)
}
after(forEach)
const items = ["foo", "bar", "baz"];

items.forEach(item => console.log(item));

要素にアクセスする[i]を忘れるミスだったり、forの条件の書き方を間違えたりループ内でiに代入したりするミスによって無限ループしたり全ての要素にアクセスできなかったりするという地獄から解放されます。ついでにタイプ数が少ないので指が痛くなりません。

関数

アロー関数

before
const doSomething = function(input) {
	return input - 2018;
};

phase1

after-phase1
const doSometing = (input) => {
	return input - 2018;
};

function式アロー関数 は完全に同じではありません。
(this が束縛されない・prototypeがない…)
パフォーマンス等によってアロー関数のほうが優れている場合があります。

phase2 (引数、処理部分のかっこを省略)

after-phase2
const doSomething = input => input - 2018;

アロー関数では、

  • 引数が1つしかない場合、引数を囲むかっこ(丸括弧・パーレン)を
  • 処理と返り値が等しい場合、処理部分を囲むかっこ(波括弧・ブレース)を

省略することができます。

パラメータの初期値

before
function squareArea(width, height) {
	if(width === undefined) {
		width = 10;
	}
	if(height === undefined) {
		height = 5;
	}
	return width * height;
}
after
const squareArea = (width = 10, height = 5) => width * height;

= 10, = 5 部分でデフォルト値を指定できます。

逆に必須にして、エラーを投げたいときは、

const errorThrower = () => {
	throw new Error();
};

const squareArea = (width = 10, height = errorThrower()) => width * height;

パラメータをオブジェクトで受け取って変数に展開

@yuta0801 さんより追記

before
const func1 = obj => {
	const a = obj.a;
	const b = obj.b;
	const c = obj.xxx.c;

	// do something...
};
after
const func2 = ({a, b, xxx: {c}}) => {
	// do something...
	console.log(a, b, c);
};

func2({
	a: "aaa!",
	b: "bbb!",
	xxx: {
		c: "ccc!"
	}
}); //> "aaa!" "bbb!" "ccc!"

標準のJavaScriptの関数の返り値から取り出したリ、
APIを叩いてデータを取得するときにも使えます。

初期値もセットできます。

返り値について返す前に処理

before
const func = num => {
	num += 1;
	return num;
};
after
const func1 = num => ++num;
const func2 = num => (num+=1, num);

代入演算子

代入演算子は、変数に計算結果を代入するが、
同時に、式の値としても計算結果を返す。

let num = 10;
console.log(num += 5); //> 15
console.log(num);      //> 15

+= -= *= /= %= **=

インクリメント・デクリメント、前置・後置

  • 後置 なら加算/減算 の値を返す。
  • 前置 なら加算/減算 の値を返す。

カンマ演算子

複数の式を評価して、最後の結果を返す。

説明は割愛したいと思う。

数値

10の累乗

一、十、百、千、万、十万、、、

1e0 === 1
1e1 === 10
1e2 === 100
1e3 === 1000

6.96e8 === 696000000
1e-10  === 0.0000000001

1e3 は $ 1×10^3 $、
6.96e8 は $ 6.96×10^8 $、
1e-10 は $ 1×10^{-10} $

文字列

1文字取り出す

const str = "abcdefg";

// 3文字目取り出す
str.substring(2, 3); //> "c"
const str = "abcdefg";

str[2]; //> "c"

オブジェクト

プロパティ名とキーが一致している

before
const obj = {
	lorem: lorem,
	ipsum: ipsum
};
after
const obj = {
	lorem,
	ipsum
};

プロパティに関数を代入する ※追記

@yuta0801 さんより追記

before
const obj = {
	name : "Alice",
	greet: function() {
		console.log(`I'm ${this.name}`);
	}
};

after
const obj = {
	name : "Alice",
	greet() {
		console.log(`I'm ${this.name}`);
	}
};

配列をそれぞれの変数に代入する

before
const first = arr[0];
const second = arr[1];
const third = arr[2];
after
const [first, second, third] = arr;

プロパティをそれぞれ変数に代入する

before
const id    = obj.id;
const name  = obj.name;
const birth = obj.birth;
after
const {id, name, birth} = obj;

分割代入はいろいろなタイミングで使えるので、絶対に覚えておくべき。

153
134
11

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
153
134

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?