Apakah ada operator “null coalescing” di JavaScript?

1381

Apakah ada operator penggabungan nol di Javascript?

Misalnya, dalam C #, saya bisa melakukan ini:

String someString = null;
var whatIWant = someString ?? "Cookies!";

Perkiraan terbaik yang dapat saya ketahui untuk Javascript menggunakan operator kondisional:

var someString = null;
var whatIWant = someString ? someString : 'Cookies!';

Yang agak IMHO icky. Bisakah saya berbuat lebih baik?

Daniel Schaffer
sumber
31
catatan dari 2018: x ?? ysintaks sekarang dalam status proposal tahap 1 - nullish coalescing
Aprillion
2
Sekarang ada plugin Babel yang menggabungkan sintaksis yang tepat ini.
Jonathan Sudiaman
10
Catatan dari 2019: sekarang adalah status tahap 3!
Daniel Schaffer
3
Catatan dari Januari 2020: Nullish coalescing operator tersedia secara native di Firefox 72 tetapi operator chaining opsional masih tidak.
Kir Kanos
4
Operator penggabungan nullish ( x ?? y) dan operator rantai opsional ( user.address?.street) sekarang keduanya Tahap 4. Berikut adalah deskripsi yang baik tentang apa artinya: 2ality.com/2015/11/tc39-process.html#stage-4%3A-finished .
Mass Dot Net

Jawaban:

2135

Memperbarui

JavaScript sekarang mendukung operator penggabungan nullish (??) . Ini mengembalikan operan sisi kanan ketika operan sisi kiri adalah nullatau undefined, dan sebaliknya mengembalikan operan sisi kiri.

Silakan periksa kompatibilitas sebelum menggunakannya.


Setara JavaScript dari operator penggabungan C # null ( ??) menggunakan logika OR ( ||):

var whatIWant = someString || "Cookies!";

Ada beberapa kasus (diklarifikasi di bawah) bahwa perilaku tidak cocok dengan C #, tetapi ini adalah cara umum, singkat untuk menetapkan nilai default / alternatif dalam JavaScript.


Klarifikasi

Terlepas dari jenis operan pertama, jika casting ke hasil Boolean false, tugas akan menggunakan operan kedua. Waspadalah terhadap semua kasus di bawah ini:

alert(Boolean(null)); // false
alert(Boolean(undefined)); // false
alert(Boolean(0)); // false
alert(Boolean("")); // false
alert(Boolean("false")); // true -- gotcha! :)

Ini berarti:

var whatIWant = null || new ShinyObject(); // is a new shiny object
var whatIWant = undefined || "well defined"; // is "well defined"
var whatIWant = 0 || 42; // is 42
var whatIWant = "" || "a million bucks"; // is "a million bucks"
var whatIWant = "false" || "no way"; // is "false"
Ates Goral
sumber
48
String seperti "false", "undefined", "null", "0", "kosong", "dihapus" semuanya benar karena semuanya adalah string yang tidak kosong.
Beberapa
4
Ini perlu diklarifikasi. "" bukan nol tetapi dianggap falsey. Jadi jika Anda memeriksa nilai untuk null dan kebetulan "" itu tidak akan lulus tes ini dengan benar.
ScottKoon
99
Yang perlu diperhatikan adalah bahwa ||mengembalikan nilai "truey" pertama atau "falsey" terakhir (jika tidak ada yang dapat mengevaluasi ke true) dan yang &&bekerja dengan cara yang berlawanan: mengembalikan nilai truey terakhir atau yang pertama falsey.
Justin Johnson
19
FYI kepada siapa pun yang masih peduli, 0 dan string kosong sedang dievaluasi sama dengan nol jika Anda menggunakan konstruktor tipe ini untuk mendeklarasikannya. var whatIWant = new Number(0) || 42; // is Number {[[PrimitiveValue]]: 0} var whatIWant = new String("") || "a million bucks"; // is String {length: 0, [[PrimitiveValue]]: ""}
Kevin Heidt
5
@LuisAntonioPestana var value = myObj && myObj.property || ''akan kembali ke ''apakah myObj atau myObj.property falsy.
Ates Goral
77
function coalesce() {
    var len = arguments.length;
    for (var i=0; i<len; i++) {
        if (arguments[i] !== null && arguments[i] !== undefined) {
            return arguments[i];
        }
    }
    return null;
}

var xyz = {};
xyz.val = coalesce(null, undefined, xyz.val, 5);

// xyz.val now contains 5

solusi ini berfungsi seperti fungsi SQL coalesce, ia menerima sejumlah argumen, dan mengembalikan nol jika tidak ada yang memiliki nilai. Berperilaku seperti C # ?? operator dalam arti bahwa "", false, dan 0 dianggap TIDAK NULL dan karenanya dianggap sebagai nilai aktual. Jika Anda berasal dari latar belakang .net, ini akan menjadi solusi perasaan yang paling alami.

Brent Larsen
sumber
13
Permintaan maaf untuk penambahan yang terlambat, tetapi saya hanya ingin mencatat untuk kelengkapan bahwa solusi ini memang memiliki peringatan bahwa ia tidak memiliki evaluasi hubung singkat; jika argumen Anda adalah panggilan fungsi maka semuanya akan dievaluasi terlepas dari apakah nilainya dikembalikan, yang berbeda dari perilaku operator OR logis, jadi patut dicatat.
Haravikk
63

Ya, itu akan segera datang. Lihat proposal di sini dan status implementasi di sini .

Ini terlihat seperti ini:

x ?? y

Contoh

const response = {
  settings: {
    nullValue: null,
    height: 400,
    animationDuration: 0,
    headerText: '',
    showSplashScreen: false
  }
};

const undefinedValue = response.settings?.undefinedValue ?? 'some other default'; // result: 'some other default'
const nullValue = response.settings?.nullValue ?? 'some other default'; // result: 'some other default'
const headerText = response.settings?.headerText ?? 'Hello, world!'; // result: ''
const animationDuration = response.settings?.animationDuration ?? 300; // result: 0
const showSplashScreen = response.settings?.showSplashScreen ?? true; // result: false
Vaughan
sumber
2
Ini dalam tahap 3 sekarang, dan direncanakan untuk rilis TypeScript berikutnya! github.com/microsoft/TypeScript/issues/26578
lautaro.dragan
1
Operator penggabungan nullish ( x ?? y) dan operator rantai opsional ( user.address?.street) sekarang keduanya Tahap 4. Berikut adalah deskripsi yang baik tentang apa artinya: 2ality.com/2015/11/tc39-process.html#stage-4%3A-finished .
Mass Dot Net
45

Jika ||sebagai pengganti C # ??tidak cukup baik dalam kasus Anda, karena menelan string dan nol kosong, Anda selalu dapat menulis fungsi Anda sendiri:

 function $N(value, ifnull) {
    if (value === null || value === undefined)
      return ifnull;
    return value;
 }

 var whatIWant = $N(someString, 'Cookies!');
sth
sumber
1
alert (null || '') masih mengingatkan string kosong, dan saya pikir saya benar-benar menyukai peringatan itu ('' || 'bla') mengingatkan bla daripada string kosong - baik untuk diketahui! (+1)
Daniel Schaffer
1
Saya pikir saya mungkin sebenarnya lebih suka mendefinisikan fungsi yang mengembalikan falsejika (ketat) null / tidak terdefinisi dan truesebaliknya - menggunakannya dengan logika atau; itu bisa lebih mudah dibaca daripada banyak panggilan fungsi bersarang. misalnya $N(a) || $N(b) || $N(c) || dlebih mudah dibaca daripada $N($N($N(a, b), c), d).
Bob
Solusi Brent Larsen lebih umum
Assimilater
if .. return .. else ... returnadalah kasus yang sempurna untuk seorang ternary. return (value === null || value === void 0) ? ifnull : value;
Alex McMillan
15

Di sini tidak ada yang menyebutkan potensi NaN, yang - bagi saya - juga merupakan nilai nol-ish. Jadi, saya pikir saya akan menambahkan dua sen saya.

Untuk kode yang diberikan:

var a,
    b = null,
    c = parseInt('Not a number'),
    d = 0,
    e = '',
    f = 1
;

Jika Anda menggunakan ||operator, Anda mendapatkan nilai non-false pertama:

var result = a || b || c || d || e || f; // result === 1

Jika Anda menggunakan metode penggabungan yang khas, seperti yang diposting di sini , Anda akan mendapatkannya c, yang memiliki nilai:NaN

var result = coalesce(a,b,c,d,e,f); // result.toString() === 'NaN'

Tak satu pun dari ini tampaknya benar bagi saya. Dalam dunia kecil saya sendiri dari logika bersatu, yang mungkin berbeda dari dunia Anda, saya menganggap tidak terdefinisi, null, dan NaN sebagai semuanya "null-ish". Jadi, saya berharap untuk mendapatkan kembali d(nol) dari metode penggabungan.

Jika otak siapa pun bekerja seperti otak saya, dan Anda ingin mengecualikan NaN, maka metode ini akan mencapai itu:

function coalesce() {
    var i, undefined, arg;

    for( i=0; i < arguments.length; i++ ) {
        arg = arguments[i];
        if( arg !== null && arg !== undefined
            && (typeof arg !== 'number' || arg.toString() !== 'NaN') ) {
            return arg;
        }
    }
    return null;
}

Bagi mereka yang menginginkan kode sesingkat mungkin, dan tidak keberatan sedikit kejelasan, Anda juga dapat menggunakan ini seperti yang disarankan oleh @impinball. Ini mengambil keuntungan dari kenyataan bahwa NaN tidak pernah sama dengan NaN. Anda dapat membaca lebih lanjut tentang itu di sini: Mengapa NaN tidak sama dengan NaN?

function coalesce() {
    var i, arg;

    for( i=0; i < arguments.length; i++ ) {
        arg = arguments[i];
        if( arg != null && arg === arg ) { //arg === arg is false for NaN
            return arg;
        }
    }
    return null;
}
Kevin Nelson
sumber
Praktik terbaik - memperlakukan argumen seperti array, manfaatkan NaN! == NaN ( typeof+ num.toString() === 'NaN'redundan), simpan argumen saat ini dalam variabel, bukan arguments[i].
Isiah Meadows
@impinball, hasil edit yang Anda sarankan tidak berfungsi, ini mengembalikan NaN daripada 0 (nol) dari test case saya. Secara teknis saya dapat menghapus !== 'number'cek karena saya sudah mengevaluasi bahwa itu bukan nullatau undefined, tetapi ini memiliki keuntungan menjadi sangat jelas bagi siapa saja yang membaca kode ini dan kondisinya akan bekerja terlepas dari pesanan. Saran Anda yang lain sedikit mempersingkat kodenya, jadi saya akan menggunakannya.
Kevin Nelson
2
@impinball, saya menemukan bug Anda di sunting yang Anda sarankan, Anda membiarkannya arg !== arg, tetapi Anda harus arg === arg... kemudian berhasil. Namun, itu memiliki kerugian menjadi sangat tidak jelas tentang apa yang Anda lakukan ... memerlukan komentar dalam kode untuk mencegah dihapus oleh orang berikutnya yang melewati kode dan dianggap arg === argberlebihan ... tapi saya akan memasangnya bagaimanapun.
Kevin Nelson
Tangkapan yang bagus. Dan omong-omong, itu adalah cara cepat memeriksa NaN mengambil keuntungan dari fakta NaN! == NaN. Jika Anda mau, Anda bisa menjelaskannya.
Isiah Meadows
1
periksa "bukan angka" dapat diganti dengan fungsi bawaan: isNaN ()
Yury Kozlov
5

Waspadalah terhadap definisi spesifik JavaScript tentang null. ada dua definisi untuk "tidak ada nilai" dalam javascript. 1. Null: ketika suatu variabel adalah null, itu berarti tidak mengandung data di dalamnya, tetapi variabel sudah didefinisikan dalam kode. seperti ini:

var myEmptyValue = 1;
myEmptyValue = null;
if ( myEmptyValue === null ) { window.alert('it is null'); }
// alerts

dalam kasus seperti itu, tipe variabel Anda sebenarnya adalah Object. menguji.

window.alert(typeof myEmptyValue); // prints Object
  1. Tidak terdefinisi: ketika suatu variabel belum didefinisikan sebelumnya dalam kode, dan seperti yang diharapkan, itu tidak mengandung nilai apa pun. seperti ini:

    if ( myUndefinedValue === undefined ) { window.alert('it is undefined'); }
    // alerts

jika demikian, jenis variabel Anda 'tidak terdefinisi'.

perhatikan bahwa jika Anda menggunakan operator perbandingan konversi tipe (==), JavaScript akan bertindak sama untuk kedua nilai kosong ini. untuk membedakannya, selalu gunakan operator perbandingan ketat-tipe (===).

farzad
sumber
1
Sebenarnya, null adalah sebuah nilai. Ini adalah nilai khusus dari Object type. Variabel yang disetel ke nol berarti berisi data, data menjadi referensi ke objek nol. Variabel dapat didefinisikan dengan nilai yang tidak ditentukan dalam kode Anda. Ini tidak sama dengan variabel yang tidak dideklarasikan.
Ates Goral
Perbedaan aktual antara variabel yang dideklarasikan atau tidak: alert (window.test) / * undefined * /; alert ("test" di jendela) / * false * /; window.test = tidak terdefinisi; lansiran (window.test) / * tidak terdefinisi * /; alert ("test" di jendela) / * true * /; for (var p in window) {/ * p dapat menjadi "test" * /}
Ates Goral
1
Namun (sedikit paradoks) Anda dapat mendefinisikan variabel dengan terdefinisi nilaivar u = undefined;
Serge
@AtesGoral kembali nol. Sementara apa yang Anda katakan itu benar, dengan konvensi , "null" mewakili "tidak adanya data (berguna)" . Oleh karena itu dianggap "tidak ada data". Dan jangan lupa bahwa ini adalah jawaban untuk pertanyaan tentang "operator penggabungan nol"; dalam konteks ini, null jelas diperlakukan sebagai "tidak ada data" - terlepas dari bagaimana itu direpresentasikan secara internal.
ToolmakerSteve
4

Setelah membaca klarifikasi Anda, jawaban @Ates Goral menyediakan cara melakukan operasi yang sama dengan yang Anda lakukan dalam C # dalam JavaScript.

@Gumbo jawaban menyediakan cara terbaik untuk memeriksa nol; namun, penting untuk mencatat perbedaan ==versus ===dalam JavaScript terutama ketika menyangkut masalah pemeriksaan undefineddan / atau null.

Ada artikel yang sangat bagus tentang perbedaan dua istilah di sini . Pada dasarnya, pahami bahwa jika Anda menggunakan ==alih-alih ===, JavaScript akan mencoba menyatukan nilai yang Anda bandingkan dan mengembalikan apa hasil perbandingan setelah penggabungan ini.

Tom
sumber
Satu hal yang mengganggu saya tentang artikel itu (dan Jash) adalah, properti window.hello yang tidak ditentukan sedang dievaluasi menjadi nol karena beberapa alasan. Ini seharusnya tidak didefinisikan sebagai gantinya. Cobalah konsol kesalahan Firefox dan lihat sendiri.
Ates Goral
3

Perhatikan bahwa create-react-apprantai alat React mendukung penggabungan nol sejak versi 3.3.0 (dirilis 5.12.2019) . Dari catatan rilis:

Operator Pengawetan dan Nullish Opsional

Kami sekarang mendukung operator chaining dan nullish opsional!

// Optional chaining
a?.(); // undefined if `a` is null/undefined
b?.c; // undefined if `b` is null/undefined

// Nullish coalescing
undefined ?? 'some other default'; // result: 'some other default'
null ?? 'some other default'; // result: 'some other default'
'' ?? 'some other default'; // result: ''
0 ?? 300; // result: 0
false ?? true; // result: false

Ini mengatakan, jika Anda menggunakan create-react-app3.3.0+ Anda dapat mulai menggunakan operator null-coalesce hari ini di aplikasi Bereaksi Anda.

Lars Blumberg
sumber
3

Ya, dan usulannya adalah Tahap 4 sekarang. Ini berarti bahwa proposal tersebut siap untuk dimasukkan dalam standar formal ECMAScript. Anda sudah dapat menggunakannya di versi desktop Chrome, Edge dan Firefox baru-baru ini, tetapi kami harus menunggu sedikit lebih lama hingga fitur ini mencapai stabilitas lintas-browser.

Lihat contoh berikut untuk menunjukkan perilakunya:

// note: this will work only if you're running latest versions of aforementioned browsers
const var1 = undefined;
const var2 = "fallback value";

const result = var1 ?? var2;
console.log(`Nullish coalescing results in: ${result}`);

Contoh sebelumnya setara dengan:

const var1 = undefined;
const var2 = "fallback value";

const result = (var1 !== null && var1 !== undefined) ?
    var1 :
    var2;
console.log(`Nullish coalescing results in: ${result}`);

Perhatikan bahwa nullish coalescing tidak akan mengancam nilai palsu seperti yang dilakukan ||operator (hanya memeriksa undefinedatau nullnilai), maka cuplikan berikut ini akan bertindak sebagai berikut:

// note: this will work only if you're running latest versions of aforementioned browsers
const var1 = ""; // empty string
const var2 = "fallback value";

const result = var1 ?? var2;
console.log(`Nullish coalescing results in: ${result}`);


Untuk pengguna TypeScript, mulai dari TypeScript 3.7 , fitur ini juga tersedia sekarang.

setia
sumber
2

Mudah-mudahan ini akan segera tersedia dalam Javascript, karena masih dalam tahap proposal pada April, 2020. Anda dapat memantau status di sini untuk kompatibilitas dan dukungan - https://developer.mozilla.org/en-US/docs/Web/ JavaScript / Referensi / Operator / Nullish_coalescing_operator

Untuk orang yang menggunakan TypeScript, Anda bisa menggunakan operator penggabungan nullish dari Typescript 3.7

Dari dokumen -

Anda dapat memikirkan fitur ini - the ?? operator - sebagai cara untuk "mundur" ke nilai default saat berhadapan dengan nullatau undefined. Ketika kita menulis kode suka

let x = foo ?? bar();

ini adalah cara baru untuk mengatakan bahwa nilai fooakan digunakan ketika "hadir"; tetapi ketika itu nullatau undefined, hitung bar()di tempatnya.

Vandesh
sumber
0

Ok jawaban yang tepat

Apakah ada di JavaScript? Ya, benar. TAPI. Saat ini pada 2020-02-06 di Tahap 3 dan belum didukung di mana-mana. Ikuti tautan di URL di bawah ini dan buka tajuk "Spesifikasi" dan "Kompatibilitas peramban" untuk info lebih lanjut tentang di mana ia berada.

Kutipan dari: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator

Nullish coalescing operator (??) adalah operator logis yang mengembalikan operan di sisi kanan ketika operan di sisi kiri adalah null atau tidak terdefinisi, dan sebaliknya mengembalikan operan di sisi kiri.

Berlawanan dengan operator logis OR (||), operan kiri dikembalikan jika itu adalah nilai palsu yang bukan nol atau tidak terdefinisi. Dengan kata lain, jika Anda menggunakan || untuk memberikan beberapa nilai default ke variabel foo lain, Anda mungkin menemukan perilaku tak terduga jika Anda menganggap beberapa nilai falsy dapat digunakan (mis. '' atau 0). Lihat di bawah untuk contoh lebih lanjut.

Mau contoh? Ikuti tautan yang saya posting, semuanya ada.

Karl Morrison
sumber
Tautan MDN sangat membantu tetapi ini adalah jawaban rangkap. Anda harus berkomentar di bawah jawaban vaughan sebagai gantinya.
Chris
@ Chris Jawabannya tidak cukup, maka jawabanku.
Karl Morrison
0

Sekarang ia memiliki dukungan penuh dalam versi terbaru dari peramban utama seperti Chrome, Edge, Firefox, Safari dll. Berikut adalah perbandingan antara operator nol dan Operator Penggabungan Nullish

const response = {
        settings: {
            nullValue: null,
            height: 400,
            animationDuration: 0,
            headerText: '',
            showSplashScreen: false
        }
    };
    /* OR Operator */
    const undefinedValue = response.settings.undefinedValue || 'Default Value'; // 'Default Value'
    const nullValue = response.settings.nullValue || 'Default Value'; // 'Default Value'
    const headerText = response.settings.headerText || 'Hello, world!'; //  'Hello, world!'
    const animationDuration = response.settings.animationDuration || 300; //  300
    const showSplashScreen = response.settings.showSplashScreen || true; //  true
    /* Nullish Coalescing Operator */
    const undefinedValue = response.settings.undefinedValue ?? 'Default Value'; // 'Default Value'
    const nullValue = response.settings.nullValue ?? ''Default Value'; // 'Default Value'
    const headerText = response.settings.headerText ?? 'Hello, world!'; // ''
    const animationDuration = response.settings.animationDuration ?? 300; // 0
    const showSplashScreen = response.settings.showSplashScreen ?? true; //  false
rajesh kumar
sumber