为啥 4 不是 Number 的实例?

Posted

技术标签:

【中文标题】为啥 4 不是 Number 的实例?【英文标题】:Why is 4 not an instance of Number?为什么 4 不是 Number 的实例? 【发布时间】:2010-10-03 02:42:20 【问题描述】:

只是好奇:

4 instanceof Number => false new Number(4) instanceof Number => true?

这是为什么?与字符串相同:

'some string' instanceof String 返回错误 new String('some string') instanceof String => 是的 String('some string') instanceof String 也返回 false ('some string').toString instanceof String 也返回 false

对于对象、数组或函数类型,instanceof 运算符按预期工作。我只是不知道如何理解。

[新见解]

Object.prototype.is = function() 
        var test = arguments.length ? [].slice.call(arguments) : null
           ,self = this.constructor;
        return test ? !!(test.filter(function(a)return a === self).length)
               : (this.constructor.name ||
                  (String(self).match ( /^function\s*([^\s(]+)/im )
                    || [0,'ANONYMOUS_CONSTRUCTOR']) [1] );

// usage
var Newclass = function();  // anonymous Constructor function
var Some = function Some(); // named Constructor function
(5).is();                     //=> Number
'hello world'.is();           //=> String
(new Newclass()).is();        //=> ANONYMOUS_CONSTRUCTOR
(new Some()).is();            //=> Some
/[a-z]/.is();                 //=> RegExp
'5'.is(Number);               //=> false
'5'.is(String);               //=> true

【问题讨论】:

你必须使用Number.prototype.isPrototypeOf(inp) - 如果正确使用你的方式也可以:inp.constructor === Number;它可能会失败,因为constructor 只是原型的一个属性,可以被覆盖! 我不确定我理解你所说的“可以被覆盖”是什么意思。这并不意味着我可以用其他构造函数覆盖构造函数(尝试过)。 Number.prototype.isPrototypeOf(4) 顺便返回 false,所以我不能用它来检查原始值的类型,对吗? 这就是重点(原始!== 包装原始)!检查构造函数是危险的,因为obj['constructor'] = ??? 有效!我建议使用我的typeOf() 函数;要同等对待基元和包装基元,请使用 if(typeOf(x).toLowerCase() === 'string') 根据我的经验,将任何内容分配给 Obj.constructor 不会更改其构造函数。事实上,这样的分配似乎根本没有任何作用。 ('hellowrld').constructor = Number 仍然返回带有 getType 的字符串。 当然试过你的 typeOf ,是的,它适用于原始类型。我想要所有类型的 1 个函数,无论是否原始。将尝试破坏 getType,如果我不能,我认为它是可用的。 【参考方案1】:

value instanceof ConstructorConstructor.prototype.isPrototypeOf(value) 相同,并且都检查 value 的 [[Prototype]] 链是否出现特定对象。

字符串和数字是原始值,不是对象,因此没有 [[Prototype]],因此只有将它们包装在常规对象中(称为“装箱”)才有效在 Java 中)。

另外,正如您所注意到的,String(value)new String(value) 做不同的事情:如果您在不使用 new 运算符的情况下调用内置类型的构造函数,它们会尝试转换('cast')特定类型的参数。如果您使用new 运算符,它们会创建一个包装器对象。

new String(value) 大致相当于Object(String(value)),其行为方式与new Object(String(value)) 相同。


更多关于 javascript 中的类型:ECMA-262 定义了以下原始类型:UndefinedNullBooleanNumber 字符串。此外,对于具有属性的事物,还有类型 Object

例如,函数是 Object 类型的(它们只是有一个特殊的属性称为 [[Call]]),而nullNull类型的原始值>。这意味着typeof 运算符的结果并没有真正返回值的类型...

此外,JavaScript 对象还有另一个称为 [[Class]] 的属性。您可以通过Object.prototype.toString.call(value) 获取它(这将返回'[objectClassname]')。数组和函数的类型是 Object,但它们的类是 ArrayFunction

instanceof 失败时(例如,当对象在窗口/框架边界之间传递并且不共享相同的原型时),上面给出的对象类的测试有效。


另外,您可能想查看typeof 的改进版本:

function typeOf(value) 
    var type = typeof value;

    switch(type) 
        case 'object':
        return value === null ? 'null' : Object.prototype.toString.call(value).
            match(/^\[object (.*)\]$/)[1]

        case 'function':
        return 'Function';

        default:
        return type;
    

对于原语,它将以小写返回它们的类型,对于对象,它将以大写返回它们的 .

示例:

对于 type Number 的原语(例如5),它将返回'number',用于的包装对象> 数字(如new Number(5)),会返回'Number'

对于函数,它将返回'Function'

如果您不想区分原始值和包装对象(无论出于何种原因,可能是不好的原因),请使用typeOf(...).toLowerCase()

已知的错误是 IE 中的一些内置函数,当与某些 COM+ 对象一起使用时,这些函数被视为 'Object' 和返回值 'unknown'

【讨论】:

@annakata:检查 ECMA-262。这些类型称为 Undefined、Null、Boolean、Number、String 和 Object;不管typeof 返回什么... @Christoph - 这非常重要,因为包装对象是大写的,而 typeofs 是小写的,没有其他东西可以访问。因此,约定和实践是指小写的数据类型,如下所示:developer.mozilla.org/En/JS/Glossary @annakata: typeof 已损坏 - 它的返回值与实际类型无关! 好吧,我猜你会遵循规范,而我会遵循实践,在这种情况下,我认为这是正确的。我认为引用具有相同格式的类型和包装对象是不明智的,但我不会进一步编辑您的帖子。 我比赛Strings and numbers are primitive values, not objects and therefore don't have a [[Prototype]]示例:(new Number(123)).__proto__ == (123).__proto__; // true【参考方案2】:

您可以尝试评估:

>>> typeof("a")
"string"
>>> typeof(new String("a"))
"object"
>>> typeof(4)
"number"
>>> typeof(new Number(4))
"object"

【讨论】:

【参考方案3】:

这是我发现的 Javascript 的细微差别。如果 LHS 不是 object 类型,instanceof of 运算符将始终导致 false。

请注意,new String('Hello World') 不会导致 string 类型,而是objectnew 运算符总是产生一个对象。我看到这样的事情:

function fnX(value)

     if (typeof value == 'string')
     
          //Do stuff
     

fnX(new String('Hello World'));

期望“Do Stuff”会发生,但它不会发生,因为值的类型是对象。

【讨论】:

【参考方案4】:

正如 Christoph 的回答中所述,字符串和数字文字与字符串和数字对象不同。如果您在文字上使用任何 String 或 Number 方法,请说

'a string literal'.length

文字暂时转换为对象,方法被调用,对象被丢弃。 与对象相比,文字有一些明显的优势。

//false, two different objects with the same value
alert( new String('string') == new String('string') ); 

//true, identical literals
alert( 'string' == 'string' );

始终使用文字来避免意外行为! 如果需要,可以使用 Number() 和 String() 进行类型转换:

//true
alert( Number('5') === 5 )

//false
alert( '5' === 5 )

【讨论】:

【参考方案5】:

对于原始数字,isNaN 方法也可以帮助您。

【讨论】:

以上是关于为啥 4 不是 Number 的实例?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我不能使用常量而不是 this.item.number?

js中为啥NaN的返回类型为number

为啥 Number.MAX_SAFE_INTEGER 是 9,007,199,254,740,991 而不是 9,007,199,254,740,992?

为啥不应该使用 Number 作为构造函数? [复制]

Python 之 While 循环语句(实例)

为啥JS中数值类型已经可以使用Number方法,还要引入Number对象概念?