null 与 undefined
JavaScript 中一共有 5 种基本类型,分别是 String、Number、Boolean、Null 和 Undefined 。前 3 种都比较好理解,后面两种就稍微复杂一点。 Null 类型只有一个值,就是 null ; Undefined 类型也只有一个值,即 undefined 。 null 和 undefined 都可以作为字面量(literal)在 JavaScript 代码中直接使用。
null 与对象引用有关系,表示为空或不存在的对象引用。当声明一个变量却没有给它赋值的时候,它的值就是 undefined 。
undefined 的值会出现在如下情况:
关于 null 和 undefined 有一些有趣的特性:
== 操作符的判断算法在使用 == 来判断两个值是否相等的时候,如判断 x==y,当 x 和 y 的类型一样的时候,判断逻辑与 === 一样;如果 x 和 y 的类型不一样,== 不是简单的返回 false,而是会做一定的类型转换。
需要注意的是 == 操作符不一定是传递的,即从 A == B, B == C并不能一定得出 A == C。考虑下面的例子,var str1 = new String("Hello"); var str2 = new String("Hello"); str1 == "Hello"; str2 == "Hello",但是 str1 != str2。
ArrayJavaScript 中的数组(Array)和通常的编程语言,如 Java 或是 C/C++ 中的有很大不同。在 JavaScript 中的对象就是一个无序的关联数组,而 Array 正是利用 JavaScript 中对象的这种特性来实现的。在 JavaScript 中,Array 其实就是一个对象,只不过它的属性名是整数,另外有许多额外的属性(如 length)和方法(如 splice)等方便地操作数组。
创建数组创建一个 Array 对象有两种方式,一种是以数组字面量的方式,另外一种是使用 Array 构造器。数组字面量的方式通常为大家所熟知。如 var array1 = [2, 3, 4];。使用 Array 构造器有两种方式,一种是 var array2 = new Array(1, 2, 3);;另外一种是 var array3 = Array(1, 2, 3);。这两种使用方式的是等价的。使用 Array 构造器的时候,除了以初始元素作为参数之后,也可以使用数组大小作为参数。如 var array4 = new Array(3);用来创建一个初始大小为 3 的数组,其中每个元素都是 undefined 。
Array 的方法JavaScript 中的 Array 提供了很多方法。
lengthJavaScript 中数组的 length 属性与其他语言中有很大的不同。在 Java 或是 C/C++ 语言中,数组的 length 属性都是用来表示数组中的元素个数。而 JavaScript 中,length 属性的值只是 Array 对象中最大的整数类型的属性的值加上 1 。当通过 [] 操作符来给 Array 对象增加元素的时候,如果 [] 中表达式的值可以转换为正整数,并且其值大于或等于 Array 对象当前的 length 的值的话,length 的值被设置成该值加上 1 。 length 属性也可以显式的设置。如果要设置的值比原来的 length 值小的话,该 Array 对象中所有大于或等于新值的整数键值的属性都会被删除。如 中所示。
清单 1. Array 的 length 属性var array = []; array[0] = "a"; array[100] = "b"; array.length; // 值为 101 array["3"] = "c"; array.length = 4; // 值为 "b" 的第 101 个元素被删除
arguments在 JavaScript 中,在一个 function 内部可以使用 arguments 对象。该对象中包含了 function 被调用时的实际参数的值。 arguments 对象虽然在功能上有些类似数组(),但是它不是数组。 arguments 对象与数组的类似体现在它有一个 length 属性,同时实际参数的值可以通过 [] 操作符来获取。但是 arguments 对象并没有数组可以使用的 push、pop、splice 等 function 。其原因是 arguments 对象的 prototype 指向的是 Object.prototype 而不是 Array.prototype 。
使用 arguments 模拟重载Java 和 C++ 语言都支持方法重载(overloading),即允许出现名称相同但是形式参数不同的方法;而 JavaScript 并不支持这种方式的重载。因为 JavaScript 中的 function 对象也是以属性的形式出现的,在一个对象中增加与已有 function 同名的新 function 时,旧的 function 对象会被覆盖。不过可以通过使用 arguments 来模拟重载,其实现机制是通过判断 arguments 中实际参数的个数和类型来执行不同的逻辑。如 中所示。
清单 2. 使用 arguments 模拟重载示例function sayHello() { switch (arguments.length) { case 0: return "Hello"; case 1: return "Hello, " + arguments[0]; case 2: return (arguments[1] == "cn" ? " 你好," : "Hello, ") + arguments[0]; }; } sayHello(); // 结果是 "Hello" sayHello("Alex"); // 结果是 "Hello, Alex" sayHello("Alex", "cn"); // 结果是 " 你好,Alex"
arguments.calleecallee 是 arguments 对象的一个属性,其值是当前正在执行的 function 对象。它的作用是使得匿名 function 可以被递归调用。下面以一段计算斐波那契序列(Fibonacci sequence)中第 N 个数的值的代码来演示 arguments.callee 的使用,见 。
清单 3. arguments.callee 示例function fibonacci(num) { return (function(num) { if (typeof num !== "number") return -1; num = parseInt(num); if (num < 1) return -1; if (num == 1 || num == 2) return 1; return arguments.callee(num - 1) + arguments.callee(num - 2); })(num); } fibonacci(100);
prototype 与继承JavaScript 中的每个对象都有一个 prototype 属性,指向另外一个对象。使用对象字面量创建的对象的 prototype 指向的是 Object.prototype,如 var obj = {"name" : "Alex"};中创建的对象 obj的 prototype 指向的就是 Object.prototype。而使用 new 操作符创建的对象的 prototype 指向的是其构造器的 prototype 。如 var users = new Array();中创建的对象 users的 prototype 指向的是 Array.prototype。由于一个对象 A 的 prototype 指向的是另外一个对象 B,而对象 B 自己的 prototype 又指向另外一个对象 C,这样就形成了一个链条,称为 prototype 链。这个链条会不断继续,一直到 Object.prototype。Object.prototype对象的 prototype 值为 null,从而使得该链条终止。中给出了 prototype 链的示意图。
图 1. JavaScript prototype 链示意图