前端面试
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<br>
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<br>
箭头函数不能作为generator函数
12、map和object的区别
键的类型
map可以是任意值
对象的键只能是string或者symbol
获取键值对的个数
map->size
object -> Object.keys().length
迭代
Map 是 iterable 的,所以可以直接被迭代,可用for...of遍历
Object不是 iterable,不可以被迭代,不能用for...of遍历
对象是无序的,map是有序的
13、类数组对象<br>
定义
拥有和数组相似的结构和属性,比如都有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有什么相同点和不同点<br>
相同点
都是JS开发较为常用的模块化规范,二者都把js文件视为模块,可以把一个模块中导出的<br>内容导入到当前模块中。
不同点
1.CommonJS 模块是运行时加载,ESM模块是编译时输出接口。
2.CommonJS 模块的require()是同步加载模块,ESM的import命令是异步加载
3.CommonJS是对模块的浅拷贝,ESM是对模块的引入,即ESM只存只读,不能改变其值,具体点就是指针指向不能变,类似const 。
4.import的接口是read-only(只读状态),不能修改其变量值。 即不能修改其变量的指针指向,但可以改变变量内部指针指向。可以对commonJS重新赋值(改变指针指向),但是对ESM赋值会编译报错。
17、for-in和for-of的区别<br>
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方法<br>
手写深拷贝函数<br>
21、原型和原型链
定义
原型
原型链
如何获取对象的原型
旧方法
对象.__proto__
新方法
Object.getPrototypeof()
构造函数
构造函数和对象之间的关系
构造函数中的this
prototype
一切皆对象
利用原型链实现继承
语法糖class的应用
22、Event Loop事件执行机制
JS是一门单线程的语言,同一时间只能做一件事,为了提高效率,将任务分成同步任务和异步任务
同步任务
定义
不影响执行顺序的代码,即为同步任务
同步任务执行在主线程上,在es6之后被称之为宏任务
存储主线程上同步代码的空间,称之为调用栈
异步任务
定义
影响执行顺序的代码,即称为异步任务<br>
使用
异步任务一般都是通过回调函数来执行的,其一般运行在web api(宿主环境中),当<br>异步任务执行完毕之后,会把回调函数放到任务队列中,当调用栈空了之后就会执行回调<br>函数
常见的异步任务
普通事件
资源加载
定时器
数据请求
......
event loop
当同步任务执行完毕,调用栈空掉之后,就会询问任务队列,是否有完成的异步任务回调函数<br>放在任务队列中,如果有,则执行,没有则继续询问和等待,这个不断询问的过程就是event loop
23、宏任务和微任务
es6之后,因为promise的出现,任务在同步任务和异步任务基础上出现了宏任务和微任务的区别
宏任务
同步任务
定时器
Promise回调函数中的同步代码
微任务
then
执行顺序
先同步、再异步
先宏任务、再清空一次微任务队列,再执行宏任务
24、关于promise的理解
一种异步编程的解决方案,本身是一个对象。该对象利用状态的改变来执行不同的回调函数从而解决传统js中回调地狱的问题<br>
三种状态
pending
fulfilled
rejected
状态切换
默认是pending 状态,一旦通过resolve()或者reject()函数修改了状态,那么<br>整个promise的状态将无法再次改变
方法
then()方法
其中可以传入两个回调函数,第一个回调函数会于promise状态变为fulfilled时执行,第二个<br>回调函数会于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()方法多次使用导致出现<br>链式操作的问题,也就是为了优化then方法而提出。async是异步简写,await是等待,所以async/await的<br>本质就是声明一个异步函数,等待异步方法调用完成。
async函数的返回值是一个promise对象,如果在函数中设置一个返回值,那么async会把其包装到Promise.resove()函数中,在<br>函数的外层可以通过.then方法取到返回值
有await的async函数,会暂时阻碍await下面所有代码的执行,在async函数中并且在await前面的代码(以及await紧跟着的那个异步函数也会正常运行)会正常运行,待await等待到他后面异步函数的结果之后,再执行await下面的代码。注意:await在没有等待到它后面的异步函数的结果时只是阻碍async函数中且在await下面的代码的执行,async函数中且在await前面、await后面紧跟着的那个异步任务的代码,以及async函数之后的代码不会受到影响,会正常运行<br>
0 条评论
下一页