4.数据类型中的一点细节知识;5.数据类型转换规则和练习题;
/*
* 数据类型解读
* @1 NaN / Infinity / isNaN / Object.is ...
* @2 symbol & 对象属性类型
* @3 bigint
*
* 数据类型转换
* @1 把其它数据类型转换为number
* + Number([val])
* + 一般用于浏览器的隐式转换中
* + 规则:
* @1 把字符串转换为数字:空字符串变为0,如果出现任何一个非有效数字字符,结果都是NaN
* @2 把布尔转换为数字:true->1 false->0
* @3 null->0 undefined->NaN
* @4 Symbol无法转换为数字,会报错:Uncaught TypeError: Cannot convert a Symbol value to a number
* @5 BigInt去除“n”(超过安全数字的,会按照科学计数法处理)
* @6 把对象转换为数字:
* + 先调用对象的 Symbol.toPrimitive 这个方法,如果不存在这个方法
* + 再调用对象的 valueOf 获取原始值,如果获取的值不是原始值
* + 再调用对象的 toString 把其变为字符串
* + 最后再把字符串基于Number方法转换为数字
*
* + parseInt([val],[radix])
* + parseFloat([val])
* + 一般用于手动转换
* + 规则:[val]值必须是一个字符串,如果不是则先转换为字符串;然后从字符串左侧第一个字符开始找,把找到的有效数字字符最后转换为数字「一个都没找到就是NaN」;遇到一个非有效数字字符,不论后面是否还有有效数字字符,都不再查找了;parseFloat可以多识别一个小数点;
*
* + 场景:数学运算中「除了“+”还有字符串拼接的效果」、isNaN([val])、“==”比较的时候有可能也要转换为数字...
*
*
* @2 把其它类型转换为string
* + “+”代表的字符串拼接
* + 有两边,一边是字符串
* + 有两边,一边是对象
* + 只出现在左边
* + ...
* + Object.prototype.toString
*
* @3 把其它类型转换为布尔
* + 除了“0/NaN/空字符串/null/undefined”五个值是false,其余都是true
*
* @4 “==”比较时候的相互转换规则
* + “==”相等,两边数据类型不同,需要先转为相同类型,然后再进行比较
* @1 对象==字符串 对象转换为字符串「Symbol.toPrimitive -> valueOf -> toString」
* @2 null==undefined -> true null/undefined和其他任何值都不相等
* null===undefined -> false
* @3 对象==对象 比较的是堆内存地址,地址相同则相等
* @4 NaN!==NaN
* @5 除了以上情况,只要两边类型不一致,剩下的都是转换为数字,然后再进行比较的
* + “===”绝对相等,如果两边类型不同,则直接是false,不会转换数据类型「推荐」
*/
// obj[Symbol.toPrimitive] = function (hint) {
// // hint: number / string / default 浏览器自己调用这个方法,会默认传递的实参值
// // ...
// };
//=================
/*
数字类型 number
整数、浮点数(小数)、正数、负数、零
NaN:not a number,不是一个有效数字,但是它率属于number类型
+ typeof NaN -> "number"
+ 出现场景:经常出现在,把其它类型值转换为数字的时候,如果无法转换为有效数字,结果就是NaN
+ NaN!==NaN NaN和任何值(包含自己本身),都不相等
Infinity 无穷大的值
isNaN([val]):检测[val]是否“不是个有效数字”,如果真不是,返回true,如果是有效数字,则返回false;如果[val]不是数字类型的,浏览器首先会将其隐式转换为number类型,然后再进行检测;
Object.is(NaN,NaN) -> true ES6中提供的办法,不兼容IE浏览器(EDGE不应该算IE)
*/
// let n = ? ;
// if (n === NaN) {
// // 条件永远无法成立
// console.log(`n不是有效数字`);
// }
// let n = ? ;
// if (isNaN(n)) {
// console.log(`n不是有效数字`);
// }
/*
Symbol 唯一值类型
Symbol() 创造一个唯一值
Symbol('xxx') 创造一个唯一值,只不过设置了标记
new Symbol() Uncaught TypeError: Symbol is not a constructor 不允许被new执行
----
用途1:给对象设置一个唯一的属性「对象的成员只能是 string & symbol 类型的值,Map允许属性名是不同类型的{包含对象}」
用途2:它是很多内置机制的实现方式
Symbol.toPrimitive
Symbol.hasInstance
Symbol.toStringTag
...
*/
// console.log(Symbol('AA') === Symbol('AA')); //false 创造了两个唯一值
// let sy = Symbol('AA'),
// ys = sy;
// console.log(ys === sy); //true 只创建了一个唯一值
// let key = Symbol('KEY');
// let obj = {
// // 属性名:“name” “age” “0” “1” Symbol() Symbol('KEY') “[object Object]”
// name: 'zhufeng',
// age: 12,
// 0: 100,
// 1: 200,
// [Symbol()]: 300,
// [key]: 400,
// // 把对象转换为字符串,去充当它的属性名
// [{
// name: 'xxx'
// }]: 500
// };
// console.log(obj[Symbol()]); //undefined 用新创建的唯一值去获取,肯定获取不到
// console.log(obj[key]); //400
// console.log(obj[0]); //100 -> obj[“0”]
/*
BigInt 大数
JS中的最大/最小安全数字:Number.MAX_SAFE_INTEGER / Number.MIN_SAFE_INTEGER / Math.pow(2,53)-1
-> 9007199254740991 -9007199254740991 16位
-> 超过这个范围的值进行数组运算,结果是不准确的
场景:服务器端存储的ID是一个很大的值「数据库我们可以基于longInt处理」,现在我们把这个值返回给客户端,客户端获取值之后,需要进行运算处理,如果超过安全数字,导致结果是不准确的!!
---
new BigInt() Uncaught TypeError: BigInt is not a constructor
BigInt("90071992547409919007199254740991") -> 90071992547409919007199254740991n
一个数字后面加“n”就是BigInt
---
计算完成的超长结果,基于toString转换为字符串「去掉n了」,把这个再传递给服务器即可
*/
//==================
/* let result = 100 + true + 21.2 + null + undefined + "Tencent" + [] + null + 9 + false;
console.log(result); */
//=========================
/* console.log([] == false); //true
// [] -> 0 false -> 0
console.log(![] == false); //true
// ![] -> false
// false == false */
/*
“==”比较:数据类型转换的机制,需要把a转换为数字
因为把对象转换为数字,我么可以做的事很多 Symbol.toPrimitive -> valueOf -> toString -> Number
*/
// var a = {
// i: 0,
// // 还可以重写 valueOf & toString
// [Symbol.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声明的变量是给GO{window}设置的一个属性
获取属性a的值:Object.defineProperty 进行数据劫持
*/
// var i = 0;
// Object.defineProperty(window, 'a', {
// get() {
// return ++i;
// }
// });
// if (a == 1 && a == 2 && a == 3) {
// console.log('OK');
// }
//=========================
/* let arr = [27.2, 0, '0013', '14px', 123];
arr = arr.map(parseInt);
/!*
parseInt(27.2,0)
parseInt('27.2',10) -> '27' -> 把'27'看做10进制,转换为10进制 =>27
parseInt(0,1) =>NaN
parseInt('0013',2)
parseInt('0013',2) -> '001' -> 把'001'看做2进制,转换为10进制 =>1
0*2^2 + 0*2^1 + 1*2^0
parseInt('14px',3)
parseInt('14px',3) -> '1' -> 把'1'看做3进制,转换为10进制 =>1
1*3^0
parseInt(123,4)
parseInt('123',4) -> '123' -> 把'123'看做4进制,转换为10进制 =>27
1*4^2 + 2*4^1 + 3*4^0
parseInt传递的第二个值是一个radix进制
+ radix不写或者写0,默认是10进制「如果第一个传递的字符串是以“0x”开始的,那么默认是16进制」
+ radix取值范围:2~36,不在这个范围内,处理的结果都是NaN
+ 在传递的字符串中,从左到右,找到符合radix进制的值{遇到不符合的则结束查找},把找到的值,看做radix进制,最后转换为10进制
+ 把其它进制的值转换为10进制:“按权展开求和”
*!/
console.log(arr); */
arr = arr.map(function (item, index) {
return item + '@';
});
'12.21' 看做3进制,转换为10进制
1*3^1 2*3^0 2*3^-1 1*3^-2 3^-1 1/3 3^-2 1/9
console.log([] == false); //true
// [] -> 0 false -> 0
console.log(![] == false); //true
// ![] -> false
// false == false
JS中的值,在计算机底层都是按照64位的2进制值来进行存储的
JS中我们平时写的数字 浏览器都认为是10进制的
浏览器有一个操作:把我们自己写的10进制值 交给计算机的时候,会转换为2进制