zoukankan      html  css  js  c++  java
  • JavaScript Garden2

    Types

    Equality and Comparisons

    JavaScript has two different ways of comparing the values of objects for equality.

    The Equality Operator

    The equality operator consists of two equal signs: ==

    JavaScript features weak typing. This means that the equality operator coerces types in order to compare them.

    ""           ==   "0"           // false
    0            ==   ""            // true
    0            ==   "0"           // true
    false        ==   "false"       // false
    false        ==   "0"           // true
    false        ==   undefined     // false
    false        ==   null          // false
    null         ==   undefined     // true
    " 	
    "    ==   0             // true

    The above table shows the results of the type coercion, and it is the main reason why the use of == is widely regarded as bad practice. It introduces hard-to-track-down bugs due to its complicated conversion rules.

    Additionally, there is also a performance impact when type coercion is in play; for example, a string has to be converted to a number before it can be compared to another number.

    The Strict Equality Operator

    The strict equality operator consists of three equal signs: ===.

    It works like the normal equality operator, except that strict equality operator does not perform type coercion between its operands.

    ""           ===   "0"           // false
    0            ===   ""            // false
    0            ===   "0"           // false
    false        ===   "false"       // false
    false        ===   "0"           // false
    false        ===   undefined     // false
    false        ===   null          // false
    null         ===   undefined     // false
    " 	
    "    ===   0             // false

    The above results are a lot clearer and allow for early breakage of code. This hardens code to a certain degree and also gives performance improvements in case the operands are of different types.

    Comparing Objects

    While both == and === are called equality operators, they behave differently when at least one of their operands is an Object.

    {} === {};                   // false
    new String('foo') === 'foo'; // false
    new Number(10) === 10;       // false
    var foo = {};
    foo === foo;                 // true

    Here, both operators compare for identity and not equality; that is, they will compare for the same instance of the object, much like is in Python and pointer comparison in C.

    In Conclusion

    It is highly recommended to only use the strict equality operator. In cases where types need to be coerced, it should be done explicitly and not left to the language's complicated coercion rules.

    The typeof Operator

    The typeof operator (together with instanceof) is probably the biggest design flaw of JavaScript, as it is almost completely broken.

    Although instanceof still has limited uses, typeof really has only one practical use case, which does not happen to be checking the type of an object.

    Note: While typeof can also be called with a function like syntax, i.e. typeof(obj), this is not a function call. The parentheses behave as normal and the return value will be used as the operand of the typeof operator. There is no typeof function.

    The JavaScript Type Table

    Value               Class      Type
    -------------------------------------
    "foo"               String     string
    new String("foo")   String     object
    1.2                 Number     number
    new Number(1.2)     Number     object
    true                Boolean    boolean
    new Boolean(true)   Boolean    object
    new Date()          Date       object
    new Error()         Error      object
    [1,2,3]             Array      object
    new Array(1, 2, 3)  Array      object
    new Function("")    Function   function
    /abc/g              RegExp     object (function in Nitro/V8)
    new RegExp("meow")  RegExp     object (function in Nitro/V8)
    {}                  Object     object
    new Object()        Object     object

    In the above table, Type refers to the value that the typeof operator returns. As can be clearly seen, this value is anything but consistent.

    The Class refers to the value of the internal [[Class]] property of an object.

    From the Specification: The value of [[Class]] can be one of the following strings.ArgumentsArrayBoolean,DateErrorFunction,JSONMathNumber,ObjectRegExpString.

    In order to retrieve the value of [[Class]], one has to make use of the toString method of Object.prototype.

    The Class of an Object

    The specification gives exactly one way of accessing the [[Class]] value, with the use of Object.prototype.toString.

    function is(type, obj) {
        var clas = Object.prototype.toString.call(obj).slice(8, -1);
        return obj !== undefined && obj !== null && clas === type;
    }
    
    is('String', 'test'); // true
    is('String', new String('test')); // true

    ES5 Note: For convenience the return value of Object.prototype.toString for both null and undefined was changed from Object to Null and Undefined in ECMAScript 5.

    In the above example, Object.prototype.toString gets called with the value of this being set to the object whose [[Class]] value should be retrieved.

    Testing for Undefined Variables

    typeof foo !== 'undefined'

    The above will check whether foo was actually declared or not; just referencing it would result in a ReferenceError. This is the only thingtypeof is actually useful for.

    In Conclusion

    In order to check the type of an object, it is highly recommended to use Object.prototype.toString because this is the only reliable way of doing so. As shown in the above type table, some return values of typeof are not defined in the specification; thus, they can differ between implementations.

    Unless checking whether a variable is defined, typeof should be avoided.

    The instanceof Operator

    The instanceof operator compares the constructors of its two operands. It is only useful when comparing custom made objects. Used on built-in types, it is nearly as useless as the typeof operator.

    Comparing Custom Objects

    function Foo() {}
    function Bar() {}
    Bar.prototype = new Foo();
    
    new Bar() instanceof Bar; // true
    new Bar() instanceof Foo; // true
    
    // This just sets Bar.prototype to the function object Foo,
    // but not to an actual instance of Foo
    Bar.prototype = Foo;
    new Bar() instanceof Foo; // false

    Using instanceof with Native Types

    new String('foo') instanceof String; // true
    new String('foo') instanceof Object; // true
    
    'foo' instanceof String; // false
    'foo' instanceof Object; // false

    One important thing to note here is that instanceof does not work on objects that originate from different JavaScript contexts (e.g. different documents in a web browser), since their constructors will not be the exact same object.

    In Conclusion

    The instanceof operator should only be used when dealing with custom made objects that originate from the same JavaScript context. Just like the typeof operator, every other use of it should be avoided.

    Type Casting

    JavaScript is a weakly typed language, so it will apply type coercion wherever possible.

    // These are true
    new Number(10) == 10; // Number.toString() is converted
                          // back to a number
    
    10 == '10';           // Strings gets converted to Number
    10 == '+10 ';         // More string madness
    10 == '010';          // And more 
    isNaN(null) == false; // null converts to 0
                          // which of course is not NaN
    
    // These are false
    10 == 010;
    10 == '-10';

    ES5 Note: Number literals that start with a 0 are interpreted as octal (Base 8). Octal support for these has been removed in ECMAScript 5 strict mode.

    To avoid the issues above, use of the strict equal operator is highly recommended. Although this avoids a lot of common pitfalls, there are still many further issues that arise from JavaScript's weak typing system.

    Constructors of Built-In Types

    The constructors of the built in types like Number and String behave differently when being used with the new keyword and without it.

    new Number(10) === 10;     // False, Object and Number
    Number(10) === 10;         // True, Number and Number
    new Number(10) + 0 === 10; // True, due to implicit conversion

    Using a built-in type like Number as a constructor will create a new Number object, but leaving out the new keyword will make the Number function behave like a converter.

    In addition, passing literals or non-object values will result in even more type coercion.

    The best option is to cast to one of the three possible types explicitly.

    Casting to a String

    '' + 10 === '10'; // true

    By prepending an empty string, a value can easily be cast to a string.

    Casting to a Number

    +'10' === 10; // true

    Using the unary plus operator, it is possible to cast to a number.

    Casting to a Boolean

    By using the not operator twice, a value can be converted a boolean.

    !!'foo';   // true
    !!'';      // false
    !!'0';     // true
    !!'1';     // true
    !!'-1'     // true
    !!{};      // true
    !!true;    // true

     

  • 相关阅读:
    [luoguP2486] [SDOI2011]染色(树链剖分)
    [POJ3162]Walking Race(DP + 单调队列)
    [HDU3586]Information Disturbing(DP + 二分)
    [luoguP1280] 尼克的任务(DP)
    [luoguP1282] 多米诺骨牌(DP + 背包)
    AOJ 0558 Cheese【BFS】
    POJ 3009 Curling 2.0【带回溯DFS】
    AOJ 0033 Ball【DFS】
    AOJ 0118 Property Distribution【DFS】
    POJ 1979 Red and Black【DFS】
  • 原文地址:https://www.cnblogs.com/ghgyj/p/4006600.html
Copyright © 2011-2022 走看看