[深入06] 隐式转换 和 运算符
Posted woow_wu7
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[深入06] 隐式转换 和 运算符相关的知识,希望对你有一定的参考价值。
导航
[[深入01] 执行上下文](https://juejin.im/post/684490...
[[深入02] 原型链](https://juejin.im/post/684490...
[[深入03] 继承](https://juejin.im/post/684490...
[[深入04] 事件循环](https://juejin.im/post/684490...
[[深入05] 柯里化 偏函数 函数记忆](https://juejin.im/post/684490...
[[深入06] 隐式转换 和 运算符](https://juejin.im/post/684490...
[[深入07] 浏览器缓存机制(http缓存机制)](https://juejin.im/post/684490...
[[深入08] 前端安全](https://juejin.im/post/684490...
[[深入09] 深浅拷贝](https://juejin.im/post/684490...
[[深入10] Debounce Throttle](https://juejin.im/post/684490...
[[深入11] 前端路由](https://juejin.im/post/684490...
[[深入12] 前端模块化](https://juejin.im/post/684490...
[[深入13] 观察者模式 发布订阅模式 双向数据绑定](https://juejin.im/post/684490...
[[深入14] canvas](https://juejin.im/post/684490...
[[深入15] webSocket](https://juejin.im/post/684490...
[[深入16] webpack](https://juejin.im/post/684490...
[[深入17] http 和 https](https://juejin.im/post/684490...
[[深入18] CSS-interview](https://juejin.im/post/684490...
[[深入19] 手写Promise](https://juejin.im/post/684490...
[[深入20] 手写函数](https://juejin.im/post/684490...
[[react] Hooks](https://juejin.im/post/684490...
[[部署01] nginx](https://juejin.im/post/684490...
[[部署02] Docker 部署vue项目](https://juejin.im/post/684490...
[[部署03] gitlab-CI](https://juejin.im/post/684490...
[[源码-webpack01-前置知识] AST抽象语法树](https://juejin.im/post/684490...
[[源码-webpack02-前置知识] Tapable](https://juejin.im/post/684490...
[[源码-webpack03] 手写webpack - compiler简单编译流程](https://juejin.im/post/684490...
[[源码] Redux React-Redux01](https://juejin.im/post/684490...
[[源码] axios ](https://juejin.im/post/684490...
[[源码] vuex ](https://juejin.im/post/684490...
强制转换
- Number,String,Boolean
- js是动态类型的语言,变量没有类型限制,可以随意赋予任意值
- <font color=red>虽然变量的数据类型不确定,但各种(运算符)对变量的(数据类型)是有限制的</font>
Number()强制转换
- 参数:两种情况,参数是原始类型的值,参数是对象
- 结果:将任意的数据类型转换成数值,<font color=red>数值</font> 或者 <font color=red>NaN</font>
- Number的转换要比parseInt严格,只要一个字符不能转换成数值,整个字符串就会被转换成NaN
- <font color=red>Null => 0</font>
- <font color=red>undefined => NaN</font>
Number参数:原始类型的值
Number() 参数是原始类型的值
1. 为0的情况
Number(false)
Number(\'\')
Number(Null)
2. 为NaN的情况
Number(undefined)
Number(\'123abc\') // 不能转成数值的字符串
// Number比parseInt严格的多,只要一个字符不能转换成数值,整个字符串将被转换成NaN
// parseInt(\'123abc\') // 123
// Number(\'123abc\') // NaN
3. 为1的情况
Number(true)
Number参数:对象
Number() 的参数类型是对象时,只要不是单个数值的数组,都会转成NaN
Number() 参数是对象 Number([7]) // 7 Number([1,2]) // NaN Number({a:1}) // NaN
Number具体的转换规则
Number具体的转换规则
1. 调用对象自身的 valueOf 方法
- 如果返回原始类型的值,则直接使用Number函数,不在进行后续步骤
- 如果返回对象,则继续判断
2. valueOf返回对象,则调用对象自身的 toString 方法
- 如果返回原始类型的值,则直接使用Number函数,不在进行后续步骤
- 如果返回对象,则继续判断
3. toString返回对象,则报错
总结:
valueOf => 对象 => toStirng => 对象 => 报错
以上步骤,如果返回原始类型的值,就调用Number(),并终止后续步骤
// valueOf : 对象的valueOf 返回对象本身
// toString : 对象的toString 返回对象的字符串形式
// valueOf和toString可以自定义
String()强制转换
- 将任意类型的值转换成字符串
- 参数:原始类型的值 或 对象
结果:字符串
String()强制类型转换
- 参数:原始类型的值
String(123) // "123"
String(\'abc\') // "abc"
String(true) // "true"
String(undefined) // "undefined"
String(null) // "null" - 参数:对象
- 参数是对象,返回类型字符串
- 参数是数组,返回数组的字符串形式
String({name: \'woow_wu7\'}) // 参数是对象,返回类型字符串 ==> \'[object Object]\'
String([1,2]) // 参数是数组,返回数组的字符串形式,==> \'1,2\' - 具体的转换规则
- 调用对象的 toStirng 方法
- 如果返回原始类型的值,则使用String()方法转换
- 如果返回的是对象,继续以下步骤
- 调用对象的 valueOf 方法
- 如果返回原始类型的值,则使用String()方法转换
- 如果返回对象,继续以下步骤
valueOf返回对象,则报错
总结:
先调用 toString() -> 对象 -> valueOf() -> 对象 -> 报错
以上步骤,如果返回原始类型的值,则调用 String(),并中止后续步骤
// String参数是对象时
// 参数是对象:返回类型字符串
// 参数是数字:返回数组的字符串形式
Boolean()强制转换
将任意类型的值转成布尔值
Boolean类型转换 除了以下6个值是false,其他都为true Boolean(+0) // false Boolean(-0) // false Boolean(\'\') // false Boolean(null) // false Boolean(undefined) // false Boolean(NaN) // false
自动转换
自动转换发生的时机
- 不同类型的数据相互运算
- 对非布尔类型的数据求布尔值
- 对非数值类型的值使用一元运算符
自动转换的规则
- 预期什么类型的值,就调用该类型的转换函数
自动转化为字符串
- 字符串的自动转换,主要发生在字符串的加法运算时
当一个值是字符串,另一个值是非字符串,相加,非字符串转换成字符串
\'5\' + 1 // \'51\' \'5\' + true // "5true" \'5\' + false // "5false" \'5\' + {} // "5[object Object]" ======> {} => toString => 返回类型字符串 \'[object Object]\' \'5\' + [] // "5" =====================> [] => toString => 返回数组的字符串形式 \'\' => \'5\' + \'\' \'5\' + function (){} // "5function (){}" \'5\' + undefined // "5undefined" \'5\' + null // "5null"
自动转化为数值
- <font color=red>除了 + 有可能将运算子转换成字符串,其他运算符都会把运算子转换成数值</font>
一元运算符也会把运算子转成数值
\'5\' - \'2\' // 3 \'5\' * \'2\' // 10 true - 1 // 0 false - 1 // -1 \'1\' - 1 // 0 \'5\' * [] // 0 ----------------------- 5 * 0 false / \'5\' // 0 ----------------------- 0 / 5 \'abc\' - 1 // NaN --------------------- NaN - 1 null + 1 // 1 -------------------------- 0 + 1 undefined + 1 // NaN ------------------- NaN + 1 一元运算符也会把运算子转成数值 +\'abc\' // NaN -\'abc\' // NaN +true // 1 -false // 0
运算符
加法运算符
- <font color=red>重载(overload): 加法运算符存在 相加 和 连接,运算子的不同,导致不同的语法行为。</font>
- 除了加法运算符,其他的运算符都不存在重载,将运算子都转换成数值,再进行数学运算
<font color=red>如果运算子是对象,必须先将对象转成原始类型的值,然后再相加</font>
- true // 2
- \'a\' // "1a" ------------------- 数值和字符串新加,+存在重载,所以 1 被转成字符串 \'1\' => \'1a\'
(2) 重载导致运算结果的不同
\'3\' + 4 + 5 // "345"- 4 + \'5\' // "75" ---------- 注意顺序导致结果不一样
(3) 运算子是对象
var obj = { p: 1 };
obj + 2 // "[object Object]2"
------- valueOf => 对象本身{ p: 1 } => toString() => \'[object Object]\' + 2 => \'[object Object]2\'
------- 对象的valueOf返回对象本身
------- 注意:字符串和数值相加,由于+存在重载, 此时 + 表示相连
------- 注意:toString()之后,+具有重载性,可能调用Number()也可能调用String()
null和undefined
null和undefined与自身严格相等
undefined === undefined // true null === null // true var v1; // undefined var v2; // undefined v1 === v2 // true
相等运算符 ==
- <font color=red>相等运算符,用来比较
相同类型的数据
时,与严格相等运算符
等价</font> - 相同类型的数据:== 和 === 等价
不同类型的数据:== 会先进行类型转化,再使用 === 比较
- 原始类型的数据:转成数值,再比较
- 对象类型的数据:先将对象转成原始类型的值,再比较
- null和undefined:相互比较true,和任意其他类型比较false
缺点:存在隐式转化,容易出错
原始类型的值:先转换成数值,再进行比较
== true // true
// 等同于 1 === Number(true)\'true\' == true // false
// 都转换成数值
// 等同于 Number(\'true\') === Number(true)
// 等同于 NaN === 1\'1\' == true // true
// 等同于 Number(\'1\') === Number(true)
// 等同于 1 === 1false == \'false\' // false // Number(false) == Number(\'false\') => 0 === NaN => false
false == \'0\' // true对象类型的值: 先将对象转成原始类型的值,再比较
[1] == 1 // true
// 等同于 Number([1]) == 1[1] == \'1\' // true
// 等同于 Number([1]) == Number(\'1\')[1] == true // true
// 等同于 Number([1]) == Number(true)null和undefined:相互比较true,和任意其他类型比较false
false == null // false
false == undefined // false- == null // false
== undefined // false
undefined == null // true
false == undefined // false
--------------- undeined和null和任意其他类型==比较,都返回false,相互==返回true
--------------- 原理:Number(false) == Number(undefined) => 0 === NaN => false
false == null // false
null == undefined // true
优先级
- 最高优先级:属性访问拥有最高的优先级
.
()
- 最低优先级:赋值运算符 = 拥有最低的优先级
- 操作符中,一元运算符拥有最高优先级
结合性
- 优先级相同时,如 乘和除,优先级相同时,考虑结合性
- <font color=red>结合性分类:左结合 和 右结合</font>
- <font color=red>右结合:一元操作符,三元操作符,赋值操作符是右结合,其他所有的操作符都是左集合</font>
左结合:其他都是左结合
运算顺序
- 从左向右运算
isNaN 和 Number.isNaN
- isNaN()先将参数转换成number类型,再用isNaN判断
- Number.isNaN()先判断参数是不是number类型,不是返回false,是再用isNaN就行判断
var n = 1 / \'foo\'
var a = \'str\'
console.log(n) // 1/Number(\'foo\') => 1/NaN => NaN
console.log(n == NaN) // NaN == NaN => false
console.log(NaN === NaN) // false
console.log(isNaN(n)) // true
console.log(isNaN(a)) // isNaN(Number(\'str\')) => isNaN(NaN) => true
console.log(Number.isNaN(n)) // Number.isNaN(NaN) => true
console.log(Number.isNaN(a)) // Number.isNaN()先判断参数是否是Number类型,false返回false, true再用isNaN判断 => 直接false
案列1
[] == ![]
// true
解析:
1. 优先级: ! > == 所以先算 ![] => false // 除了\'\',+-0,null,undefined,NaN是ture以外,其他都是false
2. [] == false
3. == 相等运算符的运算子有对象时,先将[]转换成原始类型的值,再比较
4. Number([]) == false => valueOf => [] => toString => \'\' => Number(\'\') => 0 == false
5. 0 == false
6. 0 == Number(false) => 0 == 0 类型相同 == 等于 === => 0 === 0 => true
7. true
案列2
[] + []
// \'\'
解析:
1. + 的运算子是对象,先转化成原始类型的值,然后再相加
2. [] => valueOf([]) => [] => toString([]) => \'\'
3. \'\' + \'\'
4. 字符串相加,+存在重载,这里表示连接
5. \'\'
以上是关于[深入06] 隐式转换 和 运算符的主要内容,如果未能解决你的问题,请参考以下文章