Какая причина использовать null вместо undefined в JavaScript?

103

Я пишу JavaScript довольно давно, и у меня никогда не было причин его использовать null. Кажется, что undefinedэто всегда предпочтительнее и программно служит той же цели. Какие практические причины использовать nullвместо undefined?

Джимми Куадра
источник
Это возможный дубликат stackoverflow.com/questions/461966/…
lawnsea 07
Что ж, есть такие методы, document.getElementById()которые могут возвращать, nullно нет undefined, поэтому в таких случаях зачем вам тестировать возврат undefined? (Конечно, это сработает, если вы используете ==вместо ===, но все же, почему вы намеренно проверяете не то, что нужно?)
nnnnnn
Может быть полезно иметь предсказуемые типы, и это может направить мышление на то, чтобы использовать тот или иной. Если объект всегда возвращается, нужен или желателен по дизайну, используйте null для ложных результатов (например document.getElementById('does-not-exist')). По var a;умолчанию переменные и возвращаемые значения функций не определены. В прошлом null был в глобальной области видимости, поэтому его использование замедляло выполнение и заставляло меня предпочитать другие ложные типы (false, '', 0) свободным ссылкам. Я лично избегаю null, если нет веской причины, потому что я считаю его проще, что в целом лучше.
Джиммонт

Ответы:

60

Null и undefined - это два разных значения, которые означают одно и то же. Единственное отличие состоит в конвенциях о том , как использовать их в вашей системе. Как уже упоминалось, некоторые люди используют null для обозначения «нет объекта», когда вы иногда можете получить объект, а undefined означает, что объект не ожидался (или что произошла ошибка). Моя проблема в том, что это совершенно произвольно и совершенно ненужно.

Тем не менее, есть одно существенное отличие - переменные, которые не инициализированы (включая параметры функции, где не был передан аргумент, среди прочего), всегда не определены.

Вот почему в моем коде я никогда не использую null, если что-то, что я не контролирую, возвращает null (например, соответствие регулярных выражений). Прелесть этого в том, что это многое упрощает. Мне никогда не нужно проверять x === undefined || х === ноль. И если вы привыкли использовать == или просто такие вещи, как if (x) .... Прекрати. !xбудет оценивать значение true для пустой строки, 0, null, NaN - то есть вещей, которые вам, вероятно, не нужны. Если вы хотите написать неплохой javascript, всегда используйте тройное равное === и никогда не используйте null (вместо этого используйте undefined). Это облегчит тебе жизнь.

BT
источник
138
Я не согласен с этим. Null используется для определения чего-то программно пустого. Undefined означает, что ссылка не существует. Нулевое значение имеет определенную ссылку на «ничего». Если вы вызываете несуществующее свойство объекта, вы получите undefined. Если бы я сделал это свойство намеренно пустым, тогда оно должно быть пустым, чтобы вы знали, что это сделано специально. Так работают многие библиотеки javascript.
com2ghz 04
6
@ com2ghz То, что вы описываете, является одной из многих философий. Многие js-библиотеки действительно работают именно так. Многие также так не работают. В javascript вы можете так же легко сохранить явное неопределенное значение в объекте или массиве, как и с помощью null. Значения обоих полностью и полностью зависят от контекста. Т.е. они имеют в виду то, что вы хотите.
BT
3
Вот почему JS - ужасный язык. Как вы говорите, у многих библиотек есть своя философия, но вы включаете много библиотек для одного проекта. Итак, вы сталкиваетесь со многими соглашениями этих библиотек. Сколько раз вам нужно делать разные проверки на ложность. Это будет не последний раз, когда вы объединяете нулевой объект со строкой и получаете «null» в виде строки. Или передайте 0 как числовое значение и задаетесь вопросом, почему оператор IF обрабатывает t как ложное.
com2ghz
2
@ com2ghz Значит, JS - ужасный язык, потому что в нем есть как null, так и undefined? Я могу насчитать десятки неверных языковых решений на всех основных языках, js здесь не исключение. Мне буквально никогда не нужно и не хочу использовать проверки на ложность в моем коде, и я всегда использую ===или !==. JS - фантастически выразительный язык, если вы знаете, как им пользоваться.
BT
6
Правильно. Я только что узнал, что дихотомия null/ undefinedбыла необходима, потому что в начальной версии JS не было оператора hasOwnPropertyили in. Теперь, когда это произошло, я действительно не понимаю, почему одно из них не было отменено в ES6 или каких-либо предложениях ES7, которые я видел.
Энди
86

На самом деле у меня нет ответа, но, по словам Николаса Закаса , страница 30 его книги « Профессиональный JavaScript для веб-разработчиков » :

При определении переменной, которая в дальнейшем будет содержать объект, рекомендуется инициализировать переменную, nullа не что-либо еще. Таким образом, вы можете явно проверить значение, nullчтобы определить, была ли переменная была заполнена ссылкой на объект позже.

BBG
источник
8
+1 да, я согласен, и я всегда стараюсь не забывать инициализировать vars нулевым значением. Тогда я (почти) уверен, что это undefinedозначает катастрофу. Просто имхо.
Pete Wilson
9
@Pete - но это ничего не говорит вам о "катастрофе", так в чем смысл? И вы можете сделать это предположение, только если знаете, что функция следует соглашению.
RobG 07
7
С другой стороны, вы также можете инициализировать переменную var myVar;и явно проверить значение, undefinedчтобы определить, была ли она заполнена ссылкой на объект позже. Я считаю, что это чисто академический подход - вы можете делать это в любом случае, и любой, кто советует один способ, а не другой, просто продвигает свои собственные правила.
thdoan
1
Единственная проблема, с которой я столкнулся (с тех пор как я начал с JavaScript 15 лет назад), заключается в том, что вам слишком часто приходится тестировать undefinedи null. Это все еще очень раздражает. Я избегаю присваивать переменную nullтолько для того, чтобы уменьшить количество дополнительных nullтестов.
G Man
4
@GMan - это единственное место, где ==сравнение (в отличие от ===) имеет смысл: v == null(или v == undefined) будет проверять наличие null или undefined.
Рик Лав
15

В конце концов, поскольку оба nullи undefinedприводят к одному и тому же значению ( Boolean(undefined) === false && Boolean(null) === false), вы можете технически использовать любой из них для выполнения работы. Однако есть правильный путь, ИМО.

  1. Оставьте использование undefined компилятору JavaScript.

    undefinedиспользуется для описания переменных, которые не указывают на ссылку. Это то, что компилятор JS позаботится о вас. Во время компиляции движок JS установит значение всех поднятых переменных в undefined. По мере того, как движок выполняет код и значения становятся доступными, движок присваивает соответствующие значения соответствующим переменным. Для тех переменных, для которых не было найдено значений, переменные будут продолжать поддерживать ссылку на примитив undefined.

  2. Используйте null только в том случае, если вы явно хотите обозначить значение переменной как «не имеющее значения».

    Как утверждает @ com2gz: nullиспользуется для определения чего-то программно пустого. undefinedозначает, что ссылка не существует. nullЗначение имеет определенную ссылку на «ничего». Если вы вызываете несуществующее свойство объекта, вы получите undefined. Если я намеренно сделаю это свойство пустым, то это должно быть nullтак, чтобы вы знали, что это сделано намеренно.

TL; DR; Не используйте undefinedпримитив. Это значение, которое компилятор JS автоматически установит для вас, когда вы объявляете переменные без присваивания или если вы пытаетесь получить доступ к свойствам объектов, для которых нет ссылки. С другой стороны, используйтеnull тогда и только тогда, когда вы намеренно хотите, чтобы переменная не имела значения.

Я никогда явно не устанавливал что-либо на undefined (и я не встречал этого во многих кодовых базах, с которыми я взаимодействовал). Также редко пользуюсь null. Я использую только один раз null, когда хочу обозначить значение аргумента функции как не имеющее значения, то есть:

function printArguments(a,b) {
  console.log(a,b);
}

printArguments(null, " hello") // logs: null hello
Говинд Рай
источник
Это должен был быть выбранный ответ
alaboudi
13

undefined там, где не существует понятия о вещи; у него нет типа, и на него никогда раньше не ссылались в этой области; null - это место, где известно, что вещь существует, но она не имеет ценности.

Яплекс
источник
4
Как узнать, что была предпринята попытка присвоить значение, но она не удалась и вместо этого было назначено значение undefined ?
RobG 07
11

У каждого свой способ кодирования и собственная внутренняя семантика, но с годами я обнаружил, что это самый интуитивный совет, который я даю людям, задающим этот вопрос: в случае сомнений делайте то, что делает JavaScript .

Допустим, вы работаете со свойствами объекта, такими как параметры для плагина jQuery ... спросите себя, какое значение JavaScript дает свойство, которое еще не определено - ответ будет undefined. Поэтому в этом контексте я бы инициализировал эти типы вещей с помощью undefined, чтобы они соответствовали JavaScript (для переменных вы можете использовать var myVar;вместо var myVar = undefined;).

Теперь предположим, что вы выполняете манипуляции с DOM ... какое значение JavaScript присваивает несуществующим элементам? Ответ есть null. Это значение, которое я бы инициализировал, если вы создаете переменную-заполнитель, которая позже будет содержать ссылку на элемент, фрагмент документа или подобное, относящееся к DOM.

Если вы работаете с JSON, необходимо сделать особый случай: для неопределенных значений свойств вы должны либо установить их на, ""либо nullпотому что значениеundefined не считается правильным форматом JSON.

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

thdoan
источник
Хотя это хорошая позиция, я хотел бы добавить этот ответ: stackoverflow.com/a/37980662/883303
Фредерик Краутвальд,
@FrederikKrautwald спасибо за ссылку - это очень четкое разграничение.
thdoan
10

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

Чтобы соглашение было полезным, вы сначала должны знать, что вызываемая функция следует соглашению. Затем вам нужно явно протестировать возвращаемое значение и решить, что делать. Если вы получили значение undefined , вы можете предположить, что произошла какая-то ошибка , о которой знала вызываемая функция . Но если произошла ошибка, и функция знала об этом, и полезно отправить ее в более широкую среду, почему бы не использовать объект ошибки? т.е. вывести ошибку?

Итак, в конце концов, соглашение практически бесполезно ни для чего, кроме очень маленьких программ в простых средах.

РобГ
источник
3

Полезное свойство в null, которое undefined не квалифицирует:

> null + 3
3
> undefined + 3
NaN

Я использую, nullкогда хочу «выключить» числовое значение или инициализировать некоторые. Мое последнее использование манипулировало преобразованием css:

const transforms = { perspective : null, rotateX : null };
// if already set, increase, if not, set to x
runTimeFunction((x) => { trasforms.perspective += x; });
// still useful, as setting perspective to 0 is different than turning it off
runTimeFunction2((x) => { transforms.perspective = null; });

// toCss will check for 'null' values and not set then at all
runTimeFunction3(() => { el.style.transform = toCss(transforms); });

Не уверен, стоит ли мне использовать эту собственность, подумал ...

Faccion
источник
2

Узлы и элементы DOM не являются неопределенными, но могут иметь значение NULL.

  • NextSibling последнего дочернего элемента имеет значение NULL.

  • Предыдущий брат первого потомка равен нулю.

  • Ссылка document.getElementById имеет значение NULL, если элемент не существует в документе.

Но ни в одном из этих случаев значение не определено ; там просто нет узла.

Kennebec
источник
Спасибо за объяснение. Для меня это не могло быть более нелогичным.
tomekwi
Это действительно зависит от того, что вы пытаетесь проверить. Например, если вы хотите узнать, существует ли глобальная переменная с именем myVar, тогда window.myVarвернет undefined, если она не существует. Есть масса вещей, которые возвращают «undefined» в JavaScript, просто есть множество вещей, которые возвращают «null» - все зависит от контекста.
thdoan
2

Некоторые сказали, что можно инициализировать объекты null. Я просто хотел указать, что значения по умолчанию для аргументов деструктуризации не работают null. Например:

const test = ({ name } = {}) => {
  console.log(name)
}

test() // logs undefined
test(null) // throws error

Это требует выполнения nullпроверок перед вызовом функции, что может происходить часто.

Мэтт Уэй
источник
1

Я работаю над этим вопросом прямо сейчас и смотрю на следующую философию:

  1. Любая функция, которая предназначена для возврата результата, должна возвращать null, если не может найти результат.
  2. Любая функция, которая НЕ предназначена для возврата результата, неявно возвращает undefined.

Для меня этот вопрос важен, потому что у любого, вызывающего функцию, которая возвращает результат, не должно возникать вопросов о том, следует ли проверять undefined или null.

Этот ответ не пытается адресовать:

  1. Значения свойств null vs undefined
  2. Переменные в ваших функциях являются нулевыми по сравнению с неопределенными

На мой взгляд, переменные - это ваш собственный бизнес, а не часть вашего API, а свойства в любой объектно-ориентированной системе определены и, следовательно, должны быть определены со значением, отличным от того, что они были бы, если бы не были определены (null для определенного, undefined - это то, что вы получить при доступе к чему-то, чего нет в вашем объекте).

Майкл
источник
1

Причина: var undefined = 1 допустим, javascript, но var null = 1есть синтаксическая ошибка. Разница в том, что nullэто ключевое слово языка, а undefinedпо какой-то причине - нет.

Если ваш код основан на сравнении, undefinedкак если бы это было ключевое слово ( if (foo == undefined)- очень простая ошибка), это работает только потому, что никто не определил переменную с таким именем. Весь этот код уязвим для того, чтобы кто-то случайно или злонамеренно определил глобальную переменную с этим именем. Конечно, все мы знаем, что случайное определение глобальной переменной в javascript совершенно невозможно ...

Джоэл Мюллер
источник
1
Используйте void 0вместо undefined.
Фредерик Краутвальд
1

Просто хочу добавить, что при использовании определенных библиотек javascript значения null и undefined могут иметь непредвиденные последствия.

Например, getфункция lodash , которая принимает значение по умолчанию в качестве третьего аргумента:

const user = {
  address: {
    block: null,
    unit: undefined,
  }
}
console.log(_.get(user, 'address.block', 'Default Value')) // prints null
console.log(_.get(user, 'address.unit', 'Default Value')) // prints 'Default Value'
console.log(_.get(user, 'address.postalCode', 'Default Value')) // prints 'Default Value'

Другой пример: если вы используете defaultProps в React, если свойство передается null, свойства по умолчанию не используются, потому что null интерпретируется как определенное значение . например

class MyComponent extends React.Component {
   static defaultProps = {
      callback: () => {console.log('COMPONENT MOUNTED')},
   }
   componentDidMount() {
      this.props.callback();
   }
}
//in some other component
<MyComponent />   // Console WILL print "COMPONENT MOUNTED"
<MyComponent callback={null}/>   // Console will NOT print "COMPONENT MOUNTED"
<MyComponent callback={undefined}/>   // Console WILL print "COMPONENT MOUNTED"
Lilbitofchee
источник
0

Я полностью не согласен с тем, что использование null или undefined не требуется. undefined - это то, что поддерживает весь процесс цепочки прототипов. Таким образом, компилятор только с нулевым значением не может проверить, равно ли это свойство нулю или оно не определено в прототипе конечной точки. В других языках с динамической типизацией (например, Python) он выдает исключение, если вам нужен доступ к неопределенному свойству, но для языков на основе прототипов компилятор также должен проверять родительские прототипы, и именно здесь undefined больше всего требуется.

Весь смысл использования null - это просто привязать переменную или свойство к объекту, который является одноэлементным и имеет значение пустоты, а также использование null имеет цели производительности. Эти 2 кода имеют разное время выполнения.

var p1 = function(){this.value = 1};
var big_array = new Array(100000000).fill(1).map((x, index)=>{
    p = new p1();
    if(index > 50000000){
       p.x = "some_string";
    }

    return p;
});
big_array.reduce((sum, p)=> sum + p.value, 0)

var p2 = function(){this.value = 1, p.x = null};
var big_array = new Array(100000000).fill(1).map((x, index)=>{
    p = new p2();
    if(index > 50000000){
       p.x = "some_string";
    }

    return p; 
});
big_array.reduce((sum, p)=> sum + p.value, 0)
ВаагнНикогосян
источник
undefinedне имеет особого значения для наследования прототипов. Свойство, установленное на, undefinedвсе равно переопределит свойство (с тем же именем), унаследованное от прототипа.
Matthijs
0

Неизвестный переменная undefined.

Известные переменная еще нет значения: null.

  1. Вы получаете объект с сервера server_object.
  2. Вы ссылаетесь server_object.errj. Он говорит вам, что это undefined. Это означает, что он не знает, что это такое.
  3. Теперь ссылка server_object.err. Он говорит вам, что это null. Это означает, что вы ссылаетесь на правильную переменную, но она пуста; поэтому ошибки нет.

Проблема в том, что вы объявляете имя переменной без значения ( var hello) js объявляет, что как undefined: эта переменная не существует; тогда как программисты в основном имеют в виду: «Я еще не придал этому значения», определение null.

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

Вы, конечно, можете убедиться, что вы всегда будете это делать, var hello = nullно большинство из них не будет засорять свой код как таковой, чтобы гарантировать корректность типов на преднамеренно слабо типизированном языке, когда они и !оператор рассматривают оба undefinedи nullкак эквивалентные.

новые пять
источник