面试题-斯芬克斯-js的类型转换

76 阅读5分钟

在古代神话中,狮身人面像是巨人与蛇妖所生的怪物:人的头,狮子的躯体,带着翅膀,名叫斯芬克斯。斯芬克斯生性残暴,他从智慧女神缪斯那里学到了许多谜语,常常守在大路口。每一个行人要想通过,必须猜谜,猜错了,统统吃掉,难倒无数的人。

有一次,以为国王的儿子被斯芬克斯吃掉了,国王愤怒极了,发出悬赏:“谁能把他制服,就给他王位!”。勇敢的青年狄浦斯,应国王征召前去报仇。他走呀走呀,来到了斯芬克斯把守的路口。

“小伙子,猜出谜题才能让你通过” 斯芬克斯拿出最难最难的一道题给他猜。

“javascript的类型有两种,一种是基础类型,另一种是引用类型,这两种分别是?”

js的基础类型有undefined、null、Boolean、Number、String
js的引用类型有Object、Array、Function、Date、RegExp

聪明的狄浦斯很快就猜出来了,然而斯芬克斯却不服输,又给狄浦斯出了一道谜题:
“typeof的使用及其底层原理”

  • typeof 数值/NaN // 'number'
  • typeof 字符串 // 'string'
  • typeof true/false // 'boolean'
  • typeof 函数 // 'function'
  • typeof js内置对象 // 'object'
  • typeof null // 'object'
  • typeof undefined // 'undefined'
  • typeof 未定义的变量 // undefined

typeof是直接根据值的二进制表示来判断其类型的

  • 000 //对象
  • 1 //整数
  • 100 //字符串
  • 110 //布尔
  • 000000…. //null
  • -2^30 //undefined 因为null的二进制表示是全0,所以会被判断成object

如果对象中有了call方法,那么会被判断成function

typeof只能区分基本类型以及引用类型的Object、Function

Object.prototype.toString().call()

Object这个构造器的原型有toString方法,所有继承自Object的类( Array、String、Boolean、Function等)都会继承这个方法。 而这个方法会返回[object 调用该方法的变量的构造器的名字], 比如:

  • Object.prototype.toString.call(1) // [object Number] 因为1会被js内置的Number构造器包装起来,所以返回[Object Number]
  • Object.prototype.toString.call('1') // [object String] 同上String构造器
  • Object.prototype.toString.call(true) // [object Boolean] 同上Boolean构造器
  • Object.prototype.toString.call(Symbol()) // [object Symbol] 同上Symbol构造器
  • Object.prototype.toString.call(foo) // [object Function] 同上Function构造器
  • Object.prototype.toString.call([1,2,3]) // [object Array] 同上Array构造器
  • Object.prototype.toString.call({}) // [object Object] 同上Object构造器
  • Object.prototype.toString.call(undefined) // [object Undefined] 比较特殊 直接判断
  • Object.prototype.toString.call(null); // [object Null] 比较特殊 直接判断

单绝大部分js的类都会重写toString方法,所以想要用最原始的toString功能,就得通过Object.prototype.toString.call()来改变this指向 该方法能清晰的判断所有的基本类行和引用类型

斯芬克斯大吃一惊,此人竟能回复的如此详细,待我再给他一道。

“二元操作符===和==分别是干什么的”

狄浦斯思考了片刻,回答道:

===是比较两个变量是否类型相同,并且值是否相同

  • 1==='1' // false
  • 1===2 // false
  • 1===1 // true

==是放宽版的===,允许两个变量的类型不一致,会进行一定的类型转换

  • null == undefined // true 规定
  • 1 == '1' // true 一个数值、一个字符串,将字符串转数值,然后比较
  • true == '1' // true 当有布尔类型时,true转1,false转0,然后去比较
  • 引用类型变量 == 基础类型变量 // 当两个变量的其中一个是引用类型,另一个是基础类型,则将引用类型转化为数值再进行比较
  • 其他类型的比较都返回false

斯芬克斯吐了一口老血,嘴上骂道:“你tm是犀牛书转世吧!”

“这是我最后的波纹了,你要答对,我就去世”

“引用类型这么多,他们是如何转化成基础类型变量的”

“哼”,狄浦斯嘴角一歪,摆出一个标准的龙王不屑√

引用类型转基础类型主要就是转成Number和String

`当一个引用类型需要转成string类型时`\
`如果引用类型有toString()方法,且toString()返回的是基础类型,则将其转成字符串,再返回`\
`否则,如果引用类型没有toString()方法,或者toString()返回的不是一个基础类型,则调用valueOf()`

比如

  • {x:1,y:2}.toString() // [object Object]
  • [1,2,3].toString() // '1,2,3'
  • function(x) { f(x) }.toString() // function(x) {\nf(x)\n}
  • /\d+/g.toString() // /\\d+/g
  • new Date(2010,0,1).toString() // Fri Jan 01 2010 00:00:00 GMT+0800 (GMT+08:00)

当一个引用类型需要转换成数值类型时:

`如果引用类型有valueOf(),且方法返回一个基础类型,则将其转化成数值类型,然后返回`\
`否则,如果引用类型没有valueOf(),或者valueOf()返回的并不是一个基础类型,则调用toString()`\
`而valueOf()方法挺简单的,一般就返回对象本身,而Date类型的valueOf()会返回:197011日以来的毫秒数`\
`let d = new Date(2010, 0, 1)`\
`d.valueOf() //1262275200000`

来看这个例子:

function a(){
    return 0
}
a.toString = function(){
    return 1
}
console.log(a + '0') // 字符串'10' 
console.log(a + 0)   // 数值1

a + '0'时,很明显a需要转换成字符串,所以直接调用了我们给a重写的toString方法()
a + 0时,很明显a需要转换成数值类型,所以寻找a的valueOf,然后a没有valueOf方法,所以从原型链的上游Function类找valueOf,找到了该方法,然而a.valueOf()返回的不是数值类型,所以转而去调用a.toString()方法,返回了1

斯芬克斯卒,享年不详 image.png