zoukankan      html  css  js  c++  java
  • 读《编写可维护的JavaScript》第八章总结

    第八章 避免“空比较”

    我们在对传进来的参数做处理之前,肯定需要验证一下是否是我们想要的,也就是说大多数情况下,我们需要对比一下它的类型。

    作者首先给了一个看起来都感觉不对的代码:

          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"。

    最后一个原始值:null。如果我们所期待的值真的是null,则可以和null进行比较:

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

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

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

    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+、Safari5、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")) {
            // 执行这里的代码
        }
  • 相关阅读:
    51nod1363-最小公倍数之和
    [模板] 数论题的一些经验
    WC2019游记 && 课件
    (伪)WC2019题解
    [模板] 后缀自动机&&后缀树
    [模板] 二分图博弈 && BZOJ2463:[中山市选2009]谁能赢呢?
    界面修改日志
    [模板] dp套dp && bzoj5336: [TJOI2018]party
    BZOJ1025:[SCOI2009]游戏
    [模板] BSGS/扩展BSGS
  • 原文地址:https://www.cnblogs.com/xhy-steve/p/5133727.html
Copyright © 2011-2022 走看看