高频前端面试题汇总js篇【上】
一、数据类型
1.js有那些数据类型,他们的区别?
js共有八种数据类型,分别为undefined、Null、Boolean、Number、String、Object、Symbol、BigInt.
其中symbol和bigInt是es6中新增的数据类型:
symbol代表创建后独一无二且不可变的数据类型,他主要是为了解决可能出现的全局变量冲突的问题
bigInt是一个数字类型的数据,他可以表示任意精度格式的整数,使用bingInt可以安全的储存和操作大整数,即使这个数已经超出了Number能够Number能够表示的安全整数范围。
这些数据可以分为原始数据类型和引用数据类型:
栈:原始数据类型(undefined、Null、boolean、Number、string)
堆:引用数据类型(对象、数组和函数)
两种数据类型的区别在于储存位置的不同:
原始数据类型直接储存在栈中的简单数据段,占据空间小、大小固定,
引用数据类型储存在堆中的对象,占据空间大、大小不固定。如果储存在栈中,将会影响程序运行的性能,引用数据类型在栈中存储了指针,实体存在堆中
堆栈的概念存在于数据结构和操作系统内存中,在数据结构中:
在数据结构中,堆中的数据的存取方式为先进后出。
堆是一个优先队列,是按优先级来进行排序的,优先级可以按照大小来规定。
在操作系统中,内存被分为栈区和堆区:
栈区内存由编译器自动分配释放,存放函数的参数值,局部变量的值等,其操作方式类似于数据结构中的栈。
堆区内存一般由开发者分配释放,若开发者不释放,程序结束时可能由垃圾回收机制回收。
2.数据类型检测的方式由那些
2.1 typeof,注意tupeof数组\对象和null的结果都是Object'
2.2 instanceof可以正确判断对象的类型,其内部运行机制时判断在其原型链中能否找到该类型的原型
2.3 constructor有两个作用,一时判断数据的类型,二是对象实例通过constrcutor对象访问它的构造函数。需要注意,如果创建一个对象来改变他的原型,constructor就不能用来判断数据类型了
2.4Object.prototypr.toString.call(),使用Object对象的原型方法toString来判断数据类型
3.判断数组的方式有那些
通过Object.prototype.toStrign.cal(obj);
通过原型链做判断:obj.__proto__===Array.prototype
通过es6的Array.isArray()做判断
通过instanceof做判断
通过Array.prototype.isPrototypeOf(Obj)
4.null和undefined区别
首先undefined和null都是基本数据类型,这两个基本数据类型分别都只有一个值,就是undefined和null.undefined代表的含义是未定义,null代表的含义是空对象。一般变量声明了但是还没有定义的时候会返回undefined,null主要用于赋值给一些可能会返回对象的变量作为初始值
5.typeof null的结果是什么,为什么?
typeof null的结果是object.
在javaScript第一个版本中,所有都存在32位的单元中,每个单元包含一个小的类型标签(1-3;bits)以及当前要储存值的真实数据。类型标签储存在每一个单元的低位中,共有五种数据类型:
000: object - 当前存储的数据指向一个对象。 1: int - 当前存储的数据是一个 31 位的有符号整数。 010: double - 当前存储的数据指向一个双精度的浮点数。 100: string - 当前存储的数据指向一个字符串。 110: boolean - 当前存储的数据是布尔值。
有两个特殊的数据类型:
undefined的值是(-2)30(一个超出整数范围的数字)
null的值是机器码null指针(null指针的值全是0)
那也就是说null的类型标签也是000,和Object的标签一样,所以会呗判定为Object.
6.instanceof操作符的实现原理及实现
instanceof运算符用于判断构造函数的prototype属性是否出现在对象的原型链中的任何位置。
function myInstanceof(left,right){ //获取对象原型 let proto=Object.getPrototypeOf(left) //获取构造函数的prototype对象 let prototype=right.prototype; //判断构造函数的prototype对象 while (true) { if (!proto) return false; if (proto === prototype) return true; // 如果没有找到,就继续从其原型上找,Object.getPrototypeOf方法用来获取指定对象的原型 proto = Object.getPrototypeOf(proto); } }
7.为什么0.1+0.2!==0.3,如何让他相等
在开发过程中遇到类似这样的问题:
let n1 = 0.1, n2 = 0.2 console.log(n1 + n2) // 0.30000000000000004 //这里得不到不是想要的结果,要相等于0.3,就要把他进行转换: (n1 + n2).toFixed(2) // 注意,toFixed为四舍五入
为什么会出现这样的结果?
计算机时通过二进制的方式储存数据,所以计算机0.1+0.2的时候,实际上是计算的两个数的进制和。0.1的进制是0.00011001100...,这两个数的二进制都是无限循环的数,那js是如何处理这种无限循环的小数呢?
一般我们认为数字包括整数和小数,但是js中只有一种数字类型:numbel,他的实现遵循ie754标准,使用64位固定长度来表示,也就是标准的double双精度浮点数。在二进制科学表示法中,双精度浮点数的小数部分最多保留52位,再加上前面的1,其实就是还位有效数字,剩余的需要社区,遵循‘0舍1入’的原则。
根据这个原则,0.1和0.2的二进制数相加,再转化位十进制数就是:0.300004。
8.typeof NaN的结果是什么?
NaN是一个不是数字的数字,typeof NaN的结果是number,NaN是一个特殊值,他和自身不相等,唯一一个非自反的值
9.proxy可以实现什么功能?
再vue3.0中通过proxy来替换原本的Objext.defineProperty来实现数据响应式。proxy是es6中新增的功能,他可以用来定义对象中的操作。
10.js脚本延时加载的方式有那些?
延时加载就是等页面加载完成之后再加载js文件,js延时加载有助于提高页面加载速度。一般有一下几种方式:
defer属性:给js脚本添加defer属性,这属性会让脚本加载于文档的解析同步解析,然后再文档解析完成后再执行这个脚本文件,这样的化就能让脚本加载于文档的解析同步解析,然后再文档解析完成后再执行这个脚本文件,这样的话就能使页面的渲染不被阻塞,多个设置defer属性的脚本按照标准来水最后是顺序执行的,但是再一些浏览器可能不是这样的
async属性:给js脚本添加async属性,这个属性回事脚本异步加载,不会阻塞页面的解析过程,但是当脚本加载完成后立即执行脚本,这个时候如果文档没有解析完成的话同样会阻塞。多个async属性的脚本的执行顺序是不可预测的,一般不会按照代码的顺序执行。
动态创建dom方式:动态创建dom标签的方式,可以堆文本的加载事件进行监听,当文档加载完成后再动态的拆功能键script标签来引入js脚本。
使用setTimeout延时方法:设置一个定时器来延时加载js脚本文件
让js最后加载:将js脚本方再文档的底部,来时js脚本尽可能的再最后执行加载
11.数组有那些原生的方法
数组和字符串转换的方法:toString()、tolocelString()、join()方法可以指定转换为字符串时的分隔符。
数组尾部操作的方法pop()和push,push方法可以传入多个参数。
数组首部操作的方法shift()和unshift()重排序的方法reverse()和sort方法可以传入一个函数来进行比较,传入前后两个值,如果返回值为正数,则交换两个数的参数。
数组的链接方法concat(),返回的时拼接好的数组,不影响原数组
数组截取的方法slice,用于截取数组中的一部分返回,不影响原数组。
数组插入方法splice(),用于截取数组中的一部分返回,不影响原数组。
数组插入方法splice(),影响原数组查找特定的索引的方法,indexOf()和lastIndexOf()迭代方法every()、some()、filtere()、map()和forEach()方法
数组归并方法reduce()和reduceRight()方法
12.为什么
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)