Чи є в JavaScript оператор “null coalescing”?


1381

Чи є в Javascript нульовий оператор згортання?

Наприклад, у C # я можу це зробити:

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

Найкраще наближення, яке я можу зрозуміти для Javascript, - це використання умовного оператора:

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

Що таке своєрідне ІМХО. Чи можу я зробити краще?


31
Примітка від 2018 року: x ?? yсинтаксис зараз перебуває у статусі пропозиції 1 етапу - нульове з’єднання
квітня

2
Зараз існує плагін Babel, який містить саме цей синтаксис.
Джонатан Судяман

10
Примітка від 2019 року: зараз статус 3 етапу!
Даніель Шаффер

3
Примітка від січня 2020 року: Nullish оператор злиття доступний в оригіналі в Firefox 72, але необов'язковий оператор ланцюга все ще немає.
Кір Канос

4
Нульовий оператор злиття ( x ?? y) та необов'язковий оператор ланцюга ( user.address?.street) тепер є етапом 4. Ось хороший опис того, що це означає: 2ality.com/2015/11/tc39-process.html#stage-4%3A-finished .
Mass Dot Net

Відповіді:


2133

Оновлення

Тепер JavaScript підтримує нульовий оператор злиття (??) . Він повертає його правого операнда, коли його лівий операнд - nullабо undefined, інакше повертає його лівий операнд.

Перевірте сумісність перед її використанням.


Еквівалент JavaScript оператора ??з’єднання C # null ( ) використовує логічний АБО ( ||):

var whatIWant = someString || "Cookies!";

Є випадки (пояснено нижче), що поведінка не відповідає поведінці C #, але це загальний, нетривалий спосіб призначення значень за замовчуванням / альтернативою в JavaScript.


Уточнення

Незалежно від типу першого операнда, якщо приведення його до булевих результатів при falseпризначенні використовуватиме другий операнд. Остерігайтеся всіх випадків нижче:

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

Це означає:

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"

48
Рядки, такі як "false", "undefined", "null", "0", "empty", "delete", істинні, оскільки вони є не порожніми рядками.
десь

4
Це потрібно з’ясувати. "" не є нульовим, але вважається фальсийним. Тож якщо ви перевіряєте значення null, і це трапляється, він не "" пройде правильно цей тест.
ScottKoon

99
Слід зазначити, що ||повертає перше значення "truey" або останнє "falsey" (якщо жодне не може оцінити істинне), і воно &&працює в зворотному напрямку: повернення останнього значення true або першого фальси.
Джастін Джонсон,

19
FYI будь-кому, хто все ще переймається, 0 і порожній рядок оцінюються такими ж, як і нулі, якщо ви використовуєте конструктор типу для оголошення цього. var whatIWant = new Number(0) || 42; // is Number {[[PrimitiveValue]]: 0} var whatIWant = new String("") || "a million bucks"; // is String {length: 0, [[PrimitiveValue]]: ""}
Кевін Хайдт

5
@LuisAntonioPestana var value = myObj && myObj.property || ''повернеться до того, що ''якщо myObj або myObj.property є хибним.
Атес Горал

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

це рішення працює як функція змикання SQL, воно приймає будь-яку кількість аргументів і повертає нуль, якщо жоден з них не має значення. Він поводиться як C # ?? оператора в тому сенсі, що "", false і 0 вважаються НЕ НУЛЬНИМ і тому вважаються фактичними значеннями. Якщо ви походите з .net фону, це буде найбільш природним рішенням почуттів.



13
Вибачте за таке пізнє доповнення, але я просто хотів відзначити повноту, що це рішення має застереження, що воно не має короткого замикання; якщо ваші аргументи викликів функції , то вони будуть все бути оцінені незалежно від того , повертається їх вартість, яка відрізняється від поведінки логічного оператора АБО, тому варто відзначити.
Харавік

63

Так, це скоро. Дивіться пропозицію тут та статус реалізації тут .

Це виглядає приблизно так:

x ?? y

Приклад

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

2
Зараз він знаходиться на етапі 3, і планується наступний реліз TypeScript! github.com/microsoft/TypeScript/issues/26578
lautaro.dragan

1
Нульовий оператор злиття ( x ?? y) та необов'язковий оператор ланцюга ( user.address?.street) тепер є етапом 4. Ось хороший опис того, що це означає: 2ality.com/2015/11/tc39-process.html#stage-4%3A-finished .
Mass Dot Net

45

Якщо ||замість C # ??у вашому випадку недостатньо хороша, оскільки вона проковтує порожні рядки та нулі, ви завжди можете написати власну функцію:

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

 var whatIWant = $N(someString, 'Cookies!');

1
alert (null || '') все ще сповіщає про порожню рядок, і я думаю, що мені насправді подобається це попередження ('' || 'blah') попередження blah, а не порожня рядок - все-таки добре знати! (+1)
Даніель Шаффер

1
Я думаю, що я міг би віддати перевагу визначенню функції, яка повертається, falseякщо (строго) нульова / невизначена, trueінакше - використовуючи її з логічним або; це може бути читабельніше, ніж багато вкладених функцій викликів. наприклад $N(a) || $N(b) || $N(c) || d, читабельніше, ніж $N($N($N(a, b), c), d).
Боб

Рішення Брента Ларсена є більш загальним
асимілятор

if .. return .. else ... returnє ідеальним випадком для трійника. return (value === null || value === void 0) ? ifnull : value;
Алекс Макміллан

15

Тут ніхто не згадав про потенціал NaN, який, для мене, також є нульовим значенням. Отже, я думав, що додам свої два центи.

Для даного коду:

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

Якщо ви хочете скористатися ||оператором, ви отримаєте перше неправдиве значення:

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

Якщо ви використовуєте типовий метод злиття, який розміщено тут , ви отримаєте c, який має значення:NaN

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

Жодне з них мені не здається правильним. У моєму власному маленькому світі зв'язаної логіки, який може відрізнятися від вашого світу, я вважаю невизначеним, нульовим і NaN як усі "недійсними". Отже, я б розраховував повернутися d(нуль) методом коалесценції.

Якщо мозок когось працює як мій, і ви хочете виключити NaN, то цей метод досягне цього:

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;
}

Для тих, хто хоче, щоб код був максимально коротким і не мав уваги з невеликою недостатністю ясності, ви також можете використовувати це, як запропонував @impinball. Це використовує той факт, що NaN ніколи не дорівнює NaN. Більше про це можна прочитати тут: Чому NaN не дорівнює 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;
}

Найкращі практики - трактуйте аргументи як масив, скористайтеся NaN! == NaN ( typeof+ num.toString() === 'NaN'зайвий), зберігайте поточний аргумент у змінній замість arguments[i].
Isiah Meadows

@impinball, запропонована редакція не працює, вона повертає NaN замість 0 (нуль) з мого тестового випадку. Я міг технічно зняти!== 'number' перевірку , так як я вже оцінив , що це не так nullабо undefined, але це має ту перевагу, що дуже ясно , хто читає цей код і умова буде працювати незалежно від того. Ваші інші пропозиції трохи скорочують код, тому я буду використовувати їх.
Кевін Нельсон

2
@impinball, я знайшов вашу помилку у запропонованій вам редакції, ви залишили її як arg !== arg, але вам потрібно, щоб вона була arg === arg... тоді вона працює. Однак це має недолік, коли він дуже незрозумілий, що ти робиш ... вимагає коментаря в коді, щоб запобігти його видаленню наступною людиною, яка проходить код і вважає arg === argзайвою ... але я поставлю це все одно.
Кевін Нельсон

Хороший улов. І до речі, це швидкий спосіб перевірити NaN, скориставшись фактом NaN! == NaN. Якщо ви хочете, ви можете пояснити це.
Ісія Медоуз

1
галочка "не число" може бути замінена вбудованою функцією: isNaN ()
Юрій Козлов

5

остерігайтеся конкретного JavaScript-визначення. є два визначення для "без значення" в JavaScript. 1. Null: коли змінна null, це означає, що вона не містить в ній даних, але змінна вже визначена в коді. подобається це:

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

у такому випадку тип вашої змінної насправді є Object. перевірити його.

window.alert(typeof myEmptyValue); // prints Object
  1. Не визначено: коли змінна раніше не була визначена в коді, і як очікувалося, вона не містить жодного значення. подобається це:

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

якщо такий випадок, тип вашої змінної є "невизначеним".

зауважте, що якщо ви використовуєте оператор порівняння, що конвертує тип (==), JavaScript буде діяти однаково для обох цих порожніх значень. щоб розрізняти їх, завжди використовуйте оператор порівняння суворих типів (===).


1
Власне, null - це значення. Це особливе значення типу Object. Змінна, встановлена ​​на null, означає, що вона містить дані, дані є посиланням на об'єкт null. Змінна може бути визначена зі значенням, яке не визначене у вашому коді. Це не те саме, що змінна не декларується.
Атес Гораль

Фактична різниця між змінною, яка оголошується чи не: попередження (window.test) / * undefined * /; попередження ("тест" у вікні) / * false * /; window.test = невизначений; попередження (window.test) / * undefined * /; попередження ("тест" у вікні) / * true * /; for (var p in window) {/ * p може бути "тестом" * /}
Ates Goral

1
однак (трохи парадоксально) ви можете визначити змінну із невизначеним значеннямvar u = undefined;
Серж,

@AtesGoral re null. Хоча те, що ви говорите, є істинним, за умовою "null" являє собою "відсутність (корисних) даних" . Отже, воно вважається "відсутністю даних". І давайте не забувати, що це відповідь на питання про "нульовий оператор злиття"; у цьому контексті нуль, безумовно, трактується як "відсутні дані" - незалежно від того, як він представлений внутрішньо.
ToolmakerSteve

4

Прочитавши ваше пояснення, у відповіді @Ates Goral вказано, як виконати ту саму операцію, яку ви робите в C # в JavaScript.

@ Відповідь Gumbo забезпечує найкращий спосіб перевірити наявність нуля; однак важливо відзначити різницю ==порівняно ===з JavaScript, особливо коли мова йде про питання перевірки undefinedта / або null.

Там дійсно хороша стаття про різницю в двох доданків тут . В основному, розумійте, що якщо ви використовуєте ==замість ===, JavaScript намагатиметься зв'язати значення, які ви порівнюєте, і повернути результат результату порівняння після цього зближення.


Однією з речей, яка мене заважає про цю статтю (та Jash), є невизначене властивість window.hello з якихось причин. Він повинен бути невизначеним. Спробуйте консоль помилок Firefox і переконайтеся самі.
Атес Гораль

3

Зауважте, що create-react-appланцюжок інструментів React підтримує поєднання нуля з версії 3.3.0 (випущена 5.12.2019) . З приміток до випуску:

Необов'язкові оператори ланцюгового та нульового з'єднання

Зараз ми підтримуємо необов'язкові оператори ланцюгової та нульової з’єднання!

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

Це сказано, якщо ви використовуєте create-react-appверсію 3.3.0+, ви можете почати використовувати оператор null-coalesce вже сьогодні у своїх програмах React.


3

Так, і його пропозиція зараз є етапом 4 . Це означає, що пропозиція готова до включення до формального стандарту ECMAScript. Ви вже можете використовувати його в останніх настільних версіях Chrome, Edge та Firefox, але нам доведеться почекати трохи довше, поки ця функція не досягне стабільності перехресного веб-переглядача.

Подивіться на наступний приклад, щоб продемонструвати його поведінку:

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

Попередній приклад еквівалентний:

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

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

Зверніть увагу , що nullish коалесцирует буде НЕ загроза falsy значення то , як ||оператор зробив (він тільки перевіряє undefinedчи nullзначення), отже , наступний фрагмент коду буде діяти наступним чином :

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


Для користувачів TypesScript, починаючи з TypeScript 3.7 , ця функція також доступна зараз.


2

Будемо сподіватися, що незабаром він стане доступним у Javascript, оскільки він знаходиться у фазі пропозицій станом на квітень 2020 року. Ви можете відстежувати стан тут щодо сумісності та підтримки - https://developer.mozilla.org/en-US/docs/Web/ JavaScript / Довідка / Оператори / Nullish_coalescing_operator

Для людей , що використовують машинопис, ви можете використовувати nullish оператор коалесцирует з машинопису 3.7

З документів -

Ви можете подумати про цю функцію - ??оператор - як про спосіб «відкинутись» до значення за замовчуванням при роботі з nullабо undefined. Коли ми пишемо код, як

let x = foo ?? bar();

це новий спосіб сказати, що значення fooбуде використовуватися, коли воно є "присутнє"; але коли це nullчи undefined, обчисліть bar()на його місці.


0

Добре відповідь

Чи існує він у JavaScript? Так. АЛЕ Наразі це стадіон 2020-02-06 на етапі 3 та ще не підтримується скрізь.Перейдіть за посиланням у URL-адресі нижче та перейдіть до заголовків "Технічні характеристики" та "Сумісність веб-переглядачів", щоб отримати докладнішу інформацію про те, де він знаходиться.

Цитата від: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator

Нульовий оператор злиття (??) - це логічний оператор, який повертає правий бік операнда, коли його лівий операнд є нульовим або невизначеним, а в іншому випадку повертає його лівий операнд.

На відміну від логічного оператора АБО (||), лівий операнд повертається, якщо це хибне значення, яке не є нульовим або невизначеним. Іншими словами, якщо ви використовуєте || щоб надати деяке значення за замовчуванням для іншої змінної foo, ви можете зіткнутися з несподіваною поведінкою, якщо вважаєте деякі хибні значення як придатні (наприклад, '' або 0). Нижче див. Додаткові приклади.

Хочете приклади? Перейдіть за посиланням, яке я опублікував, у ньому є все.



Посилання MDN є корисним, але це дублююча відповідь. Натомість слід коментувати відповідь Вуана.
Кріс

@Chris Його відповідь недостатня, звідси і моя відповідь.
Карл Моррісон

0

Тепер він має повну підтримку в останній версії основних браузерів, таких як Chrome, Edge, Firefox, Safari тощо. Ось порівняння між оператором null та Nullish Coalescing Operator

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.