读《编写可维护的JavaScript》第八章总结

 

第八章 避免“空比较”

咱们在对传进来的参数作处理以前,确定须要验证一下是不是咱们想要的,也就是说大多数状况下,咱们须要对比一下它的类型。html

做者首先给了一个看起来都感受不对的代码:正则表达式

 var Controller = { process: function(items) { if (items !== null) { items.sort(); // 很差的写法
                     items.forEach(function(){ // 执行一些逻辑
 }); } } };

在这段代码中,process()方法显然但愿items是一个数组,由于咱们看到items拥有sort()和 forEach()。数组

可是这种写法有很大的问题:items值能够是1,也能够是字符串,甚至能够是对象,这些值都和null不相等,进而致使后面执行process()会出现问题。因此接下来就是各类检测:浏览器

8.1 检测原始值

在JavaScript中有5种原始类型: 字符串、数字、布尔值、undefinednull。若是你想检测他们,最佳的办法是使用typeof运算符。(做者推荐: typeof variable这样的用法,这样写也行:typeof(variable),可是看起来像一个函数而不是运算符 )。安全

基本用法:函数

  • 对于字符串, typeof返回"string"。
  • 对于数字,typeof返回"number"。
  • 对于布尔值,typeof返回"boolean"。
  • 对于undefined,typeof返回"undefined"。
 // 检测字符串
      if (typeof name === "string") { anotherName = name.substring(3); } // 检测数字
      if (typeof count === "number") { updateCount(count); } // 检测布尔值
      if (typeof found === "boolean" && "found") { message("Found!"); } // 检测undefined
      if (typeof MyApp === "undefined") { MyApp = { //其余的代码
 } }

 typeof运算符的独特之处在于,将其用于一个未声明的变量和值也不会报错,他们都将经过typeof返回"undefined"。this

最后一个原始值:null。若是咱们所期待的值真的是null,则能够和null进行比较:spa

 // 若是你真的须要检测null,则使用这种方法
      var element = document.getElementById("my-div"); if (element !== null) { element.classname = "found"; }

这里若是DOM元素不存在,则经过document.getElementById()获得的是值为null,这个方法要么返回一个节点,要么返回null。因为这时null是可预见的一种输出,则可使用!==来检测返回结果。prototype

运行typeof null 则返回"object", 这是一种低效的判断null的方法, 若是你须要检测null,则直接使用恒等运算符(===)或非恒等运算符(!==)。code

8.2 检测引用值

引用值也称做对象(object)。JS中除了原始值以外的值都是引用。有这样几种内置的引用函数: Object、Array、Date和Error,数量很少。

typeof运算符在判断这些引用类型时显得力不从心,由于全部对象都返回"object"。

检测某个引用值的类型最好方法是使用instanceof运算符。instanceof的基本语法是:value instanceof constructor。

      // 检测日期
      if (value instanceof Date) { console.log(value.getFullYear()); } // 检测正则表达式
      if (value instanceof RegExp) { if (value.test(anotherValue)) { console.log("Mathes"); } } // 检测Error
      if (value instanceof Error) { throw value; }

instanceof的一个颇有意思的特性是它不只检测构造这个对象的构造器,还检测原型链。由于每一个对象都继承自Object,所以每一个对象的 value instanceof Object都返回true。

     var now = new Date();
console.log(now
instanceof Object); // true console.log(now instanceof Date); //
true

 

由于这个缘由, instanceof 来判断对象是否属于某个特定类型的作法并不是最佳。

接下来做者谈到 :检测自定义类型最好的作法是使用instanceof运算符。也是惟一的办法:

 function Person(name) { this.name = name; } var me = new Person("Nicholas"); console.log(me instanceof Object); // true
    console.log(me instanceof Person); // true

做者后来又补充了一个我没看懂的限制,在此先记下:

这有个严重的限制:假设一个浏览器帧(frame A) 里的一个对象被传入到另外一个帧(frame B)中。俩个帧里都定义了构造函数Person。若是来自帧A的对象是帧A的Person的实例,则以下规则成立:

    // true
    frameAPersonInstance instanceof frameAPerson // false 
    frameAPersonInstance instanceof frameBPerson

由于每一个帧(frame)都拥有Person的一份拷贝,它被认为是该帧中的Person的拷贝的实例,尽管俩个定义可能彻底同样的。

在最后,做者说明这种问题也出如今其余俩个很是重要的内置类型:函数和数组。对于他们,通常用不着使用instanceof。

 8.2.1 检测函数

对于检测函数:最好的方法是使用typeof,由于它能够跨帧(frame)使用: 

     function myFunc() { } // 好的写法
     console.log(typeof myFunc === "function"); // true

做者又补充- -(此次是由于IE):用typeof来检测函数有一个限制。在IE8和更早期的版本的IE浏览器中,用时typeof来检测DOM节点(好比document.getElementById())中的函数都返回"object"而不是"function"。

 // IE8及其更早版本的IE
    console.log(typeof document.getElementById);  // "object"
    console.log(typeof document.createElement);  // "object"
    console.log(typeof document.getElementsByTagName);  // "object"

这个问题是早期IE遗留的问题,开发者每每经过in运算符来检测DOM的方法:

     // 检测DOM方法
     if ("querySelectorAll" in document) { images = document.querySelectorAll("img"); }

这段代码检查querySelectorAll是否认义在了document中,若是是,则是用这个方法。尽管不是最理想的的方法,若是想在IE8 及更早的浏览器中检测DOM方法是否存在,这是最安全的作法。在其余全部情形,typeof运算符是检测JavaScript函数的最佳选择。

8.2.2 检测数组

 ECMAScript5将Array.isArray()正式引入JavaScript。惟一的目的就是准确的检测一个值是否为数组。

适用于(IE9+、Safari五、Opera 10.5+和Chrome)都实现了Array.isArrary()方法。

 在此以前,有一个优雅的解决方案:

function isArray(value) { return Object.prototype.toString.call(value) === "[object Array]"; }

将这俩方法合并,多数类库都相似的实现了这个方法:

 function isArray(value) { if (typeof Array.isArray === "function") { return Array.isArray(value); } else { return Object.prototype.toString.call(value) === "[object Array]"; } }

8.3 检测属性

 判断属性的最好的方法是使用in运算符。in运算符仅仅会简单地判断属性是否存在,而不会去读属性的值。

以前第三章也说过:in运算符会遍历原型链。若是你只想遍历实例对象,用hasOwnProperty()

全部继承自Object的JavaScript对象都有这个方法。

做者补充到一个例外(又是IE。。醉):在IE8和更早的版本中,DOM对象并不是继承自Object,所以也不包含这个方法。因此,你在调用DOM对象的hasOwnProperty()方法以前应当先检测其是否存在(假如你已经知道对象不是DOM。这步能够省略)。

 // 对于全部非DOM对象来讲,这是好的写法
    if (object.hasOwnProperty("realted")) { // 执行这里的代码
 } // 若是你不肯定是否为DOM对象,则能够这样写
    if ("hasOwnProperty" in object && object.hasOwnProperty("related")) { // 执行这里的代码
    }
相关文章
相关标签/搜索