typeof null === 'object'的原因

typeof

操作符唯一的目的就是检查数据类型

类型 typeof结果
undefined 基本类型 'undefined'
Boolean 基本类型 'boolean'
Number 基本类型 'number'
String 基本类型 'string'
BigInt (ECMAScript 2020 新增) 基本类型 'bigint'
Symbol 基本类型 'symbol'
null 基本类型 'object'
Object(Object、Array、Map、Set等) 引用类型 'object'
Function 引用类型 'function'

在 JavaScript 中,typeof null是'object',它错误地表明null是一个对象(它不是,它是一个原始值)

“typeof null”错误是 JavaScript 第一个版本的残余。在这个版本中,值以 32 位为单位存储,它由一个小型标签(1-3 位)和值的实际数据组成。类型标签存储在单元的低位中。其中有五个:

  • 000:对象。数据是对对象的引用。
  • 1:整数。数据是一个 31 位有符号整数。
  • 010:双倍。数据是对双浮点数的引用。
  • 100:字符串。数据是对字符串的引用。
  • 110:布尔值。数据是一个布尔值。

也就是说,最低位是任一位,那么类型标签只有一位长。或者它是零,那么类型标签的长度是三位,为四种类型提供两个额外的位。

两个值很特别:

  • undefined ( JSVAL_VOID ) 是整数 -2^30 (整数范围之外的数字)。
  • null ( JSVAL_NULL ) 是机器码空指针。或者:一个对象类型标签加上一个为零的引用。

现在应该很明显为什么typeof认为null是一个对象:它检查了它的类型标签,并且类型标签表示“对象”。以下是typeof的引擎代码。

    JS_PUBLIC_API(JSType)
    JS_TypeOfValue(JSContext *cx, jsval v)
    {
        JSType type = JSTYPE_VOID;
        JSObject *obj;
        JSObjectOps *ops;
        JSClass *clasp;

        CHECK_REQUEST(cx);
        if (JSVAL_IS_VOID(v)) {  // (1)
            type = JSTYPE_VOID;  // undefined
        } else if (JSVAL_IS_OBJECT(v)) {  // (2)
            obj = JSVAL_TO_OBJECT(v);
            if (obj &&
                (ops = obj->map->ops,
                 ops == &js_ObjectOps
                 ? (clasp = OBJ_GET_CLASS(cx, obj),
                    clasp->call || clasp == &js_FunctionClass) // (3,4)
                 : ops->call != 0)) {  // (3)
                type = JSTYPE_FUNCTION; // function
            } else {
                type = JSTYPE_OBJECT; //object
            }
        } else if (JSVAL_IS_NUMBER(v)) {
            type = JSTYPE_NUMBER; //number
        } else if (JSVAL_IS_STRING(v)) {
            type = JSTYPE_STRING; //string
        } else if (JSVAL_IS_BOOLEAN(v)) {
            type = JSTYPE_BOOLEAN; //boolean
        }
        return type;
    }

上述代码执行的步骤是:

  • 在 (1) 处,引擎首先检查值v是否未定义(VOID)。此检查是通过使用 equals 比较值来执行的:
  • #define JSVAL_IS_VOID(v) ((v) == JSVAL_VOID)
  • 下一个检查 (2) 是该值是否具有对象标记。如果它另外是可调用的 (3) 或其内部属性 [[Class]] 将其标记为函数 (4),则v是一个函数。否则,它是一个对象。这是typeof null产生的结果。
  • 随后的检查是针对数字、字符串和布尔值。甚至没有对null的显式检查,这可以由以下 C 宏执行。
  • #define JSVAL_IS_NULL(v) ((v) == JSVAL_NULL)

这似乎是一个非常明显的错误,但不要忘记完成 JavaScript 的第一个版本的时间很少。

在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签是 0,typeof null 也因此返回 "object"。(参考来源)

曾有一个 ECMAScript 的修复提案(通过选择性加入的方式),但被拒绝了。该提案会导致 typeof null === 'null'

Object.prototype.toString(扩展)

还有一个不错的判断类型的方法,就是 Object.prototype.toString ,我们可以利用这个方法来对一个变量的类型来进行比较准确的判断

Object.prototype.toString.call("abc"); // "[object String]"
Object.prototype.toString.call(100); // "[object Number]"
Object.prototype.toString.call(true); // "[object Boolean]"
Object.prototype.toString.call(null); // "[object Null]"
Object.prototype.toString.call(undefined); // "[object Undefined]"
Object.prototype.toString.call([1,2,3]); // "[object Array]"
Object.prototype.toString.call(/\w/); // "[object RegExp]"

参考:https://2ality.com/2013/10/typeof-null.html
https://www.pzijun.cn/blog/1/1.1.html#typeof

你可能感兴趣的:(typeof null === 'object'的原因)