2009-12-01 3 views
0

Так что я прошел через большинство вопросов здесь. Также немало статей хороших и плохих.Другой Javascript Неопределенный нулевой вопрос

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

Выполните приведенный ниже код.

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 

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

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

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 в предыдущем примере, но его нет. Вы должны фактически инициализировать что-то, и тогда вы можете заставить его вести себя так, как это делает b. И не позволяйте ему перебрасывать ошибки времени выполнения.

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

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

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

+0

** Примечание * *: в вашем примере выше, * a * будет * undefined *, а не * null *. – jldupont

ответ

2

можно сразу предположить, с есть не определен, если не определено?

Да.

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

Да.

+2

typeof null === 'object' // true – NVI

+0

a is undefined, not null – NVI

+0

@NV: может быть, вы могли бы указать это автору? то есть «if (a.c) // Ошибка выполнения - c является нулевым или не является объектом« * a * будучи * undefined *, а не * null *. – jldupont

0

Обычно вы не столкнетесь с необходимостью испытать чрезвычайно (более трех уровней) вложен объект, где любой из родителей может быть 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. 
} 

If 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. 
} 
0

причина

alert(typeof(a.c)) 

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

alert(typeof(b)) 

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

0

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

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

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

Does VBScript's IsEmpty have an equivalent in JavaScript?

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

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

1

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

if(a == undefined) // True 

if(a === undefined) // True 

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

var local_undefined; 
0

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

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

примерки улове маршрута является более элегантным и гораздо меньше типа кодирования Решение

И вот пример:

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 был включен блок 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 

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


, но думаю, что я получил просветление, зло решение)

// 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

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

Они охватывают все, что когда-либо необходимо для проверки в переменной/свойства/объекта на любого уровня вложенности является определено/пустой/необъявленнаяникогда не вызывая ошибку во время выполнения в 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 блок должен быть использован в этой функции


Вот Alte rnative злую решение для тестирования локальных переменных функции Эти фрагменты кода могут быть определены в глобальном масштабе, а затем вызывается с 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 
} 
Смежные вопросы