JavaScriptでメソッドチェーン対応の計算クラスを作成する方法
課題
本記事では、JavaScriptにおいて値と演算を交互に、任意の回数だけ連鎖(チェーン)できるユーザー定義データ型「Streak」を作成する方法を解説します。
使用できる値は、次のいずれかの文字列です。
one, two, three, four, five, six, seven, eight, nine
また、使用できる演算子は次の文字列です。
plus(加算), minus(減算)
たとえば、このクラスを使って次のように記述したとします。
streak.one.plus.five.minus.three;
このとき、期待される出力結果は次の通りです。
const output = 3;
出力の解説
この結果が得られるのは、内部で次のような計算が行われているためです。
1 + 5 - 3 = 3
まず one で初期値が 1 に設定され、続いて plus.five で 5 が加算され 6 に、最後に minus.three で 3 が減算され、結果として 3 が返されます。
実装コード
以下が実際のコードです。
const Streak = function() {
let value = 0;
const operators = {
'plus': (a, b) => a + b,
'minus': (a, b) => a - b
};
const numbers = [
'zero', 'one', 'two', 'three', 'four', 'five',
'six', 'seven', 'eight', 'nine'
];
// 演算子ごとに、数値プロパティを持つオブジェクトを生成
Object.keys(operators).forEach((operator) => {
const operatorFunction = operators[operator];
const operatorObject = {};
numbers.forEach((num, index) => {
Object.defineProperty(operatorObject, num, {
get: () => value = operatorFunction(value, index)
});
});
// 演算子をNumber.prototypeに追加し、全ての数値から利用可能にする
Number.prototype[operator] = operatorObject;
});
// 初期値としてアクセスできる数値プロパティをインスタンスに定義
numbers.forEach((num, index) => {
Object.defineProperty(this, num, {
get: () => {
value = index;
return Number(index);
}
});
});
};
const streak = new Streak();
console.log(streak.one.plus.five.minus.three);仕組みのポイント
このコードの鍵となるのは getter(ゲッター) の活用です。
- 初期値の設定:
streak.oneのようにアクセスすると、Object.definePropertyで定義された getter が呼ばれ、内部変数valueに該当する数値(1)が代入されます。同時にNumber(index)を返すことで、その後も演算子によるチェーンが可能になります。 - 演算子の連鎖: 演算子オブジェクト(
plusやminus)はNumber.prototypeに登録されているため、返却された数値からさらに.fiveや.threeへのアクセスが可能です。これらも getter なので、参照した瞬間に演算が実行されます。 - 柔軟な拡張性:
operatorsオブジェクトに新しい演算子(例:times(乗算)やdividedBy(除算))を追加すれば、同じ仕組みで簡単に機能を拡張できます。
出力結果
上記のコードを実行すると、コンソールには次のように表示されます。
3
このように getter と prototype を組み合わせることで、自然言語に近い読みやすい連鎖構文を実現できます。DSL(ドメイン固有言語)的なAPI設計の良い練習例として、ぜひ参考にしてください。
-
JavaScriptでリンクリスト(連結リスト)を作成する方法
連結リスト(リンクリスト)は、各要素が「データ」と「次の要素への参照」を持つデータ構造です。配列と異なり、要素の挿入や削除を効率的に行えるのが大きな特徴です。この記事では、JavaScriptを使ってシンプルな連結リストを実装する方法を、サンプルコードとともにわかりやすく解説します。 LinkedListクラスとNodeクラスの定義 まず、headをnullで初期化するコンストラクタを持つシンプルなクラスを定義することから始めましょう。あわせて、LinkedListクラスのプロトタイプに、連結リストの各ノードを表すNodeクラスも定義します。 例 class LinkedList { &nbs
-
JavaScriptで2進数文字列を反転させる方法(0と1の入れ替え)
はじめに今回は、0と1のみで構成される2進数の文字列を受け取り、その反転(すべての0を1に、すべての1を0に入れ替えた結果)を返す関数をJavaScriptで作成する方法を解説します。例えば、入力が「1101」であれば、出力は「0010」になります。このような処理は、ビット演算やデータ変換の基礎として非常に重要です。実装コードそれでは、この関数のコードを見ていきましょう。const num = 1101; const n = 11010111; const inverseBinary = (binary) => { return binar