Еще один Javascript неопределенный нулевой вопрос - PullRequest
0 голосов
/ 01 декабря 2009

Итак, я прошел через большинство вопросов здесь. Также немало статей хороших и плохих.

Одна вещь, на которую я обращаю внимание, это то, как обрабатываются неопределенные и необъявленные переменные.

Возьмите код ниже.

var a;

if(a == null) // True - Due to Type Coercion

if(a == 'null') // False

if(a === null) // False

if(a === 'null') // False

if(a == undefined) // True

if(a === undefined) // True

if(a == 'undefined') // False

if(a === 'undefined') // False

if(a) // False - A is undefined

alert(typeof(a)) // undefined

Все вышесказанное я понимаю. Но все становится странным, когда вы смотрите на необъявленную переменную. Обратите внимание, что я специально опускаю "var b;".

 alert(typeof(b)) // undefined

 if(typeof(b) == 'undefined') // True

 if(typeof(b) === 'undefined') // True - This tells me the function typeof is returning a string value

 if(typeof(b) == 'null') // False

 if(typeof(b) === 'null') // False

 if(typeof(b) == null) // False

 if(typeof(b) === null) // False

 if(b) // Runtime Error - B is undefined

Любая другая операция, кроме typeof (b), приводит к ошибке во время выполнения. Тем не менее я могу понять логику того, как язык оценивает выражения.

Так что теперь я смотрю на несуществующее свойство а и действительно запутался.

if(a.c) // Runtime Error - c is null or not an object
alert(typeof(a.c)) // Runtime Error - undefined is null or not an object

Я бы подумал, что c в этом случае будет рассматриваться как b в предыдущем примере, но это не так. Вы должны на самом деле инициализировать a чем-то, тогда вы можете заставить его вести себя как b. И остановите его от выдачи ошибок во время выполнения.

Почему это так? Есть ли какая-то специальная обработка неопределенного типа или функция typeof делает что-то рекурсивное для оценки подчиненного свойства, которое выдает ошибку времени выполнения?

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

  2. И каков наилучший способ, если бы я хотел проверить какой-то чрезвычайно вложенный объект, чтобы увидеть, был ли он установлен как x в MyObject.Something.Something.Something.x? Мне нужно перемещаться по элементу структуры по элементам, чтобы убедиться, что каждый из них существует, прежде чем перейти к следующему в цепочке?

Ответы [ 7 ]

2 голосов
/ 01 декабря 2009

Я могу сразу предположить, что это undefined если a не определено?

Да.

Я должен перемещаться по структура элемент по элементам уверен, что каждый существует, прежде чем идти в следующий в тылу?

Да.

1 голос
/ 01 декабря 2009

Не забывайте, что undefined - это глобальная переменная (!), И вы (или кто-то еще) можете присвоить ей значение, поэтому ваш пример может быть неверным:

if(a == undefined) // True

if(a === undefined) // True

Если вам действительно нужен undefined, вы можете получить свою собственную «копию»

var local_undefined;
1 голос
/ 01 декабря 2009

Причина, по которой

alert(typeof(a.c))

приводит к ошибке времени выполнения и

alert(typeof(b))

не означает, что в первом примере вы пытаетесь получить доступ к свойству неопределенного объекта, что вызывает ошибку времени выполнения до , результат может быть передан в typeof()

0 голосов
/ 20 июля 2013

Важное обновление для функции exist () - существуют две дополнительные функции, которые используют существующие ()

Они охватывают все, что когда-либо необходимо для проверки, является ли переменная / свойство / объект на любым уровнем вложенности определено / пусто / необъявлено , не вызывая ошибки времени выполнения в JavaScript

function exists (v) {
    var local_undefined;
    try{ if( eval(v) !== local_undefined ) {
        return true
    }}catch(e){}
    return false
}

function empty (v) {
    if (exists(v)) {
        v = eval(v);
        if (typeof v == 'object') {
            return Object.keys(v).length === 0
        } else if (v)
            return false
    }
    return true
}

function value (v) {
    var local_undefined;
    if (exists(v))
        return eval(v)
    return local_undefined
}


/////////////////////////////////////////
// TEST

ref = 'a.b.c.d.e';

alert( ref +' : '+ value(ref) + '\n'
        + '\nexists\t' + exists(ref)
        + '\nempty\t' + empty(ref)
        + '\nvalue\t' + value(ref)
    );

a = { b:{ c:{ d:{ e:"Hello Ancestor" } } } };
alert( ref +' : '+ value(ref) + '\n'
        + '\nexists\t' + exists(ref)
        + '\nempty\t' + empty(ref)
        + '\nvalue\t' + value(ref)
    )

a = { b:{ c:{ d:{ e:0 } } } };
alert( ref +' : '+ value(ref) + '\n'
        + '\nexists\t' + exists(ref)
        + '\nempty\t' + empty(ref)
        + '\nvalue\t' + value(ref)
    );

b='a'; obj={a:5}; ref='obj[b]';
alert( ref +' : '+ value(ref) + '\n'
        + '\nexists\t' + exists(ref)
        + '\nempty\t' + empty(ref)
        + '\nvalue\t' + value(ref)
    );

Однако эти методы работают только тогда, когда функции exists() empty() value() имеют доступ к этим переменным, т. Е. И функция, и переменные определены в одной и той же области видимости.

Необходимо также иметь возможность проверять локальные переменные функции, в противном случае переменные локальной функции, объявленные с помощью var, будут undefined в вызываемой функции exists() empty() value()

Чтобы проверить локальную переменную функции без включения exists() empty() value(), в этой функции должен использоваться блок try/catch


Вот альтернативное зло решение для проверки переменных локальной функции Эти фрагменты кода могут быть определены в глобальной области видимости и затем вызваны с помощью eval ()

is_ = "v_='"
var_ = "v_='"
get_ = "v_='"
set_ = "v_='"

_exists = "';\nvar local_undefined;\n"
        + "try{ if( eval(v_) === local_undefined ) false; else true }\n"
        + "catch(e){false}\n"

_empty = "';\nif ( eval(\"'\"+_exists) ) {\n"
        + " v_ = eval(v_);\n"
        + " if (typeof v_ == 'object') {\n"
        + "     Object.keys(v_).length === 0;\n"
        + " }\n\telse if (v_)\n"
        + "     false;\n"
        + " else true\n"
        + "} else true"

_value = "';\nif ( eval(\"'\"+_exists) )\n"
    + " eval(v_);\n"
    + "else local_undefined"

_valOrEmpty = "';\n( eval(\"'\"+_exists) )\n"
    + " ? eval(\"'\"+_value) : ''"

_valOrDefault_ = "';\n( eval(\"'\"+_exists) )\n"
    + " ? eval(\"'\"+_value) : "

function f() {
    var a = { b:{ c:{ d:{ e:"Hello Ancestor" } } } };
    ref = 'a.b.c.d.e'
    alert( ref+'\n'   
        +'\nexists\t\t'     + eval(is_  +ref+ _exists)
        +'\nempty\t\t'      + eval(is_  +ref+ _empty)
        +'\nvalue\t\t'      + eval(get_ +ref+ _value)
        +'\n'
        +'\nvalOrEmpty\t'   + eval(get_ +ref+ _valOrEmpty)
        +'\nvalOrDefault\t' + eval(get_ +ref+ _valOrDefault_ +'"Default Value"')
        )
}

d=""; while (d.length < 20) d="—"+d; d="\n\n// "+d+"\n// "
jsCode  ='// ( is_  +var+ _exists )\n\n'                + is_ +'a.b.c.d.e'+_exists
        +d+' ( is_  +var+ _empty )\n\n'                 + is_ +'a.b.c.d.e'+_empty
        +d+' ( get_ +var+ _value )\n\n'                 + get_+'a.b.c.d.e'+_value
        +d+' ( get_ +var+ _valOrEmpty )\n\n'            + var_+'a.b.c.d.e'+_valOrEmpty
        +d+' ( get_ +var+ _valOrDefault_ default )\n\n' + var_+'a.b.c.d.e'+_valOrDefault_+"'Default Value'"

alert(jsCode)

f()
// even though that looks ugly, this is the tidiest solution
// to the awkward 17-year old JavaScript error-handling

Используйте это с умом

if ( eval(is_  +'any.var.or.property.from.local.or.global.scope'+ _exists) ) {
    // do your stuff
}
0 голосов
/ 20 июля 2013

Для глубоко вложенных детей

try{ if(a.b.c.d.e) {
    // do your stuff
}}catch(e){}

try-catch маршрут - это более элегантное и гораздо менее удобное решение для кодирования типов

А вот пример:

grand=""
a={ b:{ c:{ d:{ e:"Hello Ancestor" } } } }

try{ if(a.b.c.d.e) {
    grand = a.b.c.d.e
}}catch(e){}

alert( grand )

просто взгляните на скучный метод typeof:

if(typeof a === undefined) {
    if(typeof a.b === undefined) {
        if(typeof a.b.c === undefined) {
            if(typeof a.b.c.d === undefined) {
                if(typeof a.b.c.d.e === undefined) {
                    // your stuff
                }
            }
        }
    }
}

Это может быть еще более элегантное и идеальное решение после переноса блока try-catch в функцию, однако нет никакого известного способа заменить имя переменной, на которую ссылаются, которая могла бы быть передана в функцию в виде «строки», переменной содержание. например следующее невозможно:

function isDefined(v) {
    if (typeof valueOfVar(v) !== undefined)
        return true
    else
        return false
}
alert( isDefined('a.b.c.d.e') ) // must be passed as a string to avoid runtime error

в JavaScript не существует valueOfVar (), это просто пример


но угадайте что, я получил просвещение, решение зло :)

// a={ b:{ c:{ d:{ e:0 } } } }

function exist(v) {
    var local_undefined
    try{ if( eval(v) !== local_undefined ) {
        return true
    }}catch(e){}
    return false
}
alert( exist('a.b.c.d.e') )
0 голосов
/ 01 декабря 2009

JavaScript странен тем, что значение undefined (также typeof a === "undefined") - это то, что переменные имеют до тех пор, пока им не будет дано значение. null - это отдельное значение, которое отличается от undefined. Поскольку система типов в JavaScript свободна, при сравнении и проверке значений переменных происходит неявное приведение типов.

Если переменная не объявлена, вы не можете ссылаться на нее без ошибок, но вы можете проверить ее с помощью оператора typeof (результатом будет строка "undefined"). На переменную, которая была объявлена, но не назначена, можно ссылаться, но она все равно содержит значение undefined. Вы всегда можете ссылаться на неопределенные свойства объектов, и если они не были назначены, они будут иметь значение undefined.

См. Также этот ответ, поскольку я более подробно рассказал о приведении типов JavaScript и различных значениях, которые часто полезно считать пустыми:

Имеет ли VBScript IsEmpty эквивалент в JavaScript?

  1. При тестировании вложенных объектов, если родительский элемент undefined (или null), у него нет дочерних элементов, поэтому дальнейшее тестирование не требуется.

  2. Чтобы безопасно проверить объект с высокой степенью вложенности, вам нужно проверить самого верхнего родителя, используя typeof, но вы можете проверить любые дочерние объекты на фактические значения ( см. Проверку пустого ответа ). Это потому, что верхний уровень, возможно, не был объявлен, но вы всегда можете ссылаться на неопределенные свойства объектов.

0 голосов
/ 01 декабря 2009

Как правило, вы не столкнетесь с необходимостью проверки вложенного объекта чрезвычайно (более трех уровней), где любого из родителей может быть undefined. Поэтому, когда вам нужно проверить, я написал бы что-то вроде этого:

if( typeof(a) != 'undefined' && a.c ) {
   // Do something won't run because a is undefined
}

var a = {};

if( typeof(a) != 'undefined' && a.c ) {
   // Do something won't run because though a is defined,
   // a.c is undefined. This expression tests to see if a.c evaluates
   // to true, but won't throw an error even if it is 
   // undefined.
}

Если a.c может в любое время содержать 0 или false, но вам все еще нужно пройти тест, то используйте полный тест typeof:

var a = {};
a.c = false;

if( typeof(a) != 'undefined' && typeof(a.c) != 'undefined' ) {
   // Do something will run because though both a and a.c are defined.
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...