Установите переменную, если она не определена в JavaScript

Я знаю, что могу проверить переменную JavaScript, а затем определить ее, если она равна undefined, но нельзя ли как-то сказать

var setVariable = localStorage.getItem('value') || 0;

кажется гораздо более понятным способом, и я почти уверен, что видел это на других языках.


person pedalpete    schedule 23.03.2011    source источник
comment
это не проверка на неопределенность, это проверка на ложность   -  person Alnitak    schedule 23.03.2011
comment
Обратите внимание, что localStorage.getItem() вызовет исключение, если пользователь отключил файлы cookie (по крайней мере, в Chrome), поэтому вы можете заключить его в предложение try...catch.   -  person urish    schedule 10.05.2014
comment
Возможный дубликат Что означает конструкция x = x || в смысле?   -  person Michał Perłakowski    schedule 10.04.2016


Ответы (13)


Да, он может это сделать, но, строго говоря, это присвоит значение по умолчанию, если полученное значение falsey, а не действительно undefined. Следовательно, он будет соответствовать не только undefined, но и null, false, 0, NaN, "" (но не "0").

Если вы хотите установить значение по умолчанию только в том случае, если переменная строго undefined, то самый безопасный способ - написать:

var x = (typeof x === 'undefined') ? your_default_value : x;

В более новых браузерах на самом деле безопасно писать:

var x = (x === undefined) ? your_default_value : x;

но имейте в виду, что это можно обойти в старых браузерах, где было разрешено объявлять переменную с именем undefined, имеющую определенное значение, что приводило к сбою теста.

person Alnitak    schedule 23.03.2011
comment
Я удивлен, что этот шаблон не включен в другие библиотеки JS. - person joemaller; 15.02.2013
comment
есть ли обратная сторона использования var x = (x === undefined ? def_val : x); в качестве немного более длинного var x = (typeof x === 'undefined') ? def_val : x;. Отличается ли поведение? - person Marco Pashkov; 25.02.2014
comment
@marco в старых браузерах можно было переопределить undefined, что привело к сбою проверки на равенство. - person Alnitak; 26.02.2014
comment
@Alnitak Каков наилучший подход к использованию синтаксиса, аналогичного тому, который использует OP, и при этом проверять неопределенность? - person Ivo Pereira; 23.12.2014
comment
@IvoPereira Вы не можете использовать подход || в строгом тесте для неопределенного, вы должны использовать явный тест для undefined с условным условием. - person Alnitak; 23.12.2014
comment
Это работает, но экономически невыгодно, так как вам нужно написать имя переменной три раза. if ( x==undefined) {x = def_val} ясен и требует только одного повторения. Я думаю, что действительно стоит добавить компактный способ. Что-то вроде |= (или любой другой удобный символ для пары со значением =: назначьте, если он еще не определен) - person a1an; 04.04.2016
comment
@ a1 В других языках есть оператор объединения null, который не имеет (часто нежелательного) поведения ||=, когда он соответствует любому ложному значению, а не только строго неопределенным значениям. JS, к сожалению, нет. - person Alnitak; 04.04.2016
comment
@Alnitak, есть ли где-нибудь список этих старых браузеров? - person dieresys; 18.05.2016
comment
Следующий вариант лучше var x = (x === void 0) ? def_val : x; просто потому, что он короче. - person Victor Dombrovsky; 05.01.2017
comment
Использование void 0 вместо undefined решает указанную вами старую проблему с браузером. - person Trevor Dixon; 13.07.2018

Логическое нулевое назначение, решение ES2020+

В настоящее время в браузеры добавляются новые операторы ??=, ||= и &&=. Этот пост будет посвящен ??=.

Это проверяет, является ли левая сторона undefined или null, короткое замыкание, если оно уже определено. Если нет, правая часть присваивается левой переменной.

Сравнение методов

// Using ??=
name ??= "Dave"

// Previously, ES2020
name = name ?? "Dave"

// Before that (not equivalent, but commonly used)
name = name || "Dave" // name ||= "Dave"

Основные примеры

let a       // undefined
let b = null
let c = false

a ??= true  // true
b ??= true  // true
c ??= true  // false

// Equivalent to
a = a ?? true

Примеры объектов/массивов

let x = ["foo"]
let y = { foo: "fizz" }

x[0] ??= "bar"  // "foo"
x[1] ??= "bar"  // "bar"

y.foo ??= "buzz"  // "fizz"
y.bar ??= "buzz"  // "buzz"

x  // Array [ "foo", "bar" ]
y  // Object { foo: "fizz", bar: "buzz" }

??= Поддержка браузера март 2021 г. — 85 %

??= Документация Mozilla

||= Документация Mozilla

&&= Документация Mozilla

person Gibolt    schedule 09.07.2020
comment
Действительно ли стоит скопировать этот ответ на два других вопроса (Заменить значение, если оно равно нулю или не определено в JavaScript и Есть ли в JavaScript оператор "нулевого объединения"?)? Не лучше ли дублировать VTC или дать ссылку на похожие вопросы в комментариях? - person Sebastian Simon; 12.07.2020
comment
Все вопросы немного разные; как таковы и ответы. Примеры согласуются, чтобы улучшить встроенный контекст с первого взгляда. Вероятно, можно было бы дать ссылку для более подробной информации, но потребовался бы дополнительный прыжок, из-за которого люди могли бы пропустить решение. - person Gibolt; 12.07.2020
comment
Обратите внимание, что некоторые IDE (NetBeans) определяют ??= как недопустимый синтаксис. Автоматическое форматирование источника по умолчанию преобразует его в ?? = с пробелом между ними, что является недопустимым JS. Теперь, чтобы выяснить, как настроить автоформатер... - person OXiGEN; 16.09.2020
comment
не могу поверить, что это еще не поддерживается, такая базовая функция - person samthet; 13.11.2020

Ответ 2018 ES6:

return Object.is(x, undefined) ? y : x;

Если переменная x не определена, вернуть переменную y... в противном случае, если переменная x определена, вернуть переменную x.

person Sterling Bourne    schedule 27.09.2017
comment
Насколько я могу судить, Object.is в данном случае не лучше, чем ===. Оператор === (а также оператор ==) рассматривает числовые значения -0 и +0 как равные и рассматривает Number.NaN как не равное NaN. (developer.mozilla.org/en-US /docs/Web/JavaScript/Reference/) Здесь не имеет значения. - person Trevor Dixon; 13.07.2018
comment
Тем не менее, Тревор, вы всегда должны использовать Object.is() вместо === по привычке. - person Sterling Bourne; 13.07.2018
comment
Я не согласен. Знайте их оба и используйте подходящий. В частности, используйте Object.is, если оба операнда могут быть NaN. - person Trevor Dixon; 15.07.2018
comment
Если Object.is() работает в 100% случаев использования, а === работает в 98% случаев использования, зачем вообще рисковать использованием ===? Например: console.log(+0 === -0); // выводит true, а console.log(Object.is(+0, -0)); // выводит ложь -- что лучше? Отрицательный 0 совпадает с положительным 0? Это вопрос, который вы должны задать себе, но если вы используете Object.is(), вы всегда знаете ответ. Они не совпадают, поэтому вывод false является правильным и ожидаемым результатом. - person Sterling Bourne; 18.07.2018
comment
Конкретный контекст здесь всегда сравнивается с undefined. Так что === будет работать в 100% случаев, а не только в 98%. Преимущество === в том, что его легче читать, особенно с первого взгляда, он короче и позволяет избежать ненужного вызова метода. Лично я бы использовал Object.is() только тогда, когда этого требует ситуация, и предпочел бы === во всех остальных случаях. - person blubberdiblub; 05.04.2019
comment
Абсолютно; если вы опытный кодер. Если вы случайно не забудете знак равенства, в этом случае отладка, почему == где-то не работает, — это то, чего я никогда не пожелал бы ни одному разработчику. Лучше перестраховаться, чем сожалеть, и всегда использовать Object.is(). Причина, по которой эта функция была включена в спецификацию, заключалась в том, чтобы помочь разработчикам писать код с меньшим количеством ошибок. - person Sterling Bourne; 29.10.2019

ES2020 Ответ

С помощью оператора Nullish Coalescing вы можете установите значение по умолчанию, если value имеет значение null или не определено.

const setVariable = localStorage.getItem('value') ?? 0;

Однако вы должны знать, что нулевой оператор объединения не возвращает значение по умолчанию для других типов ложных значений, таких как 0 и ''.

Однако обратите внимание на поддержку браузера. Возможно, вам потребуется использовать компилятор JavaScript, например Babel, чтобы преобразовать его во что-то более обратно совместимое. Если вы используете Node.js, он поддерживается с версия 14.

person wentjun    schedule 13.04.2020

Мне нужно было «установить переменную, если она не определена» в нескольких местах. Я создал функцию, используя ответ @Alnitak. Надеюсь, это поможет кому-то.

function setDefaultVal(value, defaultValue){
   return (value === undefined) ? defaultValue : value;
}  

Использование:

hasPoints = setDefaultVal(this.hasPoints, true);
person Mcestone    schedule 16.01.2017

Логичнее проверить typeof вместо undefined? Я предполагаю, что вы ожидаете число, поскольку вы устанавливаете переменную в 0, когда она не определена:

var getVariable = localStorage.getItem('value');
var setVariable = (typeof getVariable == 'number') ? getVariable : 0;

В этом случае, если getVariable не число (строка, объект и т. д.), для setVariable устанавливается значение 0.

person Bruno    schedule 30.06.2016

В наши дни вы действительно можете реализовать свой подход с помощью JS:

// Your variable is null
// or '', 0, false, undefined
let x = null;

// Set default value
x = x || 'default value';

console.log(x); // default value

Итак, ваш пример БУДЕТ работать:

const setVariable = localStorage.getItem('value') || 0;
person tarkh    schedule 27.06.2020

Если вы поклонник FP (функционального программирования), Ramda имеет удобную вспомогательную функцию для этого, которая называется по умолчанию :

использование:

const result = defaultTo(30)(value)

Это более полезно при работе с логическими значениями undefined:

const result2 = defaultTo(false)(dashboard.someValue)

person Damian Green    schedule 17.12.2018
comment
это точно const result = value || 30;, за исключением использования промежуточной функции и библиотеки +1000 байт - person Adelin; 17.12.2018
comment
@Adelin не соответствует действительности, он также обрабатывает ложные значения для логических типов. Если вы уже используете эту библиотеку (как и я), то она довольно полезна и лаконична. - person Damian Green; 17.12.2018

Сегодня также столкнулся с этим сценарием, когда я не хотел, чтобы ноль был перезаписан для нескольких значений. У нас есть файл с некоторыми общими служебными методами для подобных сценариев. Вот что я добавил, чтобы справиться со сценарием и быть гибким.

function getIfNotSet(value, newValue, overwriteNull, overwriteZero) {
    if (typeof (value) === 'undefined') {
        return newValue;
    } else if (value === null && overwriteNull === true) {
        return newValue;
    } else if (value === 0 && overwriteZero === true) {
        return newValue;
    } else {
        return value;
    }
}

Затем его можно вызвать с двумя последними параметрами, которые являются необязательными, если я хочу установить только неопределенные значения или также перезаписать значения null или 0. Вот пример вызова, который установит идентификатор в -1, если идентификатор не определен или равен нулю, но не перезапишет значение 0.

data.ID = Util.getIfNotSet(data.ID, -1, true);
person Mark Seefeldt    schedule 30.10.2014

Работает, даже если значение по умолчанию является логическим значением:

var setVariable = ( (b = 0) => b )( localStorage.getItem('value') );
person Tsz Lam Yau    schedule 12.01.2019

Мне кажется, что для текущих реализаций javascript

var [result='default']=[possiblyUndefinedValue]

это хороший способ сделать это (используя деконструкцию объекта).

person T S    schedule 02.08.2019

Вы можете использовать любой из приведенных ниже способов.

let x;
let y = 4;
x || (x = y)

в ES12 или позже

let x;
let y = 4;
x ||= y;
person SuperNova    schedule 20.06.2021
comment
Это уже предлагалось. ||= не устанавливает переменную, если она просто не определена; он устанавливает его, если он ложный. - person Sebastian Simon; 20.06.2021

person    schedule
comment
Также не будет присваивать 0, если localStorage.getItem('value')) возвращает false - person Karl Adler; 04.07.2016