zoukankan      html  css  js  c++  java
  • Effective JavaScript Item 54 将undefined视为"没有值"

    将undefined视为"没有值"

    JavaScript中的undefined是一个特殊的值:当JavaScript没有提供详细的值时。它就会产生undefined。

    比方:

    1. 未被赋值的变量的初始值就是undefined
    2. 訪问对象中不存在的属性会得到undefined
    3. 没有返回值的函数。undefined会作为其返回值
    4. 函数的參数没有提供时。它的值就是undefined
    // 情形1
    var x;
    x; // undefined
    
    // 情形2
    var obj = {};
    obj.x; // undefined
    
    // 情形3
    function f() {
        return;
    }
    function g() { }
    
    f(); // undefined
    g(); // undefined
    
    // 情形4
    function f(x) {
        return x;
    }
    f(); // undefined

    将undefined视为不论什么详细值的缺失是JavaScript语言的一种约定。

    所以,将它作为其他用途使用就是一种具有风险的行为。比方,一个库中的highlight方法用来改变元素的背景颜色:

    element.highlight(); // use the default color
    element.highlight("yellow"); // use a custom color

    假设我们想让highlight方法具备返回随机颜色的功能,我们或许会尝试使用undefined作为这样的情况下须要传入的參数来和其它情况差别开:

    element.highlight(undefined); // use a random color

    可是,这样做是有风险的。比方。我们可能会向该方法中传入一个对象的属性。假设该属性没有值时。highlight方法就会返回一个随机的颜色,可是这样的情况下,用户期望的结果应该是为该元素使用默认的颜色。

    var config = JSON.parse(preferences);
    // ...
    element.highlight(config.highlightColor); // may be random

    除了使用undefined之外。有些开发者可能会选择相同比較特殊的null作为參数传入来进行区分:

    element.highlight(null);

    可是。这种代码的可读性比較差。用户第一眼看上去会猜想此方法是要移除element的背景颜色,而不是八竿子打不着的返回随机颜色。

    一个更好的API应该是这种,通过传入字符串来表名意图:

    element.highlight("random");
    
    // 或者通过配置对象。关于配置对象能够參考Item 55
    element.highlight({ random: true });

    另外一个须要注意undefined的地方是拥有可选參数的函数。尽管能够通过arguments对象(关于此对象,能够參考Item 51)对实际传入的參数进行推断,可是对參数进行undefined推断能够让API更加健壮。比方。一个Server对象也许会接受host名作为參数:

    var s1 = new Server(80, "example.com");
    var s2 = new Server(80); // defaults to "localhost"
    
    function Server(port, hostname) {
        if (arguments.length < 2) {
            hostname = "localhost";
        }
        hostname = String(hostname);
        // ...
    }

    以上代码使用arguments的length值作为推断根据。来给hostname參数一个默认值。可是,假设hostname被传入了undefined,就会导致默认值不会生效:

    // config.hostname为undefined时,就跳过了以上的检查
    var s3 = new Server(80, config.hostname);
    
    // 更好的办法是显式地对undefined进行检查
    function Server(port, hostname) {
        if (hostname === undefined) {
            hostname = "localhost";
        }
        hostname = String(hostname);
        // ...
    }

    一种替代方案是进行真值推断(參见Item 3):

    function Server(port, hostname) {
        hostname = String(hostname || "localhost");
        // ...
    }

    根据是undefined在做真值推断时会返回false,因此默认值localhost会生效。

    可是须要注意在某些情况下使用真值推断也是不安全的。

    当一个函数可以接受空的字符串作为合法參数时。进行真值推断就会将传入的空字符串替换为默认值。类似的,假设一个函数可以接受数字0(或者特殊的NaN)作为合法參数,真值推断也会将它替换成默认值。

    比方,以下的API用来通过传入元素的宽度和高度进行创建。

    假设没有传入。则使用默认值:

    var c1 = new Element(0, 0); //  0, height: 0
    var c2 = new Element(); //  320, height: 240
    
    function Element(width, height) {
        this.width = width || 320; // wrong test
        this.height = height || 240; // wrong test
        // ...
    }
    
    var c1 = new Element(0, 0);
    
    c1.width; // 320
    c1.height; // 240

    当我们传入0时,真值推断会将它替换成默认值。然而这并非我们想要的行为。更好的方式是显式对undefined进行推断:

    function Element(width, height) {
        this.width = width === undefined ?

    320 : width; this.height = height === undefined ?

    240 : height; // ... } var c1 = new Element(0, 0); c1.width; // 0 c1.height; // 0 var c2 = new Element(); c2.width; // 320 c2.height; // 240

    总结

    1. 不要使用undefined来表达除了缺失特定值外的不论什么其它意义。
    2. 在须要表达特殊情况时。不要使用undefined或者null。

      而是使用更具表达性的字符串或者对象。

    3. 在函数中显式地对參数进行undefined检查,而不要依赖于诸如arguments.length等检查方法。

    4. 对于可以接受真值推断返回false的特殊值(如0,NaN,null,""),不要使用真值推断。
  • 相关阅读:
    Partition4:增加分区
    Partition5:Partiton Scheme是否指定Next Used?
    UniqueIdentifier 数据类型 和 GUID 生成函数
    SQL Server 并发控制 第三篇:隔离级别和行版本(2)
    SQL Server 常用内置函数
    In-Memory:在内存中创建临时表和表变量
    Partition2:对现有表分区
    Partition1:新建分区表
    Partition3:分区切换(Switch)
    Pivot 和 Unpivot
  • 原文地址:https://www.cnblogs.com/gccbuaa/p/6791225.html
Copyright © 2011-2022 走看看