编写可维护的javascript(八):避免“空比较”

来源:互联网 发布:迷彩服淘宝分类 编辑:程序博客网 时间:2024/05/18 20:36

在Javascript中,常常看到这种代码:变量和null的比较,如下:

    var Controller = {        process: function(items) {            if (items !== null) { // bad                items.sort();                item.forEach(function(item) {                    // 执行代码逻辑                });            }        }    };

这段代码中,process() 方法显然是希望items是一个数组,如果参数不是一个数组,则停止接下来的操作。
问题在于,仅仅和null比较并不能提供足够的信息来判断变量是否为一个数组。好在可以Javascript提供了多种方法检测变量的真实值。


检测原始值
Javascript的数据类型有:字符串、数字、布尔值、Null、Undefined、对象、Symbol(ES6新增数据类型);
Javascript有6中原始数据类型:字符串、数字、布尔值、Null、Undefined、Symbol。
typeof 运算符会返回一个表示值得类型的字符串(typeof是一个运算符不是函数)

  • 对于字符串,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运算符的独特之处是,将其用于一个未声明的变量也不会报错。未定义的变量和值为undefined的变量通过typeof都将返回”undefined”。
当然如果你所期望的值是null,则可以直接和null进行比较。这时应当使用===或者!==来和null进行比较。比如:

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

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


检测引用值
引用值也称作对象(object)。
在Javascript中除了原始值之外的都是引用值。有这几种内置引用类型:Object、Array、Date和Error等。typeof运算符在判断这些引用类型的时则显得力不从心,因为所有对象都会返回“object”。

    console.log(typeof {});             // object    console.log(typeof []);             // object    console.log(typeof new RegExp());   // object    console.log(typeof new Date());     // object    注:    console.log(typeof new Function()); // function (ECMA-262条款中实现了,称为函数对象)

typeof另外一种不推荐的用法就是当检测null的类型时,typeof运算符用于null时将返回“object”。

    console.log(typeof null);           // object

这很怪异(null明明是原始类型值),被认为是标准规范的bug,因此在编程时要杜绝使用typeof来检测null的类型。检测某个引用值的最好方法是使用instanceof运算符。如下例子:

    // 检测日期    if (value instanceof Date) {        console.log(value.getFullYear());    }    // 检测正则    if (value instanceof RegExp) {        // 代码    }    // 检测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运算符也可以检测自定义的类型,如下:

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

代码中创建了Person类型,变量me是Person的实例,因此me instanceof Person是true。
当然所有对象都被认为是Object的实例,因此me instanceof Object也是true。
函数和数组这两个类型来说,一般也用不着使用instanceof。


检测函数

从技术上讲,Javascript中的函数都是引用类型,同样存在Function构造函数,每个函数都是其实例。

    function myFunc() {}    // bad    console.log(myFunc instanceof Function);  // true

然而这个方法不能跨帧(frame)使用,因为每个帧都有各自的Function构造函数。好在typeof运算符可以用于函数,返回“function”。

    function myFunc() {}    // good    console.log(typeof myFunc === "function"); // true

检测函数最好的方法是使用typeof,因为它可以跨帧使用。


检测数组
在ECMAScript5中将Array.isArray() 正式引入到Javascript。唯一的目的就是准确的检测一个值是否为数组。底层的实现如下:

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

调用内置的toString() 方法在所有浏览器中都会返回标准的字符串结果。对于数组来说,返回的字符串是“[object Array]”。


检测属性
判断属性是否存在最好的方法就是使用in运算符。
in运算符仅仅会简单地判断属性是否存在,而不会去读属性的值。
如果实例对象的属性存在、或者继承自对象的原型,in运算符都会返回true。如下:

    var object = {        count: 0,        related: null    };    // good    if ("count" in object) {        // 这里的代码会执行    }    // bad(检测假值)    if (object["count"]) {        // 这里的代码不会执行    }    // good    if ("related" in object) {        // 这里的代码会执行    }    // bad(检测是否为null)    if (object["related"] !== null) {        // 这里的代码不会执行    }

如果你想检查 实例对象 的某个属性是否存在,则使用hasOwnProperty() 方法。
所有继承自Object的JavaScript对象都有这个方法,如果实例中存在这个属性则返回true(如果这个属性只存在原型里而实例中不存在,则返回false)。

    if (object.hasOwnProperty("related")) {        // 代码    }

文章内容从《编写可维护的Javascript》[美] Nicholas C. Zakas著 一书中总结写出。