关于javascript:建议星星13道隐式类型转换面试题让你一次爽到底

37次阅读

共计 11859 个字符,预计需要花费 30 分钟才能阅读完成。

前言

这是我梳理 JavaScript 根底系列文章中的一篇,次要记录 JavaScript 中的类型转换、相等性判断和运算符优先级,文尾筹备了一些常见的类型转换面试题,看完本文的话,置信这些题对你们来说都是 so easy 的。日常博客记录在语雀,欢送关注我的 语雀文档。

如果文章对你有帮忙的话,欢送 点赞评论珍藏加转发。有问题和纳闷的话也能够在评论区留言,我会第一工夫回复大家,如果感觉我的文章哪里有知识点谬误的话,也恳请可能告知,把错的货色了解成对的,无论在什么行业,都是致命的。

类型转换

相等性判断中存在对类型的隐式转换,咱们须要先理解数据类型转换的根本规定,这里次要探讨根本数据类型、一般对象、和一些非凡的值或类型。

留神:全局属性 NaN 的值示意不是一个数字,应用 isNaN 进行判断。

ToString

转换成 string 能够应用构造方法 String()toString,区别在于 toStringnullundefined 会报异样;

console.log(String(000111)) //73
console.log(000111.toString()) //73

//Number.prototype.toString(radix) 有提供一个参数,指定进制,默认值为 10。console.log(000111.toString(3)) //2201
console.log(String(1),typeof String(1))// 1 string
console.log(String(-100),typeof String(-100))// -100 string
console.log(String(1.23),typeof String(1.23))// 1.23 string
console.log(String(1e221),typeof String(1e221))// 1e+221 string

console.log(String(3333n),typeof String(3333n)) // 3333 string

console.log(String(Infinity),typeof String(Infinity))// Infinity string

console.log(String(NaN),typeof String(NaN))// NaN string

console.log(String(false),typeof String(false))// false string
console.log(String(true),typeof String(true))// true string

console.log(String(null),typeof String(null))// null string
console.log(String(undefined),typeof String(undefined))// undefined string

console.log(String([]),typeof String([]))// string
console.log(String([1]),typeof String([1]))// 1 string
console.log(String([1,'2',false,null,undefined,NaN,Infinity]),typeof String([1,'2',false,null,undefined,NaN,Infinity]))// 1,2,false,,,NaN,Infinity string

console.log(String({}),typeof String({})) // [object Object] string
console.log(String({a:1}),typeof String({a:1})) // [object Object] string

console.log(String(Symbol("foo")),typeof String(Symbol("foo"))) // Symbol(foo) string

小结

  1. null、undefined、布尔值 、NaN、Symbol 别离转为它们各自的字符串;
  2. 数值类型间接转换成数字类型的字符串(包含 Infinity,正数模式的字符串)指数体现化为e 后增加一个 + 号,其余进制数值转为十进制;
  3. BigInt类型是去掉了前面的 n 符号的字符串;
  4. 空数组转换后是空字符串,非空数组相当于应用 join 转换成字符串,数组中的 nullundefined,当做空字符串解决;
  5. 对象转换为字符串为"[object Object]"

    ToNumber

    转换成 number 能够应用构造方法 NumberparseFloat、parseInt,后两者和隐式类型转换无关,本文不做论述。

    console.log(Number('12321'), typeof Number('12321'))// 12321 number
    console.log(Number('1 手机 1'), typeof Number('1 手机 1'))// NaN number
    console.log(Number('1.23 手机'), typeof Number('1.23 手机'))// NaN number
    console.log(Number(''), typeof Number(''))// 0 number
    
    console.log(Number(3333n), typeof Number(3333n)) // 3333 number
    
    console.log(Number(Infinity), typeof Number(Infinity))// Infinity number
    
    console.log(Number(NaN), typeof Number(NaN))// NaN number
    
    console.log(Number(false), typeof Number(false))// 0 number
    console.log(Number(true), typeof Number(true))// 1 number
    
    console.log(Number(null), typeof Number(null))// 0 number
    console.log(Number(undefined), typeof Number(undefined))// NaN number
    
    console.log(Number([]), typeof Number([]))// 0 number
    console.log(Number([1]), typeof Number([1]))// 1 number
    console.log(Number([1.1]), typeof Number([1.1]))// 1.1 number
    console.log(Number([1.11,2]), typeof Number([1.11,2]))// NaN number
    console.log(Number(['1.11',2]), typeof Number(['1.11',2]))//NaN number
    console.log(Number([1, '2', false, null, undefined, NaN, Infinity]), typeof Number([1, '2', false, null, undefined, NaN, Infinity]))// NaN number
    
    console.log(Number({}), typeof Number({})) // NaN number
    console.log(Number({a: 1}), typeof Number({a: 1})) // NaN number
    
    console.log(Number(Symbol("foo")), typeof Number(Symbol("foo"))) // 无奈转换 Cannot convert a Symbol value to a number
    console.log(Number(333n), typeof Number(333n))// 333 number

    小结

  6. null和空字符、空数组转为 0undefined 转为 NaNNaNInfinity不变;
  7. 纯数值字符串,转为对应的数字, 其余都转为NaN
  8. truefalse 转为 10
  9. 数组对象可能须要进行 ToPrimitive 转换,具体看前面;
  10. 数组第一位为数值,转为该数值,否则转为NaN
  11. 对象转为NaN
  12. BigInt是去掉了前面的 n 符号的数组,Symbol 无奈转换。

    ToBoolean

    转换成 boolean 能够应用构造方法Boolean

    console.log(Boolean(1),typeof Boolean(1))// true boolean
    console.log(Boolean(-100),typeof Boolean(-100))// true boolean
    console.log(Boolean(1.23),typeof Boolean(1.23))// true boolean
    console.log(Boolean(1e221),typeof Boolean(1e221))// true boolean
    
    console.log(Boolean(3333n),typeof Boolean(3333n)) // true boolean
    
    console.log(Boolean(Infinity),typeof Boolean(Infinity))// true boolean
    
    console.log(Boolean(NaN),typeof Boolean(NaN))// false boolean
    
    console.log(Boolean(false),typeof Boolean(false))// false boolean
    console.log(Boolean(true),typeof Boolean(true))// true boolean
    
    console.log(Boolean(null),typeof Boolean(null))// false boolean
    console.log(Boolean(undefined),typeof Boolean(undefined))// false boolean
    
    console.log(Boolean([]),typeof Boolean([]))//true boolean
    console.log(Boolean([1]),typeof Boolean([1]))// true boolean
    console.log(Boolean([1,'2',false,null,undefined,NaN,Infinity]),typeof Boolean([1,'2',false,null,undefined,NaN,Infinity]))// true boolean
    
    console.log(Boolean({}),typeof Boolean({})) // true boolean
    console.log(Boolean({a:1}),typeof Boolean({a:1})) //true boolean
    
    console.log(Boolean(Symbol("foo")),typeof Boolean(Symbol("foo"))) // true boolean
    

    除了这 8 种,其余都是true

    console.log(Boolean(false),typeof Boolean(false))// false boolean
    console.log(Boolean(0),typeof Boolean(0))// false boolean
    console.log(Boolean(-0),typeof Boolean(-0))// false boolean
    console.log(Boolean(0n),typeof Boolean(0n))// false boolean
    console.log(Boolean(NaN),typeof Boolean(NaN))// false boolean
    console.log(Boolean(null),typeof Boolean(null))// false boolean
    console.log(Boolean(undefined),typeof Boolean(undefined))// false boolean
    
    // 这三个演绎为空字符串
    console.log(Boolean(""),typeof Boolean(""))// false boolean
    console.log(Boolean(''),typeof Boolean(''))// false boolean
    console.log(Boolean(``),typeof Boolean(``))// false boolean

    小结

    JavaScript中存在一个术语 falsyfalsy 蕴含的 8 个值均为false,其它值转为布尔型都为true

    ToPrimitive

    ToPrimitiveMDN 的解释是,通过尝试调用对象的 valueOf()toString() 办法,将参数转换为原始类型。

    当对象类型须要转为原始类型时,它会先查找对象的 valueOf 办法,如果 valueOf 办法返回原始类型的值,则 ToPrimitive 的后果就是这个值,如果 valueOf 不存在或者 valueOf 办法返回的不是原始类型的值,就会尝试调用对象的 toString 办法,也就是会遵循对象的 ToString 规定,而后应用 toString 的返回值作为 ToPrimitive 的后果。
    留神:对于不同类型的对象来说,ToPrimitive的规定有所不同,比方 Date 对象会先调用toString,具体能够参考 ECMA 规范

valueOf 和 toString 用法

let exp=new String(1) // 应用 String 结构一个数字 1
console.log(typeof a) // 类型是 'object'
console.log(exp.valueOf()) // "1"
console.log(typeOf exp.valueOf()) //'string' 原始类型是 "1" 是 'string' 类型
console.log(Number([])) // ''=> 0
console.log(Number(['10'])) //'10'=>10

const obj1 = {valueOf() {return 1},
    toString() {return 2}
}
console.log(Number(obj1))  // 1

const obj2 = {toString() {return 2}
}
console.log(Number(obj2)) // 2

const obj3 = {toString() {return {}
    }
}
// 如果 valueOf 和 toString 都没有返回原始类型的值,则会抛出异样。console.log(Number(obj3)) //TypeError: Cannot convert object to primitive value

小结

当对象类型须要被转为原始类型时会进行 ToPrimitive 转换的,咱们来举几个例子。

  1. String({}),空对象会先调用valueOf,但返回的是对象自身{},不是原始类型,所以会持续调用toString,失去'[object Object]'String('[object Object]'),所以转换后的后果为'[object Object]'
  2. Number([]),空数组会先调用valueOf,但返回的是数组自身[],不是原始类型,所以会持续调用toString,失去'',相当于Number(''),所以转换后的后果为0
  3. 再看下面 valueOftoString的例子,obj1.valueOf()返回的是根本类型 1,所以不会再去执行toStringToPrimitive 的后果为 1,相当于Number(1)
  4. obj2没有 valueOf 办法,会去执行 toStringtoString 返回 2,ToPrimitive的后果为2,相当于Number(2)
  5. obj3toString 办法返回的不是一个原始类型,无奈ToPrimitive,所以会抛出谬误;
  6. 留神 Boolean() 转换,falsy之外的值全为true

看到这里,咱们曾经总结到了类型转换的一些规定,上面咱们来看看 JavaScript 中的相等性判断。

相等性判断

四种算法

  1. 非严格(形象)相等比拟:==
  2. 严格相等比拟:===
  3. 零值相等:-0===0
  4. 同值相等:Object.is()

    非严格相等

    MDN提供的一张对应表,咱们须要记住他

    undefinednull 比拟都是true

    console.log(undefined==null) //true
    console.log(null==null) //true
    console.log(undefined==null) //true

    其余类型和 undefinednull 浅比拟都是false

    console.log(1==null) //false
    console.log("null"==null) //false
    console.log(false==null) //false
    console.log(NaN==undefined) //false
    console.log(true==undefined) //false
    console.log(Infinity==undefined) //false
    console.log({}==undefined) //false
    console.log([]==undefined) //false

    8 个 falsy 值认定为false,其余值转成布尔值都是true

    console.log(!!false) //false
    console.log(!!0)     //false
    console.log(!!-0)    //false
    console.log(!!0n)    //false
    console.log(!!'')    //false
    console.log(!!"")    //false
    console.log(!!null)  //false
    console.log(!!undefined)//false
    console.log(!!NaN)   //false

    非凡状况,窄对象 document.all 等于 nullundefined

    console.log(null==document.all) //true
    console.log(undefined==document.all) //true

    Number、String、Boolean、Object、Array比拟(遵循上表或下图):

  5. 类型雷同为全等比拟;
  6. 其它比拟都是转成数值进行比拟;

小结

  1. undefinednull 比拟都是true
  2. 其余类型和 undefinednull 比拟都是false
  3. 8 个 falsy 值认定为false,其余值转成布尔值都是true
  4. 非凡状况,窄对象 document.all 等于 nullundefined
  5. Number、String、Boolean、Object、Array 比拟:

    • 类型雷同为全等比拟;
    • 其它比拟都是转成数值进行比拟;

严格相等

严格相等存在两个非凡的判断:

  1. +0等于-0(辨别+0-0 在解决一些特定的数学问题时是必要的);
  2. NaN不等于NaN

    console.log(undefined===undefined) //true
    console.log(null===null)//true
    console.log(null===undefined) //false
    
    console.log(+0===-0)   //true
    console.log(0===0)     //true
    console.log(NaN===NaN) //false

    零值相等 && 同值相等

    严格相等中 0NaN的不同判断,务必会让人感到纳闷。JavaScript中应用 Object.is 做同值相等判断,次要就是用来解决严格相等中正零负零、NaN的问题。

    console.log(Object.is(+0,-0)) //false
    console.log(Object.is(NaN,NaN)) //true

    运算符优先级

    总结的一些规定:

  3. 类型转换是由操作符规定的;
  4. ToPrimitive个别作用于 == 比方 ![] 就不须要进行 ToPrimitive 转换,相当于!Boolean([])
  5. 后置 + 被用作字符拼接,其余类型大多是转成数值类型;
  6. 加法运算只有其中一个是字符串,那么另外一个也会转换为字符串;
  7. 数值加 null 或者 undefined,那么还是把null 或者 undefined 进行 Number() 转换。

局部运算符优先级:
吐槽 markdown 的表格,这里只能上图片了,不想粘一大堆HTML,语雀表格看这里【倡议星星】13 道隐式类型转换面试题,让你一次爽到底

必做题目

八股题不想做也得做😣😣😣😣

题目 1

定义一个变量 a,使得 a == 1 && a == 2 && a == 3 的表达式后果为true

// 这个题能够利用咱们文中提到的 valueOf, 每次读取都会给原值减少 1
//let num=0
const a = {
  num: 0,
  valueOf: function() {
    //return num += 1 这样也是的 只有保留一个变了就行
    return this.num += 1
  }
};
const equality = (a==1 && a==2 && a==3);
console.log(equality); // true

利用 Object.defineProperty 也能实现。

let val=1
Object.defineProperty(window, 'a', {get: function() {return val++}
});

console.log(a == 1 && a == 2 && a == 3)

题目 2

为什么表达式 [] == 0 后果为 true
解答:

  1. 数组先进行 ToPrimitive 转换,[].valueOf().toString(),值为空字符串;
  2. 当初为 ''==0 空字符转成数字为0
  3. 00 比拟为true,判断成立。

题目 3

为什么表达式 [] == ![] 后果为 true。
解答:

  1. 这里考运算符优先级和隐式类型转换,这里须要留神,!优先级比 == 高,右侧 ![] 不须要进行 ToPrimitive 转换,间接 !Boolean([]) 后果为false
  2. 当初是 [] == false,这个时候左侧就要进行ToPrimitive 转换了,依照转换规则,[].valueOf().toString()为空字符串''
  3. 当初是''==false,两侧都转成数字计算;
  4. 空字符串转成数字是 0,右侧false 转成数字也是 000相等,判断成立。

题目 4

解答:

// 字符串 '0', 转成数值为 0,false 转成数值也是 0 判断成立 判断成立
'0' == false // true

// 数组只有一个值且是数字或字符串数字, 转成字符串就是以后值,// 转成字符串为 '0', 字符串 '0' 转成数值为 0,false 转成数值也是 0 判断成立
['0'] == false // true

// 数组只有一个值且是数字或字符串数字, 转成字符串就是以后值,// 转成字符串为 '2', 字符串 '2' 转成数值为 2,2==2 判断成立
[2] == 2  //true 

// 空数组转成字符串为 '','' 空转为数值为 0,false 转成数值为 0 判断成立
[] == false // true 

// 数组中的 null 和 undefined 转换成 string 时, 当做空字符串解决,//[null].valueOf().toString()为空字符串 '',空字符串转数字为 0,判断成立
[null] == 0 // true

///[null].valueOf().toString()为空字符串 '',空字符串转数字为 0,false 转成数字也是 0.
[null] == false // true

// 数组中的 null 和 undefined 转换成 string 时, 当做空字符串解决,//[undefined].valueOf().toString()为空字符串 '',空字符串转数字为 0,false 转成数字也是 0,判断成立。[undefined] == false // true

// 其余类型和 undefined、null 浅比拟都是 false
undefined == false // false
null == 0 // false
null == false // false

题目 5

true + false 的值。
解答:转换为数字相加,1+0=1

题目 6

"number" + 15 + 3
解答:'+' 运算符按从左到右的程序的执行,所以优先执行 "number" + 15, 把 15 转为 string 类型,失去"number" 而后同理执行"number15" + 3,后果为"number153"

题目 7

100 + true + 21.2 + null + undefined + "Tencent" + [] + null + 9 + false;
解答:这里没得运算符优先级,间接从左侧开始计算,ok,咱们开始合成

  1. 100 + true, 数值和布尔值相加,将布尔值转成数字,失去100+1=101
  2. 101 + 21.2,数值和数值间接相加,失去101 + 21.2=122.2
  3. 122.2+null, 数值和 null 相加,null转为0,122.2+0=122.2
  4. 122.2 + undefined, 数值和 undefined 相加,undefined转成数字是 NaNNaN 和数值相加均为NaN,122.2+NaN=NaN
  5. NaN+ "Tencent"NaN转换成字符串是'NaN',"NaN"+ "Tencent"="NaNTencent"
  6. "NaNTencent" + [],空数组转成字符串是"","NaNTencent"+""="NaNTencent"
  7. "NaNTencent" + null,null转成字符串是"null""NaNTencent" + "null"="NaNTencentnull"
  8. "NaNTencentnull" + 9, 字符串和数字相加, 加号有拼接的作用,把 9 转成字符串"9""NaNTencentnull" + "9"="NaNTencentnull9"
  9. "NaNTencentnull9" + false,字符串和布尔值相加, 把 false 转成字符串"false","NaNTencentnull9" + "false"="NaNTencentnull9false"

    let result = 100 + true + 21.2 + null + undefined + "Tencent" + [] + null + 9 + false;
    console.log(result) //'NaNTencentnull9false'

    题目 8

    {} + [] + {} + [1] 的值
    解答:

  10. 左侧的 {} 会当成一个空的执行块,而不是一个对象,这个块没有返回值,就相当于+[] + {} + [1]
  11. +是一个一元操作符,优先执行,把 [] 转成数字是0, 当初是0+{}+[1];
  12. 对象转成字符串是 "[object Object]";0+"[object Object]"+[1] 失去"0[object Object]"+[1];
  13. [1]转成字符串是"1", 后果为"0[object Object]1"

    let result = 100 + true + 21.2 + null + undefined + "Tencent" + [] + null + 9 + false;
    console.log(result) //'NaNTencentnull9false'

    题目 9

    ! + [] + [] + ![] 的值
    解答:

  14. 先整顿优先级,逻辑非和一元加在一起时,从右到左执行 ! (+ []) + [] + ![]
  15. +被当做了一个一元操作符, (+ []) 这块后果为0;
  16. 当初为 !0+ [] + ![]=>!00进行布尔值装换,0false,对false 取反为true
  17. true+ [] + ![]`[]转成布尔值是true, 取反是false`;
  18. []转成字符串是''
  19. true+ ''+ false把三者拼接起来, 失去"truefalse"

    题目 10

    [1] > null
    解答:比拟运算符 > 执行 number类型隐式转换,[1]转成数字为 1null01>0true

    题目 11

    "foo" + + "bar"
    解答:转换一下为 "foo" + (+"bar")
    右侧优先级更高, (+"bar")触发 number 类型隐式转换, 转换成数字是 NaN"foo" +NaN
    拼接为'fooNaN'

题目 12

0 || "0" && {}
解答:逻辑运算符进行 Boolean 类型转换,0转成布尔值是 false0 || "0" 右侧成立
"0" && {},字符串"0" 是布尔值 true,返回右侧,失去{}

题目 13

[1,2,3] == [1,2,3]
解答:类型一样是,不就行类型转换,进行严格相等判断,数组是援用类型,两者内存地址不一样,为false

结语

看了这么久了,辛苦了,不过我也写了很久啊,无妨点个赞再走吧。😁😁😁
也能够看看我这个系列的另外两篇文章,嘿嘿嘿

🎉🎉2022 年除夕,我终于搞懂了原型和原型
🎉🎉⌈2022⌋ JavaScript 超具体循环总结

援用

首发于语雀文档 @is_tao
JavaScript 中的相等性判断
从一道面试题说起—js 隐式转换踩坑合集
Falsy 虚值
通过面试题钻研 JavaScript 数据类型转换

正文完
 0