热搜:fiddler git ip 代理 m1
历史搜索

JavaScript类型转换之`[] == ![]`的原理与实践

游客2024-08-08 15:03:01
目录文章目录
  1. 显示类型转换
  2. 隐式类型转换
  3. 特殊方法:toString()
  4. 一元与二元运算符
  5. == 与 === 的区别
  6. 解析 [] == ![]

JavaScript类型转换之`[] == ![]`的原理与实践 1

JavaScript 的类型转换是一项重要而且影响程序行为的核心机制。它涉及到显式和隐式两种方式的类型转换,对比较运算和函数调用等多个方面产生了深远的影响。本文将深入探讨 JavaScript 中的类型转换规则,特别关注显式和隐式转换之间的差异,并对一个经典例子进行剖析:[] == ![]的结果及其背后的原理。

显示类型转换

显示类型转换,即程序员明确指定的类型转换,主要包括三种基本转换方式:

1. 转布尔值:Boolean(x),用于显式将任意值转换为布尔值,遵循 JavaScript 的真值规则。

let s='s'
let n=123
let f=false
let u=undefined
let nu=null
console.log(Boolean(s));//true
console.log(Boolean(n));//true
console.log(Boolean(Infinity));//true
console.log(Boolean(-Infinity));//true
console.log(Boolean(''));//false
console.log(Boolean(0));//false
console.log(Boolean(-1));//true
console.log(Boolean(NaN));//false
console.log(Boolean(undefined));//false
console.log(Boolean(null));//false
console.log(Boolean(false)); // false
console.log(Boolean());//false

2. 转数字:Number(x),将值转换为数字,无法直接转换的值(如对象、非数字字符串)将转换为NaN

console.log(Number('123'));//123
console.log(Number('abc'));//NaN
console.log(Number(''));//0
console.log(Number('a123'));//NaN
console.log(Number(true));//1
console.log(Number(false));//0
console.log(Number(null));//0
console.log(Number(undefined));//NaN
console.log(Number());//0

3. 转字符串:String(x),将任何值转换为字符串形式。

let num = 123;
let numStr = String(num);
console.log(numStr); // 输出 "123"

隐式类型转换

隐式类型转换通常发生在运算符或函数自动将值转换为所需类型时。

对象转 number

先调用ToNumber(x),该函数中会再调用ToPrimitive(x,Number)将对象转为原始值,ToPrimitive(x,Number)会返回一个原始类型。

ToPrimitive(object,Number)的原理:

  1. 判断接收到的值是不是原始类型,是,则返回;
  2. 否则,调用valueOf(),如果得到了原始值,则返回;
  3. 否则,调用toString()方法,如果得到了原始值,则返回;
  4. 否则,报错。
console.log(Number([]));//输出 0
// Number([])
//1. ToPrimitive()
//2. let primValue=ToPrimitive([], Number)//''
//3. Number('')

为何输出 0?

  • ArrayNumber类型时,先调用ToNumber([]),该函数中会再调用ToPrimitive([],Number)
  • ToPrimitive([],Number)中,首先会判断它是否为原始类型,[]不是原始类型,则调用valueOf(),发现也得不到原始值。那么这时候就会进行调用toString(),将[]转换成了''ToPrimitive([],Number)便完成任务。
  • 最后Number()ToPrimitive([],Number)的返回值进行转换,即Number('')值为 0。

对象转 String

先调用ToString(x),该函数中会再调用ToPrimitive(x,String)将对象转为原始值

ToPrimitive(object,String)

  1. 判断接收到的值是不是原始类型,是,则返回;
  2. 否则,调用toString(),如果得到了原始值,则返回;
  3. 否则,调用valueOf()方法,如果得到了原始值,则返回;
  4. 否则,报错。
console.log(String({}));
//ToString({})
//let primValue=ToPrimitive({}, String)//"[object Object]"
//String("[object Object]")//"[object Object]"

为何输出”[object Object]”?

  • ObjectString类型时,先调用ToNumber({}),该函数中会再调用ToPrimitive([],String)
  • ToPrimitive({},Number)中,首先会判断它是否为原始类型,{}不是原始类型,则调用toString()Object有自己的toString()方法,得到"[object Object]"ToPrimitive([],Number)便完成任务。
  • 最后String()ToPrimitive({},String)的返回值进行转换,即String("[object Object]")值为"[object Object]"

布尔值转换任何对象在需要转换为布尔值时,隐式转换结果总是true

运算符中的转换

如加法运算符+,在操作数不同时会尝试将非数字转换为数字;而比较运算符如==,则会根据两边的类型进行复杂的类型转换以进行比较。

特殊方法:toString()

toString()方法在不同类型的对象上有着不同的表现。

对象的toString()

Object.prototype.toString(x):

  1. 如果toString接收的值是undefined,则返回“[object Undefined]”
  2. 如果toString接收的值是null,则返回“[object Null]”
  3. 调用ToObject(x)将 x 转为对象,此时得到的对象内部一定拥有一个属性[[Class]],而该属性[[Class]]的值就是 x 的类型
  4. 设 class 是[[Class]]的值
  5. 返回由”[object “和 class 和”]”连接而成的字符串
let a={}
let b=[]
let c='hello'

console.log(Object.prototype.toString(a));//[object Object]
console.log(Object.prototype.toString.call(b)); //[object Array]
console.log(Object.prototype.toString.call(c));//[object String]

为何bc使用Object.prototype.toString()时为何同时使用了call()

直接调用数组和字符串实例的toString方法可能会受到对象原型上toString方法被覆盖的影响。而使用Object.prototype.toString.call()确保了调用的是最原始、未被修改的toString方法,提高了代码的稳定性和可靠性。

数组的 toString()

let arr=[1,2,3];
console.log(arr.toString());//"1,2,3"

数组的toString()方法是一个非常实用且内置的功能,它能够将数组中的所有元素转换成字符串形式,并用逗号,连接这些字符串,最后返回一个由这些字符串组成的单个字符串。这个过程简单直观,非常适合于需要将数组内容以易于阅读的文本格式展示的场景。

其它的 toString()

//Number
let num = 123;
console.log(num.toString()); // 输出 "123"

//String
let str = "Hello";
console.log(str.toString()); // 输出 "Hello"

//Boolean
console.log(true.toString()); // 输出 "true"
console.log(false.toString()); // 输出 "false"

//函数 function
let func = function() { return "Hello"; };
console.log(func.toString()); // 输出 "function (){ return "Hello"; }"

直接将值修改成字符串字面量。

Array.isArray()的特异性

对于数组这种特定的引用类型,JavaScript ES5 引入了Array.isArray()方法,它专门用于判断一个值是否为数组。虽然功能单一,但它提供了一种直接且明确的方式来识别数组,避免了使用更通用的instanceofObject.prototype.toString()所带来的潜在复杂性。

一元与二元运算符

console.log(+[])//输出 0

一元操作符+ 作为正号使用时,会对操作数进行隐式转换为数字。

console.log(1+'1');//'11'
console.log(1+[]);//1+''
console.log(1+{});//1+'[object Object],'输出'1[object Object]'
console.log({}+[]);//'[object Object]'+'',输出'[object Object]'

二元运算符+ 在字符串与非字符串相加时,会将非字符串转换为字符串;在数字与非数字相加时,会将非数字转换为数字。

== 与 === 的区别

  • == 进行宽松相等比较,会根据两边的类型进行必要的隐式类型转换,可能导致意料之外的结果。
  • === 进行严格相等比较,不仅比较值,还比较类型,不进行类型转换,是推荐使用的比较方式。

解析 [] == ![]

现在,让我们深入分析[] == ![]这一看似诡异的表达式。首先,解析步骤如下:

  1. ![]:空数组[]在布尔上下文中隐式转换为true,取反后变为false
  2. 然后进行比较[] == false。在此比较中,由于一方是对象,另一方是布尔值,根据==的规则,两边都会被转换为数字进行比较:
    • 根据上文Number([])隐式类型转换示例,得出为 0
    • false转换为数字是0
  3. 因此,[]false在转换后都等于0,根据==规则,最终结果为true

通过这个例子,我们不仅理解了 JavaScript 中的类型转换机制,还见识到了隐式类型转换在某些情况下可能导致的非直观结果。在实际编码中,推荐使用===进行严格比较,以减少因类型转换带来的潜在错误。

以上就是 JavaScript 类型转换之`[] == ![]`的原理与实践的详细内容,更多请关注www.mimiwuqi.com的其它相关文章!

标签:isArray()