当讨论JavaScript中的原始数据类型时,大多数人都知道从String、Number到Boolean的基本知识。这些原始类型相当简单,行动符合常识。但是,本文将更多关注独特的原始数据类型Null和Undefined,是甚么让它们如此类似,却又似是而非。
在JavaScript中,null是字面量同时也是语言中的关键字,用来表示没法辨认的对象值。换句话说,这用来表示“无值(no value)”,但你可以决定甚么时候得到期望值。
虽然类似,undefined实际上代表了不存在的值(non-existence of a value),也即你有东西丢失了。二者都是完全不可变的,没有属性和方法,也不能给其属性赋值。事实上, 当你试图访问或定义null 与 undefined的1个属性将会引发1个类型毛病(TypeError)。
没有值代表的布尔值是false,这意味着他们在条件上下文中会被被计算为false,如if语句。使用相等操作符(= =)比较这两个值和其他false值,他们其实不等于除自己:
null == 0; // false undefined == ""; // false null == false; // false undefined == false; // false null == undefined; // true
虽然如此,和其他类似的地方,但null和undefined其实不是等价的。每一个作为其独特的类型的唯1成员,undefined是Undefined类型和null是Object类型。使用全等操作符(===)比较这两个值,这要求类型和值都相等,下面证明这1点:
null === undefined; //false typeof null; //"object" typeof undefined; //"undefined"
上面说明:null 这是1个对象,但是为空。而且 null 是 JavaScript 保存关键字。
另外null 参与数值运算时其值会自动转换为 0 ,因此,以下表达式计算后会得到正确的数值:
123 + null; //123 123 * null; //0
undefined是全局对象(window)的1个特殊属性,其值是未定义的。但 typeof undefined 返回 ‘undefined’ 。
虽然undefined是有特殊含义的,但它确切是1个属性,而且是全局对象(window)的属性。请看下面的代码:
alert(undefined in window);//输出:true var anObj = {}; alert(undefined in anObj); //输出:false
从中可以看出,undefined是window对象的1个属性,但却不是anObj对象的1个属性。
注意:
虽然undefined是有特殊含义的属性,但却不是JavaScript的保存关键字。 undefined参与任何数值计算时,其结果1定是NaN。 随意说1下,NaN是全局对象(window)的另外一个特殊属性,Infinity也是。这些特殊属性都不是JavaScript的保存关键字!
验证1个值或1个对象为null时,需要用“===” 来判定,若只用“==”,则没法判定是null 还是 undefined.
有许多的方法产生1个undefined值的代码。它通常遇到当试图访问1个不存在的值时。在这类情况下,在JavaScript这类动态的弱类型语言中,只会默许返回1个undefined值,而不是上升为1个毛病。
1、任何声明变量时没有提供1个初始值,都会有1个为undefined的默许值:
var foo; // 默许值为 undefined
2、当试图访问1个不存在的对象属性或数组项时,返回1个undefined值:
var array = [1, 2, 3]; var foo = array.foo; // foo 属性不存在, 返回 undefined var item = array[5]; // 数组中没有索引为5的项,返回 undefined
3、如果省略了函数的返回语句, 或return语句未带任何参数返回undefined:
var value = (function(){ })(); // 返回 undefined var value1 = (function(){ return; })(); // 返回 undefined
4、调用函数时,应当提供的参数没有提供,该参数等于undefined
function f(x){ console.log(x) } f(); // undefined
最后,undefined是1个预定义的全局变量(不像null关键字)初始化为undefined值:
undefined in window; // true
ECMAScript 5中,这个变量是只读的,之前并不是如此。
null的用例是使他与众不同的主要方面,由于不像undefined,null被认为是更有用。这正是为何typeof操作符作用于null值 时返回“object”。最初的理由是,现在依然是,通经常使用作1个空援用1个空对象的预期,就像1个占位符。typeof的这类行动已被确认为1个错 误,虽然提出了修正,出于后兼容的目的,这1点已保持不变。
1般来讲,如果你需要给1个变量或属性指定1个不变值,将它传递给1个函数,或从1个函数返回null,null几近总是最好的选择。简而言之,JavaScript使用undefined并且程序员应当使用null。
null的另外一个可行的用例,也被认为是良好的实践是1个显式指定变量为无效(object= null)当1个援用不再是必须的。通过分配null值,有效地清除援用,并假定对象没有援用其他代码,指定垃圾搜集,确保回收内存。
当我们在程序中使用undefined值时,实际上使用的是window对象的undefined属性。 一样,当我们定义1个变量但未赋予其初始值,例如:
var aValue;
这时候,JavaScript在所谓的预编译时会将其初始值设置为对window.undefined属性的援用, 因而,当我们将1个变量或值与undefined比较时,实际上是与window对象的undefined属性比较。这个比较进程中,JavaScript会搜索window对象名叫‘undefined’的属性,然后再比较两个操作数的援用指针是不是相同。
由于window对象的属性值是非常多的,在每次与undefined的比较中,搜索window对象的undefined属性都会花费时 间。在需要频繁与undefined进行比较的函数中,这可能会是1个性能问题点。因此,在这类情况下,我们可以自行定义1个局部的undefined变 量,来加快对undefined的比较速度。例如:
function anyFunc() { var undefined; //自定义局部undefined变量 if(x == undefined) //作用域上的援用比较 while(y != undefined) //作用域上的援用比较 };
其中,定义undefined局部变量时,其初始值会是对window.undefined属性值的援用。新定义的局部undefined变 量存在与该函数的作用域上。在随后的比较操作中,JavaScript代码的书写方式没有任何的改变,但比较速度却很快。由于作用域上的变量数量会远远少 于window对象的属性,搜索变量的速度会极大提高。
这就是许多前端JS框架为何常常要自己定义1个局部undefined变量的缘由!