JavaScript - Определите, определено ли свойство и установлено значение undefined или undefined.

Скажем, у меня есть следующий код:

function One() {}
One.prototype.x = undefined;

function Two() {}

var o = new One();
var t = new Two();

o.x и t.x будут оценивать как undefined. o.hasOwnProperty('x') и t.hasOwnProperty('x') вернут false; то же самое и с propertyIsEnumerable. Два вопроса:

  • Есть ли способ узнать, что o.x определено и установлено в undefined?
  • Есть ли причина для этого? (должны ли они быть семантически эквивалентными?)

Небольшое предостережение: выполнение цикла (для propName in o) даст 'x' в качестве одной из строк, а выполнение этого в t - нет - так что есть разница в том, как они представлены внутри (по крайней мере, в Chrome).


person Claudiu    schedule 22.12.2008    source источник


Ответы (7)


Немного проще, чем ваш метод, - использовать оператор Javascript in

alert('x' in o); // true
alert('x' in t); // false
person Greg    schedule 22.12.2008
comment
Входит ли ключевое слово in в стандарт ECMAScript? Он реализован в Gecko и Webkit, но я не знаю, всегда ли можно полагаться на его присутствие. - person kpozin; 14.01.2011
comment
@kpozin Можешь спокойно использовать in. См. Этот вопрос: stackoverflow.com/questions/2920765/ - person chiborg; 13.03.2012

object.hasOwnProperty (name) возвращает только true для объектов, находящихся в одном объекте, и false для всего остального, включая свойства в прототипе.

function x() {
  this.another=undefined;
};

x.prototype.something=1;
x.prototype.nothing=undefined;
y = new x;

y.hasOwnProperty("something"); //false
y.hasOwnProperty("nothing"); //false
y.hasOwnProperty("another"); //true

"someting" in y; //true
"another" in y; //true

Кроме того, единственный способ удалить свойство - использовать delete. Если для него установлено значение undefined, НЕ удаляйте его.

Правильный способ сделать это - использовать in, как сказал roborg.

Обновление: undefined - это примитивное значение, см. Спецификация языка ECMAScript, разделы 4.3.2 и 4.3.9.

person some    schedule 22.12.2008

Ах, одна там нить анти-паттерны.

undefined не является ключевым словом.

Когда вы назначаете запись var foo = undefined;, вы присваиваете ей значение символа undefined, которое вы не определили, и, следовательно, вы получите значение "undefined". Вы бы получили точно такой же результат, если бы присвоили ему UnDeFiNeD, NotFineAtAll или _qwertyuiop

Почему это так ужасно? Помимо того факта, что это приводит к ложному пониманию того, что происходит, что произойдет, если вам случится загрузить библиотеку или нанять разработчика, который пишет var undefined = true;

person annakata    schedule 22.12.2008
comment
ах, очень интересно. Однако одно замечание - установка UnDeFiNed вызовет ошибку времени компиляции, поскольку эта переменная не определена. установка его на Object.randomStringinserthereplease действует так, как вы говорите. - person Claudiu; 22.12.2008
comment
вы имеете в виду время выполнения, а не компиляцию с JS - но вы правы, мое описание предполагает объем. Проблема возникает из-за того, что undefined можно рассматривать как константу во многих ситуациях и поддерживается некоторыми браузерами, но это не константа и небезопасно. - person annakata; 22.12.2008
comment
Если вы хотите узнать, является ли что-то неопределенным, независимо от того, кто-то изменил значение undefined: typeof x === undefined - person some; 22.12.2008
comment
@annakata: undefined - примитивное значение, см. раздел 4.3.9 спецификации ECMAScript. Вы ошибаетесь, когда говорите, что присваиваете ему значение символа undefined, который вы не определили (продолжение) - person some; 22.12.2008
comment
@annakata: Однако вы правы в том, что это не константа, и что она будет давать неожиданное поведение, если undefined определено для чего-то другого. Так будет это: eval = function () {alert (eval больше не поддерживается);} - person some; 22.12.2008
comment
^^ не нанимайте разработчиков, которые пишут var undefined = true в своем javascript. - person Josh Mc; 17.02.2015

Что-то вроде этого?

function isDefined(var){
   return (typeof(window[var]) == 'undefined') ? false : true;
}

or..

function isDefined(var){
   return (window.var === undefined) ? false : true;
}
person adam    schedule 22.12.2008
comment
они будут действовать одинаково для обоих вариантов, я думаю - person Claudiu; 22.12.2008

Нет. Я не думаю, что переменная, равная undefined, должна распознаваться как «определенная».

Установка его равным undefined напрямую - это просто ленивый способ его удаления - в отличие от использования ключевого слова delete. Я считаю, что это просто означает, что сборка мусора не повлияла на переменную / свойство.


[РЕДАКТИРОВАТЬ]

Что касается вашего комментария о hasOwnProperty и propertyIsEnumerable, методы / свойства прототипа не являются ни собственными, ни перечисляемыми объектами.

Object.prototype.foo = 'something';

var o = {bar: 'anything'};
o.hasOwnProperty('foo');  //=> false
o.hasOwnProperty('bar');  //=> true

Object.prototype.hasOwnProperty('foo');  //=> true
person Jonathan Lonowski    schedule 22.12.2008
comment
Установка его на примитивное значение undefined не удаляет свойство, но вы теряете ссылку на все, что содержится в свойстве. Это не имеет ничего общего с неработающей сборкой мусора. - person some; 22.12.2008

Один из способов сделать это:

var definedProperties = [];
for (var prop in o) definedProperties.push(prop);

if (o.x === undefined && contains(prop, 'x')) {
    //x is defined, but set to undefined
}

где contains просто проверяет, является ли какой-либо элемент в массиве 'x'. Это единственный способ?

person Claudiu    schedule 22.12.2008
comment
содержит ? Это не ECMAScript. Даже если бы это было так, ваше решение замедляет работу и использует больше ресурсов, чем необходимо. Используйте x в y, как сказано в других ответах. - person some; 22.12.2008
comment
Я знаю, я забыл, что в ECMAScript был оператор «in» = P. - person Claudiu; 22.12.2008

Вы можете попробовать установить часы на One.x, но это скажет вам только тогда, когда он станет неопределенным.

person nickf    schedule 22.12.2008
comment
Нет, он определяет это с помощью примитивного значения undefined. - person some; 22.12.2008
comment
Чтобы не определить его, нужно использовать delete. - person Tomalak; 22.12.2008