导航
[深入01] 执行上下文
[深入02] 原型链
[深入03] 继承
[深入04] 事件循环
[深入05] 柯里化 偏函数 函数记忆
[深入06] 隐式转换 和 运算符
[深入07] 浏览器缓存机制(http缓存机制)
[深入08] 前端安全
[深入09] 深浅拷贝
[深入10] Debounce Throttle
[深入11] 前端路由
[深入12] 前端模块化
[深入13] 观察者模式 发布订阅模式 双向数据绑定
[深入14] canvas
[深入15] webSocket
[深入16] webpack
[深入17] http 和 https
[深入18] CSS-interview
[深入19] 手写Promise
[深入20] 手写函数
[部署01] Nginx
[部署02] Docker 部署vue项目
[部署03] gitlab-CI
[源码-webpack01-前置知识] AST抽象语法树
[源码-webpack02-前置知识] Tapable
[源码-webpack03] 手写webpack - compiler简单编译流程
[源码] Redux React-Redux01
[源码] axios
[源码] vuex
前置知识
1
valueOf 和 toString
---
对象
- valueOf 返回对象自身
- toString 返回 - 类型字符串
- 所以: Object.prototype.toString.call() 可以用来判断 数据类型
// -
// {}.toString -----------------------------> '[object Object]'
// Object.prototype.toString.call([]) ------> '[object Array]'
// -
// String({name: 'woow_wu7'}) // 参数是对象,返回类型字符串 -----------------> '[object Object]'
// String([1,2]) // 参数是数组,返回数组的字符串形式,-------------------------> '1,2'
// Number([]) -> valueOf()/[] -> toString/'' -> Number('') --------------> 0
// Number({}) -> valueOf()/{} -> toString/'[object Object]' -------------> Number('[object Object]') -> NaN
// '5' + {} // "5[object Object]" ======> 先将对象转成原始值 ======> {} => toString => 返回类型字符串 '[object Object]'
// '5' + [] // "5" =====================> 先将数组转成原始值 ======> [] => toString => 返回数组的字符串形式 '' => '5' + ''
数组
- valueOf 返回数组本身
- toString 返回 - 数组的字符串形式
// -
// [1, 2, 3].toString() --------------------> "1,2,3"
// [].toString() ---------------------------> ""
// -
// String({name: 'woow_wu7'}) // 参数是对象,返回类型字符串 -----------------> '[object Object]'
// String([1,2]) // 参数是数组,返回数组的字符串形式,-------------------------> '1,2'
// Number([]) -> valueOf()/[] -> toString/'' -> Number('') --------------> 0
// Number({}) -> valueOf()/{} -> toString/'[object Object]' -------------> Number('[object Object]') -> NaN
// '5' + {} // "5[object Object]" ======> 先将对象转成原始值 ======> {} => toString => 返回类型字符串 '[object Object]'
// '5' + [] // "5" =====================> 先将数组转成原始值 ======> [] => toString => 返回数组的字符串形式 '' => '5' + ''
将其他类型转成number类型
Number("1") ------------------------ 1
+ "1" ------------------------------ 1
parseInt("1", 10) ------------------ 1
parseInt("1", 16) ------------------ 1
强制转换
- Number,String,Boolean
- js是动态类型的语言,变量没有类型限制,可以随意赋予任意值
- 虽然变量的数据类型不确定,但各种(运算符)对变量的(数据类型)是有限制的
Number()强制转换
- 参数:两种情况,参数是原始类型的值,参数是对象
- 结果:将任意的数据类型转换成数值,数值 或者 NaN
- Number的转换要比parseInt严格,只要一个字符不能转换成数值,整个字符串就会被转换成NaN
- Null => 0
- undefined => NaN
Number参数:原始类型的值
Number() 参数是原始类型的值
1. 为0的情况
Number(false)
Number('')
Number(Null)
2. 为NaN的情况
Number(undefined)
Number('123abc') // 不能转成数值的字符串
Number('324abc') // NaN
2021/09/30 补充
Number([1,2]) // NaN ---> valueOf()是原数组 ---> toString()是数组的字符串形式 ---> Number('1,2') ---> NaN
+[1,2] === Number([1,2]) 两者相等
// 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可以自定义
案例:
Number({});
// {}.valueOf() -> {} -> {}.toString() -> '[object Object]' -> Number('[object Object]') -> NaN
// - 对象的valueOf() 返回对象本身
// - 对象的toString() 返回对象的类型字符串 '[object Object]'
// - Number('[object Object]') -> NaN
Number([]);
// [].valueOf() -> [] -> [].toString() -> '' -> Number('') -> 0
// - 数组的valueOf() 返回数组本身
// - 数组的toString() 返回数组的字符串形式
// - Number('') -> 0
String()强制转换
- 将任意类型的值转换成字符串
- 参数:原始类型的值 或 对象
- 结果:字符串
String()强制类型转换
1. 参数:原始类型的值
String(123) // "123"
String('abc') // "abc"
String(true) // "true"
String(undefined) // "undefined"
String(null) // "null"
2. 参数:对象
- 参数是对象,返回类型字符串
- 参数是数组,返回数组的字符串形式
String({name: 'woow_wu7'}) // 参数是对象,返回类型字符串 ==> '[object Object]'
String([1,2]) // 参数是数组,返回数组的字符串形式,==> '1,2'
3. 具体的转换规则
1. 调用对象的 toStirng 方法
- 如果返回原始类型的值,则使用String()方法转换
- 如果返回的是对象,继续以下步骤
2. 调用对象的 valueOf 方法
- 如果返回原始类型的值,则使用String()方法转换
- 如果返回对象,继续以下步骤
3. 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"
自动转化为数值
- 除了 + 有可能将运算子转换成字符串,其他运算符都会把运算子转换成数值
- 一元运算符也会把运算子转成数值
'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
运算符
加法运算符
- 重载(overload): 加法运算符存在 相加 和 连接,运算子的不同,导致不同的语法行为。
- 除了加法运算符,其他的运算符都不存在重载,将运算子都转换成数值,再进行数学运算
- 如果运算子是对象,必须先将对象转成原始类型的值,然后再相加
1 + true // 2
1 + 'a' // "1a" ------------------- 数值和字符串新加,+存在重载,所以 1 被转成字符串 '1' => '1a'
(2) 重载导致运算结果的不同
'3' + 4 + 5 // "345"
3 + 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
相等运算符 ==
- 相等运算符,用来比较
相同类型的数据时,与严格相等运算符等价 - 相同类型的数据:== 和 === 等价
- 不同类型的数据:== 会先进行类型转化,再使用 === 比较
- 原始类型的数据:转成数值,再比较
- 对象类型的数据:先将对象转成原始类型的值,再比较
- null和undefined:相互比较true,和任意其他类型比较false
- 缺点:存在隐式转化,容易出错
原始类型的值:先转换成数值,再进行比较
1 == true // true
// 等同于 1 === Number(true)
'true' == true // false
// 都转换成数值
// 等同于 Number('true') === Number(true)
// 等同于 NaN === 1
'1' == true // true
// 等同于 Number('1') === Number(true)
// 等同于 1 === 1
false == '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
0 == null // false
0 == 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
优先级
- 最高优先级:属性访问拥有最高的优先级
.() - 最低优先级:赋值运算符 = 拥有最低的优先级
- 操作符中,一元运算符拥有最高优先级
结合性
- 优先级相同时,如 乘和除,优先级相同时,考虑结合性
- 结合性分类:左结合 和 右结合
- 右结合:一元操作符,三元操作符,赋值操作符是右结合,其他所有的操作符都是左结合
- 左结合:其他都是左结合
运算顺序
- 从左向右运算
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
2021/09/30 复习更新如下
++a 和 a++
let a = 1let b = ++a先将a+1,再整体赋值 ---> b=2, a=2let b = a++先整体赋值,再a+1 ---> b=1, a=2
一元+
- 将任何值转化为 (
数值),与Number()的作用相同
Number([1,2]) // NaN ---> valueOf()是原数组 ---> toString()是数组的字符串形式 ---> Number('1,2') ---> NaN
+[1,2] === Number([1,2]) 两者相等
指数运算符 **
- 指数运算符是指完成
指数运算- 前一个运算子是 (
底数) - 后一个运算值是 (
指数) - 2 ** 4 // 16
- 前一个运算子是 (
案列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. ''
案列3
- 2022/09/08 更新
{} + '1' --------- 1
答案: 1
解析:
1. 因为表达式以 {} 开头,{} 不会被当作对象,而是被当作 ( 代码块 )
2. +'1' 会被转成 ( number ) 类型
3. +'1' -> 1
--
对比
'1' + {} ---------- '1[object Object]'