1. 原始值类型介绍
1.1 number数据类型
1.1.1 number数据类型的特点
1. 整型
2. 浮点
+ 浮点的精度问题(十进制转为二进制小数,大部分无法精确转换,整数不存在这个问题)
+ 0.1 + 0.2 ≠ 0.3
4. 特殊的数值NaN
+ NaN是number类型,是一个数值,表示非有效数字
+ NaN与任何数进行运算都是NaN
+ NaN与任何数都不相等,包括自己
5. 数值相关的运算符
+ - * / %
6. 相关函数
isNaN() (隐式转换)
+ 检测一个值是否为非有效数字,如果不是有效数字返回true,反之是有效数字返回false
+ 在使用isNaN进行检测的时候,首先会验证检测的值是否为数字类型,如果不是,先基于Number()这个方法,把值转换为数字类型,然后再检测
7. toFixed()
保留小数点后面N位(最后 的结果是一个字符串)
8. Number.MAX_SAFE_INTEGER
console.log(Number.MAX_SAFE_INTEGER);
//=>9007199254740991
最大安全数(JS能够有效识别的最大整数)
console.log(9007199254740992 == 9007199254740993); //=>true
应该是不一样的,但是超过了最大数值,JS无法精准计算
1.1.2 把其他类型转化为数字类型
- 把字符串转化为数字,只要字符串中包含任意一个非有效数字字符(第一个点除外)结果都是NaN,空字符串会变为数字零
console.log(Number('12.5'));//12.5
console.log(Number('12.5px'));//NaN
console.log(isNaN('12px'));// true
console.log(Number(12.5.5));//NaN
console.log(Number(''));//0
- 把布尔转换为数字:true转换为1 false转换为0
console.log(Number(true));//1
console.log(Number(false));//0
console.log(isNaN(false));//false
- null转化为0,undefined转化为NaN
- 不能把Symbol类型转换为数字,否则会报错 Uncaught TypeError: Cannot convert a Symbol value to a number
- BigInt去除“n”(超过安全数字的,会按照科学计数法处理)
- 把引用数据类型转化为数字
/*
+ 先调用对象的 Symbol.toPrimitive 这个方法,如果不存在这个方法
+ 再调用对象的 valueOf 获取原始值,如果获取的值不是原始值
+ 再调用对象的 toString 把其变为字符串
+ 最后再把字符串基于Number方法转换为数字
*/
console.log(Number({name:'10'}));//NaN
console.log(Number({}));//NaN
// {}/{xxx:'xxx'}.toString() =>'[object Object]'=>NaN
console.log(Number([]));//0
// [].toString() ->''
console.log(Number(12));//12
//[12].toString() -> '12'
console.log(Number([12,13]));//NaN
//[12,13].toString() -> '12,13'
[55].valueOf => [55]
console.log(Number(Symbol(10))); // 报错
console.log(Number(BigInt(10))); // 10
1.1.3 parseInt & parseFloat([val],[进制])
也是转化为数字的方法,先转换为字符串,是从左到右依次查找有效数字字符,直到非有效数字字符,停止查找(不管后面是否还有数字,都不在找了),把找到的有效数字字符串转换为数字,如果一个都没找到结果就是NaN (parseFloat比它多识别一个小数点)
let str = '12.5px';
console.log(Number(str));//NaN
console.log(parseInt(str));//12
console.log(parseFloat(str));//12.5
console.log(parseFloat('width:12.5px'));//NaN
console.log(parseInt(true));//NaN
1.1.4 深度剖析parseInt的处理规则
// 面试题
let arr = [10.18,0,10,25,23];
arr = arr.map(parseInt);
console.log(arr);//[10,NaN,2,2,11]
arr = arr.map((item,index)=>{
// 循环遍历数组中的某一项就会触发回调函数
// 每一次还会传递当前项和当前项的索引
});
- 把一个值转化为十进制
147(8进制) => 十进制
[位权值:每一位的权重,个位是0,十位是1...]
1*8^2 + 4*8^1 + 7*8^0
12.23(4进制) => 十进制
1*4^1 + 2*4^0 + 2*4^-1 + 3*4^-2
'0x629eb' (16进制) => 十进制
0-9 a-f(10-15)
6*16^4 + 2*16^3 + 9*16^2 + 14*16^1 + 11*16^0 = 403947
- parseInt([value],[radiv])处理规则
-> [radix]这个值是一个进制,不写或者写0默认都按照10处理(特殊情况:如果value是以0x开头,则默认值不是10而是16)
-> 进制有一个取值的范围:2-36之间,如果不在这之间,整个程序运行的结果一定是NaN
-> 把[value]看做[radix]进制,最后把[radix]进制转化为十进制
流程:
1. 可能会转字符串 toString
2. 对字符串进行整数解析
3. 返回整数或NaN
支持 + -
去掉开头的空格
1. 去掉符号
2. 对数字进行解析
parseInt radix默认值10进制
0x、0X开头都是16进制
0开头:有可能是8进制、10进制(ES5规范 10进制),都要写清楚radix
parseInt('10.18',0)
// 从字符串左侧第一个字符开始查找,找到符合[radix]进制的值(遇到一个不合法的,则停止查找),把找到的值变为数字,在按照把[radix]转化成为十进制的规则处理
'10' -> 10
parseInt('0',1) -> NaN (小于2或者大于36、未填写参数、字符串第一个字符不能被正常转换数字的情况)
parseInt('10',2) =>找符合01的
10 把它看做2进制,最后转化为10进制
1*2^1 + 0*2^0 = 2
parseInt('25',3) =>找符合012的 ,不符合要求停止查找
2 当做3进制转化为10进制
2*3^0 => 2
parseInt('23',4) =>找符合0123的
23 当做4进制转化为10进制
2*4^1 + 3*4^0 => 11
// 数字转换为相应进制的字符串数字 toString
(3).toString(2) -> 3作为10进制 -> 2进制(字符串)
var filterInt = function (value){
if(/^(\-|\+)?([0-9]+|Infinity)$/.test(value)){
return Number(value);
}
return NaN;
}
1.2 BigInt:管理超过安全数值的数字
ES6中提供了一个新的数据类型 BigInt:管理超过安全数值的数字
console.log(BigInt(9007199254740992)
BigInt(9007199254740993));
1.3 string 字符串类型
1.3.1 string 字符串类型的特点
String:所有用单引号、引号、反引号包起来的都是字符串
1.3.2 把其他类型转化为字符串String
/*
转化规则:
1. 拿字符串包起来
2. 对象转字符串
+ String(对象):按照 先找Symbol.toPrimitive -> 再看valueOf -> 最后toString 来处理
+ 对象.toString():直接转换为字符串
+ 特殊:Object.prototype.toString,是用来检测数据类型的
出现情况:
@1 String([val]) 或者 [val].toString()
@2 “+”除数学运算,还可能代表的字符串拼接
+ 有两边,一边是字符串,肯定是字符串拼接
+ 有两边,一边是对象,则可能是字符串拼接,还有可能是数学运算
+ 只出现在左边,例如:+"10" 这种方式就是把其它值转换为数字
+ ...
*/
let a = 12;
console.log(a.toString());//'12'
console.log((NaN).toString());//'NaN'
// null 和 undefined是进制直接toString的
(null).toString(); //报错
// 但是和undefined一样转换为字符串的结果就是'null'/'undefined'
String(null);//'null'
String(undefined);//'undefined'
String(Symbol());// 'Symbol()'
//普通对象.toString()的结果是 "[object Object]" =>?
=>Object.prototype.toString方法不是转换为字符串的,而是用来检测数据类型的
//四则运算法则中,除了加法之外,其余都是数学计算,只有加法可能存在字符串拼接(一旦遇到字符串,则不是数学运算,而是字符串拼接)
console.log('10'+10);//1010
console.log('10'-10);//0
console.log('10px' - 10);//NaN
//加号即使一边出现字符串或者对象,也不一定是字符串拼接:++i/i++/+i这种情况是数学运算
let n = '10';
//console.log(++n);//11
console.log(+n);//10
{} + 0
// 左边的{}认为是一个代码块,不参与运算
// 运算只处理的是+0 =>0
// function(){}+0
({}+0)
//参与到数学运算中 "[object Object]0"
0+{}
//这种情况是数学运算 "0[object Object]"
//基于alert/confirm/prompt/document.write...这些方法输出内容,都是把内容先转换为字符串,然后再输出的
//面试题
let a = 10+null+true+[]+undefined+'腾讯'+null+[]+10+false;
console.log(a);
/*
10+null = 10 +0 = 10
10 + true = 10+1=11
11+[] =11+''='11' 空数组变为数字,先要经历变为空字符串,遇到字符串,啥都别想了,直接变为字符串拼接
'11'+ undefined -> '11undefined'
...
'11undefined腾讯null10false'
*/
1.4 boolean
- 只有0、NaN、空字符串、null、undefined五个值转换为FALSE,其余都转换为TRUE(而且没有任何的特殊情况)
- boolean:数据类型 TRUE、FALSE
- boolean([val])
- !(先转换为布尔类型再取反)/ !!(转换为布尔类型)
- 条件判断(隐式)
console.log(Boolean(0));
console.log(Boolean(''));
console.log(Boolean(' '));
console.log(Boolean(null));
console.log(Boolean(undefined));
console.log(Boolean([]));
console.log(Boolean([12]));
//!:取反(先转为布尔,然后取反)
//!!:取反再取反,只相当于转换为布尔<=> Boolean
console.log(!1);//false
console.log(!!1);//true
//如果条件只是一个值,不是==/===/!=/>= 等这些比较,是要把这个值先转换为布尔类型,然后验证真假
if(1){//真
console.log('Ha')
}
if('3px'+3){//真
//'3px3'
console.log('he');
}
if('3px'-3){//假
//NaN-3=NaN
console.log('hei')
}
1.5 Symbol类型
执行Symbol()产生一个唯一值
console.log(Symbol('AA') === Symbol('AA'));//false
let symb = Symbol('BB');
console.log(symb === symb); //true
+ 给对象设置唯一的属性
+ 在vuex/redux中做行为派发的时候,统一管理派发的行为标识,标识的值可以是唯一值
+ ....
dir(Symbol) =>
Symbol.hasInstance
Symbol.toPrimitive
Symbol.toStringTag
Symbol.iterator
Symbol.isConcatSpreadable
Symbol.match
...
1.6 null 和 undefined
null 表示没有,即该处不应该有值:
1) 在我们不确定一个变量具体数据类型的时候,我们可以先赋值为null,后面可以再给具体的值。。
2) 作为对象原型链的终点。
3) 获取 DOM 获取不到的时候。
undefined 表示缺少值,即此处应该有值,但没有定义:
1)定义了变量没有给值,显示 undefined。
2)定义了形参,没有传实参,显示 undefined。
3)对象属性名不存在时,显示 undefined。
4)函数没有写返回值,即没有写return,拿到的是 undefined。
5)写了return,但没有赋值,拿到的是 undefined。
2. 引用数据类型
2.1 语法
let person = {
name:'易烊千玺',
age:49,
height:'185cm',
weight:'80kg',
1:100
};
删除属性
+ 真删除:把属性彻底干掉
delete person[1];
+ 假删除:属性还在,值为空
person.weight = null;
console.log(person);
设置属性名属性值
+ 属性名不能重复,如果属性名已经存在,不属于新增属于修改属性值
person.GF = '圆圆';
person.name = '胡歌';
console.log(person['GF']);//圆圆
console.log(person['name']);
2.2 在==比较的过程中,数据转换的规则:
【类型一样的几个特殊点】
{} == {}: false 对象比较的是堆内存的地址
[] == []: false
NaN==NaN: false
【类型不一样的转换规则】
1. null == undefined:true,但是换成===结果是FALSE(因为类型不一致),剩下null/undefined和其他任何数据类型值都不相等
2. 字符串==对象 要把对象转换为字符串
3. 剩下如果 == 两边数据类型不一致,都是需要转换为数字再进行比较的
Object.is([val1],[val2]) 检测两个值是否相等「ES6新增的」
+ 核心用的是“===”
+ 特殊:Object.is(NaN,NaN) => true
console.log([] == false);//true
// 对象==布尔 都转换为数字(隐式转换)
// 对象装换为数字:先toString转换为字符串(应该是现给予valueOf获得原始值,没有原始值再去toString),再转化为数字的
// [] ->'' ->0
// false ->0 true ->1
console.log(![] == false);//true
// ![] 把数组转换为布尔类型然后取反 除了5个值以外的都为true
// false == false -> true
2.3 把对象转换为数字或者字符串的规则
把一个对象数据类型的值,转换为数字/字符串
+ 首先查找对象的 Symbol.toPrimitive 属性
+ 如果不存在这个属性,紧接着调用对象 valueOf 方法获取原始值(基本类型值)
+ 如果获取不到原始值,则再调用 toString & Number 转换为字符串或者数字
场景:
+ 在“+加号”运算中,如果左右两边出现字符串或者是部分对象值则不是属性运算,会变为字符串拼接
+ alert([value]) 把值隐式转换为字符串输出
+ 模板字符串实现的是字符串拼接,对象会转换为字符串
+ 其余的数学运算“例如:- / * % ...”,会把对象转换为数字
+ “==”比较的时候,也会把对象转换为字符串或者数字
let obj = {
name: 'AA'
};
let arr = [10, 20, 30];
let time = new Date();
let num = new Number(10);
//console.log(10 + obj); //"10[object Object]"
//console.log(10 + num); // num.valueOf()->10 20
obj[Symbol.toPrimitive] = function (hint) {
// console.log(hint); //=>default number string
return 100;
};
console.log(`${obj}`); //100
- 面试题
//1
let result = 100 + true + 21.2 + null + undefined + "Tencent" + [] + null + 9 + false;
console.log(result); //=>"NaNTencentnull9false"
//2
console.log({} + 10); //'[object Object]10'
let n = {} + 10;
console.log(n); ////'[object Object]10'
// {}出现在左侧,把最左边的{}当做一个代码块,是不参与到运算的
{} + 0 ? alert('ok') : alert('no');
// {}出现在右侧,肯定参与运算
0 + {} ? alert('ok') : alert('no');
// +value / ++value / value++都是转化为数字后再进行处理
let str = '10';
str = +str; // 不论str是什么值,最后也是转化为数字
console.log(str); // 10
let obj = { n: 100 },
arr = [100],
time = new Date(),
num = new Number(100);
console.log(Number(num));
/*
num[Symbol.toPrimitive] -> undefined
num.valueOf() -> 100
把“非标准特殊对象”(原始值对应的对象类型实例),转换为原始值,此过程我们称之为“拆箱”
把“原始值”转换为“非标准特殊对象”,我们则称之为“装箱”
*/
灵魂拷问:原始值10,是否为Number类的实例?
// 从严格意义来讲,并不是其实例「实例都应该是对象类型」
let num = 10;
console.log(num.toFixed(2)); //'10.00'
// 内部:发现num是原始值,首先默认会为其“装箱” => new Number(num) 变为Number类的实例
// 实例去调用toFixed即可
console.log(new Number(10) + 20); //30
// 内部:把实例对象默认进行“拆箱” => 转化为原始值
// 实例[Symbol.toPrimitive] -> undefined
// 实例.valueOf() -> 10
// 10+20
const time = new Date()
console.log(Number(time)); //1661503113742
console.log(String(time)); //'Fri Aug 26 2022 16:39:38 GMT+0800 (中国标准时间)'
// 解析
time[Symbol.toPrimitive] -> 函数
time[Symbol.toPrimitive](hint:'number'/'string'/'default')
Number(time) -> hint:'number'
String(time) -> hint:'string'
xxx+time -> hint:'default'
time[Symbol.toPrimitive]('number') => 1661503113742
let arr = [1,2];
console.log(Number(arr));//NaN
let arr = [100];
//解析
arr[Symbol.toPrimitive] -> undefined 没有这个属性
arr.valueOf() -> [100] 非原始值
arr.toString() -> '100'
Number('100') -> 100
const obj = {n:100}
console.log(Number(obj));
//解析
obj[Symbol.toPrimitive] -> undefined 没有这个属性
obj.valueOf() -> {n:100} 非原始值
obj.toString() -> '[object Object]'
Number('[object Object]') -> NaN