Есть ли в JavaScript JavaScript оператор "null coalescing"?
Существует ли в Javascript нулевой оператор коалесцирования?
Например, в С# я могу сделать это:
String someString = null;
var whatIWant = someString ?? "Cookies!";
Лучшее приближение, которое я могу вычислить для Javascript, использует условный оператор:
var someString = null;
var whatIWant = someString ? someString : 'Cookies!';
Какая-то нехорошая ИМХО. Могу ли я лучше?
Ответы
Ответ 1
В качестве эквивалента JavaScript оператора С# null коалесцирования (??
) используется логический OR (||
):
var whatIWant = someString || "Cookies!";
Есть случаи (пояснено ниже), что поведение не будет соответствовать поведению С#, но это общий, точный способ присвоения значений по умолчанию/альтернативных значений в 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"
Ответ 2
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, оно принимает любое количество аргументов и возвращает значение null, если ни одно из них не имеет значения. Он ведет себя как С#? оператора в том смысле, что "", false и 0 считаются NOT NULL и поэтому считаются фактическими значениями. Если вы пришли из фона .net, это будет наиболее естественное решение.
Ответ 3
Если ||
как замена С# ??
недостаточно хорош в вашем случае, поскольку он проглатывает пустые строки и нули, вы всегда можете написать свою собственную функцию:
function $N(value, ifnull) {
if (value === null || value === undefined)
return ifnull;
return value;
}
var whatIWant = $N(someString, 'Cookies!');
Ответ 4
Да, это скоро. См. Здесь предложение и статус реализации.
Это выглядит так:
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
Ответ 5
Никто не упомянул здесь потенциал для 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
Если вы используете типичный метод coalesce, как указано здесь, вы получите c
, который имеет значение: NaN
var result = coalesce(a,b,c,d,e,f); // result.toString() === 'NaN'
Ни то, ни другое из них не кажется мне правильным. В моем собственном маленьком мире логики coalesce, которая может отличаться от вашего мира, я рассматриваю undefined, null и NaN, поскольку все они являются "нуль-иш". Итак, я ожидал бы вернуть d
(ноль) из метода coalesce.
Если какой-либо мозг работает как мой, и вы хотите исключить 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;
}
Ответ 6
В настоящее время нет поддержки, но процесс стандартизации JS работает над ней: https://github.com/tc39/proposal-optional-chaining
Ответ 7
остерегайтесь специфического определения null для JavaScript. в javascript есть два определения "no value".
1. Null: когда переменная имеет значение null, это означает, что она не содержит в ней данных, но переменная уже определена в коде. например:
var myEmptyValue = 1;
myEmptyValue = null;
if ( myEmptyValue === null ) { window.alert('it is null'); }
// alerts
в этом случае тип вашей переменной - это объект Object. протестируйте его.
window.alert(typeof myEmptyValue); // prints Object
-
Undefined: когда переменная не была определена ранее в коде и, как и ожидалось, она не содержит никакого значения. например:
if ( myUndefinedValue === undefined ) { window.alert('it is undefined'); }
// alerts
если такой случай, тип вашей переменной равен 'undefined'.
обратите внимание, что если вы используете оператор сравнения типов преобразования (==), JavaScript будет действовать одинаково для обоих этих пустых значений. чтобы различать их, всегда используйте оператор строгого сравнения (===).
Ответ 8
После прочтения вашего разъяснения ответ @Ates Goral дает вам возможность выполнить ту же операцию, которую вы выполняете на С# в JavaScript.
@Ответ Gumbo обеспечивает лучший способ проверить значение null; однако важно отметить разницу в ==
по сравнению с ===
в JavaScript, особенно когда речь идет о проблемах проверки undefined
и/или null
.
Там действительно хорошая статья о различии в двух терминах здесь. В принципе, поймите, что если вы используете ==
вместо ===
, JavaScript попытается объединить значения, которые вы сравниваете, и вернуть результат сравнения после этого слияния.
Ответ 9
Этот сайт предлагает живое преобразование из С# в JS и обычно помогает понять или получить ответ:
https://deck.net/af073126fca87f3d419a8943a19b87c2
Ответ 10
Вот моя реализация elvis. Просто передайте корневой объект и цепочку в строку. Он всегда возвращает последний не ложный элемент цепочки. Работает как с объектами, так и с массивами, методами и примитивами.
elvis(myObject, 'categories.shirts[0].color');
Рабочий пример:
const elvis = (obj, keychain) => {
const keys = keychain.split('.');
let base;
let prevBase;
base = obj;
for (let i = 0; i < keys.length; i += 1) {
const handleArray = (parent, key) => {
if (key.indexOf('[') > -1) {
const arrayName = key.split('[')[0];
const arrayIndex = +key.split('[')[1].slice(0, -1);
return parent[arrayName] && parent[arrayName][arrayIndex];
}
if (key.indexOf('(') > -1) {
const methodName = key.split('(')[0];
return parent[methodName] && parent[methodName]();
}
return parent[key];
}
prevBase = handleArray(base, keys[i]);
if (!prevBase) {
return base;
}
base = prevBase;
}
return prevBase;
}
//--------
const myObject = {
categories: {
getFoo: () => 'foo',
shirts: [
{ color: 'red' },
{ color: 'blue' }
]
}
}
console.log(elvis(myObject, 'categories.shirts[0].color'));
console.log(elvis(myObject, 'categories.getFoo()'));
console.log(elvis(myObject, 'categories.getBar()'));
console.log(elvis(myObject, 'categories.shirts[0].length'));
console.log(elvis(myObject, 'categories.pans[2].color'));