たとえば、次のようなもの:
var value = someArray.indexOf(3) !== -1 ? someArray.indexOf(3) : 0
それを書くより良い方法はありますか?繰り返しますが、上記の正確な質問への答えを求めているのではなく、三項演算子式で繰り返しオペランドを使用する可能性がある場合の例です...
個人的には、これを行うための最良の方法は、古き良きif
ステートメントであると思います。
var value = someArray.indexOf(3);
if (value === -1) {
value = 0;
}
コードは読みやすいものでなければならないので、簡潔であることはどんなコストであっても簡潔であることを意味するべきではありません-そのためには、 https://codegolf.stackexchange.com/ に再投稿する必要があります。 index
という名前の変数は、読みやすさを最大化するために(実行時のコストも最小限に抑えています):
var index = someArray.indexOf( 3 );
var value = index == -1 ? 0 : index;
しかし、同僚やプロジェクトの協力者にとって残酷なサディストであるため、この表現を本当に減らしたい場合は、次の4つのアプローチを使用できます。
var
ステートメントの一時変数var
ステートメントの機能を使用して、コンマで区切られたときに2番目の一時変数index
を定義(および割り当て)できます。
var index = someArray.indexOf(3), value = index !== -1 ? index: 0;
別のオプションは、自己実行の匿名関数です。
// Traditional syntax:
var value = function( x ) { return x !== -1 ? x : 0 }( someArray.indexOf(3) );
// ES6 syntax:
var value = ( x => x !== -1 ? x : 0 )( someArray.indexOf(3) );
JavaScriptがサポートする悪名高い「コンマ演算子」もあります。これは、CおよびC++にも存在します。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator
単一の式が必要な場所に複数の式を含める場合は、カンマ演算子を使用できます。
これを使用して、value
に再割り当てすることにより、副作用を導入できます。
var value = ( value = someArray.indexOf(3), value !== -1 ? value : 0 );
これは、var value
が最初に(ステートメントとして)解釈され、then左端、最も内側のvalue
割り当て、次に右コンマ演算子の手、次に三項演算子-すべて正当なJavaScript。
コメンテーター@IllusiveBrianは、value
への割り当てが括弧付きの部分式として使用される場合、コンマ演算子(前の例)の使用は不要であると指摘しました。
var value = ( ( value = someArray.indexOf(3) ) !== -1 ? value : 0 );
論理式での否定の使用は人間にとって従うのが難しい場合があることに注意してください。したがって、上記の例はすべてidx !== -1 ? x : y
をidx == -1 ? y : x
に変更することで読みやすくなります。
var value = ( ( value = someArray.indexOf(3) ) == -1 ? 0 : value );
数字の場合
Math.max()
関数を使用できます。
var value = Math.max( someArray.indexOf('y'), 0 );
最初の結果が0
より大きい場合は、0
からの結果の境界を保持します。 indexOf
の結果が-1
の場合、-1
より大きい0を返します。
ブール値とブール値yの場合
JSの場合、 falsy 値がどのように評価されるかという理由で、特別な一般規則はありません。
しかし、何かがほとんどの場合に役立つ場合は、or演算子(||
)です:
// Instead of
var variable = this_one === true ? this_one : or_this_one;
// you can use
var variable = this_one || or_this_one;
最初の例では、indexOf
は0
を返すことができ、0 || -1
を評価すると、-1
は falsy 値であるため、0
を返すため、これには非常に注意する必要があります。
実際には、別の変数を使用するだけです。
あなたの例はこのようなものに一般化します。
var x = predicate(f()) ? f() : default;
計算された値をテストし、述語を渡す場合にその値を変数に割り当てます。計算値の再計算を避ける方法は明らかです。結果を保存するために変数を使用します。
var computed = f();
var x = predicate(computed) ? computed : default;
私はあなたの言うことを理解します-これを行うには、少しきれいに見える何らかの方法があるはずです。しかし、私はこれを行うのに(イディオム的に)最良の方法だと思います。何らかの理由でコード内でこのパターンを何度も繰り返している場合は、少しのヘルパー関数を作成できます。
var setif = (value, predicate, default) => predicate(value) ? value : default;
var x = setif(someArray.indexOf(3), x => x !== -1, 0)
||
を使用
const result = a ? a : 'fallback value';
に等しい
const result = a || 'fallback value';
a
をBoolean
にキャストすると、false
が返される場合、result
に'fallback value'
が割り当てられ、そうでない場合はa
の値が割り当てられます。
false
とresult
にキャストするEdgeのケースa === 0
に注意してください(誤って)'fallback value'
を使用します。自己責任でこのようなトリックを使用してください。
PS。 Swiftなどの言語には nil-coalescing 演算子(??
)があり、これは同様の目的を果たします。たとえば、Swiftには、JavaScriptのresult = a ?? "fallback value"
に非常に近いconst result = a || 'fallback value';
を記述します。
変数リファクタリングの抽出 を使用します。
var index = someArray.indexOf(3);
var value = index !== -1 ? index : 0
const
の代わりにvar
を使用することをお勧めします。追加の抽出を行うこともできます。
const index = someArray.indexOf(3);
const condition = index !== -1;
const value = condition ? index : 0;
実際には、index
、condition
、およびvalue
よりも意味のある名前を使用してください。
const threesIndex = someArray.indexOf(3);
const threeFound = threesIndex !== -1;
const threesIndexOrZero = threeFound ? threesIndex : 0;
私は個人的に2つのバリアントを好みます:
純粋な場合、@ slebetmanが提案したように
この例のように、無効な値をデフォルトの値に置き換える別の関数:
function maskNegative(v, def) {
return v >= 0 ? v : def;
}
Array.prototype.indexOfOrDefault = function(v, def) {
return maskNegative(this.indexOf(v), def);
}
var someArray = [1, 2];
console.log(someArray.indexOfOrDefault(2, 0)); // index is 1
console.log(someArray.indexOfOrDefault(3, 0)); // default 0 returned
console.log(someArray.indexOfOrDefault(3, 123)); // default 123 returned
おそらく合体演算子を探しています。幸いなことに、Array
プロトタイプを利用してプロトタイプを作成できます。
Array.prototype.coalesce = function() {
for (var i = 0; i < this.length; i++) {
if (this[i] != false && this[i] != null) return this[i];
}
}
[null, false, 0, 5, 'test'].coalesce(); // returns 5
関数にパラメーターを追加することで、これをさらに一般化できます。
Array.prototype.coalesce = function(valid) {
if (typeof valid !== 'function') {
valid = function(a) {
return a != false && a != null;
}
}
for (var i = 0; i < this.length; i++) {
if (valid(this[i])) return this[i];
}
}
[null, false, 0, 5, 'test'].coalesce(); // still returns 5
[null, false, 0, 5, 'test'].coalesce(function(a){return a !== -1}); // returns null
[null, false, 0, 5, 'test'].coalesce(function(a){return a != null}); //returns false
@slebetmanの答えが好きです。その下のコメントは、変数が「中間状態」にあることに対する懸念を表しています。これがあなたにとって大きな懸念であれば、関数にカプセル化することをお勧めします:
function get_value(arr) {
var value = arr.indexOf(3);
if (value === -1) {
value = 0;
}
return value;
}
それからちょうど電話
var value = get_value( someArray );
他の場所でそれらを使用している場合は、より汎用的な機能を実行できますが、非常に特殊なケースの場合は過剰なエンジニアリングをしないでください。
しかし、正直に言うと、複数の場所から再利用する必要がない限り、@ slebetmanとして実行します。
私はあなたの質問を見るのに2つの方法があります:あなたは行の長さを短くしたい、または三項で変数を繰り返すことを避けたいのです。 1つ目は簡単です(他の多くのユーザーが例を投稿しています)。
var value = someArray.indexOf(3) !== -1 ? someArray.indexOf(3) : 0;
次のように短縮することができます(関数呼び出しを考えると、そうすべきです):
var value = someArray.indexOf(3);
value = value !== -1 ? value : 0;
次のように、3進数の変数の繰り返しを防ぐより一般的なソリューションを探している場合:
var value = conditionalTest(foo) ? foo : bar;
foo
は1回だけ表示されます。次の形式のソリューションの破棄:
var cad = foo;
var value = conditionalTest(foo) ? cad : bar;
技術的には正しいが、ポイントが欠落している場合、あなたは運が悪い。求める簡潔な構文を持つ演算子、関数、およびメソッドがありますが、そのような構成体は、定義により三項演算子ではありません。
例:
javascript、||
を使用して、LHSがfalsey
のときにRHSを返します。
var value = foo || bar; // equivalent to !foo ? bar : foo
ヘルパー関数を使用します。
function translateValue(value, match, translated) {
return value === match ? translated : value;
}
これでコードは非常に読みやすくなり、繰り返しはありません。
var value = translateValue(someArray.indexOf(3), -1, 0);
コーディングの問題の階層は次のとおりです。
これまでのところ、ページ上のすべての回答は正しいように見えますが、私のバージョンは簡潔さよりも重要な最高の明快さを持っていると思います。ヘルパー関数は、再利用できるためカウントしない場合、最も簡潔です。ヘルパー関数を使用するというやや似たような提案は、残念ながらラムダを使用しますが、ラムダはそれが何をしているのかわかりにくくしています。ラムダを使用せず、値だけを使用する1つの目的を持つ単純な関数の方がはるかに優れています。
追伸ES6構文が好きな場合:
const translateValue = (value, match, translated) => value === match ? translated : value;
let value = translateValue(someArray.indexOf(3), -1, 0); // or const
||
演算子はindexOf
に合わせて調整できると思います。
var value = ((someArray.indexOf(3) + 1) || 1) - 1;
返される値は1だけ上にシフトされ、-1から0を作成します。これは偽であり、したがって2番目の1に置き換えられます。その後、戻されます。
ただし、繰り返しを避けるよりも読みやすさが優れていることに注意してください。
これは bitwise NOT と-1
のデフォルト値を使用した単純なソリューションで、後でゼロになります。
index = ~(~array.indexOf(3) || -1);
基本的には、元の値またはデフォルト値を返す二重ビット単位のNOTで機能します。デフォルト値は、ビット単位のNOTを適用するとゼロを返します。
真理値表を見てみましょう。
indexOf ~indexOf boolean default value result comment --------- --------- --------- --------- --------- --------- ------------------ -1 0 falsy -1 -1 0 take default value 0 -1 truthy -1 0 1 -2 truthy -2 1 2 -3 truthy -3 2
再割り当てを使用できます:
&&
演算子のシリアル化を使用します例.
var value = someArray.indexOf(3);
value == -1 && (value=0);
var someArray = [4,3,2,1];
var value = someArray.indexOf(1);
value == -1 && (value=0);
console.log('Found:',value);
var value = someArray.indexOf(5);
value == -1 && (value=0);
console.log('Not Found:',value);
質問のサンプルコードを考えると、3
がsomeArray
のインデックス0
に設定されているかどうかがどのように判断されるかは明確ではありません。 .indexOf()
から返された-1
は、一致する可能性のある推定される不一致を除外するために、このインスタンスで価値があります。
3
が配列に含まれていない場合、-1
が返されます。 1
を.indexOf()
の結果に追加して、結果が-1
であるfalse
として評価できます。ここで、||
OR
演算子と0
が続きます。 value
が参照されている場合、1
を減算して、配列または-1
の要素のインデックスを取得します。
これは、単に.indexOf()
を使用し、if
条件で-1
をチェックすることにつながります。または、value
をundefined
として定義して、元の参照に関連する評価条件の実際の結果に関する混乱を回避します。
var someArray = [1,2,3];
var value = someArray.indexOf(3) + 1 || 1;
console.log(value -= 1);
var someArray = [1,2,3];
var value = someArray.indexOf(4) + 1 || 1;
// how do we know that `4` is not at index `0`?
console.log(value -= 1);
var someArray = [1,2,3];
var value = someArray.indexOf(4) + 1 || void 0;
// we know for certain that `4` is not found in `someArray`
console.log(value, value = value || 0);
ターナリはif-elseのようなものです。elseの部分が必要ない場合は、代わりに単一のifを使用してください。
if ((value = someArray.indexOf(3)) < 0) value = 0;