从一道 js 面试题说下类型转换

1,题目

a 在什么情况下会执行输出语句,打印 ok ?

if (a == 1 && a == 2 && a == 3) {
    
    
  console.log('ok')
}

2,解决

解决的方法有很多,这里主要讨论下类型转换的问题。更多的解决办法放到文章最后了。

2.1,数据类型转换

分为显示转换和隐式转换。

显示转换又称为强制转换,隐式转换又称为自动转换。

显示转换主要指:通过 Number()String()Boolean() 手动将不同类型的值分别转为数字,字符串或布尔。

Number() 的参数需要分为2种情况讨论,一种是基本类型,一种是对象。

基本类型值:比较特殊的就是这3种:

Number('324abc') // NaN
Number(undefined) // NaN
Number(null) // 0

其中将字符串转为数值,Number()的规则是只要有一个字符无法转为数字,那整个字符串就会被转为NaN。而parseInt() 是逐个分析。

parseInt('123 cats') // 123
Number('321 cats') // NaN

对象:转换规则如下:

扫描二维码关注公众号,回复: 17134290 查看本文章
  1. 调用对象自身的 valueOf 方法。如果返回原始类型值,则直接对该值使用Number(),不再进行后续步骤。

  2. 如果 valueOf 方法返回的还是对象,则改为调用对象自身的 toString 方法。如果 toString 方法返回原始类型的值,则对该值使用Number(),不再进行后续步骤。

  3. 如果toString方法返回的是对象,就报错。

我们来验证下:

const num = Number({
    
    
  valueOf() {
    
    
    return 2
  },
  toString() {
    
    
    return 3
  }
})
console.log(num) // 2
const num = Number({
    
    
  valueOf() {
    
    
    return {
    
    }
  },
  toString() {
    
    
    return 3
  }
})
console.log(num) // 3
const num = Number({
    
    
  valueOf() {
    
    
    return {
    
    }
  },
  toString() {
    
    
    return {
    
    }
  }
})
console.log(num) // TypeError: Cannot convert object to primitive value

所以

Number({
    
    a: 1}) // NaN
Number([1, 2, 3]) // NaN
Number([5]) // 5

String()Number()相比,会先调用 toString() ,而不是 valueOf()


Boolean() 的转换规则比较简单,除了下面6个,其他都是true

Boolean(undefined) // false
Boolean(null) // false
Boolean(0) // false
Boolean(NaN) // false
Boolean('') // false
Boolean(false) // false

2.2,比较运算

更详细的参考:如何正确比较 - MDN

比较运算符分为两类:相等比较非相等比较。两者的规则是不一样的。

  • <<=>>=!=!== 属于非相等比较运算符。
  • == === 属于相等比较运算符。

比较算法

对非相等比较来说,算法是先看2个操作数是否都是字符串,如果是,就按照字典顺序比较(Unicode 码);否则将2个操作数都转成数值来比较大小。

对相等比较来说,

  • 严格相等运算符===比较的是是否为“同一个值”,而如果2个值不是同一类型,则直接返回 false。
  • 相等运算符==会将它们先转换成同一个类型,再用严格相等运算符比较。
    • 如果操作数都是基本类型,则都转为数值进行比较。
    • 如果操作数之一是对象,而另一个是原始值,则将对象转为基本类型再进行比较(转换规则和使用 Number() 转对象一致)。

3,解决

const a = {
    
    
  i: 1,
  valueOf() {
    
     // 这里用 toString 也可以。
    return this.i++;
  }
}

if(a == 1 && a == 2 && a == 3) {
    
    
  console.log('ok');
}

3,其他的解法

1,利用数组的 toString()

a = [1,2,3];
a.join = a.shift;
console.log(a == 1 && a == 2 && a == 3);

Array.prototype.toString() - MDN

简单来说,Array 覆盖了对象的toString(),并且在调用 toString() 时内部又调用了join()。所以可修改join() 方法来实现其他目的。

同样的,数组在比较时也会调用toString() 来转为基本类型。

2,Object.defineProperty

let index = 0;
Object.defineProperty(window, 'a', {
    
    
  get: function() {
    
    
    return ++index;
  }
});
if (a == 1 && a == 2 && a == 3) {
    
    
  console.log('ok');
}

3,隐藏空格

注意,a 的左右隐藏着特殊的空格(String.fromCharCode(65440))。代码复制到 vscode 中可明显看出不是普通空格。

var aᅠ = 1;
var a = 2;
var ᅠa = 3;
if(aᅠ==1 && a== 2 &&ᅠa==3) {
    
    
    console.log("ok")
}

以上。

猜你喜欢

转载自blog.csdn.net/qq_40147756/article/details/134847997