typeof! == «undefined» против! = null

492

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

if (typeof input !== "undefined") {
    // do stuff
}

Это кажется расточительным, поскольку включает как поиск типов, так и сравнение строк, не говоря уже о его многословности. Это нужно, потому что undefinedможно было бы переименовать.

Мой вопрос:
как этот код лучше, чем этот подход:

if (null != input) {
    // do stuff
}

Насколько я знаю, вы не можете переопределить null, поэтому он не сломается неожиданно. И, из-за приведения типов !=оператора, он проверяет и то, undefinedи другое null... что часто именно то, что вы хотите (например, для необязательных параметров функции).

Тем не менее, эта форма не кажется широко распространенной, и она даже заставляет JSLint кричать на вас за использование !=оператора зла .

Почему это считается плохим стилем?

Дерек Турн
источник
13
@ Марсель, разницы нет, но для этого есть две причины. Во-первых, для некоторых это яснее читать. И вторая причина заключается в том, что она предотвращает случайное перезапись переменной. Вы когда-нибудь делали это: if (foo = "value"), когда намеревались сделать сравнение. Если вы привыкнете менять переменную в операторе присваивания / сравнения, у вас не возникнет этой проблемы.
Layke
29
Для некоторых (включая меня) это на самом деле труднее читать. Кроме того, большинство IDE предупреждают вас о случайном назначении. Но я все еще использую эту форму, если сравниваемая переменная очень длинная. YMMV.
Johndodo
15
@MarcelKorpel Это называется "состояние Йоды": umumble.com/blogs/Programming/321
kol
55
Это сложнее читать. Никто не говорит: «Не пустая бутылка».
Ноэль Абрахамс
11
if (null != input)это только «Йода говорить» для говорящего на английском языке (из одного я .... uuammmmm), так что если они приравнивают к одной и той же вещи, это на самом деле просто семантика. ИМХО.
webLacky3rdClass

Ответы:

710

typeof безопаснее, так как позволяет идентификатору никогда не быть объявленным ранее:

if(typeof neverDeclared === "undefined") // no errors

if(neverDeclared === null) // throws ReferenceError: neverDeclared is not defined
seanmonstar
источник
3
if ((typeof neverDeclared! == "undefined") && (neverDeclared! == null)) {return true; } else {return false; }
Энтони ДиСанти,
88
Используйте === при сравнении с null / undefined.
MyGGaN
47
@MyGGaN, только если вы хотите различать два. Во многих случаях ==может быть лучше, потому что он тестирует как нулевой, так и неопределенный.
seanmonstar
10
Я не могу найти никакой разницы между typeof somevar == 'undefined' и typeof somevar === 'undefined', потому что typeof всегда возвращает строку. Для нуля это возвратит «объект». Или может быть, я ошибаюсь?
TomTom
2
Я считаю, что комментарий @ TomTom - суть проблемы - я не могу понять, почему можно использовать операторы !==or ===при сравнении значения, тип которого известен как строка.
Николас Ринаудо
49

Если переменная объявлена ​​(либо с varключевым словом, либо как аргумент функции, либо как глобальная переменная), я думаю, что лучший способ сделать это:

if (my_variable === undefined)

JQuery делает это, так что это достаточно хорошо для меня :-)

В противном случае вам придется использовать, typeofчтобы избежать ReferenceError.

Если вы ожидаете, что undefined будет переопределен, вы можете обернуть ваш код следующим образом:

(function(undefined){
    // undefined is now what it's supposed to be
})();

Или получить его через voidоператора:

const undefined = void 0;
// also safe
Джои Адамс
источник
1
Если undefined уже определен, то не передали ли бы вы его анонимной функции через параметр с именем undefined, ничего не добившись?
Энтони ДиСанти
20
@Anthony DiSanti: Нет, undefinedэто имя параметра функции, а не его значение. В функцию ничего не передается, то есть значение первого параметра не определено.
Джои Адамс
3
Ах, моя ошибка, спасибо за продолжение. Я убрал свой голос, извините за это.
Энтони ДиСанти
2
Зачем писать исключение для обработки неопределенного, объявленного другим разработчиком, если вы можете просто сделать это правильно для начала? jQuery оборачивает исходную анонимную функцию, как показано в вашей функции, чтобы гарантировать, что undefined не был определен, и уменьшить минимизированный размер. Проще говоря, если это может дать неожиданные результаты, чтобы сделать это таким образом, зачем рисковать ленивым программированием, чтобы избежать ввода (переменная typeof === 'undefined'). Что если бы мы хотели (typeof variable === 'object'), мы должны предоставить переменную по умолчанию, которая также является объектом, чтобы мы могли это сделать (variable === object)?
fyrye
28

хороший способ:

if(typeof neverDeclared == "undefined") //no errors

Но лучший способ проверить это:

if(typeof neverDeclared === typeof undefined) //also no errors and no strings
шутка
источник
6
var undefined = function () {}; if (typeof neverDeclared === typeof undefined); neverDecalred! = 'function'; jsfiddle.net/hbPZ5 return typeof var; возвращает строку Нет ошибок или строк, но не всегда даст ожидаемые результаты. Предоставленные разработчики не должны объявлять undefined, но есть некоторые фреймворки и библиотеки, которые это делают.
14:55
1
Я в основном использую, if (typeof neverDeclared === typeof undefined) { но Lint выдает ошибку. Msgstr "Ожидал строку и вместо этого увидел" typeof "." Как бы вы обойти эту ошибку? Должны ли мы подчиняться требованиям Линт и использовать вместо этого «хороший путь»?
Ayelis
2
@fyrye Знаете ли вы какие-либо библиотеки / фреймворки JavaScript, которые на самом деле мутируют неопределенно? Я знаю, что это возможно; но я хотел бы найти в диком примере: «Вот где вы можете встретить этого противного антилопу гну!»
bigtunacan
4
typeof neverDeclared === typeof void 0;-D
Алексей Ярошевич
1
Он подвержен ошибкам, потому что на самом деле вы просто полагаетесь на то, что определенная переменная («неопределенная») не определена. Что может быть ложным, как показали другие посты. Вы всегда можете сделать, if(typeof neverDeclared === typeof undefined_variable_with_a_name_assumed_to_be_never_defined) {но это довольно долго.
Пьер-Оливье Варес
12

Вы не должны беспокоиться о переименовании неопределенного. Если кто-то переименует undefined, у вас будет гораздо больше проблем, чем с несколькими, если проверки не пройдены. Если вы действительно хотите защитить свой код, оберните его в IFFE (немедленно вызванное выражение функции), например:

(function($, Backbone, _, undefined) {
    //undefined is undefined here.
})(jQuery, Backbone, _);

Если вы работаете с глобальными переменными (что уже неправильно) в среде браузера, я бы проверил неопределенность следующим образом:

if(window.neverDefined === undefined) {
    //Code works
}

Поскольку глобальные переменные являются частью объекта окна, вы можете просто проверить неопределенность, вместо приведения к строке и сравнения строк.

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

Пеетер
источник
1
Проверка ввода и проверка зависимостей являются хорошими причинами для использования этого. Если у меня есть файлы Javascript, которые зависят от других загруженных файлов или объявленных объектов init, то полезно проверить объекты или свойства, от которых зависит файл, в отношении undefined и выдать приятное исключение вместо того, чтобы позволить вашему сценарию произойти сбой в непредсказуемом месте.
AmericanUmlaut
Похоже, что вам может понадобиться что-то в линиях AMD (require.js)
Питер
1
Или я мог бы просто сделать очень простое сравнение, а не включать другую библиотеку в свой проект :)
AmericanUmlaut
Слишком поздно для редактирования :(. Хотел добавить - require.js также не является правильным решением для проверки ввода (объекты init, о которых я упоминал в моем первоначальном комментарии). Если у вас есть объект, который вы ожидаете заполнить определенным значения перед загрузкой сценария, тогда полезно генерировать исключение, если они не определены
AmericanUmlaut
1
Нет, потому что typeof возвращает строку. Поэтому typeof undefined возвращает "undefined". window.input! == undefined (если ваша переменная находится в глобальной выборке)
Peeter
5

Если вы действительно беспокоитесь о переопределении undefined, вы можете защитить его с помощью некоторого вспомогательного метода, подобного этому:

function is_undefined(value) {
   var undefined_check; // instantiate a new variable which gets initialized to the real undefined value
   return value === undefined_check;
}

Это работает, потому что когда кто-то пишет, undefined = "foo"он только позволяет имени undefined ссылаться на новое значение, но он не меняет фактическое значение undefined.

Иво Ветцель
источник
1
Тем не менее, вы теперь ввели вызов функции, который будет вредить производительности.
Тим Даун
Я не думаю, что этот вызов функции снизит производительность, гораздо более вероятно, что DOM станет узким местом. Но в любом случае, если у вас есть обычная большая анонимная функция, которая содержит вашу библиотеку, вы также можете определить undefined_checkее вверху, а затем просто использовать ее везде в своем коде.
Иво Ветцель
1
Согласен, и я не говорю, что это плохая идея. Стоит только отметить, что вызов этой функции будет выполняться медленнее, чем typeofпроверка.
Тим Даун
Я думаю, что эта функция достаточно проста, чтобы она была встроенной, чтобы производительность не пострадала.
Хайз
4
@TimDown: сначала написать код, который читается. второй код записи, который можно обслуживать, а затем, если это действительно медленно. затем подумайте о производительности.
Андреас
4

Вы также можете использовать оператор void для получения неопределенного значения:

if (input !== void 0) {
    // do stuff    
}

(И да, как отмечалось в другом ответе, это приведет к ошибке, если переменная не была объявлена, но этот случай часто может быть исключен либо путем проверки кода, либо путем рефакторинга кода, например, window.input !== void 0для тестирования глобальных переменных или добавления var input.)

Клод
источник
1

Я действительно сталкивался, если (typeof input !== 'undefined')в этом сценарии он используется для предоставления параметров функции по умолчанию:

function greet(name, greeting) {
  name = (typeof name !== 'undefined') ?  name : 'Student';
  greeting = (typeof greeting !== 'undefined') ?  greeting : 'Welcome';

  return `${greeting} ${name}!`;
}

greet(); // Welcome Student!
greet('James'); // Welcome James!
greet('Richard', 'Howdy'); // Howdy Richard!

ES6 предоставляет новые способы введения параметров функции по умолчанию следующим образом:

function greet(name = 'Student', greeting = 'Welcome') {
  return `${greeting} ${name}!`;
}

greet(); // Welcome Student!
greet('James'); // Welcome James!
greet('Richard', 'Howdy'); // Howdy Richard!

Это менее многословно и чище, чем первый вариант.

JSpecs
источник
1

function greet(name, greeting) {
  name = (typeof name !== 'undefined') ?  name : 'Student';
  greeting = (typeof greeting !== 'undefined') ?  greeting : 'Welcome';

  console.log(greeting,name);
}

greet(); // Welcome Student!
greet('James'); // Welcome James!
greet('Richard', 'Howdy'); // Howdy Richard!

//ES6 provides new ways of introducing default function parameters this way:

function greet2(name = 'Student', greeting = 'Welcome') {
//  return '${greeting} ${name}!';
console.log(greeting,name);
}

greet2(); // Welcome Student!
greet2('James'); // Welcome James!
greet2('Richard', 'Howdy'); // Howdy Richard!

Авинаш Маурья
источник
0

(function(){

  var a= b = 3;
  var ed = 103;
  
})();



//console.log(ed); //ed is not defined

console.log("a defined? " + (typeof a !== 'undefined')); //no define
console.log("b defined? " + (typeof b !== 'undefined')); //yes define
console.log(typeof(b)); //number
console.log(typeof(4+7));   //number
console.log(b); //3
console.log(typeof("4"+"7")); //string
var e= "ggg";
console.log(typeof(e)); //string
 var ty=typeof(b);
console.log(ty); //number
console.log(typeof false); //boolean
console.log(typeof 1); //number
console.log(typeof 0); //number
console.log(typeof true); //boolean


console.log(typeof Math.tan);  //function
console.log(typeof function(){}); //function 

if(typeof neverDeclared == "undefined") //no errors
if(typeof neverDeclared === "undefined") //no errors

//if(neverDeclared == null) //showing error 


console.log(typeof {a:1}); //object
console.log(typeof null); //object
console.log(typeof JSON); //object
console.log(typeof Math); //object
console.log(typeof /a-z/); //object
console.log(typeof new Date()); //object

console.log(typeof afbc); //undefined
//console.log(typeof new);//error

document.write("<br> * oprator as math ");
var r=14*"4";
document.write(r);

document.write("<br> + oprator as string ");
var r=14+"44";
document.write(r);

document.write("<br> Minus Operator work as mathematic ");
var r=64-"44";
document.write(r);


document.write("<br>");
console.log(typeof(4*"7")); //returns number
console.log(typeof(4+"7")); //returns string




 
Interview Question in JavaScript

Авинаш Маурья
источник
Можете ли вы дать объяснение?
Jhpratt GOFUNDME RELICENSING
Существует шесть возможных значений, которые возвращает typeof: object, boolean, function, number, string и undefined. Оператор typeof используется для получения типа данных (возвращает строку) своего операнда. Операнд может быть литералом или структурой данных, такой как переменная, функция или объект. Оператор возвращает тип данных. Синтаксис typeof операнд или typeof (операнд)
Авинаш Маурья
0

var bar = null;
console.log(typeof bar === "object"); //true yes 
//because null a datatype of object

var barf = "dff";
console.log(typeof barf.constructor);//function


console.log(Array.isArray(bar));//falsss


console.log((bar !== null) && (bar.constructor === Object)); //false

console.log((bar !== null) && (typeof bar === "object"));  // logs false
//because bar!==null, bar is a object


console.log((bar !== null) && ((typeof bar === "object") || (typeof bar === "function"))); //false

console.log(typeof bar === typeof object); //false
console.log(typeof bar2 === typeof undefined); //true
console.log(typeof bar3 === typeof undefinedff); //true
console.log(typeof bar2 == typeof undefined); //true

console.log((bar !== null) && (typeof bar === "object") && (toString.call(bar) !== "[object Array]")); //false

Авинаш Маурья
источник
-7
if (input == undefined) { ... }

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

else if (input) { ... }

Является ли.

Если программа переопределяет undefinedэто, это действительно мозговой смерть в любом случае.

Единственная причина, по которой я могу придумать, заключалась в совместимости с IE4, он не понимал undefinedключевое слово (к сожалению, на самом деле это не ключевое слово), но, конечно, значения могли быть undefined , поэтому вы должны были иметь это:

var undefined;

и сравнение выше будет работать просто отлично.

Во втором примере вам, вероятно, нужны двойные скобки, чтобы сделать ворс счастливым?

UniquePhoton
источник
Ваш input == undefinedвернется trueна nullвход.
mgol