Яка причина використовувати null замість невизначеного в JavaScript?


103

Я пишу JavaScript вже досить давно, і мені ніколи не було підстав користуватися null. Здається, undefinedце завжди бажано і програмно виконує ту саму мету. Які існують nullзамість практичних причин undefined?


Це можливо дублікат stackoverflow.com/questions/461966 / ...
lawnsea

Що ж, такі методи document.getElementById()можуть повернутися, nullале ні undefined, тому в тих випадках, чому б ви перевіряли повернення undefined? (Звичайно, це спрацює, якщо ви використовуєте, ==а не ===, але все-таки, чому б ви навмисно перевіряли неправильність?)
nnnnnn

Це може бути корисно мати передбачувані типи, і це може керувати мисленням для використання тих чи інших. Там, де об’єкт завжди повертається, потрібен або потрібен дизайну, використовуйте null для результатів хибних дій (наприклад document.getElementById('does-not-exist')). Змінні var a;та функції повертають значення за замовчуванням на невизначені. У минулому null був у глобальному масштабі, тому використання його сповільнило виконання і призвело до того, що я віддаю перевагу іншим фальшивим типам (false, '', 0) перед вільними посиланнями. Я особисто уникаю нуля, якщо немає переконливої ​​причини в іншому випадку, оскільки я сприймаю це як простіше, що, як правило, краще.
Джиммонт

Відповіді:


59

Нульове і невизначене - це по суті два різні значення, що означають одне і те ж. Єдина відмінність полягає в конвенціях про те , як використовувати їх в вашій системі. Як згадували деякі, деякі люди використовують нуль для значення "немає об'єкта", де іноді ви можете отримати об'єкт, тоді як невизначений означає, що жодного об'єкта не очікувалося (або що сталася помилка). Моя проблема з цим - це її абсолютно довільна і зовсім непотрібна.

Однак, є одна основна відмінність - змінні, які не ініціалізуються (включаючи параметри функції, де не було передано жодного аргументу, крім іншого), завжди не визначені.

Ось чому в моєму коді я ніколи не використовую null, якщо те, що я не контролюю, повертає null (наприклад, збігаються регулярні вирази). Краса цього полягає в тому, що вона багато спрощує речі. Мені ніколи не доведеться перевіряти, чи x === undefined || x === null. І якщо у вас є звичка використовувати == або просто такі речі, як if (x) .... Зупини це. !xбуде оцінено як істинне для порожнього рядка, 0, null, NaN - тобто речі, які ви, мабуть, не хочете. Якщо ви хочете написати javascript, який не жахливий, завжди використовуйте потрійні рівні === і ніколи не використовуйте null (замість цього використовуйте undefined). Це полегшить ваш життєвий шлях.


137
Я не згоден з цим. Null використовується для визначення чогось програмно порожнього. Невизначений означає, що посилання не існує. Нульове значення має визначене посилання на "нічого". Якщо ви викликаєте неіснуючу властивість об'єкта, ви отримаєте невизначений. Якщо я зробив би це майно навмисно порожнім, воно повинно бути недійсним, щоб ви знали, що це задумано. Багато бібліотек javascript працюють таким чином.
com2ghz

6
@ com2ghz Те, що ви описуєте, - одна з багатьох філософій. Багато js бібліотеки дійсно працюють саме так. Багато людей так і не працюють. У javascript ви можете так само легко зберігати явне невизначене значення в об’єкті або масиві, наскільки це можливо з null. Значення обох повністю і цілком залежать від контексту. IE вони означають те, що ви хочете, щоб вони означали.
BT

3
Ось чому JS - жахлива мова. Як ви кажете, у багатьох бібліотек є свої філософії, але ви включаєте багато бібліотек для 1 проекту. Тож ви стикаєтесь з багатьма умовами цих бібліотек. Скільки разів потрібно робити різні помилкові перевірки. Це був би не останній раз, коли ви прив'язуєте нульовий об’єкт до рядка і отримуєте "null" як рядок. Або передаючи 0 як числове значення і цікаво, чому оператор IF обробляє t як хибний.
com2ghz

2
@ com2ghz Отже, JS - жахлива мова, оскільки вона є і нульовою, і невизначеною? Я можу порахувати десятки поганих мовних рішень на всіх основних мовах, js - це не виняток. Мені буквально ніколи не потрібно або хочу використовувати помилкові чеки в своєму коді і завжди використовувати ===або !==. JS - фантастично виразна мова, якщо ви вмієте нею користуватися.
BT

6
Правильно. Я щойно дізнався, що null/ undefinedдихотомія необхідна, оскільки в початковій версії JS не було hasOwnPropertyабо inоператора. Тепер, коли це відбувається, я не дуже розумію, чому жодного з них не скасували в ES6 або будь-яких пропозиціях ES7, які я бачив.
Енді

86

Я не маю відповіді, але за словами Ніколаса Закаса , сторінка 30 його книги " Професійний JavaScript для веб-розробників " :

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


8
+1 так, я згоден, і я завжди намагаюся пам'ятати, щоб ініціалізувати vars на нуль. Тоді я (досить) впевнений, що це undefinedозначає, що сталася катастрофа. Просто імхо.
Піт Вілсон

9
@ Pete - але це нічого не говорить про "катастрофу", тож який сенс? І ви можете зробити це припущення лише тоді, коли знаєте, що функція слідує умові.
RobG

7
З іншого боку, ви також можете ініціалізувати змінну var myVar;і чітко перевірити її значення, undefinedщоб визначити, чи вона була заповнена посиланням на об'єкт у більш пізній час. Моя думка, це абсолютно академічно - ви можете це зробити в будь-якому випадку, і кожен, хто радить один шлях над іншим, просто підштовхує власну конвенцію.
thoan

1
Єдина проблема, яку я маю (оскільки я розпочала роботу з JavaScript 15 років тому) - це те, що вам занадто часто доводиться тестувати undefinedі null. Це все ще насправді дратує. Я уникаю призначати змінну nullпросто, щоб зменшити кількість додаткових nullтестувань.
G Man

4
@GMan - Це єдине місце, де ==порівняння (на відміну від нього ===) має сенс: v == null(або v == undefined) перевірятиметься на нулеве або невизначене.
Рік Любов

14

Зрештою, оскільки обидва nullі undefinedпримушують до одного і того ж значення ( Boolean(undefined) === false && Boolean(null) === false), ви можете технічно використовувати будь-який, щоб виконати роботу. Однак є правильний шлях, ІМО.

  1. Залиште використання undefinedна компіляторі JavaScript.

    undefinedвикористовується для опису змінних, які не вказують на посилання. Це компілятор JS подбає про вас. Під час компіляції двигун JS встановить значення всіх піднятих змінних undefined. Коли двигун переходить код і значення стає доступним, двигун призначить відповідні значення відповідним змінним. Для тих змінних, для яких вона не знайшла значень, змінні продовжували б підтримувати посилання на примітив undefined.

  2. Використовуйте null лише тоді, коли ви явно хочете позначити значення змінної як "немає значення".

    Як зазначає @ com2gz: nullвикористовується для визначення чогось програмно порожнього. undefinedозначає, що посилання не існує. nullЗначення має певну посилання на «нічого». Якщо ви називаєте неіснуючу властивість об'єкта, тоді ви отримаєте undefined. Якщо я зробив би це майно навмисно порожнім, то воно повинно бути nullтаким, щоб ви знали, що це задумано.

TLDR; Не використовуйте undefinedпримітив. Це значення, яке компілятор JS автоматично встановить для вас при оголошенні змінних без призначення або якщо ви намагаєтеся отримати доступ до властивостей об'єктів, на які немає посилання. З іншого боку, використовуйте, nullякщо і лише тоді, коли ви навмисно хочете, щоб змінна не мала значення.

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

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

printArguments(null, " hello") // logs: null hello

Це мала бути обрана відповідь
алабуді

13

невизначеним є те, де поняття про річ не існує; він не має типу, і на нього ніколи не було посилання в цьому обсязі; null - це те, де річ, як відомо, існує, але вона не має значення.


4
Звідки ви знаєте, чи була спроба призначити значення, але вона не вдалася і замість неї була визначена невизначена ?
RobG

11

У кожного свій спосіб кодування та власна внутрішня семантика, але з роками я вважаю це найбільш інтуїтивно зрозумілою порадою, яку я даю людям, які задають це питання: коли сумніваєтесь, робіть те, що робить JavaScript .

Скажімо, ви працюєте з властивостями об’єктів, як-от параметри для плагіна jQuery ... запитайте себе, яке значення JavaScript надає властивості, яку ще потрібно визначити - відповідь undefined. Тож у цьому контексті я б ініціалізував такі типи речей із ‘undefined’, щоб вони відповідали JavaScript (для змінних ви можете це зробити var myVar;замість var myVar = undefined;).

Тепер скажімо, що ви робите маніпуляції з DOM ... яке значення надає JavaScript неіснуючим елементам? Відповідь така null. Це значення, яке я би ініціалізував, якщо ви створюєте змінну заповнення заповнення, яка пізніше містить посилання на елемент, фрагмент документа або подібне, що стосується DOM.

Якщо ви працюєте з JSON, потрібно створити особливий випадок: для невизначених значень властивостей слід встановити їх ""або nullтому, що значення undefinedне вважається належним форматом JSON.

З урахуванням цього, як висловлювався попередній плакат, якщо ви виявите, що ви ініціалізуєте речі з синім місяцем nullабо undefinedне один раз, то, можливо, вам варто переглянути, як ви хочете кодувати програму.


Незважаючи на те , що це хороша позиція, я хотів би додати цей відповідь: stackoverflow.com/a/37980662/883303
Frederik Krautwald

@FrederikKrautwald дякую за посилання - це дуже чітке розмежування.
thoan

10

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

Для того, щоб зробити конвенцію корисною, спочатку потрібно знати, що викликана функція слідує умові. Тоді ви повинні явно перевірити повернене значення і вирішити, що робити. Якщо ви отримуєте не визначене , то можна припустити , що якась -небудь помилка , що викликається, знає про . Але якщо сталася помилка, і функція знала про це, і корисно відправити її в більш широке середовище, чому б не використати об’єкт помилки? тобто кинути помилку?

Тож наприкінці дня конвенція практично не потрібна ні в чому, крім дуже малих програм у простих середовищах.


3

Корисна властивість у null, що не визначено , не відповідає:

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

Не впевнений, чи повинен я використовувати цю думку про властивості ...


2

Вузли та елементи DOM не визначені, але можуть бути нульовими.

  • NextSibling останнього дочірнього елемента елемента є нульовим.

  • Попередня зміна першої дитини недійсна.

  • Посилання document.getElementById є нульовою, якщо елемент не існує в документі.

Але в жодному з цих випадків значення не визначене ; просто там немає вузла.


Дякую за пояснення. Для мене це не могло бути більш протиінтуїтивно зрозумілим.
tomekwi

Це дійсно залежить від того, що ви намагаєтеся перевірити. Наприклад, якщо ви хочете дізнатися, чи існує глобальна змінна назва "myVar", тоді window.myVarвона повернеться "невизначеною", якщо її немає. Є багато речей, які повертають "невизначені" в JavaScript, просто є багато речей, які повертають "null" - все залежить від контексту.
thoan

2

Кілька з них сказали, що нормально ініціалізувати об'єкти до null. Я просто хотів зазначити, що параметри деструктуризації за замовчуванням не працюють null. Наприклад:

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

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

Це вимагає проведення nullперевірок перед викликом функції, що може траплятися часто.


1

Я зараз працюю над цим точним питанням і переглядаю таку філософію:

  1. Будь-яка функція, яка призначена для повернення результату, повинна повернути нуль, якщо не вдалося знайти результат
  2. Будь-яка функція, НЕ призначена для повернення результату, неявно повертається невизначеною.

Для мене це питання є важливим, оскільки у кожного, хто викликає функцію, яка повертає результат, не повинно виникати питань щодо тестування на невизначений vs null.

Ця відповідь не намагається вирішити:

  1. Значення властивостей null vs undefined
  2. Змінні в межах ваших функцій - нульові та невизначені

На мою думку, змінні - це ваш власний бізнес, а не частина вашого API, а властивості в будь-якій системі ОО визначаються, і тому їх слід визначати зі значенням, відмінним від того, яке було б, якби не було визначено (нульовим для визначеного, невизначеного є те, що ви отримуйте, коли отримуєте доступ до чогось, що немає у вашого об’єкта).


1

Ось причина: var undefined = 1 це юридичний JavaScript, але var null = 1це синтаксична помилка. Різниця полягає в тому, що nullце мовне ключове слово, тоді undefinedяк, чомусь, це не так.

Якщо ваш код покладається на порівняння undefinedтак, ніби це ключове слово ( if (foo == undefined)- дуже легка помилка), яке працює лише тому, що ніхто не визначив змінну з цим іменем. Весь цей код вразливий для того, щоб хтось випадково чи зловмисно визначив глобальну змінну з цим іменем. Звичайно, ми всі знаємо, що випадково визначити глобальну змінну абсолютно неможливо в JavaScript ...


1
Використовуйте void 0замість невизначеного.
Фредерік Кройтвальд

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"

0

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

Ціле значення використання 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)

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як до еквівалентів.

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