前端面试
2023-07-06 07:58:09 0 举报
AI智能生成
前端面试整理
作者其他创作
大纲/内容
JavaScript
1、JS中数据类型有哪些,有什么区别
分类
基础数据类型
Number
数字(正数、负数、整数、小数)
NaN
无穷大
Infinity
-Infinity
Boolean
true
false
String
''
""
``
Null
null
Undefined
undefined
Symbol
独一无二的值
Symbol()
引用数据类型
Array
Function
Object
Map
Set
Date
RegExp
区别
基础类型,数据不可变,使用频率高 -- 栈
引用类型,数据可变,占据大小不固定 -- 堆
引用类型会把内存地址存储到栈中
2、数据类型的检测方式有哪些
typeof
instanceof
Object.prototype.toString.call()
3、判断数组的方式有哪些
instanceof
Object.prototype.toString.call()
Object.getPrototypeOf([]) === Array.prototype
Array.isArray
Array.prototype.isPrototypeOf([])
4、null和undefined区别
表示的意义
null表示空、undefined表示未定义
场景
undefined表示变量声明但是没有赋值
null表示赋值为空
类型
null和undefined各自代表一个类型,分别是Null和Undefined
5、Object.is()和 ==、===的区别
Object.is()的效果大多数情况下和===相等,但是区别在于+0、-0或者NaN这些特殊值的处理上
==是值相等,比较的是二者的值,但是如果类型不同,则==会让数据发生自动强制类型转换,转换完毕之后再进行值的比较
6、如何判断一个对象是否是空对象
JSON.stringify(obj) === '{}'
Object.keys(obj).length === 0
7、es6中有哪些新增
新的变量声明
let
const
解构赋值
模板字符串
新的语法糖
对象的简化写法
箭头函数
class类的操作
函数参数
默认值
rest参数
扩展运算符
数据类型
set
map
symbol
bigint
....
promise
generator
async/await
8、let、const、var区别
作用域不同
var
全局
函数作用域
let、const
块级作用域
变量提升
window对象挂载
暂时性死区
重复声明
初始值
9、const对象属性是否可以修改
const特点
内存地址上锁
10、new操作符的执行原理
创建一个空对象(相当于内存中开辟一块新的空间)
设置原型,将对象的原型设置为函数的prototype属性
让函数的this指向这个对象,执行构造函数的代码相当于为这个对象添加属性
返回新对象
11、箭头函数和普通函数的区别
简化写法
箭头函数没有this
call、bind、apply无法改变this指向
箭头函数不能作为构造函数
箭头函数没有arguments
箭头函数没有prototype
箭头函数不能作为generator函数
12、map和object的区别
键的类型
map可以是任意值
对象的键只能是string或者symbol
获取键值对的个数
map->size
object -> Object.keys().length
迭代
Map 是 iterable 的,所以可以直接被迭代,可用for...of遍历
Object不是 iterable,不可以被迭代,不能用for...of遍历
对象是无序的,map是有序的
13、类数组对象
定义
拥有和数组相似的结构和属性,比如都有length属性,都有索引值等等,但是原型却不是Array对象
常见的类数组对象
arguments
HTMLCollection
NodeList
...
转换成数组的方式
通过 call 调用数组的 slice 方法来实现转换
Array.prototype.slice.call(arrayLike);
通过 call 调用数组的 splice 方法来实现转换
Array.prototype.splice.call(arrayLike, 0);
通过 apply 调用数组的 concat 方法来实现转换
Array.prototype.concat.apply([], arrayLike);
通过 Array.from 方法来实现转换
Array.from(arrayLike);
展开运算符
14、数组中有哪些常用方法
数组和字符串的转换方法
toString()、toLocalString()、join()
数组尾部操作的方法
pop() 和 push(),push 方法可以传入多个参数
数组首部操作的方法
shift() 和 unshift() unshift方法可以传递多个参数,表示在数组开头增加
重排序的方法
reverse() 和 sort(),sort() 方法可以传入一个函数来进行比较,传入前后两个值,如果返回值为正数,则交换两个参数的位置
数组连接的方法
concat() ,返回的是拼接好的数组,不影响原数组
数组截取(浅拷贝)办法
slice(begin【end】),用于截取数组中的一部分返回,不影响原数组。
数组插入/删除/新增方法
array.splice(start[, deleteCount[, item1[, item2[, ...]]]]),改变原数组
数组归并方法
reduce() 和 reduceRight() 方法
15、什么是DOM、什么是BOM
DOM
Document Object Mode,文档对象模型,里面包括了用来操作网页文档的一些对象和接口
BOM
Borwser Object Model,浏览器对象模型,包括了用来操作浏览器的对象和接口
16、ESM和CommonJS有什么相同点和不同点
相同点
都是JS开发较为常用的模块化规范,二者都把js文件视为模块,可以把一个模块中导出的
内容导入到当前模块中。
内容导入到当前模块中。
不同点
1.CommonJS 模块是运行时加载,ESM模块是编译时输出接口。
2.CommonJS 模块的require()是同步加载模块,ESM的import命令是异步加载
3.CommonJS是对模块的浅拷贝,ESM是对模块的引入,即ESM只存只读,不能改变其值,具体点就是指针指向不能变,类似const 。
4.import的接口是read-only(只读状态),不能修改其变量值。 即不能修改其变量的指针指向,但可以改变变量内部指针指向。可以对commonJS重新赋值(改变指针指向),但是对ESM赋值会编译报错。
17、for-in和for-of的区别
for… in 会遍历对象的整个原型链,性能非常差不推荐使用,而 for … of 只遍历当前对象不会遍历原型链
对于数组的遍历,for…in 会返回数组中所有可枚举的属性(包括原型链上可枚举的属性),for…of 只返回数组的下标对应的属性值
18、数组的遍历方法有哪些
for...of
不改变原数组
for...of遍历具有Iterator迭代器的对象的属性,返回的是数组的元素、对象的属性值,不能遍历普通的obj对象
forEach()
视情况是否改变原数组
没有返回值
filter()
不改变原数组
数组方法,不改变原数组,有返回值,返回一个符合筛选规则的新数组
every() 和 some()
不改变原数组
数组方法,some()只要有一个是true,便返回true;而every()只要有一个是false,便返回false.
map()
不改变原数组
数组方法,不改变原数组,有返回值,生成一个一一对应的新数组
find() 和 findIndex()
不改变原数组
数组方法,find()返回的是第一个符合条件的值;findIndex()返回的是第一个返回条件的值的索引值
reduce() 和 reduceRight()
不改变原数组
数组方法,reduce()对数组正序操作;reduceRight()对数组逆序操作
19、forEach方法和map方法有什么区别
forEach()方法会针对每一个元素执行提供的函数,对数据的操作会改变原数组,该方法没有返回值
map()方法不会改变原数组的值,有返回值,返回一个新数组,新数组中的值为原数组调用函数处理之后的值
20、如何实现深拷贝
JSON.stringify
JSON.parse(JSON.stringify(obj))是目前比较常用的深拷贝方法之一,它的原理就是利用JSON.stringify 将js对象序列化(JSON字符串),再使用JSON.parse来反序列化(还原)js对象。
这个方法可以简单粗暴的实现深拷贝,但是还存在问题,拷贝的对象中如果有函数,undefined,symbol,当使用过JSON.stringify()进行处理之后,都会消失。
函数库lodash的_.cloneDeep方法
手写深拷贝函数
21、原型和原型链
定义
原型
原型链
如何获取对象的原型
旧方法
对象.__proto__
新方法
Object.getPrototypeof()
构造函数
构造函数和对象之间的关系
构造函数中的this
prototype
一切皆对象
利用原型链实现继承
语法糖class的应用
22、Event Loop事件执行机制
JS是一门单线程的语言,同一时间只能做一件事,为了提高效率,将任务分成同步任务和异步任务
同步任务
定义
不影响执行顺序的代码,即为同步任务
同步任务执行在主线程上,在es6之后被称之为宏任务
存储主线程上同步代码的空间,称之为调用栈
异步任务
定义
影响执行顺序的代码,即称为异步任务
使用
异步任务一般都是通过回调函数来执行的,其一般运行在web api(宿主环境中),当
异步任务执行完毕之后,会把回调函数放到任务队列中,当调用栈空了之后就会执行回调
函数
异步任务执行完毕之后,会把回调函数放到任务队列中,当调用栈空了之后就会执行回调
函数
常见的异步任务
普通事件
资源加载
定时器
数据请求
......
event loop
当同步任务执行完毕,调用栈空掉之后,就会询问任务队列,是否有完成的异步任务回调函数
放在任务队列中,如果有,则执行,没有则继续询问和等待,这个不断询问的过程就是event loop
放在任务队列中,如果有,则执行,没有则继续询问和等待,这个不断询问的过程就是event loop
23、宏任务和微任务
es6之后,因为promise的出现,任务在同步任务和异步任务基础上出现了宏任务和微任务的区别
宏任务
同步任务
定时器
Promise回调函数中的同步代码
微任务
then
执行顺序
先同步、再异步
先宏任务、再清空一次微任务队列,再执行宏任务
24、关于promise的理解
一种异步编程的解决方案,本身是一个对象。该对象利用状态的改变来执行不同的回调函数从而解决传统js中回调地狱的问题
三种状态
pending
fulfilled
rejected
状态切换
默认是pending 状态,一旦通过resolve()或者reject()函数修改了状态,那么
整个promise的状态将无法再次改变
整个promise的状态将无法再次改变
方法
then()方法
其中可以传入两个回调函数,第一个回调函数会于promise状态变为fulfilled时执行,第二个
回调函数会于promise状态变为rejected时执行
回调函数会于promise状态变为rejected时执行
catch()方法
可以捕获代码错误以及reject时的错误信息
all()方法
同时检测多个promise,所有状态全部变为fulfilled/rejected时,,触发成功的回调函数
race()方法
在传入的多个 Promise 中,只要有一个 Promise 状态变为 fulfilled 或 rejected,就会返回一个新的 Promise 对象,并采用首个完成的 Promise 的结果(无论成功还是失败)
finally()方法
指定无论 Promise 状态如何最终都要执行的回调函数
25、Promise.all()和Promise.race()的区别
26、async/await
async/await 本质来说是generator的语法糖,它的出现是为了解决then()方法多次使用导致出现
链式操作的问题,也就是为了优化then方法而提出。async是异步简写,await是等待,所以async/await的
本质就是声明一个异步函数,等待异步方法调用完成。
链式操作的问题,也就是为了优化then方法而提出。async是异步简写,await是等待,所以async/await的
本质就是声明一个异步函数,等待异步方法调用完成。
async函数的返回值是一个promise对象,如果在函数中设置一个返回值,那么async会把其包装到Promise.resove()函数中,在
函数的外层可以通过.then方法取到返回值
函数的外层可以通过.then方法取到返回值
有await的async函数,会暂时阻碍await下面所有代码的执行,在async函数中并且在await前面的代码(以及await紧跟着的那个异步函数也会正常运行)会正常运行,待await等待到他后面异步函数的结果之后,再执行await下面的代码。注意:await在没有等待到它后面的异步函数的结果时只是阻碍async函数中且在await下面的代码的执行,async函数中且在await前面、await后面紧跟着的那个异步任务的代码,以及async函数之后的代码不会受到影响,会正常运行
0 条评论
下一页