在 JavaScript 中,我们常常会看到这样的代码:变量与 null 的比较(这种用法很有问题),用来判断变量是否被赋予了一个合理的值。比如:
var Controller = { process: function(items) { if (items !== null) { // 不好的写法 items.sort(); items.forEach(function(item) { // 执行一些逻辑 }); } } }
在这段代码中, process() 方法显然希望 items 是一个数组,因为我们看到 items 拥有 sort() 和 forEach() 。这段代码的意图非常明显:如果参数 items 不是一个组数,则停止接下来的操作。这种写法的问题在于,和 null 的比较并不能真正避免错误的发生。 items 的值可以是1,也可以是是字符串,甚至可以是任意对象。这些值都和 null 不相等,进而会导致 process() 方法一旦执行到 sort() 时就会出错。
仅仅和 null 比较并不能提供足够的信息来判断后续代码的执行是否真的安全。好在 JavaScript 为我们提供了很多种方法来检测变量的真实值。
检测原始值
在 JavaScript 中有5种原始类型(也称为简单数据类型): String 、 Number 、 Boolean 、 Undefined 和 Null 。如果你希望一个值是 String 、 Number 、 Boolean 或 Undefined ,最佳选择是使用 typeof 运算符,它会返回一个表示类型的字符串。
对于字符串, typeof 返回 "string" 。
对于数字, typeof 返回 "number" 。
对于布尔值, typeof 返回 "boolean" 。
对于undefined, typeof 返回 "undefined" 。
typeof 的基本语法是: typeof variable ,你还可以这样用: typeof(variable) ,尽管这是合法的 JavaScript 语法,这种用法让 typeof 看起来像一个函数而非运算符。鉴于此,我们更推荐无括号的写法。
使用 typeof 来检测这4种原始类型是非常安全的做法。来看下面这些例子。
// 检测"String" if (typeof name === "string") { anotherName = name.substring(3); } // 检测"Number" if (typeof count === "number") { updateCount(count); } // 检测"Boolean" if (typeof found === "boolean" && found) { message("Found!"); } // 检测"Undefined" if (typeof MyApp === "undefined") { MyApp = { // 其他代码 }; }
typeof 运算符的独特之处在于,将其用于一个未声明的变量也不会报错。未定义的变量和值为 undefined 的变量通过 typeof 都将返回 "undefined" 。
最后一个原始类型 null ,通过 typeof 将返回 "object" ,这看上去很怪异,被认为是标准规范的严重 bug,因此在编程时要 杜绝使用 typeof 来检测 null 的类型 。
console.log(typeof null); // "object"
简单地和 null 进行比较通常不会包含足够的信息以判断值的类型是否合法,所以 null 一般不应用于检测语句。
但有一个例外,如果所期望的值真的是 null ,则可以直接和 null 进行比较。例如:
// 如果你需要检测 null,则使用这种方法 var element = document.getElementById("my-div"); if (element !== null) { element.className = "found"; }
如果 DOM 元素不存在,则通过 document.getElementById() 得到的值为 null 。这个方法要么返回一个节点,要么返回 null 。由于这时 null 是可预见的一种输出,则可以用恒等运算符 === 或非恒等运算符 !== 来检测返回结果。
typeof 运算符的返回值除了上述提到的 string 、 number 、 boolean 、 undefined 和 object 之外,还有 function 。从技术的角度来讲,函数在 JavaScript 中也是对象,不是一种数据类型。然而,函数也确实有一些特殊的属性,因此通过 typeof 运算符来区分函数和其他对象是有必要的。这一特性将在后面 检测函数 中用到。
检测引用值
在 JavaScript 中除了原始值之外的都是引用值(也称为对象),常用的引用类型有: Object 、 Array 、 Date 和 RegExp ,这些引用类型都是 JavaScript 的内置对象。 typeof 运算符在判断这些引用类型时全都返回 "object" 。
console.log(typeof {}); // "object" console.log(typeof []); // "object" console.log(typeof new Date()); // "object" console.log(typeof new RegExp()); // "object"
检测某个引用值类型的最好方法是使用 instanceof 运算符, instanceof 的基本语法是:
value instanceof constructor // 检测日期 if (value instanceof Date) { console.log(value.getFullYear); } // 检测 Error if (value instanceof Error) { throw value; } // 检测正则表达式 if (value instanceof RegExp) { if (value.test(anotherValue)) { console.log("Matches"); } }
instanceof 的一个有意思的特性是它不仅检测构造这个对象的构造器,还检测原型链。原型链包含了很多信息,包括定义对象所采用的继承模式。比如,默认情况下,每个对象都继承自 Object ,因此每个对象的 value instanceof Object 都会返回 ture 。比如: