为何JavaScript中NaN.typeof()与Object.prototype.typeof(NaN)结果不同?
问题:调用
NaN.typeof()与Object.prototype.typeof(NaN)结果不一致的原因 我编写了一段代码,旨在便捷判断变量类型,弥补原生typeof的不足(例如数组会被识别为'object')。大部分场景下表现符合预期:比如'this is a string'.typeof()与Object.prototype.typeof('this is a string')均返回'String';但调用NaN.typeof()时返回'Number',而Object.prototype.typeof(NaN)却能按预期返回'NaN',希望理解这两种调用结果不同的原因。
相关代码如下:
if (!Object.prototype.hasOwnProperty('stringify')) { Object.defineProperties(Object.prototype, { stringify: { value: function () { if (arguments.length >= 2) return JSON.stringify(this, ...arguments); //this means replacer is used return JSON.stringify(this, null, ...arguments) } //when replacer ( function, array) is skipped. }, getType: { value: function(target) { if (arguments.length === 0) target = this; //assuming no error, variable.typeof() will yield the target. To avoid error use Object.prototype.typeof(target); if (typeof target === 'number' && Number.isNaN(target)) return 'NaN';//NaN.typeof() will return "number" even if it's not a number if (typeof target !== 'object') return typeof target; //when typeof returns a primitive (Function, String, Number, BigInt, Symbol, Boolean, undefined); const return_value = Object.prototype.toString.call(target); // we can also use regex to do this... const type = return_value.substring( return_value.indexOf(" ") + 1, return_value.indexOf("]")); return type.toLowerCase(); } }, typeof: {value: function(target) { //this should be same as getType() above. weird that NaN.typeof() still yields 'Number' but Object.prototype.typeof(NaN) yields 'NaN' if (arguments.length === 0) target = this; //in case target is of 'null' value; return target === undefined ? 'undefined' : target === null ? 'null' : Object.is(NaN, target)? 'NaN' : target.constructor.name; }}, isTypeof: {value: function(type, val) { return ([undefined, null].includes(val) && val === type) || Object.is(NaN, val) || val.constructor.name === type; }}, is: {value: function() { if (arguments.length === 1) { let target = this; return Object.prototype.isTypeof(arguments[0], target); } else if (arguments.length === 2) { return Object.prototype.isTypeof(...arguments); } }} }); } console.log(Object.prototype.typeof(NaN)) //gets 'NaN' as expected. console.log(NaN.typeof()); //expecting 'NaN' not 'Number'
原因分析
核心问题出在原始值的自动装箱机制:
- 当调用
NaN.typeof()时,NaN是原始类型的数值,JavaScript会自动将其包装为Number对象(即“装箱”),此时方法内的this指向这个临时创建的Number实例,而非原始的NaN值。 - 看
typeof方法的逻辑:当arguments.length === 0时,target被赋值为this(也就是装箱后的Number对象)。此时Object.is(NaN, target)判断的是原始NaN和Number对象,结果为false,因此会执行target.constructor.name,返回'Number'。
而调用Object.prototype.typeof(NaN)时:
- 你直接将原始NaN作为参数传入
target,此时Object.is(NaN, target)判断成立,直接返回'NaN'。
补充说明:除了null和undefined,所有原始类型(字符串、数字、布尔值等)在调用原型方法时都会触发自动装箱,这是JavaScript的默认行为。
内容的提问来源于stack exchange,提问作者bho
相关产品推荐
相关产品推荐

