from http://segmentfault.com/q/1010000000381586#a-1020000000381836
随意的略谈,文中有错的概率接近1。所以并不要对本文过于当真,任何不满请随意留言开喷。
注意本文严格区分Null/null
,Undefined/undefined
。
Null & Undefined
从各种语言的语义上看,Undefined相当于一个变量并没有明确的被赋值。很多语言将其视为一种错误或异常:
# Py2.7
print(a) # NameError: name 'a' is not defined
而Null相当于变量被明确指定了没有值,而不是由于意外的原因被忽略掉了:
# Py2.7
b = None
print(b) # None
Null和Undefined体现的区别在于:
- 是否被赋值了是定性问题,具体赋的什么值是定量问题。
- 遗忘了赋值一般是人为错误,赋了空值是肯定是正当逻辑。
- Undefined一般是无心的,Null肯定是故意的。
也就是说从函数传参的语义上讲:
- 如果是空值,传Null是最好的。
- 不明确传值,不代表参数指定为空,而是尊重参数的默认值。
- 如果不明确传值,参数也没有默认值,多数语言会认为“缺少必要参数”是一个错误。
JavaScript的怪异之处
null
和undefined
是JavaScript的两颗雷。
JS的怪异之处就在于undefined
真的是一个可以使用的值。在其他语言需要用特别方法取消一个变量的定义(甚至定义之后不能取消)的时候:
# Py2.7
a = 1
del a
a # NameError: name 'a' is not defined
JS只需把undefined
赋给变量:
a = undefined;
这个行为和臭名昭著的VB6,在不开启“强制变量声明”(Option Explicit
)时的行为是非常相似的:
MsgBox(Str(undef1)) ' 我记得是Nothing,转换后为vbNullString
' -----------------
Option Explicit
MsgBox(Str(undef1)) ' 我记得是编译错误:变量未定义
在函数传参中undefined
的用途在于弥补JavaScript没有参数默认值语法的缺欠:
function f(x) {
if (x === undefined) {x = 1;}
return x;
}
console.log(f()); // 1
从这个意义上,还好JavaScript没有设计function f(x=1)
的语法。要不然给x传undefined
,就不知道语义是尊重x的默认值,还是把x的值覆写成undefined
了……
null
和undefined
参与运算的麻烦
JS的null
如果进入运算,真的会被解析成为0
或false
:
(1 + null) # 1
(1 * null) # 0
(1 * null) # Infinity
undefined
进入运算,一律得到NaN
:
(1 + undefined) # NaN
(1 * undefined) # NaN
(1 / undefined) # NaN
麻烦就在于这些现象都是不报错的。对于其他语言,想都想得到:
# Py2.7
1+None # TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
1+a # NameError: name 'a' is not defined
这也就是说在JS程序中,如果忘记判断外部输入的变量是否存在,会使程序产生不确定的行为。虽然外部输入不检验肯定是程序员的错……但从语言设计上看,这比其他语言干脆报错,在可靠性上不可否认的差了很多。
null
和undefined
的判断
null
和undefined
逻辑判断时都认为是false。
但是如果碰到大坑==
的时候……自己看吧。我是不理解==
的时候这TM都是个什么语义:
var foo;
console.log(foo == null); // true
console.log(foo == undefined); // true
console.log(foo === null); // false
console.log(foo === undefined); // true
console.log(null == undefined); // true
JS不明确,编程者要明确
避免问题只有一种逻辑:编程者明确自己的语义。
- 不要放过小错误,在最小的程序上也要注意语义的明确性。玩JS没有这个习惯确实容易挂的。
- 如果明确为空,那就是
null
,而不是忽略掉。尽量避免容忍参数的默认值,因为程序员不知道(也关心不到)未来上游代码会如何改变参数为默认值时的行为。 - 使用外部指定的变量前,检验存在性,必要时抛出错误。永远不假设变量有值。
- 判断一个量已定义且非空,只使用:
if (a !== null && a !== undefined)
。
JS的坑要多少有多少,需要编程者的认真控制,避免程序出现不可预测的行为。从这一个角度上看,JavaScript让编程者很累,绝对是非常非常烂(faulty)的。不知道有多少人还记得《JavaScript: The Definitive Guide》和《JavaScript: The Good Parts》的那个笑话(图)?如果没有对应的利益,恐怕避免使用JavaScript总是个不差的想法。
不过Unix哲学也指导我们:更坏就是更好。虽然有问题但实用可行,快速面世并不断发展的方案,比某些大公司闷头完善,结果最后黄花菜都凉了才扔出来的东西要强。
其他参考
http://justjavac.com/javascript/2013/04/14/javascript-quirk-2-two-non-values-undefined-and-null.html
相当值得一读(尤其值得注意一下域名)
http://www.ruanyifeng.com/blog/2011/06/10_design_defects_in_javascript.html
这篇文章的意义是了解一下==
和===
运算符,在碰到null
和undefined
时候的怪异行为。
如果你决定去读这篇文章,请注意我不认为原作者的这句话是个正确的判断:
在编程实践中,null几乎没用,根本不应该设计它。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。