змінна === undefined порівняно з typeof змінною === "undefined"


300

В Рекомендації Jquery Основні Стиль пропонують два різні способи перевірити, чи визначена змінна.

  • Глобальні змінні: typeof variable === "undefined"
  • Локальні змінні: variable === undefined
  • Властивості: object.prop === undefined

Чому jQuery використовує один підхід для глобальних змінних та інший для локальних та властивостей?


Я не можу відповісти на питання, чому JQuery використовував би обидва підходи, але у Javascript є цікаві примхи, які означають, що ці дві речі є дуже різними. Це не має значення в більшості випадків (тобто, якщо ваш код здоровий), але все ж існують відмінності: див. Тут для написання - wtfjs.com/2010/02/15/undefined-is-mutable
Spudley

2
Як зазначав @Struppi, найкоротша функція jQuery має аргумент, який називається невизначеним. У jQuery foo === undefinedпроводиться перевірка локальної копії невизначеної замість глобальної (window.undefined), яка, можливо, була змінена божевільним кодом. Те, що невизначене є змінним, безумовно, варто зазначити, і я радий, що ви зробили це. (+1)
Патрік МакЕлхані

1
Поточна посилання на цю статтю - wtfjs.com/wtfs/2010-02-15-undefined-is-mutable
загадка

Відповіді:


366

Для незадекларованих змінних typeof fooповернеться рядковий літерал "undefined", тоді як перевірка ідентичності foo === undefinedпризведе до помилки "foo не визначено" .

Для локальних змінних (які ви знаєте декларовані десь), така помилка не відбудеться, отже, перевірка ідентичності.


3
@goreSplatter Зараз його не можна видалити. :-) Важко було вибрати, але те, як формулюється питання, ця відповідь краще підходить. Кожен, хто зацікавлений у тому, як невизначено працює взагалі (як я), також повинен подивитися на інші відповіді, особливо @ Тім.
Патрік МакЕлхані

4
Я б додав лапки ( typeof foo; // -> "undefined"), щоб підкреслити, що це рядок, а не примітивне значення undefined.
c24w

117

Я б дотримувався використання typeof foo === "undefined"скрізь. Це ніколи не може піти не так.

Я уявляю, що причина, по якій jQuery рекомендує два різні методи, полягає в тому, що вони визначають свою власну undefinedзмінну в межах функції, в якій живе jQuery-код, тому всередині цієї функції undefinedзахищено від підробки ззовні. Я б також міг уявити, що хтось десь орієнтував два різні підходи і виявив, що foo === undefinedце швидше, і тому вирішив, що це шлях. [ОНОВЛЕННЯ: як зазначається в коментарях, порівняння з цим undefinedтакож трохи коротше, що може врахувати.] Однак виграш у практичних ситуаціях буде абсолютно незначним: ця перевірка ніколи не буде, ніколи не буде вузьким місцем, і що таке Ви втрачаєте важливо: оцінка властивості об'єкта хоста для порівняння може призвести до помилки, тоді як atypeof перевірити ніколи не буде.

Наприклад, для ISE для аналізу XML використовується наступне:

var x = new ActiveXObject("Microsoft.XMLDOM");

Щоб перевірити, чи є у нього loadXMLметод безпечно:

typeof x.loadXML === "undefined"; // Returns false

З іншої сторони:

x.loadXML === undefined; // Throws an error

ОНОВЛЕННЯ

Ще однією перевагою typeofперевірки, яку я забув згадати, було те, що вона також працює з незадекларованими змінними, чого foo === undefinedперевірка не робить, а насправді викидає a ReferenceError. Дякую @LinusKleen за те, що нагадав. Наприклад:

typeof someUndeclaredVariable; // "undefined"
someUndeclaredVariable === undefined; // throws a ReferenceError

Підсумок: завжди використовуйте typeofчек.


10
Дякую Тіме. Ваша думка щодо продуктивності має сенс. Команда jQuery, ймовірно, більше стурбована впливом на розмір файлу. foo === undefined, при мінімізації - це, мабуть, щось подібне f===u, тоді як typeof foo === "undefined"його можна звести лише до typeof f==="undefined".
Патрік МакЕлхані

1
Ви можете визначити var u = "undefined"і зменшити його до typeof f==u, що покращує речі, але все-таки більше.
Tim Down

5
Хороші моменти, але я не впевнений, що безпека typeofпроти недекларованих змінних є перевагою. Якщо що-небудь дозволяє друкарським помилкам прослідкувати простіше, і я не бачу, коли ви насправді хочете перевірити тип незадекларованих змінних.
Девід Тан

2
@ Box9: Я можу уявити, як використовувати його в бібліотеці, щоб перевірити наявність іншої бібліотеки.
Tim Down

2
@jontro: Це одна з причин не використовувати JSLint тоді.
Тім Даун

29

Ще одна причина використання типу-варіанту: undefinedможе бути переосмислена.

undefined = "foo";
var variable = "foo";
if (variable === undefined)
  console.log("eh, what?!");

Результат typeof variable не може.

Оновлення : зауважте, що це не так у ES5, там глобальна властивість, яка не undefinedможе бути налаштована, не підлягає запису:

15.1.1 Властиві значення глобального об'єкта
[...]
15.1.1.3 невизначено
Значення undefinedне визначено (див. 8.1). Ця властивість має атрибути
{[[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false}.

Але це все ще може бути затінене локальною змінною:

(function() {
  var undefined = "foo";
  var variable = "foo";
  if (variable === undefined)
    console.log("eh, what?!");  
})()

або параметр:

(function(undefined) {
  var variable = "foo";
  if (variable === undefined)
    console.log("eh, what?!");  
})("foo")

17
Неможливо переробити в ES5.
Ри-

6
Глобальну undefinedвластивість не можна переосмислити в ES5, але все ж може бути затінена локальною змінною. void 0коротше і безпечніше.
Оріол

7

Тому що undefinedне завжди декларується, але jQuery заявляє undefinedу своїй головній функції. Таким чином, вони використовують безпечне undefinedзначення всередині, але зовні, вони використовують typeofстиль, щоб бути безпечним.



1

Для локальних змінних перевірка з localVar === undefinedспрацьовує, оскільки вони повинні бути визначені десь у межах локальної сфери, або вони не будуть вважатися локальними.

Для змінних, які не локальні і ніде не визначені, перевірка someVar === undefinedвикине виняток: Uncaught ReferenceError: j не визначено

Ось код, який пояснить, про що я говорю вище. Будь ласка, зверніть увагу на вбудовані коментарі для подальшої ясності .

function f (x) {
    if (x === undefined) console.log('x is undefined [x === undefined].');
    else console.log('x is not undefined [x === undefined.]');

    if (typeof(x) === 'undefined') console.log('x is undefined [typeof(x) === \'undefined\'].');
    else console.log('x is not undefined [typeof(x) === \'undefined\'].');

    // This will throw exception because what the hell is j? It is nowhere to be found.
    try
    {
        if (j === undefined) console.log('j is undefined [j === undefined].');
        else console.log('j is not undefined [j === undefined].');
    }
    catch(e){console.log('Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.');}

    // However this will not throw exception
    if (typeof j === 'undefined') console.log('j is undefined (typeof(x) === \'undefined\'). We can use this check even though j is nowhere to be found in our source code and it will not throw.');
    else console.log('j is not undefined [typeof(x) === \'undefined\'].');
};

Якщо ми називаємо наведений вище код таким чином:

f();

Вихід був би таким:

x is undefined [x === undefined].
x is undefined [typeof(x) === 'undefined'].
Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.
j is undefined (typeof(x) === 'undefined'). We can use this check even though j is nowhere to be found in our source code and it will not throw.

Якщо ми називаємо наведений вище код таким (з фактичним значенням):

f(null); 
f(1);

Вихід буде:

x is not undefined [x === undefined].
x is not undefined [typeof(x) === 'undefined'].
Error!!! Cannot use [j === undefined] because j is nowhere to be found in our source code.
j is undefined (typeof(x) === 'undefined'). We can use this check even though j is nowhere to be found in our source code and it will not throw.

Коли ви робите перевірку так:, typeof x === 'undefined'ви по суті запитуєте це: Будь ласка, перевірте, чи xіснує змінна (була визначена) десь у вихідному коді. (більш-менш). Якщо ви знаєте C # або Java, цей тип перевірки ніколи не робиться, тому що якщо він не існує, він не збирається.

<== Fiddle Me ==>


1

Підсумок:

Коли в глобальному масштабі ми насправді хочемо повернути true, якщо змінна не оголошена або має значення undefined:

var globalVar1;

// This variable is declared, but not defined and thus has the value undefined
console.log(globalVar1 === undefined);

// This variable is not declared and thus will throw a referenceError
console.log(globalVar2 === undefined);

Оскільки в глобальному масштабі ми не на 100% впевнені, чи буде оголошена змінна, це може дати нам referenceError. Коли ми використовуємо typeofоператор на невідомій змінній, ми не отримуємо цю проблему, коли змінна не оголошена:

var globalVar1;

console.log(typeof globalVar1 === 'undefined');
console.log(typeof globalVar2 === 'undefined');

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


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

var obj = {};

console.log(obj.myProp === undefined);


-5

typeof a === 'undefined'швидше, ніж a === 'undefined'приблизно, у 2 рази на вузлі v6.9.1.


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