【面试】最新web前端经典面试题试题及答案(持续更新)

您所在的位置:网站首页 web前端的面试题及答案 【面试】最新web前端经典面试题试题及答案(持续更新)

【面试】最新web前端经典面试题试题及答案(持续更新)

2024-06-24 14:25| 来源: 网络整理| 查看: 265

author: aSuncat JavaScript知识点大全:https://www.yuque.com/webfront/js

所有最新最全面试题,持续更新在语雀。见 语雀-前端面试题,欢迎点击关注~

阅读目录

html/ css:https://blog.csdn.net/aSuncat/article/details/88789368javascript:2022年版(见语雀)、2019年版es6:https://blog.csdn.net/aSuncat/article/details/88818661vue:https://blog.csdn.net/aSuncat/article/details/88978775react:2022年版(见语雀)、2019年版jQuery:https://blog.csdn.net/aSuncat/article/details/108577468webpack、gulp、gruntnode前后端通信http、https、tcp:https://blog.csdn.net/aSuncat/article/details/109180153web安全前端性能浏览器:https://blog.csdn.net/aSuncat/article/details/116934548多端算法相关设计模式正则表达式hybrid全栈项目svn、git

webpack、gulp、grunt

11、前端技术体系 (1)多版本/覆盖 时间戳 发布新版本回滚 (2)ssr & 同构 (3)webpack vendor:commonchunk external:全局变量 默认css处理

模块化发展历程?

可从IIFE、AMD、CMD、CommonJS、UMD、webpack(require.ensure)、ES Module、 这几个角度考虑。 参考答案 模块化主要是用来抽离公共代码,隔离作用域,避免变量冲突等。 IIFE:使用自执行函数来编写模块化,特点:在一个单独的函数作用域中执行代码,避免变量冲突。

(function(){ return { data:[] } })()

AMD:使用requireJS 来编写模块化,特点:依赖必须提前声明好。

define('./index.js',function(code){ // code 就是index.js 返回的内容 })

CMD:使用seaJS 来编写模块化,特点:支持动态引入依赖文件。

define(function(require, exports, module) { var indexCode = require('./index.js'); })

CommonJS:nodejs 中自带的模块化。

var fs = require('fs');

UMD:兼容AMD,CommonJS 模块化语法。 webpack(require.ensure):webpack 2.x 版本中的代码分割。 ES Modules:ES6 引入的模块化,支持import 来引入另一个 js 。

import a from 'a'; webpack webpack优化方式?

待完善

24、webpack在使用层面,对插件和loader不够理解。

gulp

1、

grunt

1、

grunt和gulp的区别?

1、易用:Gulp相比Grunt更简洁,而且遵循代码优于配置策略,维护Gulp更像是写代码。 2、高效:Gulp相比Grunt更有设计感,核心设计基于Unix流的概念,通过管道连接,不需要写中间文件。 3、高质量:Gulp的每个插件只完成一个功能,这也是Unix的设计原则之一,各个功能通过流进行整合并完成复杂的任务。例如:Grunt的imagemin插件不仅压缩图片,同时还包括缓存功能。他表示,在Gulp中,缓存是另一个插件,可以被别的插件使用,这样就促进了插件的可重用性。目前官方列出的有673个插件。 4、易学:Gulp的核心API只有5个,掌握了5个API就学会了Gulp,之后便可以通过管道流组合自己想要的任务。 5、流:使用Grunt的I/O过程中会产生一些中间态的临时文件,一些任务生成临时文件,其它任务可能会基于临时文件再做处理并生成最终的构建后文件。而使用Gulp的优势就是利用流的方式进行文件的处理,通过管道将多个任务和操作连接起来,因此只有一次I/O的过程,流程更清晰,更纯粹。 6、代码优于配置:维护Gulp更像是写代码,而且Gulp遵循CommonJS规范,因此跟写Node程序没有差别。

node

(1)nodejs 实践 (2)nodejs性能高在哪里 高并发非阻塞 IO 密集 (3)stream pipe 说不出背压机制 6、node 线上oom(通过重启,打profile,复现寻找bug点)。 基本的node性能监控 alinode等profile工具 浏览器渲染帧率、动画、性能相关,h5页面优化实践, 对小程序深度性能分析优化等方面很感兴趣 13、node服务线上的稳定,日志,安全,监控都有一定的了解,也有一定的线上运维经验

npm 模块安装机制,为什么输入 npm install 就可以自动安装对应的模块?

1.npm 模块安装机制: 发出npm install命令 查询node_modules目录之中是否已经存在指定模块 npm 向 registry 查询模块压缩包的网址 下载压缩包,存放在根目录下的.npm目录里 解压压缩包到当前项目的node_modules目录 若存在,不再重新安装 若不存在 2. npm 实现原理 输入 npm install 命令并敲下回车后,会经历如下几个阶段(以 npm 5.5.1 为例): (1)执行工程自身 preinstall 当前 npm 工程如果定义了 preinstall 钩子此时会被执行。 (2)确定首层依赖模块 首先需要做的是确定工程中的首层依赖,也就是 dependencies 和 devDependencies 属性中直接指定的模块(假设此时没有添加 npm install 参数)。 工程本身是整棵依赖树的根节点,每个首层依赖模块都是根节点下面的一棵子树,npm 会开启多进程从每个首层依赖模块开始逐步寻找更深层级的节点。 (3)获取模块 获取模块是一个递归的过程,分为以下几步:

获取模块信息。在下载一个模块之前,首先要确定其版本,这是因为 package.json 中往往是 semantic version(semver,语义化版本)。此时如果版本描述文件(npm-shrinkwrap.json 或 package-lock.json)中有该模块信息直接拿即可,如果没有则从仓库获取。如 packaeg.json 中某个包的版本是 ^1.1.0,npm 就会去仓库中获取符合 1.x.x 形式的最新版本。获取模块实体。上一步会获取到模块的压缩包地址(resolved 字段),npm 会用此地址检查本地缓存,缓存中有就直接拿,如果没有则从仓库下载。查找该模块依赖,如果有依赖则回到第1步,如果没有则停止。 (4)模块扁平化(dedupe) 上一步获取到的是一棵完整的依赖树,其中可能包含大量重复模块。比如 A 模块依赖于 loadsh,B 模块同样依赖于 lodash。在 npm3 以前会严格按照依赖树的结构进行安装,因此会造成模块冗余。 从 npm3 开始默认加入了一个 dedupe 的过程。它会遍历所有节点,逐个将模块放在根节点下面,也就是 node-modules 的第一层。当发现有重复模块时,则将其丢弃。 这里需要对重复模块进行一个定义,它指的是模块名相同且 semver 兼容。每个 semver 都对应一段版本允许范围,如果两个模块的版本允许范围存在交集,那么就可以得到一个兼容版本,而不必版本号完全一致,这可以使更多冗余模块在 dedupe 过程中被去掉。 比如 node-modules 下 foo 模块依赖 lodash@^1.0.0,bar 模块依赖 lodash@^1.1.0,则 ^1.1.0 为兼容版本。 而当 foo 依赖 lodash@^2.0.0,bar 依赖 lodash@^1.1.0,则依据 semver 的规则,二者不存在兼容版本。会将一个版本放在 node_modules 中,另一个仍保留在依赖树里。 举个例子,假设一个依赖树原本是这样: node_modules – foo ---- lodash@version1 – bar ---- lodash@version2 假设 version1 和 version2 是兼容版本,则经过 dedupe 会成为下面的形式: node_modules – foo – bar – lodash(保留的版本为兼容版本) 假设 version1 和 version2 为非兼容版本,则后面的版本保留在依赖树中: node_modules – foo – lodash@version1 – bar ---- lodash@version2 (5)安装模块 这一步将会更新工程中的 node_modules,并执行模块中的生命周期函数(按照 preinstall、install、postinstall 的顺序)。 (6)执行工程自身生命周期 当前 npm 工程如果定义了钩子此时会被执行(按照 install、postinstall、prepublish、prepare 的顺序)。 最后一步是生成或更新版本描述文件,npm install 过程完成。 了解v8引擎吗,一段js代码如何执行的?

在执行一段代码时,JS 引擎会首先创建一个执行栈 然后JS引擎会创建一个全局执行上下文,并push到执行栈中, 这个过程JS引擎会为这段代码中所有变量分配内存并赋一个初始值(undefined),在创建完成后,JS引擎会进入执行阶段,这个过程JS引擎会逐行的执行代码,即为之前分配好内存的变量逐个赋值(真实值)。 如果这段代码中存在function的声明和调用,那么JS引擎会创建一个函数执行上下文,并push到执行栈中,其创建和执行过程跟全局执行上下文一样。但有特殊情况,即当函数中存在对其它函数的调用时,JS引擎会在父函数执行的过程中,将子函数的全局执行上下文push到执行栈,这也是为什么子函数能够访问到父函数内所声明的变量。 还有一种特殊情况是,在子函数执行的过程中,父函数已经return了,这种情况下,JS引擎会将父函数的上下文从执行栈中移除,与此同时,JS引擎会为还在执行的子函数上下文创建一个闭包,这个闭包里保存了父函数内声明的变量及其赋值,子函数仍然能够在其上下文中访问并使用这边变量/常量。当子函数执行完毕,JS引擎才会将子函数的上下文及闭包一并从执行栈中移除。 最后,JS引擎是单线程的,那么它是如何处理高并发的呢?即当代码中存在异步调用时JS是如何执行的。比如setTimeout或fetch请求都是non-blocking的,当异步调用代码触发时,JS引擎会将需要异步执行的代码移出调用栈,直到等待到返回结果,JS引擎会立即将与之对应的回调函数push进任务队列中等待被调用,当调用(执行)栈中已经没有需要被执行的代码时,JS引擎会立刻将任务队列中的回调函数逐个push进调用栈并执行。这个过程我们也称之为事件循环。

koa

14、koa源码了解

web安全

Web攻击方式有哪几种?

1、CSRF 2、XSS 3、SQL注入攻击 就是通过把SQL命令插入到Web表单递交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令。

简述HTTPS中间人攻击?

参考答案 https协议由 http + ssl 协议构成,具体的链接过程可参考SSL或TLS握手的概述

中间人攻击过程如下: 服务器向客户端发送公钥。 攻击者截获公钥,保留在自己手上。 然后攻击者自己生成一个【伪造的】公钥,发给客户端。 客户端收到伪造的公钥后,生成加密hash值发给服务器。 攻击者获得加密hash值,用自己的私钥解密获得真秘钥。 同时生成假的加密hash值,发给服务器。 服务器用私钥解密获得假秘钥。 服务器用加秘钥加密传输信息

防范方法: 服务端在发送浏览器的公钥中加入CA证书,浏览器可以验证CA证书的有效性

CSRF CSRF基本概念和缩写?

CSRF,Cross-site request forgery,通常被称为跨站请求伪造。

CSRF攻击原理?

在这里插入图片描述 1、前提:①用户在注册网站A登录过,②接口有漏洞。 2、引诱点击,往往是一个链接(这个链接自动携带cookie,不会带token),指向网站A的api,接口是get类型。浏览了A,浏览器自动生成新的cookie,网站A拿到cookie,接口运行。

CSRF防御措施?

1、token验证。 注册网站,或者访问网站,服务器自动向本地存储一个token。 2、refer验证。 服务器判断页面是不是我这个站点来的页面。 3、隐藏令牌。 http的head头,不会放在链接上。

XSS XSS基本概念和缩写?

XSS,cross-site scripting ,跨域脚本攻击。

XSS攻击原理?

原理:向页面注入html标签或js脚本。 eg:提交区(评论区)写img标签,script标签,利用合法渠道向页面注入js

XSS防御措施?

宗旨:让xss不可执行。 1、前端替换关键字,如替换 为; 2、后台替换。 3、任何内容写到页面之前都必须加以encode,避免不小心把html tag 弄出来。

CSRF ,XSS的区别 CSRF ,XSS的区别?

1、XSS是向页面注入js去运行,然后在js函数体中做他想做的事情。 CSRF是利用网站漏洞,自动执行接口。用户需要登陆网站。 2、XSS是获取信息,不需要提前知道其他用户页面的代码和数据包。 CSRF是代替用户完成指定的动作,需要知道其他用户页面的代码和数据包。

SQL注入 SQL注入防御措施?

1、永远不要信任用户的输入,要对用户的输入进行校验,可以通过正则表达式,或限制长度,对单引号和双"-"进行转换等。 2、永远不要使用动态拼装SQL,可以使用参数化的SQL或者直接使用存储过程进行数据查询存取。 3、永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。 4、不要把机密信息明文存放,请加密或者hash掉密码和敏感的信息。

前端性能

1、原则 (1)多使用内存、缓存或者其他方法。 (2)减少cpu占用,减少网络。

提升页面性能的方法有哪些?

一、加载页面和静态资源 1、静态资源压缩合并,减少http请求。 (1)减少http请求数量 (2)减少请求资源大小 2、非核心代码异步加载。 3、静态资源缓存:通过链接名称控制缓存,只有内容改变的时候,链接名称才会改变。 4、利用浏览器缓存 5、使用cdn让资源加载更快 6、预解析dns 7、使用ssr后端渲染,数据直接输出到html中(ssr:server site render) 二、页面渲染 1、css、js及放置位置 (1)尽量避免在HTML标签中写style属性 (2)css放前面,js放后面。 (3)避免使用CSS Expression 2、图片 (1)避免图片和iFrame等的空Src。空Src会重新加载当前页面,影响速度和效率 (2)懒加载(图片懒加载,下拉加载更多)

var img1 = document.getElementById('img1'); img1.src = img1.getAttribute('data-realsrc');

3、dom操作 (1)减少dom查询,对dom查询做缓存。

// 未缓存dom查询 var i; for (i = 0; i < document.getElementsByTagName('p').length; i++) {\ // todo } // 缓存了dom查询 var pList = document.getElementByTagName('p'); var i; for (i = 0; i < pList.length; i++) { // todo }

(2)减少dom操作,多个操作尽量合并在一起执行。

var frag = document.createDocumentFragment(); // 片段,循环插入dom,改成先插入到片段,再append到文档流

(3)用innerHTML代替DOM操作,减少DOM操作次数,优化javascript性能 4、事件 (1)尽早执行操作(如DOMContentLoaded) (2)事件节流

var textarea = document.getElementById('text'); var timeoutId; textarea.addEventListener('keyup', function() { if(timeoutId) { clearTimeout(timeoutId); } timeoutId = setTimeout(function() { // 触发change事件 }, 100) })

5、代码细节优化 (1)用hash-table来优化查找 (2)多个变量声明合并 (3)少用全局变量 (4)避免全局查询 (5)避免使用with(with会创建自己的作用域,会增加作用域链长度) (6)用setTimeout来避免页面失去响应 三、移动端性能优化 1、css (1)不滥用Float。Float在渲染时计算量比较大,尽量减少使用 (2)不滥用Web字体。Web字体需要下载,解析,重绘当前页面,尽量减少使用。 (3)避免使用css3渐变阴影效果。 2、css动画 (1)尽量使用css3动画,开启硬件加速。 可以用transform: translateZ(0)来开启硬件加速。 CSS中的属性(CSS3 transitions、CSS3 3D transforms、Opacity、Canvas、WebGL、Video)会触发GPU渲染,请合理使用。过渡使用会引发手机过耗电增加 3、合理使用requestAnimationFrame动画代替setTimeout 4、适当使用touch事件代替click事件。

什么是防抖和节流?有什么区别?如何实现??

防抖 触发高频事件后n秒内函数只会执行一次,如果n秒内高频事件再次被触发,则重新计算时间 思路: 每次触发事件时都取消之前的延时调用方法

function debounce(fn) { let timeout = null; // 创建一个标记用来存放定时器的返回值 return function () { clearTimeout(timeout); // 每当用户输入的时候把前一个 setTimeout clear 掉 timeout = setTimeout(() => { // 然后又创建一个新的 setTimeout, 这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数 fn.apply(this, arguments); }, 500); }; } function sayHi() { console.log('防抖成功'); } var inp = document.getElementById('inp'); inp.addEventListener('input', debounce(sayHi)); // 防抖

节流 高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率 思路: 每次触发事件时都判断当前是否有等待执行的延时函数

function throttle(fn) { let canRun = true; // 通过闭包保存一个标记 return function () { if (!canRun) return; // 在函数开头判断标记是否为true,不为true则return canRun = false; // 立即设置为false setTimeout(() => { // 将外部传入的函数的执行放在setTimeout中 fn.apply(this, arguments); // 最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。当定时器没有执行的时候标记永远是false,在开头被return掉 canRun = true; }, 500); }; } function sayHi(e) { console.log(e.target.innerWidth, e.target.innerHeight); } window.addEventListener('resize', throttle(sayHi)); 非核心代码异步加载 异步加载的方式?

1、动态脚本加载 script标签,加入到body中 2、defer 加载js的时候,script标签加defer和async 3、async

异步加载的区别?

1、defer是在html解析完之后才会执行,如果是多个,按照加载的顺序依次进行。 2、async是在加载完之后立即执行,如果是多个,执行顺序和加载顺序无关。

预解析dns 预解析dns的方式?

1、

2、强制打开a标签的dns预解析

页面中所有a标签,默认打开了dns预解析,如果链接是https开头的,默认关闭dns预解析

多端

小程序和 H5 有什么区别?

1、渲染方式与 H5 不同,小程序一般是通过 Native 原生渲染的,但是小程序同时也支持 web 渲染,如果使用 web 渲染的方式,我们需要初始化一个WebView 组件,然后在 WebView 中加载 H5 页面; 所以当我们开发一个小程序时,通常会使用 hybrid 的方式,即会根据具体情况选择部分功能用小程序原生的代码来开发,部分功能通过 WebView 加载 H5 页面来实现。Native 与 Web 渲染混合使用,以实现项目的最优解; 这里值得注意的是,小程序下,native 方式通常情况下性能要优于 web 方式。 2、小程序特有的双线程设计。 H5 下我们所有资源通常都会打到一个 bundle.js 文件里(不考虑分包加载),而小程序编译后的结果会有两个bundle,index.js封装的是小程序项目的 view 层,以及 index.worker.js 封装的是项目的业务逻辑,在运行时,会有两条线程来分别处理这两个bundle,一个是主渲染线程,它负责加载并渲染 index.js 里的内容,另外一个是 Service Worker线 程,它负责执行 index.worker.js 里封装的业务逻辑,这里面会有很多对底层api调用。

算法相关

通常情况下,搞金融的都会考算法。 一、排序 在这里插入图片描述 快速排序:https://segmentfault.com/a/1190000009426421 选择排序:https://segmentfault.com/a/1190000009366805 希尔排序:https://segmentfault.com/a/1190000009461832 二、堆栈、队列、链表 堆栈:https://juejin.im/entry/58759e79128fe1006b48cdfd 队列:https://juejin.im/entry/58759e79128fe1006b48cdfd 链表:https://juejin.im/entry/58759e79128fe1006b48cdfd (1)js数组本身就具备堆栈和队列特性。 (2)堆栈:先进后出。 三、递归 递归:https://segmentfault.com/a/1190000009857470 (1)60%的算法题都用到递归。 四、波兰式和逆波兰式 理论:http://www.cnblogs.com/chenying99/p/3675876.html 源码:https://github.com/Tairraos/rpn.js/blob/master/rpn.js

手写一个冒泡排序?

1、比较两个相邻的元素,如果后一个比前一个大,则交换位置。 2、 第一轮的时候最后一个元素应该是最大的一个。 3、按照第一步的方法进行两个相邻的元素的比较,由于最后一个元素已经是最大的了,所以最后一个元素不用比较。

function bubbleSort(arr) { let len = arr.length; for (let i = 0; i < len; i++) { for (let j = 0; j < len - i - 1; j++) { // j=0时,得到最大的元素,放在了最后面 if (arr[j] > arr[j+1]) { [arr[j], arr[j+1]] = [arr[j+1], arr[j]]; } } } return arr; } let arr = [3,5,1,2,7,8,4,5,3,4]; let sortedArr = bubbleSort(arr); console.log(sortedArr); 快速排序的思想?

1、在数据集之中,找一个基准点,将数据分成两个部分,一部分比另外一部分所有的数据都要小, 2、建立两个数组,分别存储左边和右边的数组 3、利用递归进行下次比较

手写一个快速排序? function quickSort(arr) { if (arr.length


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3