Pull to refresh

Comments 99

if (myArray[3] != undefined)

Распространенная ошибка — считать undefined зарезервированным именем:

<script>
var myArray = [];
if (myArray[3] != undefined) {
	alert('1: true');
}
var undefined = true;
if (myArray[3] != undefined) {
	alert('2: true');
}
</script>

На самом деле всегда нужно делать так:

<script>
var myArray = [];
if (typeof myArray[3] != 'undefined') {
	alert('1: true');
}
var undefined = true;
if (typeof myArray[3] != 'undefined') {
	alert('2: true');
}
</script>
Да не то, чтобы часто встречалась такая ситуация, когда значение undefined подошло бы :). Следовательно, проверка на значение undefined вполне уместна и без проверки на тип 'undefined '.
undefined не зарезервированное слово, всего лишь глобальная переменная, которая может быть переопределена. Поэтому не следует её использовать, только если в случае вы явно определили её значение в текущем контексте.
А в С/PHP/Ruby так вообще ничего подобного нет, представляете! )
честно говоря за несколько лет работы с javascript ниразу не видел чтоб кто-то переопределил undefined
Пока гром не грянет мужик не перекрестится? Ну ничем с точки зрения javascript слово undefined не отличается от, например, antidefined.
с точки зрения языка — нет, а с точки зрения среды в браузере — да. Знаете браузер, где переменная undefined не определена по умолчанию? Знаете браузер, где переменная antidefined определена по умолчанию?

да, есть риск, что кто-то переопределит undefined. Есть такой же риск, что кто-то переопределит setTimeout, Object.prototype и почти любую другую переменную. Просто не используйте такой код и не пишите его сами.

ps: #define TRUE FALSE
Я не вижу различия между определенной переменой «неопределенной» (undefined) и неопределенной переменной antidefined. Почему мне следует избегать переопределения именно переменной undefined? Чем код a == undefined отличается от a == antidefined? Почему я не могу использовать второй вариант и не переопределять нигде antidefined?

Ответ на эти вопросы в простом правиле: проверяйте тип, вместо соответствия непонятной переменной и все будет железно работать так, как задумывалось.
antidefined всё-таки придётся предварительно объявить, иначе ReferenceError будет.
Знаете браузер, где переменная undefined не определена по умолчанию?

IE5 =)

я вам даже сочувствую, что вы это знаете: )
Спасибо, я справляюсь. =)
Принципиально то на вопрос ответили. Итого, опасность не равна 0. Хотя тут речь скорее о переносимости кода. Ныне, например, развиваются мобильные платформы, а уж чего в них напишут…
Best practice за typeof или (function(undefined){/*code*/})();
думаю, на мобильных платформах undefined никуда не денется

проблема с отсутствием его в ie5, имхо, настолько же страшна, насколько и отсутствие document.getElementById в каком-нибудь netscape 1.0
В jQuery это красиво так сделано:
(function($, undefined) {

})(jQuery);
Что и рекомендуется делать всем при возможности. Собственно, по 2 причинам.

1. Мы однозначно определяем значение переменной undefined внутри контекста.
2. Как следствие первого, при обращении к undefined не происходит поиска по глобальному контексту, что есть вери-гуд.
при 'undefined' вообще никакого поиска не происходит.
Здрасте. При отсутствии локальной переменной 'undefined' поиск будет происходить в глобальном контексте, т.к. как уже было сказано, undefined — это всего лишь свойство объекта window.
Да, здравствуйте, 'undefined' — это строка.
А вы шутник :) А ну марш читать спецификацию!

The undefined value is a primitive value used when a variable has not been assigned a value.
Вы издеваетесь или не видите кавычки?
Скорее всего, мы говорим про разные ветки дискуссии.
Эта ветка идёт от комментария

(function($, undefined) {

})(jQuery);
Как следствие первого, при обращении к undefined не происходит поиска по глобальному контексту, что есть вери-гуд.

при 'undefined' вообще никакого поиска не происходит.

Мы говорим про локальный контекст и переменную undefined, которая в нём определена.
Вы же имели ввиду строку со значением 'undefined' (хотя я не понял, как она относится к этому вопрос, там её нет). В общем, надеюсь мы понимаем сейчас, кто о чём говорит. Вопрос же об использовании именно переменной с именем 'undefined', не typeof == 'undefined'.
Что и рекомендуется делать всем при возможности.

Так почему же не использовать строку-то, я вот к чему? Тем более, что оператор typeof строку возвращает.
Методы сравнения значения переменной со значением undefined и определение типа через typeof, который возвращает строку — разные подходы. Вы можете использовать и тот и этот, если точно уверены, что переменная 'undefined' однозначно определена. Мы обсуждали именно использование переменной.

Правда typeof == 'undefined' слегка медленнее, чем сравнение param == undefined, но разница оооочень маленькая.
вместо
(myArray[3] != undefined) и (typeof myArray[3] != 'undefined')
я использую
(myArray[3] != null)

В чём я не прав?
UFO just landed and posted this here
Индусский код какой то.

if ( !somevar )

это чем не устранивает?
лучше всего в данном случае вместо != использовать !==
Про какой конкретный случай вы пишите?

Если автору комментария нужно проверить наличие элемента и одновременно проверить на «пустое» значение, то лучше всего использовать выражение if (myArray[3]) — выполняется быстрее, чем любой из операторов сравнения.

Если нужно сравнить _только_ с undefined и с null, то оптимально использовать if (myArray[3] != null), без сравнения типов операндов — быстрее, чем оператор идентичности !==.
первое выдаст ошибку в IE (при отсутствии свойства)

второе — может быть, надо прогнать тесты. Вообще идентичность быстрее работает, если сравниваемые величины не идентичны (чем простое сравнение, это вроде очевидно). И примерно одинаково, если сравнениваемые величины равны.
Ошибку? Нет, не выдаст. Значение будет undefined. 7 и 8 версии ослика.

Насчет строгого сравнения да, вы правы. Если типы разные, то идентичность быстрее.
Если не разные, то медленнее. Но, опять же, если вы хотите сравнить одновременно с null и с undefined, то нужно использовать !=. Иначе будете сравнивать только с одним из них либо двойное условие.
Starting in Javascript 1.8.5 (Firefox 4), undefined is read only, as per the ECMAscript 5 specification.

Продолжайте писать var undefined = 'бла-бла-бла'; и проверять с помощью typeof…
как это

var myArray = [4,3,1];

console.info(1 in myArray); // will return 'true'
console.info(3 in myArray); // will return 'false' — разве false?
UFO just landed and posted this here
Вы будете просто ошеломлены, узнав, как много других полезных и странно-полезных вещей содержит в себе JS (Ecma). Просто начните читать хорошие мануалы — и много вопросов отпадёт само-собой.
Совершенно согласен, но в мануалах очень много информации, и мелкие, но приятные фичи, как эта, просто забываются.

Так что не смотря на мой + к мануалам, я считаю заметки о таких мелких «вкусностях», о которых легко забыть тоже весьма полезными.
У такой проверки есть одно но: унаследованные свойства и методы также возвращают true:

function Rabbits() {}

var rabbit = new Rabbits();

console.log( 'toString' in rabbit ) // true
Разумнее пользовать

Разумнее пользоваться hasOwnProperty

function Rabbits() { this.tail = 1; }

var rabbit = new Rabbits();

rabbit.hasOwnProperty('tail')


Хотя все зависит от ситуации
rabbit.hasOwnProperty('hasOwnProperty') =х)
Хочется заметить, что может быть следующая ситуация

var a = [1,2,undefined,3]

и в этом случае не получится проверить через if (a[2] != undeined)
т.к. ключ существует, но значение undefined!
тоже самое и с объектами
a = {b:undefined}
ключ b существует, значение undefined и проверить получится только через in

То же самое же и в статье написано.

Кстати в первом случае в IE ключа 2 существовать не будет :)
Да действительно, странно что я этого не заметил.
А еще конструкция
if('param' in object)
работает быстрее чем
if(object['param']) или if(object.param)
Точно, засекали? =)
На глаз заметно при больших объёмах данных :)
Вот небольшой тестик
  console.time('test');
  for(var i=0;i<10000000;++i) 
    if(window['clearTimeout']);
  console.timeEnd('test');
  console.time('test');
  for(var i=0;i<10000000;++i) 
    if('setTimeout' in window);
  console.timeEnd('test');

И результат запущенного кода в консоле Firefox 4
test: 38697ms
test: 2008ms
Ваш тест не совсем верный.
Вы тестируете на глобальном контексте, результаты на нём очень сильно отличаются от результатов на объектах. Да и пример не жизненный, подобного юзкейза я не могу придумать на глобальном контексте, разве что для теста только.

Попробуйте, например, продублировать все поля объекта window в какую-нибудь локальную переменную и запустите свой тест ещё раз. Вы увидите, что, мало того, что результаты почти не оличаются, так in оператор еще и работает чуть медленнее.

Хотя работа in оператора осуществляется через HasProperty() с доп. проверками перед этим, конкретную реализацию которой в браузерах я не знаю. И назначение in оператора всё же несколько иное, чем array[key], который возвращает false в случаях пустой строки, нуля, false и null.
эм, вот только если в object['param'] будет false или 0 или что то подобное,. то всё как то печально станет, не находите?
Это зависит от задачи, не находите ли?
Если нужно проверит на существование свойства то нужно использовать in.
Если нужно проверить на положительный результат то in не подходит но все равно if('param' in object && object['param']) будет быстрей с учетом конечно если много не определенных свойств.
И опять же нужно ли это использовать нужно смотреть по обстоятельствам.
А вот здесь вы совсем не правы. Двойная проверка ни к чему, она замедлит выполнение двоекратно.
Не верите? Протестируйте.
Я же уточнил если большинство не определенных свойств. Ну а в жизни конечно не видел таких обстоятельств. Это я сказал как интересный факт не более того :)
Что значит «неопределённых»? if (object['param']) — вполне достаточно, чтобы покрыть все false-значения, включая undefined (несуществующее в объекте)
А не что 0 это тоже значение, и оно иногда нужное :)
В общем спор не о чем
Извините, но вы, по-моему, не понимаете сути.

Выполняя двойную проверку if ('param' in object && object['param']) результат абсолютно аналогичный if (object['param']). Это как написать: if (3 > -1 && 3 >=0)
Хорошо вот вам еще один тест
console.time('test');
for(var i=0;i<100000;++i) 
  if(window['test'] );
console.timeEnd('test');
console.time('test');
for(var i=0;i<100000;++i) 
  if('test' in window && window['test']);
console.timeEnd('test');

Результаты
test: 1408ms
test: 592ms
Забудьте про глобальный контекст.

Попробуйте на локальныъ объектах, такой разницы не будет.
Но хотя в одном я соглашусь: если вы ВСЕГДА пытаетесь найти несуществующее значение 100000 раз, то in оператор будет быстрее процентов на ~15% плюс-минус.
>>Это зависит от задачи, не находите ли?
а название топика не на что не наводит?
if(object['param']) или if(object.param)

В этом случае проиcходит целый ряд проверок в зависимости от типа и значения param. Если param = (number)0, (boolean)false, undefined, null, (string)'' — то будет false, в остальных случаях true

Поэтому этот метод медленнее.

Было бы правильнее сравнивать производительность if('param' in object) и if(typeof object.param != 'undefined') или hasOwnProperty
вы пердпологаете что получение типа объекта и сравнение его с со строкой будет быстрей?
По моему тут и так ясно что быстрей выполняется и без тестов :)
Дело ваше, хозяйское. Просто сравнивать с заведомо медленной проверкой — странный эксперимент, вот что я хотел сказать.
т.е. этот вариант заведомо быстрый? раз вы предлагаете с ним сравнивать )))))
В нем происходит минимум операций, в отличии от if(object.param). Прежде чем сравнивать производительность, не мешало бы провести оптимизацию проверки if(object.param) и это

if(typeof object.param !=  'ненужный тип') 


или

if(typeof object.param ==  'нужный тип') 

так доступнее объяснил?
ОК держите тест :)
console.time('test');
for(var i=0;i<100000;++i) if(window['setTimeout']); console.timeEnd('test');
console.time('test');
for(var i=0;i<100000;++i) if('setTimeout' in window); console.timeEnd('test');
console.time('test');
for(var i=0;i<100000;++i) if('undefined' == typeof window['setTimeout']); console.timeEnd('test');

Результат
test: 517ms
test: 84ms
test: 529ms
Контр-пример.

obj.param: 1256ms
typeof obj.param == «number»: 1063ms
«test» in obj: 1180ms

Как видите typeof obj.param быстрее obj.param

Однако очевидно, что в разных условиях производительность разная. А значит любые утверждения тут невозможны :)

var obj = { test: 1 }

console.time('obj.param');
for(var i=0;i<10000000;++i)
if(obj['test']);
console.timeEnd('obj.param');

console.time('typeof obj.param == «number»');
for(var i=0;i<10000000;++i)
if(typeof obj['test'] == 'number');
console.timeEnd('typeof obj.param == «number»');

console.time('«test» in obj');
for(var i=0;i<10000000;++i)
if('test' in obj);
console.timeEnd('«test» in obj'); 
Чтобы проверить на «пустое» значение, использование if (obj.param) оптимальнее, чем typeof.
Зачем спорить, когда можно почитать спецификацию, как именно делается проверка, шаг-за-шагом и проверить на практике тестом.

2no_smoking: вы как проверяли на глобальном контексте, так проверяете. Неверно это, поймите.
Тут то речь не про пустое, а про отсутствующее.

З.Ы. Кроме того, явно указывая в проверке чего мы хотим, повышает читаемость кода. Ну это уже каждому свое.
Про какое «отсутствующее» вы говорите, если ваши тесты на присутствующее значение :)
Пардон, в ветке изначально было про отсутствующее, просто потом смысл слегка «уехал»
«О, сколько нам открытий чудных
Готовят просвещенья дух,
И опыт, сын ошибок трудных,
И гений, парадоксов друг,
И случай, бог изобретатель.»
А. С. Пушкин
т.е. наличие любой глобальной переменной можно поверять как if ('someName' in window)?
именно
в capabilities detection такое широко используется
Стоило еще написать, что для итерации по массивам использовать in нельзя.

Вот это — ошибка в большинстве случаев:

for (x in [1,2,3]){
}


т.к. будет пробегаться не только по элементам массива, но и по его свойствам (которые не built-in).

это я к чему — что использовать in для итерации по массивам как раз и нельзя
Да, будет ошибка. Но in использовать иногда удобно.
for(var i in obj) if(obj.hasOwnProperty(i)) {
    // some work
}

С такой проверкой и безопасно и смотрится довольно не плохо.
Перебор свойств объекта, разумеется, такой и должен быть. Перебор элементов массива так делать нельзя, и hasOwnProperty может не спасти, т.к. у самого массива могут быть нечисловые свойства.
UFO just landed and posted this here
как прервать итерацию на середине?
ну, например, так:
fn.call(...)
if (fn.call(...) === false) return;


[1,2,3].forEach(function(element, index) {
if (index === 2) return false;
});
а с методом map что будешь делать?
читал. отладка в IE невозможна даже без перехвата ексепшинов. отладка в других браузерах не напрягает даже с перехватом.
вполне себе возможна. есть куча инструментов
>> как прервать итерацию на середине?

Использовать every или some, а не forEach.
как их реализовать?
то есть копипастой кода итерирования? хорошо, как решить такую задачу:

есть массив вида [1,2,3,4,5,0,5,4,3,2,1]
нужно составить массив из квадратов чисел идущих до 0, то есть: [1,4,9,16,25]

break или continue
хотя не рекомендуют, но в случае вложенных массивов удобней и работает быстрее.
имеется ввиду из колбэка
Учите мат. часть — это же и так очевидные вещи, зачем про них на Хабре писать?
Флэнагана почитайте и пишите то, что может быть действительно интересно, а не прописные истины…
Точно. Скоро кто ни будь с восторгом про alert напишет.
Sign up to leave a comment.

Articles