一、2023javaScript面试题精选
1.js的数据类型
数据类型分为两种:基本数据类型与引用数据类型。基本数据类型有:number、string、boolean、null、undefined。引用数据类型有:array、function等(除了基本数据类型都是引用数据类型)
基本数据类型的主要特点是赋值方式是传值,并且值存在栈中。
引用数据类型的主要特点是赋值方式是传址,并且值存在堆中。
2.双等和三等的区别
双等主要是值类型进行比较,三等是值类型与数据类型进行双层比较。
简单来说就是三等因为传递的是地址,因此我们需要先对比数据类型,再看地址内部存储的数据是否相等。而双等仅仅是看值是否相等,值相等即可无需比较类型。
3.js中布尔值为false的六种情况
- undefined(未定义找不到值时出现)、
- null(代表空值)
- NaN(无法计算时候出现表示非数值,typeof(NaN)是number类型)
- false(布尔值的false,注意:‘false’的布尔值为true(''这是字符串))
- 0(数字)
- ‘’或者""(单双引号,注意中间有空格是true)
因此我举个例子:true+true=2
4.let const var 区别
var:存在变量提升,可以先去声明再去使用,一个变量可多次声明,后面的声明会覆盖前面的声明
const:const声明一个只读的变量,声明后,值就不能改变(引用类型地址不变即可值可改变)
let:不存在变量提升,let声明变量前,该变量不能使用
5.普通函数和箭头函数的区别
写法不同。箭头函数更加专注于结果写法由于()=>{}构成,写法简洁
this指向不同。箭头函数中 this 的指向不同:在普通函数中,this 总是指向调用它的对象,如果用作构造函数,它指向创建的对象实例。箭头函数中没有this,箭头函数的this指向取决于外层作用域中的this,外层作用域或函数的this指向谁,箭头函数中的this便指向谁。
6.数组有哪些方法
大家可以看看这一篇文章:http://t.csdn.cn/v6Zqu
数组的增删改查操作:
push()、unshift、shift()、pop()、splice()、join()、reverse()
数组的遍历操作:
map()、filter()、some()、every()、findindex()、reduce()
7.map()对比forEach()
1.map有返回值,可以开辟新空间,return出来一个length和原数组一致的数组,即便数组元素是undefined或者是null。
2.forEach默认无返回值,返回结果为undefined,可以通过在函数体内部使用索引修改数组元素。
3.map的处理速度比forEach快,而且返回一个新的数组,方便链式调用其他数组新方法
8.for in 对比 for of区别
简单来说就是它们两者都可以用于遍历,不过for in遍历的是数组的索引(index),而for of遍历的是数组元素值(item)
9.扁平化数组代码实现
①使用isArray()(检测是否是数组)配合concat()(合并数组)实现
②使用reduce配合isArrayy于concat遍历实现
③利用展开运算符的妙用
该三种方法的是来源于http://t.csdn.cn/s3CxR,博主:从人到猿
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> // isArray判断是不是数组 const a = [1, [2, [3, [4, 5]]]]; // const flatten = (arr) => { // let result = []; // for (let i = 0; i < arr.length; i++) { // if (Array.isArray(arr[i])) { // result = result.concat(flatten(arr[i])); // } else { // result.push(arr[i]); // } // } // return result; // }; // console.log(flatten(a)); // concat连接两个数组 // var sedan = ["S60", "S90"]; // var SUV = ["XC40", "XC60", "XC90"]; // var Volvo = sedan.concat(SUV);//['S60', 'S90', 'XC40', 'XC60', 'XC90'] // console.log(Volvo) // const flatten = (arr) => { // return arr.reduce((prev,next)=>{ // return prev.concat(Array.isArray(next)?flatten(next):next) // },[]); // }; // console.log(flatten(a)); console.log(...a,'a'); //展开运算符配合concat const flatten = (arr) => { while(arr.some(item=>Array.isArray(item))){ arr = [].concat(...arr); } return arr; }; console.log(flatten(a)); </script> </body> </html>
10.数组去重的方法
该三种方法的是来源于http://t.csdn.cn/F3jkN,博主:经海路大白狗
1.利用新旧数组遍历对比法
arr=[1,5,1,3,5,4,3,9,8] let newArr = []; /* indexOf用于查找数组元素第一次出现的位置,没找到则返回值为-1,参数有两个,第一个为元素项目,参数二(可选)需要查找的位置,负数从-1往前面加 */ for (let i=0;i<arr.length;i++) { if (newArr.indexOf(arr[i]) === -1) { newArr.push(arr[i]); } } console.log(newArr);//[1, 5, 3, 4, 9, 8]
2.利用新语法 new Set()
arr=[1,5,1,3,5,4,3,9,8] let mySet = new Set(arr); // 非重复的类数组 console.log(mySet,'mySet');//{{1, 5, 3, 4, 9,8} // let newArr = Array.from(mySet); // set转数组 let newArr = [...mySet]; // 或者是这种解构方法 console.log(newArr);//[1, 5, 3, 4, 9, 8]
3.filter与indexOf结合
/* 这个过滤就很巧妙,利用索引与每一项出现的首次位置(indexOf作用)进行对比, 当符合条件的时候返回出去 */ arr=[1,5,1,3,5,4,3,9,8] var newArr = arr.filter((item, index) => { return arr.indexOf(item) === index; }) console.log(newArr);//[1, 5, 3, 4, 9, 8]
4.includes()的妙用
arr=[1,5,1,3,5,4,3,9,8] let newArr = []; for (let i=0;i<arr.length;i++) { if (!newArr.includes(arr[i])) { newArr.push(arr[i]); } } console.log(newArr);//[1, 5, 3, 4, 9, 8]
5.利用对象属性来进行判断
arr=[1,5,1,3,5,4,3,9,8] let obj = {}; // 对象的key值是唯一的 let newArr = []; for (let i=0;i<arr.length;i++) { if (!obj[arr[i]]) { obj[arr[i]] = arr[i]; } } console.log(obj)//{1: 1, 3: 3, 4: 4, 5: 5, 8: 8, 9: 9}
11.防抖和节流
本知识点来源:http://t.csdn.cn/dwVOq,博主:留着鼻涕敲代码
防抖:多次触发只执行最后一次
应用场景:search搜索时,用户在不断输入值时,用防抖来节约请求资源
节流:规定时间内 只触发一次
应用场景:
1.鼠标不断点击触发,mousedown(单位时间内只触发一次)
2.监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断
12.事件循环机制
事件循环理论先执行同步任务,再去执行我们的异步任务(先执行微任务再执行宏任务)。
异步任务进一步划分分为:
宏任务:script标签、setTimeout()、setInterval
微任务:Promise.then、nextTick
13.原型与原型链
原型是我们创建函数的时候,系统帮我们自动生成的一个对象。 主要作用是解决构造函数内部方法内存资源浪费问题。在开发中我们一般把实例对象一些通用的方法放入原型中,在 vue 里面有时候也会给 vue 的原型添加一些公共类方法来实现所有的组件中可以共享成员。像一些常见的$router和$store 都是挂载到 vue 的原型上的。
原型链是 js 对象一种查找机制,遵循就近原则。当我们访问一个对象中的成员的时候,会优先访问自己的,如果自己没有就访问原型的,如果原型也没有就会访问原型的原型,直到原型链的终点 null. 如果还没有,此时属性就会获取 undefined,方法就会报错 xxx is not a function。一般原型链主要是用来实现面向对象继承的。
14.localStorage、sessionStorage、cookie区别
共同点:都是保存在浏览器端
区别:l
①ocalStorage、sessionStorage不会自动把数据发送给服务器仅在本地存储
②cookie数据有路径(path)概念,可以固定存储到某个路径下
③cookie每次http请求都会携带,因此cookie只适合存储小数据,最大为4K左右,其他两者为5M
④有效期不同:cookie与localStorage都在过期前有效,但是sessionStorage在关闭的时候失效
⑤localStorage、cookie在同源窗口下共享数据,sessionStorage不在不同窗口下共享
15.判断数据类型的方式以及区别 (typeof instanceof 他们两者的区别)
1.typeof:一般判断基本数据类型
2.instanceof :一般判断引用类型数据,主要的作用就是判断一个实例是否属于某种类型,或者判断一个实例是否有它的原型。
16.null typeof为什么是一个object
因为在javaScript中,不同的对象都是使用二进制存储的,如果二进制前三位都是0的话,系统会判断为是Object类型,而null的二进制全是0,自然也就判断为Object
17.事件冒泡与事件捕获原理
事件捕获:触及的事件从文档根节点(Document 对象)流向目标节点,途中会经过目标节点的各个节点,并在这些节点上触发捕获事件,直至到达事件的目标节点。是由外到内层
事件冒泡:与事件捕获相反,事件会从目标节点流向文档根节点,途中会经过目标节点的各个父级节点,并在这些节点上触发捕获事件,直至到达文档的根节点。由内到外
18.父div和子div都绑定了click事件,点击子div触发事件,这个事件的回调顺序
该原理同上,默认是事件冒泡,先触发子元素再往它的上级触发
19.阻止冒泡的方式及作用
使用 e.stopPropagation()来阻止事件冒泡。作用当然是阻止我们触发它上级的事件啦
20.事件委托的理解
js事件代理是把事件处理任务添加到上一级的元素中,这样就避免了把事件添加到多个子集元素上,底层原理是利用了事件冒泡机制
优点:
- 减少注册时间,节约内存
- 在table上代理所有td的click事件
- 在ul上代理所有的click事件
- 简化dom节点更新,相应事件的更新
- 不需要在新添加的li上绑定click事件
- 当删除某个li的时候不需要移除绑定在上面的click事件
缺点:
- 对于不冒泡的事件不给予支持
- 层级太多肯能会被中间的某层阻止掉
- 理论上会导致浏览器会频繁的调用处理函数,虽然可能不需要处理
21.call、apply、bind的区别
本知识点来源:http://t.csdn.cn/3UPti,博主:dream_reason
共同点:
- 都是用来改变函数的this对象的指向的
- 第一个参数都是this要指向的对象
- 都可以参加后续参数传参
不同点:
- bind是返回对应函数,便于稍后调用;apply、call则是立即调用
- apply和call功能一样,只是传入的参数列表形式不同,call 需要把参数按顺序传递进去,而 apply 则是把参数放在数组、伪数组里。
22.js闭包
一个作用域可以访问另外一个函数内部的局部变量,或者说一个函数(子函数)访问另一个函数(父函数)中的变量。此时就有闭包产生,那么这个变量所在的函数我们就称之为闭包函数。
优缺点:闭包的主要作用是延伸了变量的作用范围,因为闭包函数中的局部变量不会等着闭包函数执行完成就销毁,因为还有别的函数需要调用它,只有等这所有的函数都调用完了它才会被销毁。
如何解决:用完之后手动释放。
23.内存泄漏怎么理解
内存泄漏指的是我们用动态存储分配的函数来开辟空间,但是在使用完了没有释放,结果就一直占据该内存单元,直到程序结束。简而言之就是用完了还没回收这就是内存泄漏。
24.哪些操作会造成内存泄露
我们的setTimeout第一个参数是字符串而不是函数的时候
闭包、控制台日志、循环(在两个对象彼此引用且彼此保留的时候就会产生循环)
一个对象的引用数量为0,或者唯一作用就是循环引用(开辟空间没有用上)