最后
喜欢的话别忘了关注、点赞哦~
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
用**Array.flat(Infinity)**实现扁平化。
16. Promise⭐⭐⭐
含义:异步编程的一种解决方案,它通过链式调用 then 、 catch 、finally方法来处理异步调用的结果。。
三种状态:pending(进行中)、resolved (已成功)和reject(已失败) (Promise对象的状态改变,只有两种可能:从pending变为resolve和从pending变为reject。)
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/\* 异步操作成功 \*/){
resolve(value);
} else {
reject(error);
}
});
resolve:将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved)。
reject:将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected)。
Promise 可以通过链式调用的方式,让多个异步请求形成一个顺序执行的队列。
then: Promise 实例添加状态改变时的回调函数。
可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。
catch : 用于指定发生错误时的回调函数。
finally: 不管 Promise 对象最后状态如何,都会执行的操作。
其他方法
Promise.all():将多个 Promise 实例,包装成一个新的 Promise 实例。
缺点: 无法取消Promise,一旦新建它就会立即执行,无法中途取消。如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
更多详情请看Promise 对象
17.promise 和 async/await 的区别 ⭐
Promise 和 async/await 都是用于处理异步任务的方式
相同点:
Promise 和 async/await 的目的都是处理异步任务。
Promise 和 async/await 都可以避免回调地狱。
不同点:
处理异步调用的结果方法:
Promise 通过链式调用 then 方法和 catch 方法来处理异步调用的结果。
而 async/await 通过 await 关键字和 try…catch 语句来处理异步调用的结果。
异步处理方式
Promise 是一种基于回调函数的异步处理方式。
async/await 是一种基于生成器函数的异步处理方式。
创建Promise方法
Promise 可以直接使用静态方法 Promise.resolve() 和 Promise.reject() 来创建 Promise 对象。
async/await 则需要借助于 Promise 对象创建。
是否可以阻塞
Promise 是非阻塞的。
async/await 是可以阻塞执行的(注意:这里说的阻塞是指异步等待结束后再继续执行后续代码,但不会阻塞线程)。
18.JS中new操作符有什么用?⭐⭐
- 创建临时对象,并将this指向临时对象
- 将构造函数的原型属性和方法挂载到新对象的__proto__(原型指针)上
- return 临时对象
19.JS获取HTML DOM元素的方法⭐⭐
- 通过ID获取(getElementById)
- 通过name属性(getElementsByName)
- 通过标签名(getElementsByTagName)
- 通过类名(getElementsByClassName)
- 获取html的方法(document.documentElement)
- 获取body的方法(document.body)
- 通过选择器获取一个元素(querySelector)
- 通过选择器获取一组元素(querySelectorAll)
用法以及防坑可看JS获取HTML DOM元素的方法
20.事件捕获和事件冒泡⭐⭐
- 事件捕获和事件冒泡主要解决了页面事件流的问题。页面的事件流经过了三个阶段,分别是事件捕获、目标阶段和事件冒泡阶段。
- 事件捕获是由外向内;而事件冒泡则是由内向外。
- event.stopPropagation() 可以阻止事件流的进一步传播。
- 采用事件代理的方式,能够节省内存消耗,对于动态改变子元素的时候,也非常有利,避免了很多麻烦的步骤,比如重新绑定事件。(把子元素的事件委托给父元素来处理)
21.虚拟dom⭐
定义:虚拟DOM就是普通的js对象。用来描述真实dom结构的js对象,因为它不是真实的dom,所以才叫做虚拟dom。
作用:虚拟dom可以很好地跟踪当前dom状态,因为它会根据当前数据生成一个描述当前dom结构的虚拟dom,然后数据发生变化时,有生成一个新的虚拟dom,而两个虚拟dom恰好保存了变化前后的状态。然后通过diff算法,计算出当前两个虚拟dom之间的差异,得出一个更好的替换方案。
22.数组操作方法会改变原数组⭐⭐
会改变:push(),pop(),shift(),unshift() ,splice(),sort(),reverse()。
不变:concat(),split(),slice()。
23.JS有几种方法判断变量的类型?⭐⭐⭐
- typeof
判断基本数据类型,
typeof(null) 'object' typeof(undefined) 'undefined' typeof([]) 'object' typeof({}) 'object'
typeof(0) 'number' typeof('0') 'string' typeof(true) 'boolean' typeof(Symbol()) 'symbol'
对于引用数据类型除了function返回’function‘,其余全部返回’object’。
可以返回类型 number、string、boolean、undefined、object、function、symbol。
2. instanceof
区分引用数据类型,检测方法是检测的类型在当前实例的原型链上,用其检测出来的结果都是true,不太适合用于简单数据类型的检测,检测过程繁琐且对于简单数据类型中的undefined, null, symbol检测不出来。
3. constructor
检测引用数据类型,检测方法是获取实例的构造函数判断和某个类是否相同,如果相同就说明该数据是符合那个数据类型的,这种方法不会把原型链上的其他类也加入进来,避免了原型链的干扰。
4. Object.prototype.toString.call()
适用于所有类型的判断检测,检测方法是Object.prototype.toString.call(数据) 返回的是该数据类型的字符串。(举例:字符串返回的是[object String])
instanceof的实现原理:验证当前类的原型prototype是否会出现在实例的原型链__proto__上,只要在它的原型链上,则结果都为true。因此,instanceof
在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype
,找到返回true,未找到返回false。
Object.prototype.toString.call原理:Object.prototype.toString 表示一个返回对象类型的字符串,call()方法可以改变this的指向,那么把Object.prototype.toString()方法指向不同的数据类型上面,返回不同的结果
24.如何判断一个对象是否存在?⭐
直接!XXX
这样会报错,因为没有定义
建议使用typeof运算符,判断XXX是否有定义。
25.undefined和null 区别⭐
undefined:一个变量已经声明但未被赋值,或者一个对象属性不存在
null: 一个变量或对象属性被明确地赋值为 null,表示该变量或属性的值为空。
undefined 表示缺少值,而 null 表示有一个值,但这个值是空的。
type检测 null为object, undefined为undefined
以下场景会出现undefined
- 声明了一个变量,但没有赋值
- 访问对象上不存在的属性
- 函数定义了形参,但没有传递实参
- 使用 void 对表达式求值
26.break 和 return 的区别⭐
作用对象不同
break 用于跳出当前的循环或者 switch 语句。
return 用于结束当前函数并返回一个值。
结束方式不同
break 只是提前结束当前的循环或者 switch 语句,然后继续执行后续代码。
return 则会直接结束函数的执行,并将一个指定的值返回给调用处。
使用场景不同
break 通常用于跳出不满足条件或者特定情况的循环结构,避免出现死循环。
return 主要用于结束函数执行,返回一个执行结果或者错误信息等。
三、计算机网络与其他知识篇
1.HTTP与HTTPS⭐
HTTP:客户端与服务器之间数据传输的格式规范,表示“超文本传输协议”。
HTTPS:在HTTP与TCP之间添加的安全协议层。
默认端口号:HTTP:80,HTTPS:443。
传输方式:http是明文传输,https则是具有安全性的ssl加密传输协议。
连接方式:http的是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
2.TCP与UDP的区别⭐
- TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接。
- TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
- 每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
- TCP首部开销20字节;UDP的首部开销小,只有8个字节。
- TCP提供可靠的服务。UDP适用于一次只传少量数据、对可靠要求不高的环境。
3.三次握手四次挥手⭐
原因:TCP是面向连接的,三次握手就是用来建立连接的,四次握手就是用来断开连接的。
关于三次握手先看草图(看图理解)
最开始客户端和服务端都处于关闭状态,客户端主动打开连接。
第一次握手:客户端向服务端发送SYN报文,并处于SYN_SENT状态。
第二次握手:服务端收到SYN后应答,并返回SYN+ACK报文,表示已收到,并处于SYN_RECEIVE状态。
第三次握手:客户端收到服务端报文后,再像服务端发送ACK包表示确认。此时双方进入ESTABLISHED状态。(这次报文可以携带数据)
为什么不是两次握手?
原因:是因为如果只有两次,在服务端收到SYN后,向客户端返回一个ACK确认就进入ESTABLISHED状态,万一这个请求中间遇到网络情况丢失而没有传给客户端,客户端一直是等待状态,后面服务端发送的信息客户端也接受不到了,所以要客户端再次确认。
关于四次挥手先看草图(看图理解)
最开始客户端和服务端都处于ESTABLISHED状态,客户端主动关闭连接。
第一次挥手:客户端准备关闭连接,向服务端发送一个FIN报文,进入FIN_WAIT1状态。
第二次挥手:服务端收到后,向客户端发送ACK确认报文,进入CLOSE_WAIT状态,
第三次挥手:客户端收到服务端的 ACK 应答报文后,之后进入 FIN_WAIT_2 状态。等待服务端处理完数据后,向客户端发送 FIN 报文,之后服务端进入 LAST_ACK 状态。
第四次挥手:客户端收到FIN+ACK包后,再向服务端发送ACK包,
等待两个周期后再关闭连接。服务器收到了 ACK 应答报文后,关闭连接。
客户端在要等2周期再关闭?
为的是确认服务器端是否收到客户端发出的 ACK 确认报文,当客户端发出最后的 ACK 确认报文时,并不能确定服务器端能够收到该段报文。服务端在没收收到ACK报文之前,会不停的重复发送FIN包而不关闭,所以得等待两个周期。
4.HTTP常见的状态码⭐
5.如何解决跨域⭐⭐⭐
什么是跨域?
跨域是因为浏览器的同源策略(Same Origin Policy)限制导致的。
浏览器从一个域名的网页去请求另一个域名的资源时,域名、端口、协议任一不同,都是跨域
常见的:
1、JSONP跨域
JSONP 可以跨域传递数据,基本原理是通过前端动态创建一个 <script>
标签,其中的 src 属性指向一个跨域 API 的 URL,该 URL 带有一个参数 callback,跨域 API 返回一段特定格式的 JavaScript 代码,其中 callback 函数的参数就是前端传回去的数据,前端获得结果后可以在本地执行回调函数。
2、跨域资源共享(CORS)
服务器端设置 HTTP 响应头部,使得浏览器可以跨域访问,服务器返回的响应头中包含 Access-Control-Allow-Origin 字段,指定可访问该资源的域名白名单,浏览器在接收响应时自动识别该字段判断该响应是否可跨域访问。
3、代理跨域 API 请求
使用自己的后端服务器作为代理服务器,把 API 请求发给服务器,服务器将请求转发到目标域名 API 并从服务器返回数据给前端,此时,前端 AJAX 请求的就是同域的 API,不存在跨域请求的问题了。
4、WebSocket协议跨域
基于 WebSocket 协议进行实时双向数据传输,但是需要服务端和客户端同时支持该技术。WebSocket 允许跨域使用。
5、proxy
前端配置一个代理服务器(proxy)代替浏览器去发送请求:因为服务器与服务器之间是可以通信的不受同源策略的影响。
所有的请求都发送到同一个本地后端 API,后端服务器再将请求转发到真正的目标域名服务器上。
6.网页从输入url到页面加载发生了什么⭐⭐
- DNS解析
- TCP连接
- 发送HTTP请求
- 服务器处理请求并返回HTTP报文
- 浏览器解析并渲染页面————>1.解析文档构建dom树。2.构建渲染树。3.布局与绘制渲染树。
- 连接结束
7.HTTP 传输过程⭐
含义:从建立连接到断开连接一共七个步骤,就是三次握手四次挥手
- TCP 建立连接
- 浏览器发送请求命令
- 浏览器发送请求头
- 服务器应答
- 服务器回应信息
- 服务器发送数据
- 断开TCP连接
8.浏览器如何渲染页面的?⭐
- 浏览器解析html源码,将HTML转换成dom树,
- 将CSS样式转换成stylesheet(CSS规则树),
- 浏览器会将CSS规则树附着在DOM树上,并结合两者生成渲染树(Render Tree)
- 生成布局(flow),浏览器通过解析计算出每一个渲染树节点的位置和大小,在屏幕上画出渲染树的所有节点
- 合成绘制生成页面。
9.对MVC和MVVM的理解⭐
M:model(数据模型),V:view(视图),C:controller(逻辑处理),VM:(连接model和view)
MVC:单向通信。必须通过controller来承上启下。
MVVM:数据双向绑定,数据改变视图,视图改变数据。
10.深拷贝,浅拷贝⭐⭐⭐
浅拷贝:创建一个新对象,这个对象有着原始对象属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是基本类型的值,如果属性是引用类型,拷贝的就是内存地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
深拷贝:将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。
总而言之,浅拷贝改动拷贝的数组原数组也会变(慎用!项目中很多地方共用的数组都会变)。深拷贝修改新数组不会改到原数组。
实现方法
浅拷贝:
- Object.assign()
- 函数库lodash的 _.clone 方法
- es6的扩展运算符 …(只能浅拷贝数组或对象中的引用类型的元素)
- Array.prototype.concat()
- Array.prototype.slice()
let arr=[{name:"uzi"}]
1. let arr1= Object.assign({}, arr); arr1[0].name="xiaoming"
2. let arr2= _.clone(arr); arr2[0].name="mlxg"
3. let arr4 = arr.concat() arr4[0].name="zitai"
4. let arr5 = arr.slice(); arr5[0].name="clearLove"
console.log(arr[0].name==arr[1].name==arr[2].name==……);
//true arr[0].name="clearLove"
深拷贝:
- JSON.parse(JSON.stringify())
- 函数库lodash的 _.cloneDeep 方法
- **jQuery.extend()**方法
- 手写递归方法(转)
- 扩展运算符…(只是一层的数组或者对象)
var $ = require('jquery');
let arr=[{name:"theShy",age:"21"}]
1. let arr1= JSON.parse(JSON.stringify(arr)); arr1[0].name="rookie"
2. let arr2= _.cloneDeep(arr); arr2[0].name="ning"
3. let arr3= $.extend(true, {}, arr); arr3[0].name="baolan"
console.log(arr[0].name==arr[1].name==arr[2].name==……);
//fales arr1[0].name="rookie" arr2[0].name="ning"
JSON.parse(JSON.stringify())使用限制:
该方法无法复制函数、正则表达式等非 JSON 数据类型。
对象属性的顺序会发生变化。
该方法无法处理循环引用的情况。
下面是一个简单的手写递归方法
function deepCopy(obj) {
if (typeof obj !== "object" || obj === null) {
return obj;
}
let newObj = Array.isArray(obj) ? [] : {};
for (let key in obj) {
newObj[key] = deepCopy(obj[key]);
}
return newObj;
}
对于扩展运算符的深拷贝和浅拷贝不同情况可以看数组一些常用的方法
11.防抖与节流⭐⭐⭐
防抖:触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间(多次执行变为最后一次执行)
应用场景:
提交按钮、用户注册时候的手机号验证、邮箱验证、
节流:高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率(多次执行变成每隔一段时间执行)
应用场景:
window对象的resize、scroll事件
拖拽时候的mousemove
射击游戏中的mousedown、keydown事件
文字输入、自动完成的keyup事件
vue中使用详情可以看vue中使用防抖和节流
12.性能优化⭐⭐
前端性能优化手段从以下几个方面入手:加载优化、执行优化、渲染优化、样式优化、脚本优化
- 加载优化:减少HTTP请求、缓存资源、压缩代码、无阻塞、首屏加载、按需加载、预加载、压缩图像、减少Cookie、避免重定向、异步加载第三方资源
- 执行优化:CSS写在头部,JS写在尾部并异步、避免img、iframe等的src为空、尽量避免重置图像大小、图像尽量避免使用DataURL
- 渲染优化:设置viewport、减少DOM节点、优化动画、优化高频事件、GPU加速
- 样式优化:避免在HTML中书写style、避免CSS表达式、移除CSS空规则、正确使用display:display、不滥用float等
- 脚本优化:减少重绘和回流、缓存DOM选择与计算、缓存.length的值、尽量使用事件代理、尽量使用id选择器、touch事件优化
13.webpack是怎么打包的,babel又是什么⭐
Webpack:把所有依赖打包成一个 bundle.js文件,通过代码分割成单元片段并按需加载。Webpack是以公共JS的形式来书写脚本的,但对AMD/CMD的支持也很全面,方便旧项目进行代码迁移。
把项目当做一个整体,通过一个给定的主文件(如:index.js),Webpack将从这个文件开始找到项目的所有依赖文件,使用loaders处理它们,最后打包为一个(或多个)浏览器可识别的JavaScript文件。
babel将es6、es7、es8等语法转换成浏览器可识别的es5或es3语法。
14.git 和 svn的区别⭐
SVN是集中式版本控制系统,版本库是集中放在中央服务器的,首先要从中央服务器哪里得到最新的版本,干完活后,需要把自己做完的活推送到中央服务器。集中式版本控制系统是必须联网才能工作(如果在局域网还可以,带宽够大,速度够快,如果在互联网下,如果网速慢的话,就纳闷了)
Git是分布式版本控制系统,没有中央服务器的,每个人的电脑就是一个完整的版本库,这样,工作的时候就不需要联网了,因为版本都是在自己的电脑上。自己在电脑上改了文件A,其他人也在电脑上改了文件A,这时,只需把各自的修改推送给对方,就可以互相看到对方的修改了。
15.vite和webpack的区别⭐⭐
- 构建速度
Vite 通过 ES Module 原生支持和开箱即用的特性,可以快速实现客户端和服务端的热更新,开发时的启动速度快,在初次构建和增量构建时性能均优于 Webpack。
Webpack 需要通过分析所有的模块之后进行构建,而 Vite 利用浏览器支持的 ESM 原生支持的特性,通过直接加载文件来进行编译和构建,速度较 Webpack 更快。 - 打包方式
Vite 支持基于 ES Module 的原生打包,可以直接使用浏览器原生支持的 ES Module 特性进行代码打包和分发。
Webpack 对开发者使用的方式相对更为多样化,例如支持 CommonJS、AMD 等 JavaScript 模块系统,更加灵活。 - 插件生态
相比于 Vite,Webpack 社区相对更成熟和庞大,拥有更多的第三方插件和工具支持,可以满足更为复杂的打包需求。 - 应用场景
Vite 仅支持现代浏览器,因此仅适用于现代浏览器、轻量级应用场景和小型项目。
Webpack 支持更为广泛,适用于大型项目和复杂应用场景。
总结:Vite 在性能和速度方面上优于 Webpack,特别是在开发环境下。
如果较大的项目,建议使用 Webpack 进行管理和构建。
当项目较小,且需要快速启动和热更新时,可以使用 Vite 来开发项目,更加高效。
16.require和import区别⭐⭐
- 调用时间
require 运行时 调用,理论上可以运用在代码任何地,甚至不需要赋值给某个变量之后再使用。
lmport是 编译时 调用,必须放在文件开头,而且使用格式也是确定的。 - 遵循规范
require 是 AMD规范引入方式,
import是es6的一个语法标准,如果要兼容浏览器的话必须转化成es5的语法 - 本质
require是赋值过程,其实require 的结果就是对象、数字、字符串、函数等,再把require的结果赋值给某个变量。
import是解构过程。
通过require 引入基础数据类型时,属于复制该变量。
通过require 引入复杂数据类型时,数据浅拷贝该对象。
出现模块之间的循环引用时,会输出已经执行的模块,而未执行的模块不输出(比较复杂)。CommonJS模块默认export的是一个对象,即使导出的是基础数据类型。
ES6 模块语法是 JavaScript 模块的标准写法,坚持使用这种写法,取代 Node.js 的 CommonJS 语法。
使用import取代require()。
// CommonJS 的写法
const moduleA = require('moduleA');
const func1 = moduleA.func1;
const func2 = moduleA.func2;
// ES6 的写法
import { func1, func2 } from 'moduleA';
使用export取代module.exports。
// commonJS 的写法
var React = require('react');
var Breadcrumbs = React.createClass({
render() {
return <nav />;
}
});
module.exports = Breadcrumbs;
// ES6 的写法
import React from 'react';
class Breadcrumbs extends React.Component {
render() {
return <nav />;
}
};
export default Breadcrumbs;
17.事件循环(Event Loop)⭐⭐⭐
原因:JavaScript是单线程,所有任务需要排队,前一个任务结束,才会执行后一个任务。
所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。
同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;
异步任务:不进入主线程、而进入"任务队列"的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
同步和异步任务分别进入不同的执行环境, 先执行同步任务,把异步任务放入循环队列当中挂起,等待同步任务执行完,再执行队列中的异步任务。异步任务先执行微观任务,再执行宏观任务。一直这样循环,反复执行。
微任务:Promise.then、catch、finally、async/await。
宏任务:整体代码 Script、UI 渲染、setTimeout、setInterval、Dom事件、ajax事件。
如果使用同步的方式,有可能造成主线程阻塞,从而导致消息队列中很多其他任务无法执行。这样一来,一方面会导致主线程白白浪费时间,另一方面导致页面无法及时更新,给用户造成卡死。
所以浏览器采用异步的方式来避免,从最大限度的保证了单线程的流畅运行。
18.什么是单页面应用(SPA)⭐
一个系统只加载一次资源,之后的操作交互、数据交互是通过路由、ajax来进行,页面并没有刷新。
在一个页面上集成多种功能,甚至整个系统就只有一个页面,所有的业务功能都是它的子模块,通过特定的方式挂接到主界面上。
优点:
- 前后端分离
- 良好的交互体验——用户不用刷新页面,页面显示流畅
- 减轻服务器压力——服务器只出数据
- 共用一套后端代码——多个客户端可共用一套后端代码
- 加载速度快,内容的改变不需要重新加载整个页面,对服务器压力小
缺点:
- SEO难度高——数据渲染在前端进行
- 页面初次加载比较慢,页面复杂提高很多
多页面:一个应用多个页面,页面跳转时整个页面都刷新,每次都请求一个新的页面
优点:SEO效果好
缺点:页面切换慢,每次切换页面需要选择性的重新加载公共资源
详情可以参考构建单页Web应用
19.什么叫优雅降级和渐进增强?⭐
渐进增强(Progressive Enhancement):一开始就针对低版本浏览器进行构建页面,完成基本的功能,然后再针对高级浏览器进行效果、交互、追加功能达到更好的体验。
优雅降级(Graceful Degradation):一开始就构建站点的完整功能,然后针对浏览器测试和修复。
在传统软件开发中,经常会提到向上兼容和向下兼容的概念。渐进增强相当于向上兼容,而优雅降级相当于向下兼容。向下兼容指的是高版本支持低版本的或者说后期开发的版本支持和兼容早期开发的版本,向上兼容的很少。大多数软件都是向下兼容的。
二者区别:
1、优雅降级和渐进增强只是看待同种事物的两种观点。
2、优雅降级观点认为应该针对那些最高级、最完善的浏览器来设计网站。
3、渐进增强观点则认为应关注于内容本身。
19.浏览器内存泄漏?⭐⭐
概念:程序中己动态分配的堆内存由于某种原因未释放或无法被浏览器所回收,造成系统内存占用越来越大,最终导致程序运行缓慢甚至系统崩溃等严重后果。
原因:
- 滥用全局变量,使这个变量一直留在内存中无法被回收
- 不合理的使用闭包,从而导致某些变量一直被留在内存当中。
- 没有清除定时器。
- 未被销毁的事件监听。
- 某些DOM操作(使用Dom对象绑定事件时,Dom对象消失后,还保留着没有及删除)。
20. iframe的优点、缺点⭐
优点:
- iframe能够原封不动的把嵌入的网页展现出来。
如果有多个网页引用iframe,那么你只需要修改iframe的内容,就可以实现调用的每一个页面内容的更改,方便快捷。 - 网页如果为了统一风格,头部和版本都是一样的,就可以写成一个页面,用iframe来嵌套,可以增加代码的可重用。
- 如果遇到加载缓慢的第三方内容如图标和广告,这些问题可以由iframe来解决。
缺点:
- iframe会阻塞主页面的onload事件;
- iframe和主页面共享连接池,而浏览器对相同域的连接有限制,所以会影响页面的并行加载。会产生很多页面,不容易管理。
- iframe框架结构有时会让人感到迷惑,如果框架个数多的话,可能会出现上下、左右滚动条,会分散访问者的注意力,用户体验度差。
- 代码复杂,无法被一些搜索引擎索引到,iframe会不利于搜索引擎优化(SEO)。
- 很多的移动设备无法完全显示框架,设备兼容性差。
- iframe框架页面会增加服务器的http请求,对于大型网站是不可取的。
21.排序方式⭐
- 冒泡排序:比较所有相邻元素,如果第一个比第二个大,则交换它们。(复杂度 O(n^2))
- 选择排序:找到数组中的最小值,选中它并将其放置在第一位。(复杂度 O(n^2))
- 插入排序:从第二个数开始往前比,比它大就往后排。(复杂度 O(n^2))
- 归并排序:把数组劈成两半,再递归地对数组进行“分”操作,直到分成一个个单独的数。(复杂度 O(nlog(n)))
- 快速排序:从数组中任意选择一个基准,所有比基准小的元素放到基准前面,比基准大的元素放到基准的后面。(复杂度 O(nlog(n)))
- 计数排序:使用一个用来存储每个元素在原始数组中出现次数的临时数组。在所有元素都计数完成后,临时数组已排好并可迭代以构建排序后的数组。(复杂度 O(n+k))
- 桶排序:将元素分为不同的桶(较小的数组),再使用简单的排序来对每个桶进行排序,然后将每个桶合并为数组。(复杂度 O(n))
- 基数排序:根据数字的有效位或基数将整数分布到桶中。基数是基于数组中的记数制。 (复杂度 O(n))
四、TS篇
1.TS相比JS的有哪些优点⭐
支持静态类型定义提高了代码的可维护性和可读性,减少了代码错误。
2.TS的类型 ⭐⭐⭐
原始类型(Primitive Types)
- boolean(布尔类型):true 或 false。
- number(数值类型):整数或浮点数。
- string(字符串类型):字符串值。
- null(空类型):null 值。
- undefined(未定义类型):undefined 值。
- symbol(符号类型):唯一且不可变的值。
对象类型(Object Types)
- object(对象类型):表示非原始类型即除了 number、string、boolean、symbol、null 或 undefined 以外的类型。
- Array(数组类型):以特定顺序排列的数据,可以通过索引进行访问。
- Tuple(元组类型):表示具有有限数量的未命名属性的数组,即允许不同类型的元素集合。
- Function(函数类型):表示函数的类型。
- Class(类类型):表示类的类型。
其它类型
- unknown:表示任何类型,但在使用前必须先设法验证类型。
- any:表示任意类型。
- void:用于表示没有任何返回值的函数的类型。
- never:表示不存在的类型值,通常用于表示永远不会抛出异常或永远不会有返回值的函数的类型。
3. type和interface的区别 ⭐⭐⭐
相同点:都可以给对象指定类型
区别:
interface:
- 只能为对象指定类型
- 可以使用extends继承
- 多个同名的interface会合并
type:
- 不仅可以为对象指定类型,实际上可以为任意类型指定别名
- 可以使用&运算符实现继承效果
- 多个同名的type会报错
- type 可以声明基本类型别名,联合类型,元组等类型
五、VUE篇
关于vue的面试题移步这篇文章
前端面试题 — — vue篇
六、REACT篇
1.React的生命周期(版本17.0.2)⭐⭐⭐
概念:每个组件都包含 “生命周期方法”,你可以重写这些方法,以便于在运行过程中特定的阶段执行这些方法。
挂载:
- constructor():在 React 组件挂载之前,会调用它的构造函数。(注:如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。)
- render(): class 组件中唯一必须实现的方法。
- componentDidMount():在组件挂载后(插入 DOM 树中)立即调用。依赖于 DOM 节点的初始化应该放在这里。
更新
- render(): class 组件中唯一必须实现的方法。
- componentDidUpdate():在更新后会被立即调用。首次渲染不会执行此方法。
卸载
- componentWillUnmount():在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。
具体可用一张图来表示
详情可看官网组件的生命周期
2.React如何获取组件对应的DOM元素?⭐⭐
- ref:通过当前class组件实例的一些特定属性来直接获取子节点实例。
注意:不能在函数组件上使用 ref 属性,因为他们没有实例。 - findDOMNode():findDOMNode 是一个访问底层 DOM 节点的应急方案(escape hatch)。
注意:在大多数情况下,不推荐使用该方法,因为它会破坏组件的抽象结构。严格模式下该方法已弃用。findDOMNode 不能用于函数组件。
详情请看官网:ReactDOM
3.React中可以在render访问refs吗?为什么?⭐⭐
答:不能,因为在render阶段refs还未生成。DOM 的读取在 pre-commit 阶段,DOM的使用在 commit 阶段。
4.React中什么是受控组件和非控组件?⭐⭐
渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。
受控组件更新state的流程:
- 可以通过初始state中设置表单的默认值
- 每当表单的值发生变化时,调用onChange事件处理器
- 事件处理器通过事件对象e拿到改变后的状态,并更新组件的state
- 一旦通过setState方法更新state,就会触发视图的重新渲染,完成表单组件的更新
对于受控组件来说,输入的值始终由 React 的 state 驱动。你也可以将 value 传递给其他 UI 元素,或者通过其他事件处理函数重置,但这意味着你需要编写更多的代码。
详情看官网受控组件
非受控组件
如果一个表单组件没有value props(单选和复选按钮对应的是checked props)时,就可以称为非受控组件。在非受控组件中,可以使用一个ref来从DOM获得表单值。而不是为每个状态更新编写一个事件处理程序。
官网解释:要编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,你可以 使用 ref 来从 DOM 节点中获取表单数据。
因为非受控组件将真实数据储存在 DOM 节点中,所以在使用非受控组件时,有时候反而更容易同时集成 React 和非 React 代码。如果你不介意代码美观性,并且希望快速编写代码,使用非受控组件往往可以减少你的代码量。否则,你应该使用受控组件。
官网非受控组件
总结: 页面中所有输入类的DOM如果是现用现取的称为非受控组件,而通过setState将输入的值维护到了state中,需要时再从state中取出,这里的数据就受到了state的控制,称为受控组件。
5.谈一谈React的状态提升?⭐⭐
官网是这么解释的:
多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去。
简单来说就是:将多个组件需要共享的状态提升到它们最近的父组件上,在父组件上改变这个状态然后通过props分发给子组件。对子组件操作,子组件不改变自己的状态。
可看官网的温度计数器例子
6.为什么要使用虚拟DOM?(什么是 Virtual DOM?)⭐⭐
Virtual DOM算法
用一张图片来表示
虚拟DOM
那就是虚拟DOM概念出现的地方,并且其性能要比真实DOM好得多。虚拟DOM只是DOM的虚拟表示。每当我们的应用程序状态更改时,虚拟DOM就会更新,而不是真实DOM。
React如何使用虚拟DOM
在React中,每个UI块都是一个组件,每个组件都有一个状态。React遵循可观察的模式,并监听状态变化。当组件的状态改变时,React更新虚拟DOM树。虚拟DOM更新后,React然后将虚拟DOM的当前版本与虚拟DOM的先前版本进行比较。此过程称为“差异化”。
一旦React知道哪些虚拟DOM对象已更改,然后React就会在真实DOM中仅 更新那些对象。与直接操作真实DOM相比,这使性能好得多。
原因:对于局部的小视图的更新,重新构造整棵 DOM没问题;但是对于大型视图,如全局应用状态变更的时候,需要更新页面较多局部视图的时候,这样的做法不可取。 Virtual DOM只是加了一些特别的步骤来避免了整棵 DOM 树变更。
简而言之就是:
- 频繁的DOM操作昂贵且性能沉重。
- 虚拟DOM是真实DOM的虚拟表示。
- React使用虚拟DOM来增强其性能。
- JS 和 DOM 之间的缓存。
更深入可看深度剖析:如何实现一个 Virtual DOM 算法
七、其它篇
1.谈项目⭐⭐⭐
2.项目开发中遇到的bug?⭐⭐
项目中或者地图中遇到引入如图片不显示。
解决办法:使用require动态引入图片。
详细可看:设置content加载不出图标
合并多个对象并去重
原因:普通去重不能去除对象。
解决方法:可看数组中有对象去除
移动端1px问题
原因:手机分辨率高,它的实际物理像素数更多了,不同手机屏幕分辨率不同,一般都差不多2倍左右,所以显得更粗。
解决方法:可以参考第二篇CSS的11题。
移动端点击穿透问题
原因:
- 点击蒙层上的关闭按钮,蒙层消失后触发了按钮下面元素的click事件
- 如果按钮下面恰好是一个有href属性的a标签,那么页面就会发生跳转
- 这次没有蒙层,直接点击页内按钮跳转至新页,然后发现新页面中对应位置元素的click事件被触发了.
解决方法:
最优解决方法——只用touch
最简单的解决方案,完美解决点击穿透问题
把页面内所有click全部换成touch事件( touchstart、touchmove、touchend)
项目中遇到bug总结:
基本上都是遇到一些样式的Bug,逻辑上的想想就解决了,没什么难的。
3.说说你在项目中遇到印象最深,最困难的地方,是怎么解决的?⭐⭐
(待补充)
4.你觉得你们项目还有哪些不足的地方?⭐⭐
(待补充)
5.工作之余你会做什么,看什么书?⭐
6.近几年的职业规划?⭐⭐
(待补充)
后言
其他hr常问的问题可以看这
总结
每天多学习一点,更进步一点
祝:大家早日找到理想的工作~
码字不易,持续更新中…
哪里有不足之处,麻烦指出,谢谢~~
最后
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
方法**:可以参考第二篇CSS的11题。
移动端点击穿透问题
原因:
- 点击蒙层上的关闭按钮,蒙层消失后触发了按钮下面元素的click事件
- 如果按钮下面恰好是一个有href属性的a标签,那么页面就会发生跳转
- 这次没有蒙层,直接点击页内按钮跳转至新页,然后发现新页面中对应位置元素的click事件被触发了.
解决方法:
最优解决方法——只用touch
最简单的解决方案,完美解决点击穿透问题
把页面内所有click全部换成touch事件( touchstart、touchmove、touchend)
项目中遇到bug总结:
基本上都是遇到一些样式的Bug,逻辑上的想想就解决了,没什么难的。
3.说说你在项目中遇到印象最深,最困难的地方,是怎么解决的?⭐⭐
(待补充)
4.你觉得你们项目还有哪些不足的地方?⭐⭐
(待补充)
5.工作之余你会做什么,看什么书?⭐
6.近几年的职业规划?⭐⭐
(待补充)
后言
其他hr常问的问题可以看这
总结
每天多学习一点,更进步一点
祝:大家早日找到理想的工作~
码字不易,持续更新中…
哪里有不足之处,麻烦指出,谢谢~~
最后
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
[外链图片转存中…(img-MIC1vkdf-1715747328026)]