1、把其他数据类转换为Number
Number([val])
-
一般用于浏览器的隐式转换中
-
数学运算
-
isNaN检测
-
==比较
...
-
-
规则:
-
字符串转为数字:空字符串变为0,如果出现任何非有效数字字符,结果都是NaN
-
把布尔转换为数字:true -> 1 false -> 0
-
[] -> 0
-
null -> 0 undefined -> NaN
-
Symbol无法转换为数字,会报错:Uncaught TypeError: Cannot convert a Symbol value to a number
-
BigInt去除“n”(超过安全数字,会按照科学计数法处理)
-
把对象转为数字:
-
1.先调用对象的 Symbol.toPrimitive 这个方法,如果不存在这个方法(Symbol.toPrimitive获取对象的原始值,相比valueOf算是新的获取原始值的方法)
/* xxx[Symbol.toPrimitive](hint){ // hint:'number'/'string'/'default' // + number:获取当前对象的数学类型的原始值 // + string:获取当前对象的字符串类型的原始值 // + default:根据操作获取数字或者字符串类型的原始值 } */ let obj = { name: 'zhufeng', age: 20, [Symbol.toPrimitive](hint) { let result; switch (hint) { case 'number': result = 0; break; case 'string': result = JSON.stringify(obj);; break; default: result = 1; } return result; } } console.log(Number(obj)); // hint:"number" console.log(String(obj)); // hint:"string" console.log(10 + obj); // hint:"default" console.log(10 - obj); // hint:"number" */ -
2.再调用对象的 valueOf 获取原始值,如果获取的值不是原始值
-
3.再调用 toString 把其变为字符串
-
4.最后再把字符串基于Number方法转为数字
let obj = {} //undefined Number(obj) //NaN obj[Symbol.toPrimitive] //undefined obj.valueOf() //{} obj.toString() //"[object Object]" Number("[object Object]") //NaN
let num = new Number(10) //undefined Number(num) //10 num[Symbol.toPrimitive] //undefined num.valueOf() //10 Number(num) //10 String(num) //"10"
let time = new Date(); /undefined Number(time) //1627283629808 time[Symbol.toPrimitive] //ƒ [Symbol.toPrimitive]() { [native code] } time[Symbol.toPrimitive]('number') //1627283629808 String(time) //"Mon Jul 26 2021 15:13:49 GMT+0800 (中国标准时间)" time[Symbol.toPrimitive]('string') //"Mon Jul 26 2021 15:13:49 GMT+0800 (中国标准时间)" -
-
parseInt([val],[radix]) parseFloat([val])
-
一般用于手动转换
-
规则:
-
[val] 值必须是一个字符串,如果不是则先转为字符串;然后从字符串左侧第一个字符开始找,把所有的有效数字字符最后都转为数字[一个都没找到就是NaN];遇到一个非有效数字字符,不论后面是否还有有效数字字符,都不再查找了;parseFloat可以多识别一个小数点;
-
parseInt([val {string}],[radix])
在parseInt本身处理规则的基础上,还可以设置[radix]进制:在[val]字符串中,从左到右查找符合[radix]进制的内容(遇到一个不符合的则结束查找),把找到的内容当做[radix]进制值最后转换为10进制
@1 把其它进制转换为10进制 按权展开求和
'10011'(2进制) -> 10进制
12^4 + 02^3 + 02^2 + 12^1 + 1*2^0 => 19
@2 [radix]不设置(或者设置为零),则默认值是10;但是如果字符串是以‘0x’开头的,则默认值是16;
@3 [radix]有取值范围:2~36,不在范围内,最后处理的结果都是NaN
---
在浏览器中有一个特殊情况:如果数字(不是字符串)是以0开始的,浏览器会认为这应该是8进制的值,它会把8进制默认转化为10进制再处理
012 -> 10
08^2+18^1+2*8^0 => 10
parseInt('10px',10);
在字符串中找到所有符合十进制的内容 -> '10'
把找到的 '10' 看作十进制转换为十进制 => 10
parseInt('1030px',2);
在字符串中找到所有符合二进制的内容 -> '10'
把找到的 '10 ' 看作二进制转换为十进制(如何把其它机制的值转换为十进制 “按权展开求和”)
个位数权重0 十位数权重1 百位数权重2 ...
1x2^1 + 0x2^0 => 2
-
-
练习题:
let arr = [27.2, 0, '0013', '14px', 123];
arr = arr.map(parseInt);
解析:数组中有多少项,回调函数就被执行多少次
arr.map(function(item, index) {
//item:当前迭代这一项
//index:对应的索引
//函数执行的返回的结果是啥,把数组中对应项替成,原始数组不变,以新数组形式返回
return 'xxx'
})
arr[0] = parseInt(27.2,0);
parseInt('27.2',10);
找到符合十进制的内容 -> '27'
把'27'看作十进制转为十进制 => 27
arr[1] = parseInt(0,1);
parseInt('0',1); => NaN 因为一进值不在进制范围之内,会返回NaN
arr[2] = parseInt('0013',2);
parseInt('0013',2);
找到符合二进制的内容 -> '001'
把'001'看做二进制转为十进制
0x2^2 +0x2^1 + 1x2^0 => 1
arr[3] = parseInt('14px',3);
parseInt('14px',3);
找到符合三进制的内容 -> '1'
把'1'看做三进制转为十进制
1x3^0 => 1
arr[4] = parseInt(123,4);
parseInt('123',4);
找到符合四进制的内容 -> '123'
把'123'看做四进制转为十进制
1x4^2 + 2x4^1 + 3x4^0 => 27
2、把其他数据类型转为String
转化规则:
- 拿字符串包起来
- 特殊:Object.prototype.toString
出现情况:
-
String([val]) 或者 [val].toString
-
字符串拼接「“+” 在JS中除了数学运算也有字符串拼接的意思」
- 有两边,一边是字符串,一定是字符串拼接 代码:[value]+'' => 把[value]转换为字符串
- 有两边,一边是对象:可能会是字符串拼接,因为其要把对象转换为数字,转换过程中如果遇到转换为字符串,则直接变为字符串拼接;如果遇不到还是数学运算;
- 只有一边 +[value]:一定是把[value]转换为数字的
-
parseInt([value]) 如果[value]不是字符串也要先变为字符串再处理
-
alert/confirm/prompt/document.write 都会把内容变为字符串,然后再输出
-
...
把对象obj转为字符串
- String(obj):Symbol.toPrimitive -> valueOf -> toString 浏览器默认隐式转换是使用String(obj)
- obj.toString():直接调用这个方法转字符串,不会在执行以上的规则
‘+’有两边,其中一边如果是对象obj,则会
- 1、调用obj[Symbol.toPrimitive]('default')
- 2、没有这个属性,则在此调用valueOf
- 3、valueOf 获取的不是原始值,则继续toString,此时获取的结果是字符串,”+“就变为字符串拼接
console.log(10 + [10]);
- 没有Symbol.toPrimitive -> valueOf获取的也不是原始值 -> 调用toString ”10“ => "1010"
consoleo.log(10 + {})
- 没有Symbol.toPrimitive -> valueOf获取的也不是原始值 -> 调用toString "[object Object]" => "10[object Object]"
console.log(10 + new Date());
- 调用日期的Symbol.toPrimitive('default') 默认转为字符串 => "10Sun Jul 25 2021 11:28:37 GMT+0800 (中国标准时间)"
console.log(10 + new Number(10));
new Number(10) -> Number {10} 是一个对象
没有Symbol.toPrimitive -> valueOf 10 => 20
console.log(10 + new String('10'));
- 没有Symbol.toPrimitive -> valueOf "10" => "1010"
“+”有两边,其中一边是字符串,妥妥的字符串拼接
“+”有两边,剩下的情况一般都是数学运算了
特殊:{} + 10 => 10
10 + {} => "10[object Object]"
let a = {} + 10
a =>"[object Object]10"
({} + 10)=> "[object Object]10"
练习题:
let result = 100 + true + 21.2 + null + undefined + "Tencent" + [] + null + 9 + false;
console.log(result);
122.2 + undefined = NaN;//undefined -> NaN 数字加NaN都等于NaN
NaN + "Tencent" = "NaNTencent"
在往后都是字符串拼接
console.log(result); // "NaNTencentnull9false"
注意:右边为对象或字符串一般都是拼接
3、把其他数字类型转为Boolean
转换规则:
- 只有 “0/NaN/空字符串/null/undefined” 五个值是false,其余都是true「哪怕是把对象转换为布尔,也不再调用Symbol.toPrimitive那套机制了,直接看是否是五个中的一个即可」
- 1 -> true 0 -> false
出现情况
-
Boolean([val]) 或者 !/!!
-
条件判断
...
4、‘==’比较时候的相互转换规则
“==”相等,两边数据类型不同,需要先转为相同类型,然后再进行比较
-
对象==字符串 对象转字符串「Symbol.toPrimitive -> valueOf -> toString」
-
null==undefined -> true null/undefined和其他任何值都不相等
null===undefined -> false
-
对象==对象 比较的是堆内存地址,地址相同则相等
-
NaN!==NaN
-
除了以上情况,只要两边类型不一致,剩下的都是转换为数字,然后再进行比较的
“===”绝对相等,如果两边类型不同,则直接是false,不会转换数据类型「推荐」
练习题:
console.log([] == false);
都转换为数字 Number([]) => 0 Number(false) => 0
TRUE
console.log(![] == false);
需要先算 ![] => false; []不在转Boolean的五个值内,所以为true
false == false => TRUE
综合练习题
var a = ?;
if (a == 1 && a == 2 && a == 3) {
console.log('OK');
}
解决方案一:
利用 == 比较的时候,会把对象转换为数字 Number(a)
在转换的过程中会执行一下步骤:
Symbol.toPrimitive
valueOf
toString
把字符串变为数字
可重写其中的一个方法,让它的返回值变成我们自定义的值
let a = { i: 0 }; a[Symbol.toPrimitive] = function toPrimitive() { // this -> a return ++this.i; }; if (a == 1 && a == 2 && a == 3) { console.log('OK'); }解决方案二:
var a = [1, 2, 3]; a.toString = a.shift; if (a == 1 && a == 2 && a == 3) { console.log('OK'); }解决方案三:
在全局上下文中,基于 var/function 声明的变量,并不是给VO(G)设置的全局变量「基于let/const声明的变量才是」,而是给GO(window)全局对象设置的属性 var a=? ==> window.a=?,我们基于数据劫持完成对应的操作
var i = 0; Object.defineProperty( window , 'a' , { get(){ return ++i; } } if (a == 1 && a == 2 && a == 3) { console.log('OK'); }//Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
备注:应当直接在
Object构造器对象上调用此方法,而不是在任意一个Object类型的实例上调用。
练习题
isNaN(parseInt(new Date())) + Number([1]) + typeof undefined; //NaNundefined true
//parseInt(new Date()) -> NaN
//parseInt("字符串");
// let time = new Date()
// time[Symbol.toPrimitive] -> ƒ [Symbol.toPrimitive]() { [native code] }
// time[Symbol.toPrimitive]('string')
// "Wed Jul 28 2021 09:23:56 GMT+0800 (中国标准时间)"
//NaNundefined
!(!"Number(undefined)"); //true
//Number(undefined) -> NaN/Number(null) -> NaN
parseFloat("1.6px") + parseInt("1.2px") + typeof parseInt(null); // 2.6number
//parseInt(null) -> parseInt("null") => NaN
Boolean(Number("")) + !isNaN(Number(null)) + Boolean("parseInt([])") + typeof !(null);
//空字符串变为0 --0
//parseInt([]) -> NaN =>"NaN"
//Boolean("parseInt([])") => true
//false + true + true + "boolean" -> "1boolean"
isNaN(Number(!!Number(parseInt("0.8")))); //false
!typeof parseFloat("0"); //false
Number(""); //0
16 + {}; //"16[object Object]"
{} + 16; //16特殊
var n = 6;
console.log((n++) + n-- + 5 + --n + --n);
console.log(n); //获取的n跟之前的计算有关系
//+/-号在前,先赋值后计算; +/-号在后,先计算后赋值
//6 + 7 + 5 + 5 + 4
//4
var str = 'abc123';
var num = parseInt(str);
if (num == NaN) {
alert(NaN);
} else if (num == 123) {
alert(123);
} else if (typeof num == 'number') {
alert('number');
} else {
alert('str');
}
//alert('number');NaN是属于数字类型
if (isNaN(NaN) == "") {
console.log("珠峰")
} else {
console.log("培训")
}
//isNaN(NaN); true -> 1
//"" -> 0
//培训