每日五道前端面试题--day3
第三天要刷的面试题如下:
- 叙述js中其他类型的值到字符串类型的转换规则
- 叙述js中其他类型的值到布尔值的转换规则
- 对比操作符 ||, && 和 ??
- 对比 ==, === 和 Object.is,并手写Object.is
- 什么是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: 内部机制
所谓内部机制,指的就是:
- 判断x是否有valueOf方法,如果有的话根据其返回值做出不同的反映:
- 返回值为symbol类型,报错
- 返回值为引用类型, 跳到2
- 返回值y为其它非引用类型,最终结果为:
String(y)
- 如果没有valueOf方法,或valueOf返回引用类型,则接着判断是否有toString方法,如果有的话根据其返回值做出不同的反映:
- 返回值为symbol类型,报错
- 返回值为引用类型,
报错
- 返回值y为其它非引用类型的y,最终结果为:
String(y)
- 如果没有toString方法,则返回
Object.prototype.toString,call(x)
2. 叙述js中其他类型的值到布尔值的转换规则
js中其他类型的值向布尔类型转换就比较简单了;事实上,js中常见的一共只有8种假值,也就是不能通过if()
判断的值:
-
- ""
-
- false
-
- +0
-
- -0
-
- NaN
-
- null
-
- undefined
-
- Boolean(false)
其余的值都能够通过if()
的判断,也就是所谓的真值。下面是一些容易搞混的假值:
-
- ![]
-
- !({})
-
- !123n
-
- !Symbol(0)
-
- !Object(false)
3. 对比操作符 ||, && 和 ??
- 共同点:
- 这三个操作符都具有短路的特性
??
可以看成是||
的收紧版本,||
对js中的假值短路生效,而??
只对undefined
和null
生效(也就是说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
的判断机制是:-
- 如果a和b的类型相同(这里指的是typeof作用之后的返回值相同),那么对
非引用值
直接进行比较原始值;而对引用值
比较的是内存地址;
- 如果a和b的类型相同(这里指的是typeof作用之后的返回值相同),那么对
-
- 如果a和b的类型不同,则首先判断是否其中有一个是
引用类型的
,如果两个都不是引用类型
,则直接返回false;如果有一个是,则根据js设计规格将两者强制转成同一个非引用类型
进行比较。
- 如果a和b的类型不同,则首先判断是否其中有一个是
-
a === b
的判断机制是:-
- 如果a和b的类型不相同,则直接返回false
-
- 如果a和b都是
引用
类型的,则比较内存地址
- 如果a和b都是
-
- 如果a和b都是
非引用
类型的,则比较原始值
- 如果a和b都是
-
Object.is(a,b)
的判断机制是:-
- 检查是否符合两种特例,如果不符合,则直接返回
a===b
的结果
- 检查是否符合两种特例,如果不符合,则直接返回
-
- 特例一:a和b都是NaN,此时应该返回true
-
- 特例二: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