Why does instanceof return false for some literals?

前端 未结 10 804
耶瑟儿~
耶瑟儿~ 2020-11-22 13:13
"foo" instanceof String //=> false
"foo" instanceof Object //=> false

true instanceof Boolean //=> false
true instanceof Object //=>         


        
相关标签:
10条回答
  • 2020-11-22 13:16

    I use:

    function isString(s) {
        return typeof(s) === 'string' || s instanceof String;
    }
    

    Because in JavaScript strings can be literals or objects.

    0 讨论(0)
  • 2020-11-22 13:20

    Primitives are a different kind of type than objects created from within Javascript. From the Mozilla API docs:

    var color1 = new String("green");
    color1 instanceof String; // returns true
    var color2 = "coral";
    color2 instanceof String; // returns false (color2 is not a String object)
    

    I can't find any way to construct primitive types with code, perhaps it's not possible. This is probably why people use typeof "foo" === "string" instead of instanceof.

    An easy way to remember things like this is asking yourself "I wonder what would be sane and easy to learn"? Whatever the answer is, Javascript does the other thing.

    0 讨论(0)
  • 2020-11-22 13:22

    https://www.npmjs.com/package/typeof

    Returns a string-representation of instanceof (the constructors name)

    function instanceOf(object) {
      var type = typeof object
    
      if (type === 'undefined') {
        return 'undefined'
      }
    
      if (object) {
        type = object.constructor.name
      } else if (type === 'object') {
        type = Object.prototype.toString.call(object).slice(8, -1)
      }
    
      return type.toLowerCase()
    }
    
    instanceOf(false)                  // "boolean"
    instanceOf(new Promise(() => {}))  // "promise"
    instanceOf(null)                   // "null"
    instanceOf(undefined)              // "undefined"
    instanceOf(1)                      // "number"
    instanceOf(() => {})               // "function"
    instanceOf([])                     // "array"
    
    0 讨论(0)
  • 2020-11-22 13:23

    Or you can just make your own function like so:

    function isInstanceOf(obj, clazz){
      return (obj instanceof eval("("+clazz+")")) || (typeof obj == clazz.toLowerCase());
    };
    

    usage:

    isInstanceOf('','String');
    isInstanceOf(new String(), 'String');
    

    These should both return true.

    0 讨论(0)
  • 2020-11-22 13:25

    In JavaScript everything is an object (or may at least be treated as an object), except primitives (booleans, null, numbers, strings and the value undefined (and symbol in ES6)):

    console.log(typeof true);           // boolean
    console.log(typeof 0);              // number
    console.log(typeof "");             // string
    console.log(typeof undefined);      // undefined
    console.log(typeof null);           // object
    console.log(typeof []);             // object
    console.log(typeof {});             // object
    console.log(typeof function () {}); // function
    

    As you can see objects, arrays and the value null are all considered objects (null is a reference to an object which doesn't exist). Functions are distinguished because they are a special type of callable objects. However they are still objects.

    On the other hand the literals true, 0, "" and undefined are not objects. They are primitive values in JavaScript. However booleans, numbers and strings also have constructors Boolean, Number and String respectively which wrap their respective primitives to provide added functionality:

    console.log(typeof new Boolean(true)); // object
    console.log(typeof new Number(0));     // object
    console.log(typeof new String(""));    // object
    

    As you can see when primitive values are wrapped within the Boolean, Number and String constructors respectively they become objects. The instanceof operator only works for objects (which is why it returns false for primitive values):

    console.log(true instanceof Boolean);              // false
    console.log(0 instanceof Number);                  // false
    console.log("" instanceof String);                 // false
    console.log(new Boolean(true) instanceof Boolean); // true
    console.log(new Number(0) instanceof Number);      // true
    console.log(new String("") instanceof String);     // true
    

    As you can see both typeof and instanceof are insufficient to test whether a value is a boolean, a number or a string - typeof only works for primitive booleans, numbers and strings; and instanceof doesn't work for primitive booleans, numbers and strings.

    Fortunately there's a simple solution to this problem. The default implementation of toString (i.e. as it's natively defined on Object.prototype.toString) returns the internal [[Class]] property of both primitive values and objects:

    function classOf(value) {
        return Object.prototype.toString.call(value);
    }
    
    console.log(classOf(true));              // [object Boolean]
    console.log(classOf(0));                 // [object Number]
    console.log(classOf(""));                // [object String]
    console.log(classOf(new Boolean(true))); // [object Boolean]
    console.log(classOf(new Number(0)));     // [object Number]
    console.log(classOf(new String("")));    // [object String]
    

    The internal [[Class]] property of a value is much more useful than the typeof the value. We can use Object.prototype.toString to create our own (more useful) version of the typeof operator as follows:

    function typeOf(value) {
        return Object.prototype.toString.call(value).slice(8, -1);
    }
    
    console.log(typeOf(true));              // Boolean
    console.log(typeOf(0));                 // Number
    console.log(typeOf(""));                // String
    console.log(typeOf(new Boolean(true))); // Boolean
    console.log(typeOf(new Number(0)));     // Number
    console.log(typeOf(new String("")));    // String
    

    Hope this article helped. To know more about the differences between primitives and wrapped objects read the following blog post: The Secret Life of JavaScript Primitives

    0 讨论(0)
  • 2020-11-22 13:29

    I believe I have come up with a viable solution:

    Object.getPrototypeOf('test') === String.prototype    //true
    Object.getPrototypeOf(1) === String.prototype         //false
    
    0 讨论(0)
提交回复
热议问题