另一个Javascript Undefined Null问题

时间:2009-12-01 18:54:05

标签: javascript null undefined

所以我在这里遇到了大部分问题。也有不少文章的好与坏。

我正在寻找一些额外的澄清,是如何处理未定义和未声明的变量。

请使用以下代码。

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)会导致运行时错误。我仍然可以理解laguage评估表达式的方式背后的逻辑。

所以现在我看一个不存在的属性,我真的很困惑。

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函数以递归方式执行某些操作以评估抛出运行时错误的子属性?

  1. 我想这里的实际问题是如果我在a.c中检查嵌套对象c我可以立即假设如果a未定义则c未定义?

  2. 如果我想检查一些非常嵌套的对象,看它是否在MyObject.Something.Something.Something.x中设置为x,那么最好的方法是什么?我必须逐个元素地导航元素,确保每个元素都存在,然后才能进入下一个链中的一个元素吗?

7 个答案:

答案 0 :(得分:2)

  

我可以立即假设c是   如果a未定义,则为undefined?

  

我必须浏览   结构元素由元素制作   确保每一个都存在之前   在廊中下一个?

答案 1 :(得分:1)

原因

alert(typeof(a.c))

导致运行时错误和

alert(typeof(b))

不是在第一个示例中,您尝试访问未定义对象上的属性,这会导致运行时错误,然后将结果输入typeof()

答案 2 :(得分:1)

不要忘记undefined是全局变量(!),而你(或其他人)可以为它赋值,所以你的例子在这里可能是错误的:

if(a == undefined) // True

if(a === undefined) // True

如果您确实需要未定义,那么您可以获得自己的“副本”

var local_undefined;

答案 3 :(得分: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.
}

如果a.c可以随时包含0false,但仍需要通过测试,请使用完整的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.
}

答案 4 :(得分: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)。这是因为可能尚未声明顶级,但您始终可以引用对象的未定义属性。

答案 5 :(得分:0)

深层嵌套子项

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') )

答案 6 :(得分:0)

exists()函数的重要更新 - 使用exists()

的两个附加函数

这些涵盖了测试任何嵌套级 变量/属性/对象 定义/空/未声明所需的所有内容 没有在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

  

这是一个替代的 evil 解决方案来测试本地函数变量 这些代码片段可以在全局范围内定义,然后使用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
}