前端开发常见面试题

Tesia ·
更新时间:2024-09-21
· 878 次阅读

常见面试题

介绍js的基本数据类型、引用类型、特殊类型

基本数据类型:String、Number、Boolean、undefined、unll (新增Symbol)

引用类型 : function、Object

特殊类型 :undefined、null

原型链是什么 ?

用new运算符加上函数的调用,调用的结果就是一个对象,new出来的这个对象我们称他为实例

prototype(原型)是一个指针指向了一个原型对象,这个对象里面存放所有的实例共享的属性和方法

实例的__proto__指向了构造函数的prototype,构造函数是object的实例,构造函数的prototype下的__proto__指向了object的prototype 我们称他为原型链

javascript作用链域?

全局函数无法查看局部函数的内部细节,但局部函数可以查看其上层的函数细节,直至全局细节。
当需要从局部函数查找某一属性或方法时,如果当前作用域没有找到,就会上溯到上层作用域查找,
直至全局函数,这种组织形式就是作用域链。

谈谈This对象的理解。

1全局this指window 2事件对象里面的this指事件触发对象,特殊的是,IE中的attachEvent中的this总是指向全局对象Window

4.3自调用函数this指window

4.4对象方法里面的this指对象本身

4.5构造函数的this及构造函数原型方法里面的this都是指向将来new的实例对象

4.6没有归属的局部函数this指向window

4.7箭头函数没有自己的this

4.8 forEach,reduce,定时器里面的this都是指向window

改变this指向的方法

bind方法:在函数声明的时候改变this的指向

call方法:是在函数调用的时候改变this的指向(window,18,19,20)传参的方式不一样

apply方法: 是在函数调用的时候改变this的指向(window,[18,19,20])传一个数组

什么是闭包(closure),为什么要用它?

1.函数内再嵌套函数
2.内部函数可以引用外层的参数和变量
3.参数和变量不会被垃圾回收机制回收

new操作符具体干了什么呢?

​ 1、创建一个空对象

​ 2、将创建的对象的_proto_指向构造函数的prototype

​ 3、改变了this的指向

​ 4、返回了一个对象

function create(Con,...args) { const obj = {} obj._proto_ = Con.prototype coonst result = Con.apply(obj,args) return result instanceof object ? result : obj }

Ajax 是什么? 如何创建一个Ajax?

异步传输+js+xml

(1)创建XMLHttpRequest对象,也就是创建一个异步调用对象
(2)使用 XMLHttpRequest对象的open()和send()方法发送资源请求给服务器
(3)onreadystatechange函数,状态改变时发送数据回客户端,使用 XMLHttpRequest对象的responseText 或responseXML属性获得服务器的响应

//GET方法 var xhr= new XMLHttpRequest(); xhr.open("GET","url",true); //get请求,url请求地址,true代表异步 xhr.send(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4){ if (xhr.status == 200) { console.log(xhr.responseText); } } } //POST方法 var ajax = new XMLHttpRequest(); ajax.open("POST","url",true); ajax.setRequestHeader("Content-type","application/x-www-form-urlencoded"); ajax.send("name=zhangsan&age=18"); ajax.onreadystatechange = function(){ if(ajax.readyState == 4){ if (ajax.status == 200) { var json = JSON.parse(ajax.responseText); fn(json); }

常见的跨域方式有几种

jsonp、cors、代理服务器

function fn(resp) { console.log(resp) } function sendMsg() { tools.jsonp('http://localhost/day24-ajax-promise/02.php', 'fn', { id: 10 }) } /** jsonp跨域请求 * @param url 请求地址 * @param cb 回调函数名 * @param query 要携带的其他参数 */ jsonp: function (url, cb, query) { url += `?cb=${cb}` if (query) { for (var key in query) { url += `&${key}=${query[key]}` } } // 创建script标签 var script = document.createElement('script') script.src = url document.body.appendChild(script) document.body.removeChild(script) // 过河拆桥 }

AMD、CMD规范区别?

区别:

对于依赖的模块,AMD 是提前执行,CMD 是延迟执行。

AMD 推崇依赖前置,CMD 推崇依赖就近。

AMD提前执行(不管什么时候使用,首先加载在代码的头部)//特点:前期网络资源消耗大,后期平稳 代表作 require.js

.CMD按需执行: //特点:网络资源的消耗处于平缓的状态,随时都有可能在加载模块 代表作 sea.js

// AMD 默认推荐 define(['./a', './b'], function(a, b) { // 依赖必须一开始就写好 a.doSomething() // 此处略去 100 行 b.doSomething() // ... }) //引入模块 //按顺序引入的模块,在回调函数里面也可以按顺序接受 require(['要使用的模块路径/文件名不加后缀'],( 接受模块的返回 class类) =>{ new 接受模块的返回class类 }) // CMD define(function(require, exports, module) { var a = require('./a') a.doSomething() // 此处略去 100 行 var b = require('./b') // 依赖可以就近书写 b.doSomething() // ... })

CommonJS和es6的模块引入导出??

commonJS规范:

module.exports导出模块 require引入模块,使用 一般用于服务端

es6的模块化:

导出引入的方法一

//导出 export let A = 123; export function test(){ console.log('test') } export class hello { test(){ console.log('class') } } //引入 //默认方法 1.import {A,test,hello} from './class/lesson17' // 当引入的数目太多时(无需一一对应) import * as lesson from './class/lesson17' console.log(lesson.A)

导出引入的方法二

//导出 let A = 123; function test(){ console.log('test') } class hello { test(){ console.log('class') } } export default { A, test, hello } //引入 import Lesson from './class/lesson17' //调用 console.log(Lesson.A)

什么是前端路由,什么是后端路由

前端路由:根据配置好的路由映射表,不同的url相对应不同的模块

后端路由:根据不同的url地址,返回给前端不同的数据

正向代理和反向代理 **有问题,待完善

正向代理:用户请求自己的服务器,正向代理是在客户端的

反向代理:用户请求自己的服务器,自己的服务器取到别人服务器的数据返回 给用户,反向代理是在服务器端的,是一个虚拟的ip

nginx作为软件支持反向代理,也就是说nginx可以作为负载均衡器

在浏览器中输入url时,发生了什么

1.利用DNS域名解析系统进行域名解析,将域名解析成IP,根据ip地址找到对应的服务器
注:因为域名只是一个别名,计算机只认识ip,所以需要DNS解析一下 (有端口号识别端口号,否则进入默认端口:http的默认端口是80,https默认端口443)

2.TCP的三次握手,经过三次在客户端和服务器之间的传递报文,建立连接 (确认发起请求,打开接口,服务器确认返回请求,开始发送正式请求)
3.查找本地是否有缓存文件service work,有缓存加载缓存
4.发起http请求,请求入口文件,后端接受到相关请求信息,返回入口文件(入口文件index.html)
• 过程中如果碰到AJAX请求
• 1.后端会返回一个状态码为4,而且AJAX的状态码为200
• 2.接收到入口文件.
• 2.浏览器会对该响应码进行解码,渲染显示
4.解析入口文件,同时如果还有资源请求,继续发送http请求
5.过程中如果碰到css文件,js文件,需要去加载外部文件
• 1.加载css,渲染html结构
• 2.加载js
• 3.执行js逻辑,有ajax请求,再次去服务器请求数据(json文件)
• 4.通过数据刷新DOM
6.文件渲染完成(tcp的四次挥手,断开连接)

请介绍一下JS之事件节流,什么是JS的函数防抖?

​ 函数防抖是指 :对于在事件被触发n秒后再执行的回调,如果在这n秒内又重新被触发,则重新开始计时

​ 考虑一个情景,有一个按钮点击会触发网络请求,但是我们并不希望每次点击都会发起网络请求,而是当用户点击按钮一段时间后没有再次点击的情况才去发起网络请求,对于这种情况我们可以使用防抖。

//func是用户传入需要防抖的函数 //wait是等待时间 const debounce = (func,wait= 5000 ) =>{ let timer = 0 return function () if (timer) clearTimeout(timer) timer = setTimeout (func,wait) } //传入了一个防抖函数,默认timer为0,当5s后,启动定时器执行回调函数,在此期间如果再次触发事件,if (timer) clearTimeout(timer)的作用就是先覆盖之前的,重新再次调用定时器。

​ 函数的节流是指: 对于持续触发的事件,规定一个间隔时间(n秒),每隔一段只能执行一次。

//func是用户传入需要防抖的函数 //wait是等待时间 const throttle = (func,wait = 50) =>{ let lastTime = 0 return function(){ let now = Date.now() if (now - lastTime > wait){ lastTime = now func.apply(this) } } } setInterval( throttle(()=>{ console.log(1) },5000) ) //这里的思想是利用事件戳的判断上次执行函数的时间戳和这个触发函数的时间是否在规定的时间以外,符合条件,则执行函数

git是什么–作用–常见命令–多人协作流程

16.1 配置用户名和邮箱

​ (1) 配置身份,设置用户名与邮箱

git config --global user.name "username" git config --global user.email "your email"

​ (2) 查看配置的用户名和邮箱

git config --global user.name git config --global user.email

16.2 创建代码仓库 git init

16.3 代码添加到暂存存 git add -A

16.4 将暂存区的代码提交到本地仓库 git commit -m ‘说明这一次提交的事情’

16.5 将本地仓库的代码push到线上仓库 git push origin master 或 git push

16.6 回溯到指定版本 :git reset --hard 版本号前7位

16.7 查看版本记录包括回溯的版本: git reflog

16.8 查看当前版本的分支 : git branch -a

16.9 创建一个新的分支 : git branch 分支名

16.10 切换分支: git checkout 分支名

16.11 合并分支内容: git merge 要合并的分支名

16.12 删除分支 : git branch -D 删除的分支名

16.13 从远程克隆时(git clone 地址),只能克隆主分支。除非加上 - b 分支名(git clone -b dev 地址)

16.14 当进行切换分支时,你的本地代码也会相应的进行切换

16.15 如果在分支A上进行了更改,然后却没有提交,那么在切换到分支B上时,会和分支B进行合并!

16.16 创建一个分支后,要提交的话,必须对现有内容进行修改才行

16.17 将本地创建的分支同时线上仓库建立自己的分支 git push --set-upstream origin lx

git团队开发流程

组长在代码管理平台创建远程仓库,将构建的环境push到master分支上 然后组长远程基于master创建dev开发分支,(master代表生产分支) 组长在远程将组员拉入阻止与项目仓库中,并设置对应的权限 所有成员(组长、组员)将远程的代码克隆到本地仓库 git clone 所有组员在本地分支切换至dev分支,然后基于dev创建自己的分支,然后切换自己分支 git checkout dev git branch lx git checkout lx 所有成员在自己的分支dev lx上开发,开发完成之后 将自己的代码上传到远程仓库,同时将自己本地的分支和远程仓库分支同步 git add -A git commit -m ‘干了什么’ git push --set-upstream origin lx 开始pull远程dev分支最新内容到本地(如果有冲突就解决冲突) 所有成员将更改的内容合并到的开发分支上,然后上传代码 git merge lx git add -A git commit -m ‘干了什么’ git push 开发完成,组长将开发分支的更改合并到生产分支,发布生产代码。

js的单线程 event loop 事件轮回机制

因为js是单线程的,如果多个线程操作DOM,会造成页面的混乱,当js引擎执行js代码的时候,所有的同步任务按顺序都会在主线程上执行,形成一个执行栈,当碰到异步任务时候,将定时器放入定时器所在的异步线程,ajax请求放入异步http请求线程,浏览器事件放入事件触发线程,当同步任务结束后,js的主线程空闲下来,再去执行异步线程中的代码。例如定时器属于宏任务,peomise、http请求属于微任务,同步代码先执行,微任务大于宏任务,微任务会先执行(栈),宏任务后执行(队列) 这也是有时候造成定时器,时间不准的原因。

浏览器的运行原理

浏览器的内核分为 GUI渲染线程、js引擎线程、事件触发线程、定时器触发线程、异步http请求线程

浏览器内核渲染的流程分为5步

(1) 处理html并构建DOM树

(2) 处理css构建cssDOM树

(3) 将DOM树和cssDOM树合并为一个渲染树

(4) 根据渲染树来布局,计算每个节点的位置

(5) 调用GPU绘制,合成图层,显示在屏幕上

(6) 之后就是执行js代码

常见的web攻击,预防的方法

XSS——跨站脚本攻击

原理:往 Web 页面里插入恶意可执行网页脚本代码,当用户浏览该网页之时,嵌入其中 Web 里面的脚本代码会被执行。

防御:

​ (1) Web 页面渲染的所有内容或者渲染的数据都必须来自于服务端,尽量不要直接渲染客户端参数【后端】

​ (2) 如果真要渲染请将常用的恶意代码中的[,”,&]等符号都用[,",&]字符进行转译。当这些html标签符号被转译后,浏览器就会拿它当作一个普通字符串对待

CSRF——跨站请求伪造攻击

原理:攻击者可以盗用你的登陆信息,以你的身份模拟发送各种请求。

防御:

​ (1) 在请求地址/ HTTP 头中中添加 token 并验证

​ (2) 验证 HTTP Referer 字段;

​ 根据 HTTP 协议,在 HTTP 头中有一个字段叫Referer,它记录了该 HTTP 请求的来源地址。

​ 我们可以在后端判断此header字段的值,如果不是来源于我们指定的网站,那我 们就认为可能是黑客的 CSRF 攻击,拒绝该请求。

SQL——注入攻击

原理:可以用它来从数据库获取敏感信息

​ (1) Web 开发者没有意识到 SQL 查询是可以被篡改的,从而把 SQL 查询当作可信任的命令

​ (2) 程序没有有效的转义过滤用户的输入,使攻击者成功的向服务器提交恶意的 SQL 查询代码

防御:对用户的输入进行转义 或者 直接在后端使用预编译的方式

webpack和gulp的区别

Gulp的关注点主要在于流程的自动化,而webpack的关注点这主要在于实现模块化开发。

webpack的4个核心模块

webpack4和webpack3的区别 :webpack4实现了0配置

(1) 入口(entry)

​ 入口起点(entry point)指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始,webpack 会找出有哪些模块和 library 是入口起点(直接和间接)依赖的。

​ 默认值是 ./src/index.js,然而,可以通过在 webpack 配置中配置 entry 属性,来指定一个不同的入口起点(或者也可以指定多个入口起点)。

(2) 输出(output)

output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件,主输出文件默认为 ./dist/main.js,其他生成文件的默认输出目录是 ./dist。

(3) 模块加载器Loader (module)

​ 作为开箱即用的自带特性,webpack 自身只支持 JavaScript。而模块加载器Loader 能够让 webpack 处理那些非 JavaScript 文件,并且先将它们转换为有效 模块,然后添加到依赖图中,这样就可以提供给应用程序使用。 例如css

(4) 插件(plugins)

​ loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务,插件的范围包括:打包优化、资源管理和注入环境变量。

(5) 打包模式

​ 通过将 mode 参数设置为 development, production 或 none,可以启用对应环境下 webpack 内置的优化。默认值为 production

(6) 浏览器兼容

​ webpack可以兼容到 IE8

gulp常见的api

(1) gulp.src() 创建一个流,用于在文件系统读取文件

(2)gulp.watch() 监听文件发生变化时,执行的任务

(3) gulp.task() 制定要执行的任务

(4) gulp.dest() 文件输出到目录

(5) pipe() 管道,流向哪里

关于登陆说下session鉴权和token鉴权两种方式

(1)session鉴权

​ 原理和流程:

​ 当用户登录成功后,后端会生成一个session对象,并产生一个sessionId标识这个对象。然后会把这个sessionId返回给前端,存储在前端浏览器cookie中,从此这个sessionId就代表用户的这个身份了。

​ 当用户在登录后要发起任何操作,都会自动的带上这个sessiId向服务端表明自己的身份,服务收到这个sessionId后回去寻找到对应的session对象,如果找到了就表示身份验证通过,否在就不通过。

​ 然后如果用户不登录直接发起查询操作去请求数据,那么由于没有后端颁发的sessionId,直接就会被后端拒绝验证。

(2) token鉴权

​ 基于Token的身份验证流程

​ 1. 客户端使用用户名和密码请求登录

​ 2. 服务端收到请求,验证登录是否成功

​ 3. 验证成功后,服务端会返回一个Token给客户端,反之,返回身份验证失败的信息

​ 4. 客户端收到Token后把Token用一种方式存储起来,如(headers/ cookie / localstorage / sessionstorage / 其他 )

​ 5. 客户端每次发起请求时都会将Token发给服务端

6. 服务端收到请求后,验证Token的合法性,合法就返回客户端所需数据,反之,返回验证失败的信息 **token**生成的方法:生成Token的解决方案有许多,目前主流使用的为 Json Web Tokens 算法. JWT标准的Tokens由三部分组成 1. header:包含token的类型和加密算法 2. payload:包含token的内容 3. signature:通过密钥将前两者加密得到最终的token

微信支付等的流程逻辑

常见的深拷贝的方法,以及缺陷

JSON.parse ( JSON.stringify ( object ) )

​ 缺陷:会忽略undefined、函数、symbol、

使用递归的方式 Immutable 不仅能够做深拷贝的性能优化,还能在react,redux中做性能优化(有人说 Immutable 可以给 React 应用带来数十倍的提升,也有人说 Immutable 的引入是近期 JavaScript 中伟大的发明)

浏览器的离线缓存有几种方法

传统技术–cookie

h5新增的离线缓存

(1) localstroage --缓存数据

(2) Application Catch – 缓存文件 minifest文件中配置缓存文件

(3) service Worker --可以在基于浏览器的 web 应用中实现如离线缓存、消息推送、静默更新等 native 应用常见的功能

PWA应用就是基于service Worker为核心的渐进式Web应用

优化页面性能的方式有哪些

图片优化,使用精灵图,小图使用base64格式,尽量少用图片,用css去代替 。 懒加载 使用CDN 分布机房缓存数据 减少Http请求 利用DNS预解析 利用浏览器进行缓存 css放前面,js放后面 使用工具压缩代码
作者:lx_lucky



面试题 面试 前端 前端开发

需要 登录 后方可回复, 如果你还没有账号请 注册新账号