0

所以我已经解决了这里的大部分问题。也有不少文章有好有坏。

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

拿下面的代码。

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) 之后的任何其他操作都会导致运行时错误。我仍然可以理解语言评估表达式的方式背后的逻辑。

所以现在我看到 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 在前面的示例中,但事实并非如此。您必须将 a 实际初始化为某些东西,然后才能使其表现得像 b 一样。并阻止它抛出运行时错误。

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

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

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

4

7 回答 7

2

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

是的。

我必须逐个元素地浏览结构元素,确保每个元素都存在,然后再进入链中的下一个元素?

是的。

于 2009-12-01T18:59:41.700 回答
1

之所以

alert(typeof(a.c))

导致运行时错误和

alert(typeof(b))

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

于 2009-12-01T19:04:02.830 回答
1

不要忘记这undefined是全局变量(!),您(或其他人)可以为其分配一个值,因此您的示例在这里可能是错误的:

if(a == undefined) // True

if(a === undefined) // True

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

var local_undefined;
于 2009-12-01T19:22:04.960 回答
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()函数可以访问这些变量时才有效,即函数和变量都定义在同一范围内。

这也是能够测试局部函数变量所必需的,否则声明的局部函数变量varundefined在被调用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
}
于 2013-07-20T13:24:51.440 回答
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') )
于 2013-07-20T12:10:44.267 回答
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.
}
于 2009-12-01T19:03:16.060 回答
0

JavaScript 很奇怪,值undefined(also typeof a === "undefined") 是变量在被赋予值之前所拥有的。null是一个不同于 的独特值undefined。由于 JavaScript 中的类型系统是松散的,因此在比较和测试变量值时会发生隐式类型强制。

如果一个变量未声明,那么您不能毫无错误地引用它,但您可以使用typeof运算符对其进行测试(其结果将是 string "undefined")。已声明但未赋值的变量可以被引用但仍包含值undefined。您始终可以引用对象的未定义属性,如果尚未分配它们,则它们将具有 value undefined

当我更详细地了解 JavaScript 类型强制和不同的值时,也请参阅这个答案,这些值通常有助于考虑为空:

VBScript 的 IsEmpty 在 JavaScript 中是否有等价物?

  1. 测试嵌套对象时,如果父对象是undefined(或null),则它没有子对象,因此不需要进一步测试。

  2. 为了安全地测试一个重度嵌套的对象,您需要测试最顶层的父对象,typeof但您可以测试任何子对象的实际值(请参阅空答案的测试)。这是因为顶层可能尚未声明,但您始终可以引用对象的未定义属性。

于 2009-12-01T19:04:23.717 回答