所以我在这里遇到了大部分问题。也有不少文章的好与坏。
我正在寻找一些额外的澄清,是如何处理未定义和未声明的变量。
请使用以下代码。
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函数以递归方式执行某些操作以评估抛出运行时错误的子属性?
我想这里的实际问题是如果我在a.c中检查嵌套对象c我可以立即假设如果a未定义则c未定义?
如果我想检查一些非常嵌套的对象,看它是否在MyObject.Something.Something.Something.x中设置为x,那么最好的方法是什么?我必须逐个元素地导航元素,确保每个元素都存在,然后才能进入下一个链中的一个元素吗?
答案 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
可以随时包含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.
}
答案 4 :(得分:0)
JavaScript很奇怪,值undefined
(也是typeof a === "undefined"
)是变量所具有的值,直到它们被赋予值。 null
是一个与undefined
不同的独特值。由于JavaScript中的类型系统是松散的,因此在比较和测试变量值时会发生隐式类型强制。
如果变量未声明,则您无法在没有错误的情况下引用它,但您可以使用typeof
运算符对其进行测试(其结果将是字符串"undefined"
)。已声明但未分配的变量可以被引用但仍包含值undefined
。您始终可以引用对象的未定义属性,如果尚未分配它们,则它们将具有值undefined
。
当我详细了解JavaScript类型强制以及通常有用的不同值时,请参阅此答案:
Does VBScript's IsEmpty have an equivalent in JavaScript?
测试嵌套对象时,如果父级是undefined
(或null
),则它没有子级,因此无需进一步测试。
要安全地测试重度嵌套的对象,您需要使用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
函数
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
}