Всё только о JavaScript

undefined != undefined

undefined (неопределённое значение) — элементарное значение типа Undefined, используемое, когда переменной или свойства объекта не существует или ему ещё не было присвоено значение. Т.е. положительность условия

foo.bar == undefined

или

typeof foo.bar == 'undefined'

может означать как отсутствие свойства bar у объекта foo, так и его наличие, но со значением undefined. Равно как и положительность условия

typeof undef == 'undefined'

может означать отсутствие переменной undef или её наличие со значением undefined. Обратите внимание, что запись undef == undefined вызовет исключение ReferenceError в случае, если переменной undef не существует. В то время как typeof undef выполнится корректно.

В случаях, когда необходимо проверить наличие свойства с любым значением, в том числе undefined, необходимо проверять именно наличие свойства, а не его значение. Для этого предназначен оператор in.

if (foo.bar == undefined) {
    alert('Свойства bar у объекта foo или нет, или оно равно undefined');
}
if ('bar' in foo) {
    alert('Свойство bar у объекта foo есть.');
}

Проверить наличие глобальной переменной можно проверяя наличие свойства у window.

if ('t' in window) {
    alert('Существует глобальная переменная t');
}

Наличие локальной переменной проверить нет возможности, но это, как правило, и не требуется, т.к. локальное пространство имён находится под большим контролем, нежели глобальное.

Необязательные аргументы функций

Если в функцию не передать аргумент, то к ней придёт undefined. Также как если передать undefined придёт, разумеется, он же. Поэтому, если нужно узнать именно, был ли передан аргумент, вне зависимости от его значения, то нужно проверять свойство length объекта arguments. Оно будет равно количеству переданных в функцию аргументов.

Реализуем, например, метод push для массивов, который полученные аргументы добавляет в массив. Он конечно же должен уметь добавлять undefined.

Array.prototype.push = function() {
    for (var i = 0; i < arguments.length; i++) {
        this[this.length] = arguments[i];
    }
};

В последнее время также распространена эмуляция свойств методом, который при отсутствии аргумента притворяется геттером, а при наличии — сеттером. Здесь тоже важно проверять передан ли аргумент, а не что именно передано.

// Неправильно, при таком подходе невозможно присвоить undefined
foo.property = function(value) {
    if (typeof value == 'undefined') {
        // Возвращаем значение
    } else {
        // Присваиваем значение
    }
}

// Правильно
foo.property = function(value) {
    if (arguments.length > 0) {
        // Присваиваем значение
    } else {
        // Возвращаем значение
    }
}

Восстановление undefined

undefined это всего лишь заранее определённая глобальная переменная. Её, как и любую другую переменную, можно переопределить, и тогда более компактная конструкция foo.bar == undefined работать не будет. Поэтому для большей отказоустойчивости скриптов необходимо использовать или typeof, или "добывать" для себя значение типа Undefined. Для этого можно воспользоваться несколькими способами.

Во-первых, существует конструкция void, которая всегда возвращает undefined.

var my_undef = void 0;

Во-вторых, можно описать локальную переменную, но не инициализировать её.

(function() {
    var undefined;
})();

В-третьих, можно завернуть исполняемый скрипт в безымянную функцию, описать у неё параметр, но сам параметр при вызове не передавать.

(function(undefined) {

})();