【面试】最新web前端经典面试题试题及答案(持续更新) |
您所在的位置:网站首页 › web前端的面试题及答案 › 【面试】最新web前端经典面试题试题及答案(持续更新) |
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、gitwebpack、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不够理解。 gulp1、 grunt1、 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进调用栈并执行。这个过程我们也称之为事件循环。 koa14、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、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)懒加载(图片懒加载,下拉加载更多) ![]() 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调用。 算法相关 通常情况下,搞金融的都会考算法。 一、排序 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 |