web-dev-qa-db-ja.com

jQuery / JavaScriptでは1行の関数を避けるべきですか?

そのため、次のコードを作成した方法について同僚に不満を言われました。

...
var foo = getKendoDropdown(window.foo);
var bar = getKendoDropdown(window.foo);
var sna = getKendoDropdown(window.sna);
var fu = getKendoDropdown(window.fu);
...
function getKendoDropdownList(controlId) {
    return $('#' + controlId).data("kendoDropDownList")
}

彼は、jQueryを使用するときに1行の関数を作成する必要はないと述べ、代わりに以下を使用する必要があると述べました。

...
var foo = $('#' + window.foo).data("kendoDropDownList");
var bar = $('#' + window.bar).data("kendoDropDownList");
var sna = $('#' + window.sna).data("kendoDropDownList");
var fu = $('#' + window.fu).data("kendoDropDownList");
...

ただし、C#で以下に遭遇した場合、

...
var redFord = cars.Where(x => x.Name = "Ford").First(x => x.Colour = "Red");
var redToyota = cars.Where(x => x.Brand = "Toyota").First(x => x.Colour = "Red");
...

...私はそれを書いた人なら誰でも、コードの繰り返しを停止して [〜#〜] wet [〜#〜] コードをメソッドに挿入するように指示します:

public static Car FindTheMatchingRed(this IEnumerable<Car> cars, string brand) =>
    cars.Where(x => x.Brand == brand).First(x => x.Colour = "Red");

それで、私の同僚は正しいですか?もしそうなら、なぜですか? JavaScript/jQueryの違いは何ですか。この場合DRYは適用されません。

更新

この場合、「赤」は意味がある(ちょうど「kendoDropDownList」が意味があるのと同じ)ことを指摘して、私の例をより強く(そしてJSの例に近く)する必要があります。たぶん、このコードは、赤い車が違法である国で実行するために必要です。そのため、「x.Colour = "Red"」ロジックは、誤って繰り返されたものから、意味のある同一のものに変わります。私の経験や学習では、これが、繰り返されるロジックの複数のビットを抽象化するかどうかの条件です。

2
Sarov

同僚のポイントがわかります。比較的短いjQuery式を繰り返すことから、少しだけ短い関数呼び出しを繰り返すことへと進みました。これは、名前が大幅に改善されない限り、繰り返し呼び出す関数を作成してもそれほど購入しないサイズの範囲にあると思います。

次のようなものを使用して、繰り返しの多くを削除できます。

const [foo, bar, sna, fu] = ["foo", "bar", "sna", "fu"].map(getKendoDropdown);

これにより、すべてのIDで同じ操作を実行していることが明らかになり、十分に短いので、別の関数を作成する価値があると見なします。はい、getKendoDropdownボディをラムダでインライン化することもできますが、この定式化はすべてを同じ抽象化レベルに保つため、非常にクリーンに感じると思います。

2
Karl Bielefeldt

私の経験に基づいて、私はあなたに同意します。提案された置き換えは、要素の検索ロジックとデータの検索ロジックの多くの繰り返しを導入します。これらはどちらも将来変更される可能性があり、同期が外れるリスクがあります。

より一般的には、ソフトウェアエンジニアリングの抽象的な概念は、特定の言語の構文やツールに関係なく適用されます。せいぜい表面的な規則は異なりますが、そのツールを使用して表現するロジックは、アプリケーションのロジックであり、プログラミング言語のロジックではありません。

1
Denis

ブラウザはその関数呼び出しを最適化できますが( https://www.codereadability.com/performance-cost-javascript-function- call-and-foreach / )。

ただし、この場合、データを取得しているキー( "kendoDropDownList")が1か所にしか存在しないため、コードは読みやすく、リスクが少なくなります。そして、ブラウザがそれを最適化するつもりなら、それをもっと読みやすく/維持可能にしてはどうですか?

1
Jon E

私の経験では、関数を作成しても読みやすさが損なわれ、メリットはありません。

これは、関数が非常に短く、抽象化されていないためです。

関数が長い場合、または関数内のコードよりも抽象的である場合、関数の追加に反対することはありません。


あなたのC#の例についての私の意見は同じです。これをリファクタリングしました:

...
var redFord = cars.Where(x => x.Brand = "Ford").First(x => x.Colour = "Red");
var redToyota = cars.Where(x => x.Brand = "Toyota").First(x => x.Colour = "Red");
...

これに:

...
var redFord = FindBrandedRedCar(cars, "Ford");
var redToyota = FindBrandedRedCar(cars, "Toyota");
...

しかし、なぜ赤いのですか?次の行は次のようになります。

var blueHonda = cars.Where(x => x.Brand = "Honda").First(x => x.Colour = "Blue");

青い車を探しているので、これをFindBrandedRedCarへの呼び出しにリファクタリングすることはできません。引数としてブランドと色を使用するFindBrandedColouredCarを作成できます。

var redFord = FindBrandedColouredCar(cars, "Ford", "Red");
var redToyota = FindBrandedColouredCar(cars, "Toyota", "Red");
var blueHonda = FindBrandedColouredCar(cars, "Honda", "Blue");

しかし、別の基準を検索したい場合はどうでしょうか。すべてのトヨタステーションワゴン? FindBrandedColouredCarではこれを行うことはできないため、FindCarByFieldsに一般化してみましょう。

var redFord = FindCarByFields(cars, "Brand", "Ford", "Colour", "Red");
var redToyota = FindCarByFields(cars, "Brand", "Toyota", "Colour", "Red");
var blueHonda = FindCarByFields(cars, "Brand", "Honda", "Colour", "Blue");
var toyotaStationWagon = FindCarByFields(cars, "Brand", "Toyota", "Style", "StationWagon");

しかし、エンジン排気量が1.5リットル未満の車をどうやって見つけるのでしょうか。フィールドではないため、"Engine.TotalDisplacement"FindCarByFieldsに渡すことはできません。代わりに、ラムダを渡せるようにしましょう:

var redFord = FindCarByLambda(cars, x => x.Brand == "Ford" && x.Colour == "Red");
var redToyota = FindCarByLambda(cars, x => x.Brand == "Toyota" && x.Colour == "Red");
var blueHonda = FindCarByLambda(cars, x => x.Brand == "Honda" && x.Colour == "Blue");
var toyotaStationWagon = FindCarByLambda(cars, x => x.Brand == "Toyota" && x.Style == "StationWagon");
var smallEngineCar = FindCarByLambda(cars, x => x.Engine.TotalDisplacementLitres < 1.5);

ご存知のように、.NETには既にこのメソッドがあります。それはFirstと呼ばれます:

var redFord = cars.First(x => x.Brand == "Ford" && x.Colour == "Red");
var redToyota = cars.First(x => x.Brand == "Toyota" && x.Colour == "Red");
var blueHonda = cars.First(x => x.Brand == "Honda" && x.Colour == "Blue");
var toyotaStationWagon = cars.First(x => x.Brand == "Toyota" && x.Style == "StationWagon");
var smallEngineCar = cars.First(x => x.Engine.TotalDisplacementLitres < 1.5);

ああ、私たちは最初から戻ってきました。関数が実際に何らかの形で役立つ場合にのみ、関数を抽出します。関数を抽出するのに役立つさまざまな方法がたくさんありますが、このような些細な重複を隠すことはそれらの1つではありません。


JavaScriptの例に戻ると、次のようになります。

var foo = getKendoDropdown(window.foo);
var bar = getKendoDropdown(window.foo);
var sna = getKendoDropdown(window.sna);
var fu = getKendoDropdown(window.fu);

ここにはまだ重複があります!このようなコードを書く方がはるかに良いのではないでしょうか?

...
var kendoDropdownLists = getKendoDropdownLists(["foo", "bar", "sna", "fu"]);
...
function getKendoDropdownLists(controlIds) {
    var result = {};
    for (var k = 0; k < controlIds.length; k++) { // pardon me not being up to date with modern JavaScript practices
    {
        var controlId = controlIds[k];
        result[controlId] = $('#' + controlId).data("kendoDropDownList");
    }
    return result;
}
...

ママを見て、重複はまったくありません!しかし、それはより良いですか?私はそうは思いません。

1
user253751