Чому в JavaScript існує значення "null"?


116

У JavaScript є два значення, які в основному кажуть "я не існую" - undefinedі null.

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

Я колись думав, що в цьому є потреба, nullоскільки undefinedце примітивна цінність і nullпредмет. Це не так, навіть якщо typeof nullдасть результат 'object': Насправді, обидва є примітивними значеннями - це означає, що ні повернутись із функції конструктора undefinedне nullможна, ні обидва будуть перетворені на порожній об'єкт (треба викинути помилку, щоб оголосити провал у конструкторах).

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

То чому є те і інше, undefinedі nullякщо це просто бентежить програмістів, які неправильно перевіряють, nullнамагаючись з’ясувати, встановлено чи ні властивість?

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

Таким чином, загальний консенсус, схоже, undefinedозначає, що "такої власності немає", а null"властивість існує, але вона не має ніякого значення".

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

Я фактично використовую, undefinedколи хочу скинути значення властивостей, які вже не використовуються, але яких я не хочу delete. Чи слід використовувати nullзамість цього?


3
Щоб відповісти на ваше останнє запитання: Ні, вам не слід встановлювати властивості undefined.
Shog9

4
"undefined" - це лише змінна в глобальному масштабі з примітивним значенням "undefined". Можна змінити інше значення змінної: {undefined = "Привіт"; оповіщення ( НЕ виразно);} Більш надійний спосіб перевірки на невизначений: {якщо (TypeOf MyVar === "не визначений") попередження ( "не визначений")}
деякі

1
Див. Розділ 4.3.9 - 12 у ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf для undefined / null та 15.1.1.3 для змінної "undefined" у глобальному масштабі.
дещо

1
Вам слід або видалити об'єкт, або встановити його на нульове значення, якщо це має більше сенсу, але не визначене.
десь

4
In JavaScript, there are two values which basically say 'I don't exist' - undefined and null.Ні, це лише undefinedговорить.
Гонки легкості на орбіті

Відповіді:


78

Питання насправді не "чому в JS є нульове значення" - в більшості мов є якесь нульове значення, і воно, як правило, вважається дуже корисним.

Питання в тому, "чому в JS є невизначене значення". Основні місця, де він використовується:

  1. коли ви заявляєте, var x;але не призначаєте це,x залишається невизначеним;
  2. коли ваша функція отримує менше аргументів, ніж декларується;
  3. коли ви отримуєте доступ до неіснуючої властивості об'єкта.

nullЗрозуміло, він би працював так само добре для (1) та (2) *. (3) дійсно слід викинути виняток відразу, а той факт, що цього не відбувається, замість повернення цього дивногоundefined який згодом вийде з ладу, є великим джерелом труднощів налагодження.

*: Ви також можете стверджувати, що (2) слід кинути виняток, але тоді вам доведеться надати кращий, більш чіткий механізм аргументів за замовчуванням / змінною.

Однак JavaScript спочатку не мав винятків чи будь-якого способу запитати об'єкт, чи не мав він учасника під певним іменем - єдиним способом було (а іноді все ще є) отримати доступ до учасника та побачити, що ви отримуєте. Зважаючи на те, що nullвже була мета, і ви, можливо, захочете встановити її члена, потрібно було інше значення поза межами діапазону. Таким чином, у нас undefinedце проблематично, як ви зазначаєте, і це ще одна чудова «функція JavaScript», якої ми ніколи не зможемо позбутися.

Я фактично використовую невизначені, коли хочу скинути значення властивостей, які вже не використовуються, але які я не хочу видаляти. Чи слід використовувати замість null?

Так. Зберігайте undefinedяк особливе значення для сигналізації, коли інші мови можуть замість цього викинути виняток.

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


10
Арги розширюються. Ви можете залишити скільки завгодно, і функція може потенційно повторити їх і використовувати їх усі. Об'єктам можна призначити нове властивість у будь-який час. Це обидві потужні функції, але я підозрюю, що викиди, які ви кинули, як би ви хотіли, були б великими накладними. ІМО, це варто компромісу. Я витрачаю набагато менше часу на перевірку існування в JS, ніж зазвичай роблю кастинг у більш жорстких мовних парадигмах.
Erik Reppen

Смішно, як прийнята відповідь на питання починається з "це насправді не питання ..."
Phillip

@bobince в ранніх версіях JS не було inоператора чи hasOwnProperty? Тому що вони набагато безпечніші, ніж obj.hello !== undefinedдля перевірки наявності властивості на об'єкті.
Енді

Незважаючи, я відповів на власне запитання. За даними MDN, вони були представлені в ES3.
Енді

37

Кращий описано тут , але підсумовано:

undefined - це відсутність типу та значення, а null - відсутність значення.

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


1
Я це знаю null !== undefined- моє питання полягало в тому, чому виникли потреба у двох речах, які виражають одне й те саме смислове поняття; також у вашому посиланні згадується, що "null is the object" - це неправильно, це примітив ...
Крістоф

2
Вони не однакові смислові поняття. Принаймні, для мене є значна різниця між властивістю, якому присвоєно нульове значення, і властивістю, яка не існує.
Даніель Шаффер

Але це просто так, вони не те саме семантичне поняття. Null примушується при використанні ==, маючи на увазі те саме, що і зручність для програміста.
Едді Паркер

1
@EricElliott: typeofбрехня - прочитайте специфікацію або спробуйте повернутися nullз конструктора
Крістоф

5
@EricElliott: повернене значення конструкторів не має нічого спільного з хибністю, але з об'єктом-ness: якщо значенням повернення є об'єкт, поверніть це; якщо це примітив на кшталт nullабо 42, відкиньте повернене значення і поверніть натомість створений об’єкт
Крістоф

17

Я не думаю, що немає жодних причин мати і те, nullі undefinedтому, що єдина причина, по якій багато людей запропонували (" undefinedозначає, що такої змінної / властивості" немає) не є дійсною, принаймні в JavaScript. undefinedне може сказати вам, чи існує змінна / властивість чи ні.

console.log(foo);               // "ReferenceError: foo is not defined"
                                // foo does not exist
var foo;
console.log(foo);               // "undefined", a different response
console.log(foo === undefined); // "true", but it does exist

var obj = {};
console.log(obj.hasOwnProperty("foo")); // "false", no such property
obj.foo = undefined;
console.log(obj.hasOwnProperty("foo")); // "true", it exists and has the value "undefined"
console.log(obj.foo === undefined);     // "true", but it does exist

obj.bar = "delete me";
obj.bar = undefined;
console.log(obj.hasOwnProperty("bar")); // "true", not actually deleted
delete obj.bar;
console.log(obj.hasOwnProperty("bar")); // "false", deleted

Як бачите, перевірка foo === undefinedне вказує, чи fooіснує, а налаштування obj.bar = undefinedфактично не видаляється bar.

Можливо, оригінальний намір автора JavaScript undefinedповинен представляти "відсутність". Однак реалізація не вийшла таким чином.


1
Замінити undefinedз nullв ваших прикладах вище коду, а відповіді все ж. Я не впевнений, як це відповідає на питання. Це малося на увазі як коментар до чужої відповіді?
Ерік Елліотт

1
@EricElliott Моя відповідь на запитання полягає в тому, що немає причин мати те і те, nullі undefinedтому, що єдина причина, яку багато хто запропонував, не вірна.
Лей Чжао

Ви повинні відредагувати свою відповідь і насправді сказати це. Я міг би відмовитись, якби ти дав цю відповідь. =)
Ерік Елліотт

@EricElliott Я думаю, ти маєш рацію. Я відредагував свою відповідь. Дякую!
Лей Чжао

3
Цей приклад фактично показує, що якщо ви не призначили змінну, вона повертається undefined. Але якщо ви це призначили undefined, це насправді undefined- це було визначено з undefinedпосиланням на нього. Єдина відмінність між ними undefinedі nullїх використання та історичне призначення. Вони обидва атомні.
Олексій Комаров

6

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


6

Я думаю, що ваш висновок про те, що JavaScript визначає undefinedяк "такого властивості немає" іnull як "властивість не має значення", є абсолютно правильним. І в мові, динамічній як JavaScript, це дуже важлива відмінність. Використання набору качок означає, що нам потрібно вміти розмежовувати властивість, яка не існує, і не має значення. Це наш основний засіб отримання інформації про тип. у мові, що вводиться статично, існує певна відмінність між полем, яке є нульовим, і полем, яке не існує. У JavaScript це не відрізняється. Однак він перевіряється під час виконання і може бути змінений до цього часу.

Мені доведеться погодитися, що реалізація дивна, оскільки багато разів розмежування розмивається. Однак я думаю, що в JavaScript відмінність є важливою. І вміти призначитиundefined - це важливо.

Я пам’ятаю, як деякий час тому читав повідомлення в блозі про онлайн-RPG, написаний на JavaScript. Він використовував приклади, коли об’єкти створювались як копії існуючих екземплярів, а не прототипи (класи, функції, що завгодно), а потім були змінені. Це дійсно змусило мене зрозуміти, наскільки потужно це undefinedможе бути при зміні існуючих об'єктів, але я не можу пригадати, хто це написав.


Не могли б ви поділитися цим RPG?
Михайло

3

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


1
але ви можете використовувати undefinedпросто штрафи для присвоєння властивостей, тож цей контракт (повернення лише undfinedтоді, коли такого майна немає) може бути легко порушений програмістом ...
Крістоф

2
Ви можете , але ви напевне не повинні. Невизначений використовується як дуже основна / спрощена форма винятку в JavaScript - не використовуйте його як значення і не призначайте його до якоїсь властивості! Це божевільна людина.
rfunduk

3

Як програміст Java, я бачу величезну різницю між невизначеним та нульовим. Кодування JavaScript не так багато, тому що JavaScript не сильно набраний, а відмінності між невизначеним та нульовим значеннями розмиваються автоматичними перетвореннями, які часто виконуються під час виконання. До речі, я часто переживаю ці перетворення; вони роблять мій JS-код більш компактним і читабельним.

Щоб відповісти на ваше запитання, невизначене означає, що значення ніколи не було встановлено. Практично кажучи, це загалом вказує на помилку. Якщо ваша власність.project.property не визначена, це означає, що ви не встановили властивість з якихось причин, або я шукаю те, чого взагалі не існує. Це справжнє питання при роботі над проектом з більш ніж одним кодером.

null означає, що "жодне значення" явно не встановлено. Практично кажучи, ви мені щось розповідаєте про властивість, можливо, вона не використовується в цьому контексті, або що значення ще належить визначити.

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


0

Спробуйте цей приклад:

<html>
<head>
    <script type="text/javascript">
        function ShowObjProperties(obj) {
            var property, propCollection = "";

            for(property in obj) {
                propCollection += (property + ": " + obj[property] + "\n");
            }

            alert(propCollection);
        }

        var obj = {
            userid: 3,
            name: 'me!',
            speak: function() { alert('Hi! My name is ' + this.name + ' and my ID is ' + this.userid + '.'); }
        }

        //Shows all properties
        ShowObjProperties(obj);

        //The Speak function is no longer in the list!
        delete obj.speak;
        alert(typeof obj.speak);
        ShowObjProperties(obj);

        //The UserID is still listed, it just has no value!
        obj.userid = null;
        ShowObjProperties(obj);
    </script>
</head>
<body>

</body>
</html>

Я думаю, що тут є дуже реальне використання для двох різних типів.


І в прототипах, я думаю, це член нульовий або просто не визначений.
Кев

але це працює лише до тих пір, поки ніхто не намагатиметься його зламати - якщо я встановлю obj.userid = undefined, це не вдасться - дивіться останню редакцію мого питання
Крістоф

0

Це зводиться до динамічного характеру Javaскриптів.

Речі можуть бути невизначеними, щоб їх можна було додати в подальшому. Це, мабуть, тому javascript настільки потужний і розширюваний.


і це стосується мого питання, яким чином?
Крістоф

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

0

це важлива мовна особливість, якщо ви обмотаєте програму навколо рівномірної парадигми javascript.

// a key exists as a placeholder for something
if(obj[name] === null) 
// no key exists int eh hashtable that is in this object
if(obj[name] === undefined)

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

filter_func_pt = {
  date:function(d){ return Math.round(d.getTime()/1000);},
  user: null,
}

function transform(obj){
    var ret = {};
    for( var prop in obj){
       var f = filter_func_pt[prop];
       if(f)
          ret[prop] = f(obj);
       else if(filter_func_pt[prop] === null)
         continue;
       else
         ret[prop] == obj;
    }
  return ret;
}

var a = {
   date: new Date(),
   user: 'sam'
   votes: [23, 41, 55] 
};

var b = transform(a);

/* b = {
 *    date: 1298582417
 *    votes: [23, 41, 55]
 * }
 */

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


Цей приклад надуманий і трохи безглуздий. Null зовсім не уточнює ваш намір - скоріше, він маскує його. Ви могли використати більш явний рядок, щоб уточнити значення. Як, наприклад, "утримувати" або "смуга", і тоді ви також можете отримати більш чітке опис типу функції і фактично перевірити наявність функції.
Ерік Елліотт

0

null прекрасна

як і всі інші типи живого сценарію.

cite: У JavaScript є два значення, які в основному говорять "я не існую" - невизначене та null.

Чому б ви хотіли сказати неправильні речі ?!

"null" - це "порожній об'єкт" так само, як "0" є "порожнім числом" . 0, не є нічого, але воно існує як річ типу число. Нуль , звичайно, також порожній, але "він є", і це чітко визначена річ типу об'єкта .

Про ці речі прийнято говорити як про "типи", коли їх немає. Насправді вони є "категоріями". Але це закінчилося зараз.

Тож дотримуватиметься цього, щоб сказати, що "null" - це тип об'єкта без виду. І "null" говорить "я дуже існую [!], Але не маю такого змісту".

Тоді як для невизначеного не вистачає і типу, і виду, де невизначене також є його визначенням типу. Невизначений тип типу стає його характерною типологією. Сорт [чи "нічого" не існує, і як ви визначаєте "нічого"?].

cite: undefined ні null не може бути повернуто з функції конструктора, оскільки обидва будуть перетворювачем у порожній об'єкт

Вам вдалося ще раз сказати неправильну річ. Звичайно, ні, "невизначений" - це не Об'єкт, це звичайний жетон, який ми розуміємо; але всупереч цьому нулю є - і це говорить вам про те, що його Тип правильний, але той вид, який ви шукаєте, не міститься в ньому, або, принаймні, - зараз. Приходьте до нас пізніше, коли ми помістимо \ призначити якийсь об’єкт у \.

цитувати: Єдина реальна різниця, яку я можу придумати, - це те, що один оцінює NaN, інший - 0 у числових контекстах.

Це вказує на суть їхнього основного розрізнення, як згадувалося: undefined - це звичайна лексема, і оскільки вона складається з того ж «генетичного» матеріалу, що і його далекі родичі: рядки, операція [+ undefined] перетворить його на NaN, аналогічно null, звичайно, перетворюється на правильний вид 0 \ Number замість цього, а на відміну від невизначеного, що перетворюється на рядок (! Який не порожній!), І саме тому він дає NaN замість цього. Де: + невизначений >> + "невизначений" >> NaN. Оскільки числовий контекст очікує явного значення.

У той час як булевий контекст очікує посилання - не знаходить нічого для перетворення і дає "false".

Давайте виріжемо зараз ...

цитую: Отже ще раз: яке практичне використання для окремих значень для невизначених та нульових?

Я спробую дати вам лише два емпіричні приклади і сподіваюся, що їх вистачить

oElement.onclick >> null

// означає -властивість існує; очікуване значення типу Type: Object , і цей oElement підтримує подію "onclick"!

oElement.innerText >> ""

// означає - властивість існує; очікуване значення має Type: String , що означає, що oElement підтримує властивість "innerText".

в обох випадках - якщо ви отримаєте "невизначено", це означає, що властивість не існує; не підтримується або має неправильну реалізацію (постачальник ua).

Залишайтесь морозом і отримуйте задоволення.


Не скасовуйте своїх публікацій, Еней. Видаліть їх ( натискаючи кнопку Видалити трохи вище цього коментаря), якщо ви хочете видалити свій внесок.
Майкл Петротта

немає кнопки видалення - але у випадку, якщо ви її побачите, просто натисніть її!

0

після прочитання дивовижної дискусії щодо undefined vs null, маленький пошук у google переніс мене до Mozilla Documentations https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null це згадується - null часто отримано в місці, де можна очікувати об'єкт, але жоден об'єкт не має значення.

Не схожий на Null object pattern https://en.wikipedia.org/wiki/Null_object_pattern

Отже, я думаю, це має сенс мати тип даних Null.

Документація також згадується як typeof null // "object" (не "null" з застарілих причин)

Не впевнений, які причини спадщини

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