🥳博 主:初映CY的前说(前端领域)
🌞个人信条:想要变成得到,中间还有做到!
🤘本文核心:博主收集的关于javaScript的面试题
目录
一、2023javaScript面试题精选
1.js的数据类型
2.双等和三等的区别
3.js中布尔值为false的六种情况
4.let const var 区别
5.普通函数和箭头函数的区别
6.数组有哪些方法
7.map()对比forEach()
8.for in 对比 for of区别
9.扁平化数组代码实现
10.数组去重的方法
11.防抖和节流
12.事件循环机制
13.原型与原型链
14.localStorage、sessionStorage、cookie区别
15.判断数据类型的方式以及区别 (typeof instanceof 他们两者的区别)
16.null typeof为什么是一个object
17.事件冒泡与事件捕获原理
18.父div和子div都绑定了click事件,点击子div触发事件,这个事件的回调顺序
19.阻止冒泡的方式及作用
20.事件委托的理解
21.call、apply、bind的区别
22.js闭包
23.内存泄漏怎么理解
24.哪些操作会造成内存泄露
一、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.数组去重的方法
该三种方法的是来源于https://blog.csdn.net/xingyu_qie,博主:经海路大白狗
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,或者唯一作用就是循环引用(开辟空间没有用上)