【问题标题】:Why does instanceof return false for some literals?为什么 instanceof 对某些文字返回 false ?
【发布时间】:2012-04-18 12:58:48
【问题描述】:
"foo" instanceof String //=> false
"foo" instanceof Object //=> false

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

12.21 instanceof Number //=> false
/foo/ instanceof RegExp //=> true

// the tests against Object really don't make sense

数组字面量和对象字面量匹配...

[0,1] instanceof Array //=> true
{0:1} instanceof Object //=> true

为什么不全部?或者,为什么他们不都
那么,它们是什么实例呢?

在 FF3、IE7、Opera 和 Chrome 中也是如此。所以,至少它是一致的。

【问题讨论】:

    标签: javascript literals instanceof


    【解决方案1】:

    基元是一种不同于在 Javascript 中创建的对象的类型。来自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)
    

    我找不到任何用代码构造原始类型的方法,也许这是不可能的。这可能就是人们使用typeof "foo" === "string" 而不是instanceof 的原因。

    记住这样的事情的一个简单方法是问自己“我想知道什么是理智和容易学习的”?无论答案是什么,Javascript 都会做另一件事。

    【讨论】:

    • 每天都有一个讨厌 JavaScript 的新理由是美好的一天。我知道它早就应该了,但我感谢你的这篇文章。
    • 您的术语有误。 “literal”一词是指一种无需使用构造函数即可创建数据的语法。它不引用结果数据。文字语法可用于创建对象和非对象。正确的术语是“原语”,它指的是非对象数据。一些数据同时具有原始表示和对象表示。字符串就是其中一种数据类型。
    • 仅供参考,您可以创建没有文字语法的原语。 (new String()).valueOf();
    • 请注意 typeof foo === 'string' 是不够的:请参阅 axkibe 的答案。
    • 另外,typeof new String('') 返回"object"
    【解决方案2】:

    我用:

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

    因为在 JavaScript 中字符串可以是文字或对象。

    【讨论】:

    • 我发现了一些更短的东西。 function isString(s) { return s.constructor === String; } 适用于文字和字符串对象(至少在 V8 中)
    • 如果可能,我会使用 jQuery.type(s) === 'string' (api.jquery.com/jquery.type)、jQuery.isArray()、jQuery.isFunction()、jQuery.isNumeric()。
    • @axkibe 虽然你是对的,但它是 not nearly as performanttypeof
    • 你可以使用 typeof "?" == String.name.toLowerCase() [但是为什么是 [] instanceof Array ?]
    • 布尔值存在同样的问题:true instanceof Boolean => falsetypeof true => boolean ... 甚至。 stackoverflow.com/a/4745303/362042
    【解决方案3】:

    在 JavaScript 中,一切都是对象(或者至少可以被视为对象),除了 primitives(布尔值、空值、数字、字符串和值 undefined(以及 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
    

    如您所见,对象、数组和值null 都被视为对象(null 是对不存在的对象的引用)。函数之所以与众不同,是因为它们是一种特殊类型的 callable 对象。但是它们仍然是对象。

    另一方面,true0""undefined 不是对象。它们是 JavaScript 中的原始值。然而,布尔值、数字和字符串也有构造函数 BooleanNumberString,它们分别包装各自的原语以提供附加功能:

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

    正如您所见,当原始值分别包装在 BooleanNumberString 构造函数中时,它们将成为对象。 instanceof 运算符仅适用于对象(这就是它为原始值返回 false 的原因):

    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
    

    正如您所见,typeofinstanceof 都不足以测试一个值是布尔值、数字还是字符串 - typeof 仅适用于原始布尔值、数字和字符串; instanceof 不适用于原始布尔值、数字和字符串。

    幸运的是,这个问题有一个简单的解决方案。 toString 的默认实现(即在 Object.prototype.toString 上原生定义)返回原始值和对象的内部 [[Class]] 属性:

    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]
    

    值的内部[[Class]] 属性比typeof 值有用得多。我们可以使用Object.prototype.toString 来创建我们自己的(更有用的)版本的typeof 运算符,如下所示:

    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
    

    希望这篇文章有所帮助。要了解有关原语和包装对象之间差异的更多信息,请阅读以下博客文章:The Secret Life of JavaScript Primitives

    【讨论】:

    • +1,尽管null 也是primitive value(只有typeof 运算符令人困惑)
    【解决方案4】:

    你可以使用构造函数属性:

    'foo'.constructor == String // returns true
    true.constructor == Boolean // returns true
    

    【讨论】:

    • 请注意,在测试变量时,这种技术在某些情况下可能会失败。在上面的示例中,StringBoolean 前面有一个对当前窗口的隐式引用,因此如果您正在测试在另一个窗口(如弹出窗口或框架)中创建的字符串变量的 constructor 属性,它将简单地等于String,它将等于thatOtherWindowsName.String
    • 并且instanceof不处理这个并返回适当的布尔结果吗?
    • 如果你传递了 String 的后代,这将失败。
    • @MichaelMathews:这可以解决这个问题:Object.prototype.toString.call('foo') === '[object String]'
    • @BryanLarsen 和@MichaelMathews 使用d.constructor == String 有什么问题吗?例如。使用松散的相等运算符。
    【解决方案5】:
     typeof(text) === 'string' || text instanceof String; 
    

    你可以使用它,它适用于两种情况

    1. var text="foo"; // typeof 可以工作

    2. String text= new String("foo"); // instanceof 会起作用

    【讨论】:

      【解决方案6】:

      这是在 ECMAScript 规范中定义的 Section 7.3.19 Step 3: If Type(O) is not Object, return false.

      也就是说,如果Obj instanceof Callable中的Obj不是对象,那么instanceof会直接短路到false

      【讨论】:

        【解决方案7】:

        我相信我已经想出了一个可行的解决方案:

        Object.getPrototypeOf('test') === String.prototype    //true
        Object.getPrototypeOf(1) === String.prototype         //false
        

        【讨论】:

          【解决方案8】:

          原始包装器类型是在后台自动创建字符串、数字或布尔值时自动创建的引用类型 被读取。例如:

          var name = "foo";
          var firstChar = name.charAt(0);
          console.log(firstChar);
          

          这就是幕后发生的事情:

          // what the JavaScript engine does
          var name = "foo";
          var temp = new String(name);
          var firstChar = temp.charAt(0);
          temp = null;
          console.log(firstChar);
          

          因为第二行像对象一样使用字符串(原语), JavaScript 引擎创建一个 String 实例,以便 charAt(0) 将 work.String 对象在被销毁之前只存在一个语句 检查this

          instanceof 运算符返回 false,因为临时对象是 仅在读取值时创建。因为 instanceof 实际上并没有读取 任何东西,不会创建临时对象,它告诉我们值不是 原始包装类型的实例。您可以创建原始包装器 手动输入

          【讨论】:

            【解决方案9】:

            对我来说

            造成的困惑
            "str".__proto__ // #1
            => String
            

            所以"str" istanceof String 应该返回true,因为 istanceof 的工作原理如下:

            "str".__proto__ == String.prototype // #2
            => true
            

            表达式#1#2的结果相互冲突,应该有一个错误。

            #1 错误

            我发现它是由__proto__引起的,是非标准属性,所以使用标准属性:Object.getPrototypeOf

            Object.getPrototypeOf("str") // #3
            => TypeError: Object.getPrototypeOf called on non-object
            

            现在表达式 #2#3

            之间没有混淆

            【讨论】:

            • #1 是正确的,但这是由于 property accessor 将原始值装箱到其各自的对象类型,类似于 Object("str").__proto__Object("str") instanceof String
            【解决方案10】:

            或者你可以像这样创建自己的函数:

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

            用法:

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

            这些都应该返回 true。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2018-12-16
              • 1970-01-01
              • 1970-01-01
              • 2013-02-28
              相关资源
              最近更新 更多