代码之家  ›  专栏  ›  技术社区  ›  Keibosh

另一个未定义的javascript空问题

  •  0
  • Keibosh  · 技术社区  · 14 年前

    所以我已经回答了大部分问题。也有不少文章好坏不一。

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

    取下面的代码。

    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一样工作。阻止它抛出运行时错误。

    为什么会这样?对于未定义的类型是否有一些特殊的处理,或者type of函数是否在递归地执行某些操作来评估引发运行时错误的子属性?

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

    2. 如果我想检查一些非常嵌套的对象,看看它在myObject.something.something.something.something.something.x中是否设置为x,那么最好的方法是什么?我必须逐个元素地浏览结构元素,确保每个元素都存在,然后再转到链中的下一个元素?

    7 回复  |  直到 11 年前
        1
  •  2
  •   jldupont    14 年前

    我可以马上假设C是 未定义如果a未定义?

    对。

    我必须通过 逐元素构造 在去之前肯定每个人都存在 下一个在香奈儿?

    对。

        2
  •  1
  •   Peter    14 年前

    原因何在

    alert(typeof(a.c))
    

    导致运行时错误和

    alert(typeof(b))
    

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

        3
  •  1
  •   MBO    14 年前

    别忘了 undefined 是全局变量!!),并且您(或其他人)可以为它赋值,因此您的示例在这里可能是错误的:

    if(a == undefined) // True
    
    if(a === undefined) // True
    

    如果你真的需要未定义的,那么你可以得到你自己的“副本”。

    var local_undefined;
    
        4
  •  0
  •   Doug Neiner    14 年前

    通常你不会遇到需要的测试 极其 (三级以上)嵌套对象,其中 任何 父母可能是 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.
    }
    
        5
  •  0
  •   Community Egal    7 年前

    javascript的值很奇怪 undefined (也) typeof a === "undefined" )在给定变量值之前变量的值。 null 是不同于 未定义 . 由于JavaScript中的类型系统是松散的,因此在比较和测试变量值时会发生一种隐式类型强制。

    如果某个变量未声明,则不能引用它而不出错,但可以使用 typeof 运算符(其结果将是字符串 "undefined" )。已声明但未赋值的变量可以被引用,但仍包含该值 未定义 . 始终可以引用对象的未定义属性,如果未指定这些属性,则它们将具有值 未定义 .

    在我深入了解有关JavaScript类型强制和不同值(通常认为空值很有用)的更多详细信息时,也可以看到这个答案:

    Does VBScript's IsEmpty have an equivalent in JavaScript?

    1. 测试嵌套对象时,如果父对象是 未定义 (或) 无效的 )然后它就没有孩子了,所以不需要进一步的测试。

    2. 要安全地测试高度嵌套的对象,您需要使用 类型 但您可以测试任何子级的实际值( see the testing for empty answer )这是因为顶层可能尚未声明,但可以始终引用对象的未定义属性。

        6
  •  0
  •   Steven Pribilinskiy    11 年前

    用于 深嵌套 儿童

    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 )
    

    看看这种无聊的方法:

    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') )
    
        7
  •  0
  •   Steven Pribilinskiy    11 年前

    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()空()值()) 功能

    测试函数的局部变量而不包括 exists()空()值()) , the 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
    }