JavaScript 数据类型总结及相关面试题

2022-10-30 12:25:23

JavaScript数据类型

  • 基本数据类型
  • number
    • NaN
    • Infinity
  • string
  • boolean
  • null
  • undefined
  • symbol
    • static Symbol
    • Symbol.prototype
  • bigint
  • 引用数据类型
  • object
    • 普通对象
    • 数组对象
    • 正则对象
    • 日期对象
    • Math数学函数对象
    • JSON对象
    • Set
    • Map
  • function
    • 普通函数
    • 箭头函数
    • 构造函数
    • 生成器函数
    • 匿名函数
    • 自调用函数

数据类型检测

  • typeof 检测数据类型的逻辑运算符
  • instanceof 检测是否为类的实例
  • constructor 检测构造函数
  • Object.prototype.toString.call 检测数据类型

typeof [value] 返回当前值的数据类型,返回的数据类型是字符串

  • 返回的结果都是字符串
  • 局限性:
    • typeof null => “object” 类型
    • typeof 不能细分对象类型(检测普通对象或数组对象等都是返回"object")
  • 原理:
    • 所有的数据类型值在计算机中都是按照“二进制”进行存储
    • null的二进制值是“000000”
    • 只要是对象都是以“000”开始的
    • typeof检测时是按照计算机存储的二进制值来检测的,所以检测null时也是返回“object”

把其它数据类型转换为数字的方法:

  • 强转换(基于底层机制转换) Number(value)
    • 一些隐式转换是基于Number完成的
      • isNaN(‘12px’) 先把其它类型值转换为数字再检测
      • 数学运算 “12px” - 13
      • 字符串 == 数字 两个等于号比较很多时候也是要把其它类型值转换为数字
  • 弱转换(基于额外的方法转换)parseInt(value)/parseFloat(value)

数据类型转换及面试题:

  • typeof
let a=typeoftypeoftypeof[12,23]
console.log(a)//"string"/* 步骤分析
 * typeof [12,23]  => "object"
 * typeof "object" => "string"
 * typeof "string" => "string"
*/
  • NaN 跟任何值都不相等,包括它自己,与任何值相加都是NaN
let res=parseFloat("left:200px");if(res===200){alert(200);}elseif(res===NaN){alert(NaN)}elseif(typeof res==="number"){alert("number")}else{alert("Invalid Number")}//结果:字符串number => 'number'
  • 类型转换规则
  • parseInt/parseFloat 处理的值是字符串,先从字符串左侧开始查找有效数字字符(遇到非有效数字字符则停止查找) 如果处理的值不是字 符串,需要先转换为字符串然后再开始在开始查找
  • parseInt([value],[radix])传2个参数的转换规则:
    • [radix]表示是一个进制,不写或者写0默认都是按照10进制处理,(特殊情况:如果value是以0x开头则默认是16进制)
    • 进制有一个取值范围:2-36之间,如果不在这个范围内,则转换结果一定是NaN
    • 把value看做是radix进制,最后把radix进制转换为10进制
  • Number 直接调用浏览器最底层的数据类型检测机制来完成
    + true 1 flase 0
    + null 0 undefined NaN
    + 字符串中必须保证都是有效数字才会转换为数字,否则都是NaN
  • == 两个等号比较时
    + 对象==字符串,对象转换为字符串
    + null == undefined 返回true (===返回false),但是和其它值都不相等
    + 0 == null 返回false null和undefined在进行等号比较时不进行数据类型转换
    + 其余两边不同都转换为数字
  • === 三个等号比较时:两边类型一致,值也一致才相等,类型不一样直接不对等,不会转换
  • 0 NaN null undefined “” 转换为布尔类型都是false,其余的都是true
  • 对象类型参与运算规则
  • 大括号与运算符结合:
    + 大括号在运算符前面并且没有小括号处理优先级,则不认为是数学运算,加了小括号后才会运算
    + 如果大括号出现在运算符后面则认为是数学运算
  • 普通对象toString()是调用Object.prototype.toString()用来检测数据类型的,返回’[object Object]’
  • 对象在做数学运算时的底层机制:
    • 先检测对象的Symbol.toPrimitive这个属性值,如果有则基于这个值运算,如果没有
    • 再检测对象的valueOf这个值【原始值:基本类型值】,如果有则基于这个值运算,如果没有
    • 再获取对象的toString方法,把其变为字符串,如果是‘+’处理,则看到字符串会变为字符串拼接
    • 如果最后想变为数字,则再把字符串转换为数字即可
let obj={[Symbol.toPrimitive]:function(hint){return10;},
	valueOf:function(){return20;},
	toString:function(){return30;}}

console.log(10+ obj);
parseInt('')// NaN 从最左侧查找没有找到有效数字所以返回NaNNumber('')// 0isNaN('')// false 先把''转换为数字(隐式 Number)=> isNaN(0) 所以返回falseparseInt(null)// NaN 先转换为字符串null parseInt('null')Number(null)// 0isNaN(null)// false isNaN(0)parseInt('12px')// 12Number('12px')// NaN 字符串中必须保证都是有效数字才会转换为数字,否则都是NaNisNaN('12px')// true isNaN(Number('12px')) => isNaN(NaN) => trueparseFloat('1.6px')+parseInt('1.2px')+typeofparseInt(null)// "2.6number"  1.6 + 1 + typeof NaN => 1.6 + 1 + 'number'isNaN(Number(!!Number(parseInt("0.8"))))// false isNaN(Number(!!Number(0))) => isNaN(Number(false)) => isNaN(0)typeof!parseInt(null)+!isNaN(null);// 'booleantrue' typeof true + !flase[]==true//false Number([]) == Number(true) 0 == 110+false+ undefined+[]+'Tencent'+null+true+{}// 'NanTencentnulltrue[object Object]'  10 + 0 + NaN + ''(对象转字符串) + 'Tencent' + 'null' + 'true' + {}.toString()('[object Object]')[]==false// true 都转换为数字,[]先转换为字符串''然后再用Number('')转换为数字0,false转为数字也是0![]==false// true 优先将![]转换为boolean值,[]转为布尔为true取反则为false{}+0// 0 这里会认为{}是代码块,没有进行运算,计算‘+0’({}+0)({})+0//[object Object]00+{}//0[object Object]let n='10', m=10;
console.log(n+10);//1010//console.log(+n);//10 如果+只有一边则把值转换为数字
console.log(++n);//11 也是转换为数字然后自身加1
console.log(+n);//11 因为上面已经加了1

console.log({}+m);//[object Object]10let res={}+ m;
console.log(res);//[object Object]10
console.log(m+{});//10[object Object]

console.log(m+newNumber(10));//20 new Number(10).valueOf()的原始值是10
var a={}, b='0',  c=0;
a[b]='hello';
a[c]='world';
console.log(a[b]);// world普通对象属性名只能是字符串,a[c] 也会变成a['0']
var a={}, b=Symbol('1'), c=Symbol('1');
a[b]='hello';
a[c]='world';
console.log(a[b]);// hello Symbol是唯一值, Symbol('1') === Symbol('1')返回false
var a={}, b={n:'1'}, c={m:'2'};
a[b]='hello';
a[c]='world';
console.log(a[b]);// world 对象不能作为属性名,转换为字符串变为[object Object]
var a={n:1};var b= a;
a.x= a={n:2};//可以拆分为: a.x = {n:2} a = {n:2}
console.log(a.x);// undefined a已被重新赋值变为{n:2}
console.log(b);// {n:1, x: {n:2}} b还是指向原来的堆内存地址,但是在第三步时堆内存中又增加了x:{n:2}
var x=[12,23];functionfn(y){
	y[0]=100;
	y=[100];
	y[1]=200;
	console.log(y);// [100, 200]}fn(x);
console.log(x);[100,23]// 首先开辟一块堆内存保存 12,23 让x指向该地址// 在函数中把堆内存中的第一个值12变成了100// 然后又新开辟了一块堆内存保存新值100 并让y指向该地址// 在新的堆内存中新加了一个值200// 所以x所指向的地址中值变为了100,23// y所指向的地址中值是100,200
var obj={
	name:'hello',
	fn:(function(name){
		console.log(name);})(obj.name);//这里会报错,因为先创建值在创建变量,此时变量obj还不存在}
let arr=[10.18,0,10,25,23];
arr= arr.map(parseInt);//这里会把value和index作为参数传递给回调函数parseInt
console.log(arr);//分析parseInt('10.18',0);//从字符串左侧第一个字符开始查找,找到符合[radix]进制的值(只要遇到不符合的则停止查找),把得到的值变为数字,再按照把[radix]转换为10进制的规则处理,结果为10parseInt('0',1);//1不在进制范围内直接返回NaNparseInt('10',2);//把10看做是二进制,最后再转为10进制。结果为:2parseInt('25',3);// 把值看作是3进制,三进制应该是0,1,2 所以得到3进制的值为2,然后再转换为10进制。结果:2parseInt('23',4);//把值看作是4进制,四进制应该是0,1,2,3 所以得到四进制的值为23,然后转换为10进制。结果:11
  • 其它进制转换为十进制的规则
  • 先将其它进制值的个十百千等拆分成单独的数
  • 然后由个位数乘以该进制的0次幂 + 十位数乘以该进制的1次幂 + 百位数乘以该进制的2次幂…以此类推
  • 最后相加得到的值就是十进制值,如上面代码中的4进制值23转为10进制就是:
    2x4^1 +
    3x4^0 = 8+3=11
  • 作者:一笑程序猴
  • 原文链接:https://blog.csdn.net/lixiaosenlin/article/details/108733718
    更新时间:2022-10-30 12:25:23