一篇文章让你轻松记住js的隐式转化

目录
  • 前言
  • 一、包装类
    • Boolean()
    • 扩展
    • Number()
      • 引用类型转换Number
    • 原始类型转Number
      • 还有这些混淆点是需要注意的:
      • 扩展
    • String()
      • Object.prototype.toString
      • Array.prototype.toString
  • 二、隐式转化触发规则
    • 布尔的隐式转化
    • number的隐式转化
    • 隐式转化最难的情况
  • 三、特殊情况
  • 四、工作不要使用
  • 总结

前言

之前写过一篇文章[[js让人诟病的这些feature]]中提出过一个疑问.

这个问题一开始我想简单了.认为只要记住一些特性就可以了.所以直接用穷举法来进行规律的总结.

但是当遇到console.log(Number([])) 的结果是0, 而console.log(Number([1, 2])) 的结果是NaN.都什么乱七八糟的,里面必有蹊跷.虽然能够强背背下来, 但是作为一个有追求的程序员还是要弄明白它是怎么一回事的.

console.log({} - {}) // NaN
console.log([] - []) // 0
console.log([] - [1, 2]) // NaN
console.log([] == ![]) // true
console.log({} == {}) // false

要理解上面打印的结果,就是要理解Number([]) 的值,Number([1, 2])的值, Number({})的值, 以及Boolean([])返回的值. 下面慢慢说道.

一、包装类

Boolean()

Boolean只有两种结果,true和false.

  • Boolean结果为false的类型,我们通常称他为 falsey, 中文叫虚值. 这些值在 [[[js让人诟病的这些feature]] 有所提及,即,

0、null、undefined、false、''、NaN

有些文章把-0和+0算成两个

上面这些都是原始值转原始值.其他的都是true

如果是引用值转原始值都为true. 还有下面这些一时间想不起来的引用类型.

Boolean(/d/)
Boolean(new Error())
console.log(Boolean(Symbol()))

扩展

还有一种容易弄混的typeof 返回结果, node环境中:

console.log(typeof Date())
console.log(typeof new Date())
console.log(Date()) // Thu Jan 13 202l2 22:29:36 GMT+0800 (中国标准时间)
console.log(new Date()) // 2022-01-13T14:29:36.660Z

Number()

引用类型转换Number

易错点出现在Number() 上面. 尤其是引用类型转化为原始类型. 了解了这个,开头的例子就能够理解了.

我们只有在知道了Number(引用类型)的规则才能够判断引用类型转化为原始类型的结果什么,不然是不可能判断得出的饿,靠猜走不远.

  • 我们假设有如下这么一个对象
const obj = {
  toString() {
    return 2
  },
  valueOf() {
    return 1
  }
}
  • 我们Number()包裹它
console.log(Number(obj))

打印出的结果是1. 哦,有意思的来了,

consot obj = {
  toString() {
    return 2
  },
  valueOf() {
    return {}
  }
}
console.log(Number(obj)) // 2

让我们让valueOf 返回的值是对象的时候, 打印出 2 , 反之则直接打印出String原始值,再转化为number类型.

一般来说valueof 就是代表值,没有意义,也不用处理. 值是什么就是什么,比如说[1, 2, 3].valueOf() 直接打印就是[1, 2, 3].

我们也可以通过这个方法来解决[[让 a == 1 && a == 2 && a == 3 成立]]的问题.

所以我们很容易得出这么一个规律: 当valueOf 返回值是引用类型的时候, 就去拿toString 返回的值. 展开来说就是:

  • 如果valueOf返回原始值,就Number包装之后返回
  • 如果valueOf返回的对象,就去toString()方法中找
  • 如果toString() 返回原始值,就Number包装之后返回
  • 如果toString()返回的是对象,且是自己重写的.那么就直接报错
  • 如果不是充血的,那么就调用Obejct.prototye.toString方法

这里显然还涉及到了[[原型链]]的问题,所以说其实隐式转化的问题不是想象中的那么简单的.

而我们创建的对象基本没讲过会创建这两个方法.所以它很显然就是继承至Object上面的方法. 也就是说,我们在研究这个问题的是,就是在研究Object.prototype.toString.call() 返回的值.

console.log(Object.prototype.tostring.call('123'));

console.log(Object.prototype.toString.call(123));

console.log(object.prototype.tostring.call(true));

console.log(Object.prototype.tostring.call(undefined));

console.log(Object.prototype.tostring.call(null));

console.log(Object.prototype.tostring.call(function){}));

console.log(Object.prototype.toString.call([1,2,3]));

console.log(Object.prototype.tostring.call(ff));

打印的结果如下:

[object string]
[object Number]
[object Boolean]
[object Undefined]
[object Null]
[object Functionl]
[object Arrayl]
[object objectl]

原始类型转Number

console.log(Number(undefined)) // NaN
console.log(Number (null)) // 0
console.log(Number(true)) // 1
console.log(Number (false)) // 0
console.log(Number(NaN)) // NaN
console.1og(Number (Infinity))// Infinity
console.log(Number('') // 0
console.log(Number(' ') // 0
console.log(Number('123')) // 123

上面没啥好说的, 背下就行. 需要注意的是Number的值,除了我们平时使用的的数字意义之外,还有NaN、Infinity.

还有这些混淆点是需要注意的:

console.log((123).toString()) // 123
console.log(undefined.toString()) // 报错
console.log(nul.toString()) // 报错
复制代码

undefined 和 null 没有包装类, 本身又是基础类型 ,自然没有其他乱码七糟的方法. 所以报错.

扩展

Argument和document

console.log(Object.toString.call(argument)) // [object Argument]
console.log(Object.toString.call(document)) // [object HTMLDocument]

HTMLDocument是浏览器给我们提供的对象类型.

由此也可以得知Object.prototype.toString 方法的运用之广, 识别类型之多, 比起typeof 简陋的返回值强大得多. 当然每个都有每个使用的场景就是了.

手写typeof

typeof是jscore自带,而且也不是语法糖. 我一开始看到这个面试题的时候是懵逼的. 难道要手写typeof的引擎代码? 解释一下从js第一个版本就存在的typeof null为object吗?

但是还真有公司考这个, 有点睿智,大聪明. 所以我看了看网上别人对于这的解析... 就是利用Object.prototype.toString.call()返回的结果,在进行字符串的切割,之后后面那个单词返回出去.

就这? 脱裤子放屁,多此一举.

Number转化非二进制

Number(0xfff) // 4095
Number(070) // 56

Number可以直接识别不同位数转化成十进制.

parseInt和Number关系

Number('123abc') // NaN
Number('ad123') // NaN
Number('  123') // 123

而[[parseInt]]就很好的解决了这个问题,它可以说是对于Number()很好的一个补充

parseInt('123abc') // 123
parseInt('123asd1') // 123
parseInt('ad123') // NaN
parseInt('  123') // 123

String()

Object.prototype.toString

对于String()的使用依旧使用Number()使用的例子

const obj = {
  toString() {
    return 2
  },
  valueOf() {
    return 1
  }
}

当我触发String(obj)的时候,就和Number()完全相反.

console.log(String(obj)) // 2

直接访问的是toString()方法.

const obj = {
  toString() {
    return {}
  },
  valueOf() {
    return 1
  }
}

console.log(String(obj)) // 1

但是如果toString() 返回的是引用类型的话, 就往valueOf()方法上面找. 可以说和Number()的完全相反,但是也符合情理 .

通过重写toString()和valueOf()的方法来了解内部的运行规则是一种很好的方式.

如果不重写的话,Object.prototype.toString.call(对象), 返回值参看Number()部分的内容.

console.log(String({})) // [object Object]

Array.prototype.toString

这个记忆上没啥好说的, 直接把外面的[]给拆了就行.

console.log(String([1])) // '1'
console.log(String([1, 2])) // '1, 2'
console.log(Array.prototype.toString.call([1])) // '1'
console.log(Array.prototype.toString.call([1, 2])) // '1, 2'

二、隐式转化触发规则

前面说了显示转化的规律. 下面是能够触发隐式转化的规则.

和运算符规则是和[[运算符的优先级]],在这里不提,可自行查阅.

布尔的隐式转化

当出现判断的时候,会出现隐式转化.

if,
switch,
while,
for(; ;),
&&,
||,
!,
!!,
? : 三元

number的隐式转化

只要有小学的知识都知道运算符,它是用于数字之间的计算的.在JavaScript中也是基本是一样的.

+ - * % == ~~ & | ~ ^ << <<< 等, 位运算符 、算术运算符

隐式转化最难的情况

== !== >= <= < >

如下例子, 也是面试的高频题目,背下来之余,还是要知道得到这样结果的过程.

console.log([] == ![]) // true

个人觉得隐式转化最复杂的就是这个例子了.再复杂大不了加上优先级. 回到这个例子中, 看似比较的是两个数组,或者说两个特殊对象.其实不全是.来解析这个例子:

  • 看到 等号 这个比较运算法就应该明白 等号 两边都要转化成Number类型
  • 从左到右的话,Number([]), [] 是引用类型,无法直接拿到原始值
  • valueOf拿不到值,就走Array.prototype.toString.call([]).从上面可以知道, 它返回的是去掉[],即字符串''.
  • 此时左边为Number(''). 所以左边返回的自然是0.

此时这个题目为0 == ![]. 接下来右边的转化,这就简单了.

  • 在Boolean()一节当中,就可以知道,除了falsey之外,其他都是ture.而此时在!的加持下,[]会进行Boolean()
  • 此时右边为true. !true就为false
  • Number(false)的结果为0

由上而得出 0 == 0 的结果为true.运用上面的知识点可以很好的解析问题,下面的这个例子就更加简单了.

console.log({} == {}) // false
console.log({} != {})

如果按照一样的分析方式来解释的话:

  • 两边都Number()包裹住.
  • toString()之后都是[obejct Object]
  • Number('[obejct Object]') 为NaN
  • 所以最后转化为console.log(NaN == NaN)的比较

NaN和任何一个值比较都不想等

题目不难,但是综合的东西还是有一点的. 这两题解决了,隐式转化的问题也就到头了

三、特殊情况

最容易记住的就是字符串运算符.

console.log(1 + '2' + '2') // '122'
console.log(1 + + '2' + '2') // '32'
console.log('A' - 'B' + '2') // 'NaN2'
console.log('A' - 'B' + 2) // NaN

js 字符串和任何数据类型想加都转化为字符串么?可以这么说,处理symbol类型直接报错之外.

console.log(typeof (+ '2')) // number

还有下面undfined和null的特殊情况

console.log(undefined == null) // true
console.log(NaN == NaN) // fasle
  • NaN的语意是not a number,很明显了,指的就不是一个数字
  • NaN在typeof中是number类型,但是它和任何数都不想.

四、工作不要使用

2022年了,我们只需要了解==的运行机制就够了. 都这个年份了,不需要在重申工作中使用==还是===的问题了吧

总结

到此这篇关于js隐式转化的文章就介绍到这了,更多相关js的隐式转化内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 跟我学习javascript的隐式强制转换

    JavaScript的数据类型分为六种,分别为null,undefined,boolean,string,number,object. object是引用类型,其它的五种是基本类型或者是原始类型.我们可以用typeof方法打印来某个是属于哪个类型的.不同类型的变量比较要先转类型,叫做类型转换,类型转换也叫隐式转换.隐式转换通常发生在运算符加减乘除,等于,还有小于,大于等.. typeof '11' //string typeof(11) //number '11' < 4 //false 一.基

  • JavaScript中运算符规则和隐式类型转换示例详解

    前言 本文主要给大家介绍了关于JavaScript运算符规则和隐式类型转换的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 隐式类型转换 在 JavaScript 中,当我们进行比较操作或者加减乘除四则运算操作时,常常会触发 JavaScript 的隐式类型转换机制:而这部分也往往是令人迷惑的地方.譬如浏览器中的 console.log 操作常常会将任何值都转化为字符串然后展示,而数学运算则会首先将值转化为数值类型(除了 Date 类型对象)然后进行操作. 我们首先来

  • JavaScript隐式类型转换

    JavaScript的数据类型是非常弱的(不然不会叫它做弱类型语言了)!在使用算术运算符时,运算符两边的数据类型可以是任意的,比如,一个字符串可以和数字相加.之所以不同的数据类型之间可以做运算,是因为JavaScript引擎在运算之前会悄悄的把他们进行了隐式类型转换的,如下是数值类型和布尔类型的相加: 复制代码 代码如下: 3 + true; // 4 结果是一个数值型!如果是在C或者Java环境的话,上面的运算肯定会因为运算符两边的数据类型不一致而导致报错的!但是,在JavaScript中,只

  • 简单介绍JavaScript数据类型之隐式类型转换

    JavaScript的数据类型分为六种,分别为null,undefined,boolean,string,number,object.object是引用类型,其它的五种是基本类型或者是原始类型.我们可以用typeof方法打印来某个是属于哪个类型的.不同类型的变量比较要先转类型,叫做类型转换,类型转换也叫隐式转换.隐式转换通常发生在运算符加减乘除,等于,还有小于,大于等.. typeof '11' //string typeof(11) //number '11' < 4 //false 本章节单

  • 对存在JavaScript隐式类型转换的四种情况的总结(必看篇)

    一般存在四种情况,JavaScript会对变量的数据类型进行转换. 目录 * if中的条件会被自动转为Boolean类型 * 会被转为false的数据 * 会被转为true的数据 * 参与+运算都会被隐式的转为字符串 * 会被转为空字符串的数据 * 会被转为字符串的数据 * 会被转为数据类型标记的数据 * 参与*运算都会被隐式的转为数字 * 会被转为0的数据 * 会被转为1的数据 * 会被转为NaN的数据 * == 运算符 * 为true的时候 * 为false的时候 if中的条件会被自动转为B

  • JavaScript强制类型转换和隐式类型转换操作示例

    本文实例讲述了JavaScript强制类型转换和隐式类型转换.分享给大家供大家参考,具体如下: 在JavaScript中声明变量不需指定类型, 对变量赋值也没有类型检查,同时JavaScript允许隐式类型转换.这些特征说明JavaScript属于弱类型的语言. (1).转换为字符串 转换为字符串是应用程序中的常见操作,javascript提供了toString方法.多数的JavaScript宿主环境(比如Node.js和Chrome)都提供了全局函数toString: 与此同时Object.p

  • 浅析JavaScript中的隐式类型转换

    如果把通过函数或方法调用,明确的将某种类型转换成另一种类型称为显示转换 ,相反则称为隐式类型转换 .google和维基百科中没有找到"显示类型转换","隐式类型转换"的字眼.暂且这么称呼. 一. 运算中存在的隐式类型转换 1, "+"运算符 复制代码 代码如下: var a = 11, b = '22'; var c = a + b; 这里引擎将会先把a变成字符串"11"再与b进行连接,变成了"1122".

  • 基于javascript 显式转换与隐式转换(详解)

    显示转换 1.题目:请输入今年的年龄,求5年后多大? //a.prompt接收到的数据是string类型的. var age = prompt("请输入你今年的年龄"); alert(typeof age); var age5 = age + 5; // 这里只会拼接成了15,而不是加5 alert("我今年"+age+"岁了,5年后我"+age5+"岁了"); 2.字符串要转换成number类型. 针对上述问题,需要将age

  • JavaScript中的一些隐式转换和总结(推荐)

    js中的不同的数据类型之间的比较转换规则如下: 1. 对象和布尔值比较 对象和布尔值进行比较时,对象先转换为字符串,然后再转换为数字,布尔值直接转换为数字 [] == true; //false []转换为字符串'',然后转换为数字0,true转换为数字1,所以为false 2. 对象和字符串比较 对象和字符串进行比较时,对象转换为字符串,然后两者进行比较. [1,2,3] == '1,2,3' // true [1,2,3]转化为'1,2,3',然后和'1,2,3', so结果为true; 3

  • JS面试题大坑之隐式类型转换实例代码

    1.1-隐式转换介绍 在js中,当运算符在运算时,如果两边数据不统一,CPU就无法计算,这时我们编译器会自动将运算符两边的数据做一个数据类型转换,转成一样的数据类型再计算 这种无需程序员手动转换,而由编译器自动转换的方式就称为隐式转换 例如1 > "0"这行代码在js中并不会报错,编译器在运算符时会先把右边的"0"转成数字0`然后在比较大小 1.2-隐式转换规则 转成string类型: +(字符串连接符) 2..转成number类型:++/--(自增自减运算符

随机推荐