likes
comments
collection
share

每日五道前端面试题--day3

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

第三天要刷的面试题如下:

  1. 叙述js中其他类型的值到字符串类型的转换规则
  2. 叙述js中其他类型的值到布尔值的转换规则
  3. 对比操作符 ||, && 和 ??
  4. 对比 ==, === 和 Object.is,并手写Object.is
  5. 什么是js中的包装类型,又如何反包装?

下面是我的一些理解:

1. 叙述js中其他类型的值到字符串类型的转换规则

将x转成string类型,可分为隐式转换和强制转换,所谓隐式转换就是指""+x的结果,所谓强制转换指的就是String(x)的结果:

  • undefined: "undefined"
  • null: "null"
  • string: 返回原值,注意String("abc")不是包装类型,注意与new String("abc")区别开
  • number: "Infinity", "-Infinity", "NaN", 变成相同的字面量,但是数字太大会变成字符串类型的科学计数法的模样
  • boolean: "true", "false"
  • symbol: 隐式转换报错;强制转换如:String(Symbol(9)) // "Symbol(9)"
  • bigint: 会变成将n去掉的相同的字面量,不会出现因为数字大变成字面量
  • object: 内部机制

所谓内部机制,指的就是:

  1. 判断x是否有valueOf方法,如果有的话根据其返回值做出不同的反映:
    • 返回值为symbol类型,报错
    • 返回值为引用类型, 跳到2
    • 返回值y为其它非引用类型,最终结果为:String(y)
  2. 如果没有valueOf方法,或valueOf返回引用类型,则接着判断是否有toString方法,如果有的话根据其返回值做出不同的反映:
    • 返回值为symbol类型,报错
    • 返回值为引用类型,报错
    • 返回值y为其它非引用类型的y,最终结果为:String(y)
  3. 如果没有toString方法,则返回Object.prototype.toString,call(x)

2. 叙述js中其他类型的值到布尔值的转换规则

js中其他类型的值向布尔类型转换就比较简单了;事实上,js中常见的一共只有8假值,也就是不能通过if()判断的值:

    1. ""
    1. false
    1. +0
    1. -0
    1. NaN
    1. null
    1. undefined
    1. Boolean(false)

其余的值都能够通过if()的判断,也就是所谓的真值。下面是一些容易搞混的假值:

    1. ![]
    1. !({})
    1. !123n
    1. !Symbol(0)
    1. !Object(false)

3. 对比操作符 ||, && 和 ??

  • 共同点:
    • 这三个操作符都具有短路的特性
    • ??可以看成是||收紧版本||对js中的假值短路生效,而??只对undefinednull生效(也就是说console.log(0 ?? 20)的执行结果为0而不是20)
  • 不同点:
    • x||y的特性是,x为假值(或者x表达式的返回值为假值)的时候,返回y的值(或者y表达式的返回值);但是x为真值(或者x表达式的返回值为真值)的时候,不会执行y或者y表达式,就好像||y不存在一样,直接返回x(或者x表达式的返回值)
    • x&&y的特性是,x为真值(或者x表达式的返回值为真值)的时候,返回y的值(或者y表达式的返回值);但是x为假值(或者x表达式的返回值为真值)的时候,不会执行y或者y表达式,就好像||y不存在一样,直接返回x(或者x表达式的返回值)

4. 对比 ==, === 和 Object.is,并手写Object.is

这个就不用找相同点和不同点了,这三个不能说一模一样吧,只能说是完全不同了,所以分开来单独说:

  • a == b的判断机制是:
      1. 如果a和b的类型相同(这里指的是typeof作用之后的返回值相同),那么对非引用值直接进行比较原始值;而对引用值比较的是内存地址;
      1. 如果a和b的类型不同,则首先判断是否其中有一个是引用类型的,如果两个都不是引用类型,则直接返回false;如果有一个是,则根据js设计规格将两者强制转成同一个非引用类型进行比较。
  • a === b的判断机制是:
      1. 如果a和b的类型不相同,则直接返回false
      1. 如果a和b都是引用类型的,则比较内存地址
      1. 如果a和b都是非引用类型的,则比较原始值
  • Object.is(a,b)的判断机制是:
      1. 检查是否符合两种特例,如果不符合,则直接返回a===b的结果
      1. 特例一:a和b都是NaN,此时应该返回true
      1. 特例二:a和b都是0,只不过一个为正一个为负,此时需要返回false

手写Object.is之前需要补充一个知识点:1 / Infinity === 0;的结果是true

根据Object.is的判断机制,容易写出其实现:

function myObjectIs (a, b) {
    if(Number.isNaN(a) && Number.isNaN(b)) return true;
    if(a===0 && b===0 && 1/a!==1/b) return false;
    return a===b;
}

有一个坑,那就是需要使用Number.isNaN而不是isNaN!

5. 什么是js中的包装类型,又如何反包装?

对于js中的一个变量x而言,如果typeof x的返回值是C(= "number" | "string" | "boolean"),这意味着x是非引用类型。那么,按照道理来说,x是没有属性和方法的。但是作为使用者,仍然可以通过"abc".length获得字符串的长度,或者使用123.toString(16)将number转成字符串格式。

之所以能够这样,在于js中存在着的包装类型。包装类型实际上是一种机制,在使用者做上述操作的时候,js会自动将"number" | "string" | "boolean"包装成对象,即所谓的包装对象。

这个过程可以表示为:let _x = new C(x);其中,x是"number" | "string" | "boolean"类型的,C为构造函数Number | String | Boolean.

对于包装对象有如下特征:

  • x == _x // true 除过NaN
  • x === _x // false
  • _x.valueOf() === x // true 除过NaN

可以看到,使用包装对象的valueOf方法可以反包装,得到原始值(又称为是Primitive Value)

补充:一般认为js中有六种primitive value

  • undefined
  • null
  • string
  • number
  • boolean
  • symbol
  • 至于bigint, 2020年之后才出现的,也算是
转载自:https://juejin.cn/post/7283313180730343443
评论
请登录