js类型判断,类型转换及经典面试题

193 阅读6分钟

js中的基本类型

基本类型:number(只可以表示2的53次方-1),string,boolean,undefined,null,symbol,bigint(基于数组方式表示)

引用类型:Object, Array, Function, Date, RegExp, Map/Set/WeakMap/WeakSet (ES6+)

判断js的类型有以下几种方法

一、typeof判断法(基本类型判断)

image.png 通过上面的输出我们可以发现:typeof可以判断除了null以外的其他类型基本数据, typeof判断引用数据类型,除了function 以外,其他的都返回object。

实现原理:typeof是通过将值的转化为二进制数来判断类型的,二进制的前三位为0那么就识别为对象,null的二进制全是0故判断为对象类型。

二、Instanceof(引用类型判断)

在理解 instanceof 之前,必须明确两个关键概念:

1.显式原型 (prototype):

  • 是构造函数特有的属性
  • 指向该构造函数创建的实例对象的原型对象
  • 例如:Array.prototype 是所有数组实例的原型

2.隐式原型 (proto):

  • 是每个对象都有的属性
  • 指向创建该对象的构造函数的 prototype
  • 现代代码中建议使用 Object.getPrototypeOf() 替代 proto

image.png

Instanceof方法本质上是判断左边的隐式原型是不是右边的显示原型。如果不是则继续判断左边隐式原型的隐式原型,一直判断下去,直到两边相等或者左边的值已经为null了。嘿嘿嘿,都知道原理了手搓一个代码不过分吧。

手搓Instanceof方法

function myInstanceof(left,right){
    if(left === null){
        return false;
    }
    let cur =  left.__proto__;
    while(cur){
        if(cur === right.prototype){
            return true;
        }
         cur = cur.__proto__;
    }
    return false;
}

三、Object.prototype.toString.call(任何类型)

Object.prototype.toString.call() 是 JavaScript 中用于检测对象类型的核心方法。它可以精确返回任意值的内部 [[Class]] 属性(格式为 [object Type])。

a.call(b) 的核心作用是:让函数 a 在执行时,其内部的 this 指向对象 b,也就是让b去临时借用a的方法。

Object.prototype.toString.call([])本质上是利用了 call 方法对 this 指向的控制能力。虽然 toString 是定义在 Object.prototype 上的方法,而 [] 是一个数组,但 JavaScript 通过 call,在不修改数组的前提下,临时让 Object.prototype.toString 方法在执行时,其内部的 this 指向这个数组 [] 。引擎在执行时会检查 this 的内部属性(如 [[Class]]),从而识别出它是一个数组,并返回标准字符串 "[object Array]"。整个过程执行结束后一切恢复原状,没有产生任何副作用。这种方式既安全又高效,是 JavaScript 中实现精确类型判断的核心机制。

image.png

与 typeof 和 instanceof 的对比

方法特点
typeof无法区分对象类型(如 ArrayDate 均返回 "object"
instanceof受原型链影响,跨窗口/iframe 时会失效
Object.prototype.toString最可靠,能精确识别内置类型(包括 Null 和 Undefined

小小判断题

在进一步了解我们的判断之前我们先区分一下==与====

1.==会发送隐式类型转化,所以只判断值是不是相等的

2.===不会发生类型转化,所以只会判断值和类型是不是相等的

image.png

这是因为==发生的隐式转化,所以只判断值是否相等,故第一个输出的结果为true,但是第二个===不发生类型转化,数字类型与string类型显然是不相等的嘛。

隐式转化与显式转化

js引擎在执行各种运算符对数据是有要求的,比如if需要布尔类型的数据,如果数据不符合就会发生类型转化。

通俗的来说隐式转化也就是我们看不到的类型转化,由js引擎自动完成,开发者不直接转换代码。 显示转化也就是写出来的转化,是开发者主动调用的类型转化。引用类型可以转化为原始类型 这个是基于目的来的,因为我们的判断主要是四则运算这些,四则运算又是判断基本的数据类型。 但是原始类型是不可以转化为引用类型的

一、原始类型转原始类型

image.png

源 \ 目标stringnumberbooleanbigint
string"123" → 123"" → false"123" → 123n
number123"123"0 → false123 → 123n
booleantrue"true"true → 1true → 1n
undefinedundefined"undefined"→ NaN→ false抛 TypeError
nullnull"null"→ 0→ false抛 TypeError
symbol"Symbol(x)"抛 TypeError→ true抛 TypeError

valueOf()

默认实现里,包装对象(Number、String、Boolean、Date、BigInt 等) 会返回对应的基础类型值,普通对象({}[])通常原样返回对象本身;

toString()

js中的大部分构造函数原型上面都重写了toString方法
  1. {}.toString返回由字符串 [object Object]
  2. [].toString 返回由数组中的每个元素以逗号拼接而成的字符串
  3. xxx.toString 直接返回xxx的字符串字面量

二、引用类型转原始类型

1. 转布尔----任何引用类型转布尔都是true

image.png

2.转字符串--Stirng(obj)==>ToString(obj)==>Toprimitive(obj,string)

  1. 先看 obj 本身是不是“原始值”
    如果是(numberstringboolean 等),直接把它变成字符串返回,后面步骤全部跳过。

  2. 如果不是原始值(对象或数组等),先尝试调用 obj.toString()

    • 只要 toString() 返回的是原始值(如 "[object Object]""1,2,3"),就立刻用它。
    • 如果 toString() 返回的还是对象,继续下一步。
  3. 再尝试调用 obj.valueOf()

    • 如果 valueOf() 这回返回了原始值,就把它变成字符串返回。
    • 如果还是对象,继续下一步。
  4. 两步都失败 → 直接抛 TypeError
    表示“我尽力了,实在不知道怎么把这家伙变成字符串”。

3.转数字——Number(obj)==>ToNumber(obj)==>Toprimitive(obj,Number)

Toprimitive(obj,Number)

  1. 判断obj是否为原始数据类型,若是则直接返回
  2. 否则,调用valueOf(),如果的到的是原始类型则返回
  3. 否则,调用toString(),如果得到的是原始类型则返回
  4. 否则,抛出TypeError的错误

经典面试题

console.log(1==[]);

类型不同触发隐式转换
比较 number == array,需要将数组转为原始值
执行 ToPrimitive([], 'number')
检查 Symbol.toPrimitive:数组没有定义 → 跳过
调用 valueOf():[].valueOf() 返回数组本身(非原始值)→ 继续
调用 toString():[].toString() 返回空字符串 ""
得到 Number("")
空字符串转为数字是 0
最终比较 1 == 0
结果为 false

console.log([]==![]);

![] 取反运算
[] 在布尔上下文中转为 true(所有对象转布尔都是 true)
!true 结果为 false
现在表达式变为:[] == false
false 转数字
根据规则:boolean 在 == 比较时会先转 number
Number(false) → 0
现在表达式变为:[] == 0
[] 转原始值
调用 [].valueOf() → 返回 [](仍是对象,继续转换)
调用 [].toString() → 返回 ""(空字符串)
现在表达式变为:"" == 0
"" 转数字
Number("") → 0
最终比较:0 == 0true