はじめに
思考トレーニングの一環として、LeetCodeを解く過程における思考の軌跡をアウトプットしています。
今回は、JavaScriptを使って「2726. Calculator with Method Chaining」の問題を解いた軌跡を記録していきます。
問題URL:
https://leetcode.com/problems/calculator-with-method-chaining/description/
問題の概要
- 解くのにかかった時間:合計77分
この問題を一言で言うと
足し算・引き算といった計算を行うクラスを設計する問題。
入力(Input)・出力(Output)
ケース1:
入力(Input):
actions = ["Calculator", "add", "subtract", "getResult"], //各メソッドを呼び出し
values = [10, 5, 7]
出力(Output):8
以下のように呼び出して、(10 + 5 - 7 = 8)のように計算しています。
new Calculator(10).add(5).subtract(7).getResult()
ケース2:
入力(Input):
actions = ["Calculator", "divide", "getResult"], //各メソッドを呼び出し
values = [20, 0]
出力(Output): "Division by zero is not allowed"
以下のように呼び出して、(20 / 0 )のように計算する形となり、「Division by zero is not allowed(ゼロによる割り算は許可されません)」というエラーを返します。
new Calculator(20).divide(0).getResult()
条件
以下の6つのメソッドが必要。
- add(加算)
- subtract(減算)
- multiply(掛け算)
- divide(割り算)
- power(べき乗)
- getResult(結果を返す)
※divide(割り算)のみ渡された値が0の場合に「Division by zero is not allowed(ゼロ除算は許可されていません)」というエラーを呼び出す条件がある。
分からなかったことを仮説・調査を通して整理する
①JavaScriptでのべき乗の計算方法
仮説:**を使って対象の値を2乗などで計算する
調査結果:
- 主な方法として、
- べき乗演算子(**)を使う方法
- Math.pow() メソッドを使う方法
の2種類がある。
- 今回はべき乗演算子を使用して実装した
JavaScriptでのclassの設計方法
仮説:class〇〇の下に複数のオブジェクトを指定して、それらのオブジェクトを条件に応じて呼び出す
調査結果:
- データ(プロパティ)とそれを動かす処理(メソッド)を一つにまとめて、コードを分かりやすく再利用しやすくする方法
- 今回の場合だと、
class Calculatorの下にaddやsubtractなどの計算処理を1つにまとめており、呼び出された順番によって足し算・引き算、その他の計算処理を再利用している
③thisの取り扱い・仕様
仮説:今回はオブジェクトが対象なので、this=自由自在に格納・出力出来る空のオブジェクトだと考えた。
調査結果:
- JavaScriptの
thisは、関数が「どのように呼び出されたか」によって値が動的に決まるキーワード - 中身が固定化されていない
- どうやって呼ばれたかによって中身の値が動的に変わる
発生したエラーとその対処法
エラー①:TypeError: calculator.subtract is not a function
元々書いていたコード
subtract(value){
this.value -= value;
return this.value;
}
このコードを書いたときは問題ないと思っていましたが、上記のエラーが出て調査したところメソッドの戻り値が問題であると分かりました。
修正後のコード
subtract(value){
this.value -= value;
return this;
}
JavaScriptのthisは、現在操作しているインスタンスを指すので、
return this;
とすると、計算後もCalculator自身を返すことになります。
簡潔に言うと、
return this.valueでは計算結果の「数値」を返すため、.add(5).subtract(3) と続けて呼ぶと、数値に対してsubtract()などのメソッドを呼ぶことになります。
※本来なら
calculator.add(5).subtract(3);
となっていないところを
15.subtract(3);
と返していたので、エラーが発生していました。
戻り値をreturn thisにすると Calculator 自身を返すため、次の .subtract() を続けて呼べるようになります。(私はそこを理解できていなかったので、最後のgetResultメソッドもreturn this valueにしていました)
不要だった思考・遠回りした部分
- thisを使った実装を思いついて、すぐに実装してしまった点
- もっとthisについて調べていたら、上記の戻り値に関するエラーに躓く事無く実装が完了していたと考えました
最終的な実装
実際の回答コード
class Calculator {
/**
* @param {number} value
*/
constructor(value) {
this.value = value;
}
/**
* @param {number} value
* @return {Calculator}
*/
add(value){
this.value += value;
return this;
}
/**
* @param {number} value
* @return {Calculator}
*/
subtract(value){
this.value -= value;
return this;
}
/**
* @param {number} value
* @return {Calculator}
*/
multiply(value) {
this.value *= value;
return this;
}
/**
* @param {number} value
* @return {Calculator}
*/
divide(value) {
if (value == 0) {
throw new Error("Division by zero is not allowed");
} else {
this.value /= value;
return this;
}
}
/**
* @param {number} value
* @return {Calculator}
*/
power(value) {
this.value **= value;
return this;
}
/**
* @return {number}
*/
getResult() {
return this.value;
}
}
振り返り
分かったこと
- JavaScriptにおけるclassの設計の仕方
- thisを用いたreturnの仕方
まだ分からないこと
- thisの仕様・詳しい使い方
- 多分次にthisを使う問題が出てもすぐに対応できないと思われます