Bagaimana menulis sebuah operator ternary (aka jika) ekspresi tanpa mengulangi diri sendiri

Sebagai contoh, sesuatu seperti ini:

var value = someArray.indexOf(3) !== -1 ? someArray.indexOf(3) : 0

Apakah ada cara yang lebih baik untuk menulis itu? Sekali lagi, saya tidak mencari jawaban yang tepat untuk pertanyaan di atas, hanya sebuah contoh ketika anda mungkin telah berulang kali operan di operator ternary ekspresi...

Mengomentari pertanyaan (13)

Secara pribadi saya menemukan cara terbaik untuk melakukan ini adalah masih baik tua jika pernyataan:

var value = someArray.indexOf(3);
if (value === -1) {
  value = 0;
}
Komentar (7)

Kode harus mudah dibaca, sehingga menjadi ringkas tidak harus berarti menjadi singkat dengan biaya - untuk itu anda harus repost https://codegolf.stackexchange.com/ - jadi sebagai gantinya saya akan merekomendasikan menggunakan kedua variabel lokal bernama index untuk memaksimalkan membaca comprehensibility (dengan minimal runtime biaya juga, saya perhatikan):

var index = someArray.indexOf( 3 );
var value = index == -1 ? 0 : index;

Tetapi jika anda benar-benar ingin memotong ungkapan ini turun, karena anda're kejam sadis untuk teman kerja atau proyek kolaborator, maka di sini ada 4 pendekatan yang dapat anda gunakan:

1: variabel Sementara di var pernyataan

Anda dapat menggunakan var pernyataan's kemampuan untuk menentukan (dan menetapkan) kedua variabel sementara index ketika dipisahkan dengan koma:

var index = someArray.indexOf(3), value = index !== -1 ? index: 0;

2: Self-executing fungsi anonim

Pilihan lain adalah aplikasi self-executing anonim fungsi:

// 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) );

3: operator Koma

Ada juga terkenal "operator koma" yang mendukung JavaScript, yang juga hadir dalam C dan C++.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comma_Operator

Anda dapat menggunakan operator koma ketika anda ingin memasukkan beberapa ekspresi di lokasi yang membutuhkan ekspresi tunggal.

Anda dapat menggunakannya untuk memperkenalkan efek samping, dalam hal ini oleh pemindahan untuk nilai:

var value = ( value = someArray.indexOf(3), value !== -1 ? value : 0 );

Ini bekerja karena var nilai ditafsirkan terlebih dahulu (seperti's pernyataan), dan kemudian paling kiri, batin-paling nilai tugas, dan kemudian tangan kanan dari operator koma, dan kemudian operator ternary - semua hukum JavaScript.

4: Re-assign di subexpressionn

Komentator @IllusiveBrian menunjukkan bahwa penggunaan koma operator (pada contoh sebelumnya) ini tidak dibutuhkan jika tugas untuk nilai yang digunakan sebagai tanda kurung subexpressionn:

var value = ( ( value = someArray.indexOf(3) ) !== -1 ? value : 0 );

Perhatikan bahwa penggunaan negatif dalam ekspresi logis dapat menjadi sulit bagi manusia untuk mengikuti - jadi semua contoh di atas dapat disederhanakan untuk membaca dengan mengubah idx !== -1 ? x : y untuk idx == -1 ? y : x:

var value = ( ( value = someArray.indexOf(3) ) == -1 ? 0 : value );
Komentar (15)

Untuk nomor

Anda dapat menggunakan Matematika.max()` fungsi.

var value = Math.max( someArray.indexOf('y'), 0 );

Ini akan menjaga batas-batas hasil dari 0 sampai hasil pertama yang lebih besar dari 0 jika's terjadi. Dan jika hasil dari indexOf adalah -1 maka akan mengembalikan 0 sebagai lebih besar dari -1.

Untuk boolean dan boolean-nilai y

Untuk JS tidak ada aturan umum AFAIK khusus karena cara falsy nilai-nilai dievaluasi.

Tapi jika sesuatu yang dapat membantu anda sebagian besar waktu adalah operator or (||):

// Instead of
var variable = this_one === true ? this_one : or_this_one;
// you can use
var variable = this_one || or_this_one;

Anda harus sangat berhati-hati dengan ini, karena dalam contoh pertama, indexOf dapat kembali 0 dan jika anda mengevaluasi 0 || -1 itu akan kembali -1 karena 0 adalah falsy nilai.

Komentar (6)

Tidak benar-benar, hanya menggunakan variabel lain.

Contoh generalisasi untuk sesuatu seperti ini.

var x = predicate(f()) ? f() : default;

Anda're pengujian dihitung nilai, kemudian menetapkan nilai ke variabel jika melewati beberapa predikat. Cara untuk menghindari re-menghitung nilai yang dihitung adalah jelas: menggunakan variabel untuk menyimpan hasil.

var computed = f();
var x = predicate(computed) ? computed : default;

Aku mendapatkan apa yang anda maksud - sepertinya harus ada beberapa cara untuk melakukan hal ini yang terlihat sedikit lebih bersih. Tapi saya berpikir bahwa's cara terbaik (ideomatik) untuk melakukan hal ini. Jika anda mengulangi pola ini banyak di kode anda untuk beberapa alasan, anda mungkin akan menulis sedikit helper fungsi:

var setif = (value, predicate, default) => predicate(value) ? value : default;
var x = setif(someArray.indexOf(3), x => x !== -1, 0)
Komentar (0)

EDIT: di Sini itu adalah, proposal untuk Nullary-penggabungan sekarang di JavaScript!


Gunakan ||

const hasil = a ? a : 'fallback nilai';

setara dengan

const hasil = a || 'fallback nilai';

Jika casting a ke Boolean kembali false, hasil akan ditugaskan 'fallback nilai', jika nilai dari a.


Menyadari edge case a === 0, yang melemparkan untuk palsu dan akibat akan (salah) mengambil 'fallback nilai' . Menggunakan trik seperti ini di risiko anda sendiri.


PS. Bahasa seperti Swift memiliki nihil-penggabungan operator (??), yang melayani tujuan yang sama. Untuk contoh, secara Cepat anda akan menulis hasil = a ?? "fallback nilai" yang cukup dekat dengan JavaScript's const hasil = a || 'fallback nilai';

Komentar (7)

Menggunakan ekstrak variabel refactoring:

var index = someArray.indexOf(3);
var value = index !== -1 ? index : 0

Hal ini bahkan lebih baik dengan const bukan var. Anda juga bisa melakukan tambahan ekstraksi:

const index = someArray.indexOf(3);
const condition = index !== -1;
const value = condition ? index : 0;

Dalam prakteknya, lebih banyak menggunakan nama yang bermakna dari index, kondisi, dan nilai.

const threesIndex = someArray.indexOf(3);
const threeFound = threesIndex !== -1;
const threesIndexOrZero = threeFound ? threesIndex : 0;
Komentar (1)

Saya pribadi lebih memilih dua varian:

  1. Murni jika, seperti @slebetman menyarankan

  2. Memisahkan fungsi, yang menggantikan tidak valid dengan nilai default, seperti dalam contoh ini:

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
Komentar (1)

Anda're mungkin mencari penggabungan operator. Untungnya, kita dapat memanfaatkan Fasilitas prototipe untuk membuat satu:

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

Ini bisa menjadi lebih umum untuk kasus anda, dengan menambahkan parameter ke fungsi:

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
Komentar (2)

Aku suka @slebetman's jawaban. Komentar di bawah ini menyatakan keprihatinan tentang variabel yang di "intermediate negara". jika ini merupakan masalah besar bagi anda maka saya sarankan melingkupinya dalam sebuah fungsi:

function get_value(arr) {
   var value = arr.indexOf(3);
   if (value === -1) {
     value = 0;
   }
   return value;
}

Kemudian hanya panggilan

var value = get_value( someArray );

Anda bisa melakukan fungsi yang lebih umum jika anda telah menggunakan mereka di tempat-tempat lain, tapi don't over-insinyur jika itu's yang sangat spesifik kasus ini.

Tapi jujur saya hanya akan melakukan seperti yang @slebetman kecuali aku yang dibutuhkan untuk menggunakan kembali dari beberapa tempat.

Komentar (0)

Ada dua cara yang saya bisa melihat melihat pertanyaan anda: anda ingin mengurangi panjang garis, atau anda secara khusus ingin menghindari pengulangan variabel dalam terner. Yang pertama adalah sepele (dan banyak orang lain telah diposting contoh):

var value = someArray.indexOf(3) !== -1 ? someArray.indexOf(3) : 0;

dapat (dan harus, mengingat fungsi panggilan) disingkat seperti:

var value = someArray.indexOf(3);
value = value !== -1 ? value : 0;

Jika anda mencari untuk lebih generik solusi yang mencegah pengulangan dari sebuah variabel dalam sebuah terner, seperti:

var value = conditionalTest(foo) ? foo : bar;

di mana foo hanya muncul sekali. Membuang solusi dalam bentuk:

var cad = foo;
var value = conditionalTest(foo) ? cad : bar;

secara teknis benar, tetapi titik hilang, maka anda beruntung. Ada operator, fungsi, dan metode yang memiliki terse sintaks yang anda cari, tetapi seperti konstruksi, menurut definisi, tidak't ternary operators.

Contoh:

javascript, menggunakan || untuk kembali RHS ketika LHS adalah falsey:

var value = foo || bar; // equivalent to !foo ? bar : foo
Komentar (2)

Menggunakan fungsi pembantu:

function translateValue(value, match, translated) {
   return value === match ? translated : value;
}

Sekarang anda kode ini sangat mudah dibaca, dan ada's tidak ada pengulangan.

var value = translateValue(someArray.indexOf(3), -1, 0);

Hirarki coding kekhawatiran adalah:

  1. Yang benar (termasuk sejati kinerja atau SLA kekhawatiran)
  2. Jelas
  3. Singkat
  4. Cepat

Semua jawaban pada halaman yang sejauh ini tampak benar, tapi saya pikir saya memiliki versi kejelasan tertinggi, yang lebih penting dari keringkasan. Jika anda don't hitung fungsi pembantu—seperti itu dapat digunakan kembali—ini adalah yang paling ringkas juga. Agak mirip saran untuk menggunakan fungsi pembantu sayangnya menggunakan lambda itu, bagi saya, hanya mengaburkan apa itu's lakukan. Sederhana fungsi dengan satu tujuan yang doesn't mengambil lambda, hanya nilai-nilai, adalah untuk saya jauh lebih baik.

P. S. Jika anda suka ES6 sintaks:

const translateValue = (value, match, translated) => value === match ? translated : value;
let value = translateValue(someArray.indexOf(3), -1, 0); // or const
Komentar (6)

Saya pikir || operator dapat disesuaikan dengan indexOf:

var value = ((someArray.indexOf(3) + 1) || 1) - 1;

Nilai yang dikembalikan adalah bergeser sampai dengan 1, sehingga 0 dari -1, yang falsey dan oleh karena itu akan digantikan oleh kedua 1. Maka itu bergeser kembali.

Namun, harap diingat bahwa pembacaan yang lebih unggul untuk menghindari pengulangan.

Komentar (0)

Ini adalah solusi sederhana dengan bitwise NOT dan nilai default -1 yang hasilnya kemudian menjadi nol.

index = ~(~array.indexOf(3) || -1);

Itu pada dasarnya bekerja dengan double bitwise TIDAK, yang mengembalikan nilai asli atau nilai default, yang setelah menerapkan bitwise TIDAK kembali nol.

Let's memiliki tampilan tabel kebenaran:

indexOf ~indexOf boolean nilai default hasil komentar


      -1          0     falsy          -1         -1          0   take default value
       0         -1    truthy                     -1          0
       1         -2    truthy                     -2          1
       2         -3    truthy                     -3          2
Komentar (0)

Anda bisa menggunakan kembali tugas:

  • inisialisasi variabel untuk satu nilai
  • gunakan serialisasi dari && operator untuk penugasan kembali, karena jika kondisi pertama salah, kedua ekspresi won't dievaluasi

Ex.

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);
Komentar (7)

Untuk kasus ini, anda bisa menggunakan short-circuiting dengan logis || operator. Sebagai 0 dianggap falsy, anda dapat +1 ke indeks, dengan demikian, jika index+1 dan 0 maka anda'll mendapatkan sisi kanan kembali sebagai hasil anda, jika tidak, anda'll mendapatkan index+1. Anda kemudian dapat -1 dari hasil ini untuk mendapatkan indeks:

const someArray = [1, 2, 3, 4];
const v = ((someArray.indexOf(3)+1) || 1)-1;
console.log(v);
Komentar (0)

Ternary adalah seperti if-else, jika anda don't perlu lagi bagian, mengapa tidak hanya satu jika sebaliknya..

if ((value = someArray.indexOf(3)) < 0) value = 0;
Komentar (0)

Diberikan contoh kode pada Pertanyaan tidak jelas bagaimana hal itu akan ditentukan bahwa 3 atau tidak diatur di index 0 dari someArray. -1 kembali .indexOf() akan berharga dalam hal ini, untuk tujuan tidak termasuk yang diduga non-pertandingan yang bisa menjadi sebuah pertandingan.

Jika 3 tidak termasuk dalam array, -1 akan dikembalikan. Kita dapat menambahkan 1 hasil .indexOf() untuk mengevaluasi sebagai false untuk hasil yang -1, di mana diikuti oleh || ATAU operator dan 0. Ketika nilai yang dirujuk, kurangi 1 untuk mendapatkan indeks dari elemen array atau -1.

Yang mengarah kembali untuk hanya menggunakan .indexOf() dan memeriksa -1 di jika kondisi. Atau, mendefinisikan nilai sebagai undefined untuk menghindari kebingungan yang mungkin untuk hasil yang sebenarnya dari dievaluasi kondisi yang berkaitan dengan referensi asli.

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);
Komentar (0)