likes
comments
collection
share

js类型转换之让人汗流浃背的面试题([] == ![])

作者站长头像
站长
· 阅读数 46

前言

JavaScript中的类型转换是指将一个值从一种数据类型转换为另一种数据类型。这可以是隐式(自动)或显式(由程序员进行)。今天我们用一道面试题,细说一下js的几种转换类型。

面试题如下:

js类型转换之让人汗流浃背的面试题([]  == ![])

面试官问:这个输出false还是true? 答案是true.

第一次见到这样形式的运算比较,很自然的会认为这两边字符都不等,肯定输出false,但是,既然面试官这样问了,我们肯定需要小心,不能自认为感觉是false,细品你就知道这里输出true。那么下面我们就简单介绍一些类型转换例子吧。

转换的类型

隐式类型转换:这是JavaScript自动进行的类型转换,通常在比较、运算符操作或函数调用时发生。

例如:

```
let x = "5";
let y = 2;
console.log(x + y); // 输出 "52",因为数字y被转换成字符串与x连接。


if(''){ //if里面也会进行隐式类型转换,由于if识别的是truefalse,所以空字符串是向Boolean转换为false,不会进入if内部
    console.log(123)
}
```

当出现对象类型转原始值时也被称为是隐式类型转换

  • 对象转Number:

    当出现像这样的Number({}),先调用ToNumber(x)方法规则如图,该函数中会调用ToPrimitive(),将对象转为原始值。 js类型转换之让人汗流浃背的面试题([]  == ![])

    • ToPrimitive(obj,Number) 内部执行如下方法:
    1. 判断接收到的值是不是原始值类型,是则返回
    2. 否则,调用valueof()方法,如果得到了原始值,则返回
    3. 否则,调用toString方法,如果得到了原始值,则返回,
    4. 否则报错
  • 对象转String:

    一样的当出现String({}),JavaScript就先调用ToString(x),该函数中也会调用ToPrimitive()将对象转为原始值

    • ToPrimitive(obj,String)
    1. 判断接收到的值是不是原始值类型,是则返回
    2. 否则,调用toString方法,如果得到了原始值,则返回
    3. 否则,调用valueOf方法,如果得到了原始值,则返回,
    4. 否则报错

    这两个方法就是在ToPrimitive方法的内部2、3步骤调换顺序。

  • 对象转布尔: 任何对象转布尔都是true。

    js类型转换之让人汗流浃背的面试题([]  == ![])

  • 由一元操作符触发的隐式转换

console.log(+[])  // 0
console.log(+{})  // NaN

在需要转换的数据类型前加一个运算符+,触发隐式类型转换,因为JavaScript会将其看成运算操作,这样,后面的类型就需要向Number去转换,一样的操作,数组[]和对象{}都是对象对象类型,他们都不会返回原始值,都会调用toString方法,而数组的隐式原型上存在一个toString方法,使其转换为''空字符串,空字符串转换为number0,所以输出0

但是在{}的隐式原型上不存在toString方法,他会继承Object显式原型上的toString方法,也就是Object.prototype.toString()。

下面是Object.prototype.toString()详解:

  1. 如果toString接受的值是 undefined,则返回"[[object Undefined]]"。
  2. 如果 toString 接受的值是null ,则返回"[object Null]"
  3. 调用 ToObject(X) 将X转为对象,此时得到的对象 内部一定拥有一个属性[[class]],而该属性[[class]]的值就是 X 的类型
  4. 设,class是[[class]]的值
  5. 返回由"[object " 和 class 和"]" 拼接得到字符串

当调用该方法时ToPrimitive(obj,Number)会返回一个字符串"[object Object]",然后让字符串进行Number类型转换,它是一个原始数据类型,字符串除了空字符串转number类型是0,任何带有字符的字符串都为NaN,所以这里输出的是NaN

显式类型转换:这是程序员明确执行的类型转换,使用特定的方法或构造函数。以下均为基本数据类型的转换

  • Number() / parseInt() / parseFloat() 这些函数用于将其他类型的值转换为数字。

    let str = "100";
    let num = Number(str); // 或者使用parseInt()或parseFloat()
    console.log(num); // 输出 100
    
  • String() :将任何类型的值转换为字符串。

    let num = 100;
    let str = String(num);
    console.log(str); // 输出 "100"
    
  • Boolean() :将任何类型的值转换为布尔值。

    let str = "Hello";
    let bool = Boolean(str);
    console.log(bool); // 输出 true,除非str是falsenull0""、undefined或NaN,否则结果总是true
    

类型强制:这是通过赋值操作或比较操作发生的隐式类型转换。

  • 赋值类型强制: 当你将一个值赋给一个不同类型的变量时,可能会发生类型转换。

    let x = "42"; // 字符串
    let y = x; // y也是字符串,没有类型转换
    let z = Number(y); // 显式转换为数字
    
  • 比较类型强制: 在比较操作中,如果两个操作数类型不同,JavaScript会尝试将它们转换为相同的类型。

    let x = "5";
    let y = 5;
    console.log(x == y); // 输出 true,因为字符串"x"被转换为数字然后与数字y比较。==会触发隐式类型转换
    console.log(x === y); //输出 false, 因为 === 不会触发隐式类型转换,单纯的比较值是否相等
    

面试题分析

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

由于该类型的比较涉及到多次的类型转换,我们可以分步进行分析:

右边表达式![]存在感叹号,在JavaScript中,!(逻辑非)是一个一元运算符,用于对单个操作数求反。当作用于布尔值时,它的行为很简单:将true转换为false,将false转换为true。其优先级更高,须先处理。

  • 由于空数组[]是一个对象,对象转换为布尔类型都为true,!对true取反,所以![] 被处理为false

再看左边表达式:一个单纯的[]空数组,并没有上面特殊,所以直接开始比较。表达式可以看为[] == false

  • 当进行比较操作时:两边均往number转(会去调用ToNumber(x)),由于右边为布尔类型,属于基本类型,我们知道0转为布尔是false1转为布尔是true。所以右边变为了0

  • 现在就成了[] == 0的比较,[]对象的转换我们参照上面聊的,对象向Number类型的转换,JavaScript会去调用toNumber()方法,它发现是对象类型的转换,就会去找ToPrimitive()帮忙,执行如下步骤,

    js类型转换之让人汗流浃背的面试题([]  == ![])

    alueOf方法通常用于将对象转换为其原始值,如果valueOf返回一个原始值,那么这个值将被使用;如果返回的还是一个对象,JavaScript引擎会继续尝试调用toString方法。

    这里的[]调用后还是返回一个对象,所以接下来就是调用toString方法,而数组本身就存在一个toString方法。他会将[] 转换为空字符串''。ToPrimitive()返回一个空字符串,空字符串转化为number类型就是0了。

所以console.log([]==![]) 输出 true

结尾

这里就不说什么了,我们附上一张类型转换表吧!

js类型转换之让人汗流浃背的面试题([]  == ![])

转载自:https://juejin.cn/post/7379792320156237864
评论
请登录