likes
comments
collection
share

类型转换:[ ] == ![ ]为什么返回true

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

前言

在JavaScript的世界里,类型转换和比较操作是编程日常中不可或缺的一部分,它们直接影响着代码的行为和逻辑判断的准确性。本文旨在深入探讨==(宽松相等)与===(严格相等)运算符的核心差异,以及背后涉及的类型转换机制,特别是对象到原始值的转换过程,帮助开发者更好地驾驭这门动态语言的微妙之处。

=====的区别

先看一个例子:

类型转换:[ ] == ![ ]为什么返回true

在这个例子中你会发现 1 == '1' 会返回 true,而如果是 1 === '1' 会返回 false。那这是为什么呢?是因为当使用 == 进行比较时,JavaScript 会在比较之前尝试进行类型转换,使两个操作数具有相同的类型,然后再进行值的比较。而使用 === 运算符进行比较时,不仅比较值,还会比较类型,只有当两个操作数的值和类型完全相同时,结果才为 true

今天要和大家聊一聊的就是使用 == 进行比较时,到底是怎么进行类型转换的。

在JS中不存在两个相等的对象

let a = [];
let b = [];
console.log(a == b);// 输出 false

在JS中不存在两个相等的对象,因为引用类型的大小是动态的,而栈内存是预先分配且大小固定的,不适合存储大小可变的数据结构。所以就将引用类型存储在堆中,并在栈中存放指向堆中数据的指针,这样保持了栈的轻量级,有利于提高程序执行效率,同时也保持了数据的隔离性,减少了潜在的数据冲突。

类型转换:[ ] == ![ ]为什么返回true 从上面的图可以看出[] == []在JS引擎的眼中等同于判断1001 == 1002,这无疑是false,所以可以得出一个结论:在JS中不存在两个相等的对象,因为每一个对象,也就是引用类型存放在堆里的指针都是不同的。

显示类型转换

1.原始值转布尔 Boolean(xx)

  • 当原始值为数字时,只有 0NaNfalse,其他都是true
console.log(Boolean(0));// 输出 false
console.log(Boolean(NaN));// 输出 false
console.log(Boolean(1));// 输出 true
console.log(Boolean(2));// 输出 true
console.log(Boolean(-1));// 输出 true
  • 当原始值为字符串时,只有空字符串 ''false,其他都是true
console.log(Boolean(''));// 输出 false
console.log(Boolean(' '));// 输出 true
console.log(Boolean('abc'));// 输出 true
  • 当原始值为 undefinednull 时都是 false
console.log(Boolean(undefined));// 输出 false
console.log(Boolean(null));// 输出 false

2.原始值转数字 Number(xx)

  • 当原始值为字符串时,字符串里面的字符是数字,则输出里面的数字;字符串里面的字符是字母或者字,则输出 NaN(Not a Number);空字符串 '' 输出为0
console.log(Number('12'));// 输出 12
console.log(Number('589'));// 输出 589
console.log(Number('abc'));// 输出 NaN
console.log(Number('是昔年啊'));// 输出 NaN
console.log(Number(''));// 输出 0
console.log(Number(' '));//在里面加一个空格也是输出 0
  • 当原始值为布尔值时,false0true1
console.log(Number(false));// 输出 0
console.log(Number(true));// 输出 1
  • 当原始值为 undefined,输出为 NaN ,当原始值 null 时,输出为0
console.log(Number(undefined));// 输出 NaN
console.log(Number(null));// 输出 0

3.原始值转字符串 String(xx)

无论你传的是什么原始值,都会被转成字符串。

console.log(String(123));// 输出 '123'
console.log(String(NaN));// 输出 'NaN'
console.log(String(true));// 输出 'true'
console.log(String(undefined));// 输出 'undefined'
console.log(String(null));// 输出 'null'
console.log(String('abc'));// 输出 'abc'

4.原始值转对象 new xxx()

调用构造函数 new Number()new String()new Boolean()

类型转换:[ ] == ![ ]为什么返回true

对象转成原始值(重点内容)

1.任何对象转为布尔值一定是 true

类型转换:[ ] == ![ ]为什么返回true

2.对象转字符串

先执行ToString()
再调用ToPrimitive()

3. 对象转数字

先执行ToNumber()
再调用ToPrimitive()

ToPrimitive( )得到原始类型

查看 官方文档会发现对象转为原始值会先调用JS内置的ToPrimitive( )得到原始类型,下面来看看ToPrimitive( )是怎么回事吧。

类型转换:[ ] == ![ ]为什么返回true

类型转换:[ ] == ![ ]为什么返回true 类型转换:[ ] == ![ ]为什么返回true

JS内置的函数ToPrimitive(),可以把引用类型转换成原始类型,总结步骤如下:

ToPrimitive(obj,String) ==> 借助ToPrimitive()将对象转换成字符串

  1. 如果接收到的是原始值,直接返回值
  2. 否则,调用toString方法,如何得到原始值,返回
  3. 否则,调用valueOf方法,如何得到原始值,返回
  4. 报错

ToPrimitive(obj,Number) ==> 借助ToPrimitive()将对象转换成数字

  1. 如果接收到的是原始值,直接返回值
  2. 否则,调用valueOf方法,如何得到原始值,返回
  3. 否则,调用toString方法,如何得到原始值,返回
  4. 报错

toString()方法

  1. {}.toString() 得到由"[object 和 class 和 ]" 组成的字符串,即'[object Object]'
  2. [].toString() 返回由数组内部元素以逗号拼接的字符串,即'',如果[1,2,3].toString() ,即返回'1,2,3'
  3. 其他的toString()方法,返回字符串字面量

类型转换:[ ] == ![ ]为什么返回true

valueOf()方法

valueOf()方法也可以将对象转成原始类型,但仅限于包装类对象( 如new Boolean()、new String()、new Number() )

类型转换:[ ] == ![ ]为什么返回true

类型转换:[ ] == ![ ]为什么返回true

隐式类型转换

一元运算符 +

一元 + 运算符就是将对象转成数字类型。在v8引擎中 +x 相当于 Number(x),例如 +[] == Number([])

在官方文档里面是这样描述一元运算符的:官方文档

类型转换:[ ] == ![ ]为什么返回true

类型转换:[ ] == ![ ]为什么返回true

翻译过来就是一元 + 运算符将其操作数转换为 Number类型,会先执行ToNumber(),得不到数字的话再调用ToPrimitive()方法

console.log(+[]);// 输出为 0 步骤如下:
 '+[]'
 执行ToPrimitive([],Number)
 [].valueOf()得[],不是原始类型,调用toString方法
 [].toString()得到空字符''
 '' 转数字得到 0

执行 +[] ,调用 ToPrimitive 方法,会先调用 valueOf 方法,但是 valueOf 方法无法将数组转换为原始值,就会开始调用 toString 方法。空数组调用 toString 方法会返回空字符串,然后JS会将空字符串转为数字 0 。

二元运算符 +

当执行表达式 v1 + v2 时,会有以下步骤:

  1. lprim = ToPrimitive(v1)
  2. rprim = ToPrimitive(v2)
  3. 如果 lprim 或者 rprim 是字符串,就会将不是字符串的那个转成字符串,那么就ToString(lprim) 或者 ToString(rprim) 再拼接
  4. 否则,就 ToNumber(lprim) + ToNumber(rprim)
console.log(1 + '1');// 输出 '11' 步骤如下:
 1 + '1' ===> '11'
 ToPrimitive(1) + ToPrimitive('1')
 1 + '1'
 ToString(1)  + '1'
 '1' + '1'最后得到 '11'
 

console.log(null + 1);// 输出 1 步骤如下:
 ToPrimitive(null) + ToPrimitive(1)
 null + 1
 ToNumber(null) + ToNumber(1) 
 0 + 1


console.log([] + {});// 输出 '[object Object]'  步骤如下: 
 ToPrimitive([])  +  ToPrimitive({})
 [].valueOf()  + {}.valueOf()
 [].toString()  + {}.toString()
 '' + '[object Object]'
 '[object Object]'

== 运算

这是官方文档给的说明:

类型转换:[ ] == ![ ]为什么返回true

console.log(1 == {});// 输出 false  步骤如下: 
 1 == ToPrimitive({}) 
 1 == {}.valueof() 判断不了
 1 == {}.toString()
 1 == '[object Object]'
 1 == NaN
 false

最后来到今天的重头戏,判断 [] == ![] 输出结果是什么?

console.log([] == ![]);// 输出 true  步骤如下: 
 [] == false
 [] == 0
 ToPrimitive([]) == 0
 [].valueOf() == 0
 [].toString() == 0
 '' == 0
 0 == 0
 true
  1. 在JavaScript中,符号!称为逻辑非运算符(Logical NOT Operator)。它是一个一元运算符,用于对一个布尔值进行取反操作。! 优先级比 == 高,所以会先执行取反操作。空数组转为布尔值为true,所以 ![] 的结果为false

  2. 接下来相当于判断 [] == false ,在官方文档中,如果有一个值为布尔值,先将其转换为数字,即将 false 转为了 0,相当于要判断 [] == 0

  3. 当一边是对象,一边是数字时,比较结果 ToPrimitive([]) == 0,对于ToPrimitive([])会先调用 valueOf 方法,但使用这个方法并不返回原始值,接着调用 toString方法,返回结果为空字符串''

  4. 最后相当于判断 '' == 0 ,将空字符串转为数字,结果为 0 ,判断 0 == 0 结果为 true

结语

这就是今天带给大家的内容啦,希望可以给你带来帮助!

类型转换:[ ] == ![ ]为什么返回true

转载自:https://juejin.cn/post/7371318721904443418
评论
请登录