前端高频面试题(15K级别),Web前端驱动面试

8.JavaScript 中 console 有哪些 api ?


console.clear()

console.log()

console.info()

console.warn()

console.error()

console.time()

console.timeEnd()

9.简单对比一下 Callback、Promise、Generator、Async 几个异步 API 的优劣?


  • 首先callback不是异步API,它是早年JS异步编程实现的一种手段。

  • Promise是社区为了解决回调地狱的问题在ES6版本提出的一种解决方案;

  • enerator也是一种异步编程解决方案,它最大的特点就是可以交出函数的执行权,Generator 函数可以看出是异步任务的容器,需要暂停的地方,都用 yield 语法来标注;

  • Async/await是 ES7 中提出的新的异步解决方案,async 是 Generator 函数的语法糖,async/await 的优点是代码清晰(不像使用 Promise 的时候需要写很多 then 的方法链)。async/await 不仅仅是 JS 的异步编程的一种方式,其可读性也接近于同步代码,让人更容易理解。

10.Object.defineProperty 有哪几个参数?各自都有什么作用?


Object.defineProperty(object, propertyname, descriptor)

  • object 必需。要在其上添加或修改属性的对象。这可能是一个本机 JavaScript对象(即用户定义的对象或内置对象)或 DOM 对象。

  • propertyname 必需。一个包含属性名称的字符串。

  • descriptor 必需。属性描述符。它可以针对数据属性或访问器属性。

它内部的descriptor参数如下:

  • value

属性的值,默认为 undefined。

  • writable

该属性是否可写,如果设置成 false,则任何对该属性改写的操作都无效(但不会报错),对于像前面例子中直接在对象上定义的属性,这个属性该特性默认值为为 true。

  • configurable

如果为false,则任何尝试删除目标属性或修改属性以下特性(writable, configurable, enumerable)的行为将被无效化,对于像前面例子中直接在对象上定义的属性,这个属性该特性默认值为为 true。。

  • enumerable

是否能在for-in循环中遍历出来或在Object.keys中列举出来。对于像前面例子中直接在对象上定义的属性,这个属性该特性默认值为为 true。

  • get

一旦目标对象访问该属性,就会调用这个方法,并返回结果。默认为 undefined。

  • set

一旦目标对象设置该属性,就会调用这个方法。默认为 undefined。

11.Object.defineProperty 和 ES6 的 Proxy 有什么区别?


Proxy的优势如下

  • Proxy可以直接监听整个对象而非属性。

  • Proxy可以直接监听数组的变化。

  • Proxy有13中拦截方法,如ownKeys、deleteProperty、has 等是 Object.defineProperty 不具备的。

  • Proxy返回的是一个新对象,我们可以只操作新的对象达到目的,而Object.defineProperty只能遍历对象属性直接修改;

  • Proxy做为新标准将受到浏览器产商重点持续的性能优化,也就是传说中的新标准的性能红利。

Object.defineProperty 的优势如下

  • 兼容性好,支持 IE9,而 Proxy 的存在浏览器兼容性问题,而且无法用 polyfill 磨平。

Object.defineProperty 不足在于:

  • Object.defineProperty 只能劫持对象的属性,因此我们需要对每个对象的每个属性进行遍历。

  • Object.defineProperty不能监听数组。是通过重写数据的那7个可以改变数据的方法来对数组进行监听的。

  • Object.defineProperty 也不能对 es6 新产生的 Map,Set 这些数据结构做出监听。

  • Object.defineProperty也不能监听新增和删除操作,通过 Vue.set()和 Vue.delete来实现响应式的。

12.为什么要使用 TypeScript ? TypeScript 相对于 JavaScript 的优势是什么?


首先,不一定非要用TS,大型业务产品、多人协作写大堆的业务代码不适合TS。

1.为JavaScript、IDE和实践(如静态检查)提供了高效的开发工具。(主要)

2.其他的比如强大的类型系统,泛型支持、模块支持等等(次要)

13.Vue 2.x 模板中的指令是如何解析实现的?


指令本质上就是一个 JavaScript 对象,对象上挂着一些钩子函数,无论是官方提供的指令,还是自定义指令,一个指令从第一次被绑定到元素上到最终与被绑定的元素解绑,它会经过以下几种状态:

  • bind:只调用一次,指令第一次绑定到元素时调用。在这里可以进行一次性的初始化设置。

  • inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

  • update:所在组件的 VNode 更新时调用,但是可能发生在其子 VNode 更新之前。

  • componentUpdated:指令所在组件的 VNode 及其子 VNode 全部更新后调用。

  • unbind:只调用一次,指令与元素解绑时调用。

了每个状态的钩子函数,这样我们就可以让指令在不同状态下做不同的事情。当虚拟DOM渲染更新的时候会触发create、update、destory这三个钩子函数,从而就会执行updateDirectives函数来处理指令的相关逻辑,执行指令函数,让指令生效。

14.简要说明 Vue 2.x 的全链路运作机制?


  • 初始化以及挂载init, mount

  • 在进行模板编译compile,将template编译为渲染函数render function

  • 执行render function生成Virtual DOM, render function => VNode tree

  • 再进行响应式依赖收集,render function => getter, setter => Watcher.update => patch。以及使用队列进行异步更新的策略。

  • 最后通过diff算法后进行patch更新视图

15.如何理解 Vue 是一个渐进式框架?


渐进式代表的含义是:没有多做职责之外的事。

你可以使用jsx开发,你也可以写template;你可以使用vue全家桶,你也可以把它做为某个业务的轻量视图,随你,不强求不主张。

16.Vue 里实现跨组件通信的方式有哪些?


  • 父子通信:

父向子传递数据是通过 props,子向父是通过 events(emit);通过父链/子链也可以通信(emit);通过父链 / 子链也可以通信(emit);通过父链/子链也可以通信(parent / children);ref也可以访问组件实例;provide/injectAPI;children);ref 也可以访问组件实例;provide / inject API;children);ref也可以访问组件实例;provide/injectAPI;attrs/$listeners

  • 兄弟通信:

Bus;Vuex

  • 跨级通信:

Bus;Vuex;provide / inject API、attrs/attrs/attrs/listeners

17.Vue 中响应式数据是如何做到对某个对象的深层次属性的监听的?


使用watch并且搭配deep:true 就可以实现对对象的深度监听

18.MVVM、MVC 和 MVP 的区别是什么?各自有什么应用场景?


MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式。

  • 耦合性低

  • 重用性高

  • 生命周期成本低

MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。

  • 模型与视图完全分离,我们可以修改视图而不影响模型

  • 可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部

  • 我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁。

  • 如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)

MVVM 本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。

  • 低耦合

  • 可重用性

  • 独立开发

  • 可测试

19.什么是 MVVM 框架?


MVVM,特点是采用双向绑定(data-binding): View的 变动,自动反映在View Model,反之亦然。这样开发者就不用处理接收事件和View更新的工作,框架已经帮你做好了。

20.Vue CLI 3.x 有哪些功能?Vue CLI 3.x 的插件系统了解?


插件系统是给vue项目提供可选功能的npm包,如:Babel/TypeScript 转译、ESLint 集成、unit和 e2e测试 等

21.Vue CLI 3.x 中的 Webpack 是如何组装处理的?


对比vue-cli2,cli3 最主要的就是生成的项目中,进行webpack配置的文件没有了。cli3的脚手架封装了webpack绝大部分配置,使得生成的项目更加清晰,但是在开发中免不了会有自己的个性需求,来添加一些自己的项目配置,此时只需在项目的根目录下新建一个vue.config.js文件即可。而webpack中是通过 resolve.alias 来实现此功能的。在vue.config.js中修改webpack的配置,可以通过configureWebpack方法。

22.Vue 2.x 如何支持 TypeScript 语法?


  • 配置ts-loader,tsconfig

  • 增加类型扩展,让ts识别vue文件

  • vue文件中script里面换成ts写法, 需要增加几个ts扩展的package, 比如vue-property-decorator

23.Webpack 中 Loader 和 Plugin 的区别是什么?


在webpack中 Loader 就是负责完成项目中各种各样资源模块的加载,从而实现整体项目的模块化,而 Plugin 则是用来解决项目中除了资源模块打包以外的其他自动化工作,对比 Loader 只是在模块的加载环节工作,而插件的作用范围几乎可以触及 Webpack 工作的每一个环节。

24.如何发布开发项目的特定文件夹为 Npm 包的根目录?


一般情况下,npm包的根目录时node_modules,可以使用package.json的directories属性里的directories.lib,更改 Npm 包的根目录。

25.Npm 包中 peerDependencies 的作用是什么?


peerDependencies的目的是提示宿主环境去安装满足插件peerDependencies所指定依赖的包,然后在插件import或者require所依赖的包的时候,永远都是引用宿主环境统一安装的npm包,最终解决插件与所依赖包不一致的问题。

26.如何优雅的调试需要发布的 Npm 包?


  • 在需要调试的npm包目录下结构下的控制台输入npm link 这个命令会把当前包映射到本地的一个全局的npm包里面;

  • 在引用的目录结构下的控制台输入 npm link 包名称 这个命令会把本地引用的这个npm包的路径定位到全局的npm包下;

  • 全局的npm包相当于一个中转站,在编辑区域与引用区域之间中转。

27.了解 Git (Submodule)子模块吗?简单介绍一下 Git 子模块的作用?


子模块是进行开发和需求进行对接将需求文档作为子模块项目,嵌入开发人员的项目中。子模块的使用既可以减少需求或设计人员的git操作,又可以及时的将doc文档发布到项目的目录文件下,而且不会对开发人员的项目产生任何影响。

28.Git 如何修改已经提交的 Commit 信息?


  • git rebase -i <commit id> 列出 commit 列表

  • 找到需要修改的 commit 记录,把 pick 修改为 edit 或 e,:wq 保存退出

  • 修改 commit 的具体信息git commit --amend,保存并继续下一条git rebase --continue,直到全部完成

  • 中间也可跳过或退出git rebase (–skip | --abort)

29.Git 如何撤销 Commit 并保存之前的修改?


  • 查看commit git log --pretty=oneline

  • 撤销到上一个commit,但是保存当前的修改。git reset --soft <commit>

  • 修改成功。重建分支,进行提交。

30.Git 如何 ignore 被 commit 过的文件?


  • 删除 track 的文件 (已经 commit 的文件)

  • 在 .gitignore 文件中添加忽略规则

在 .gitignore 文件中添加 ignore 条目, 如: .DS_Store 提交 .gitignore 文件: git commit -a -m “添加ignore规则”

  • 推送到远程仓库让 ignore 规则对于其他开发者也能生效

31.在使用 Git 的时候如何规范 Git 的提交说明(Commit 信息)?


用Commitizen,Commitizen 是一个撰写符合上面 Commit Message 标准的一款工具。在push操作时检查commit的信息,使用正则检查是否匹配(比如使用angular的git规范),不符合的不允许Push。

32.ESLint 和 Prettier 的区别是什么?两者在一起工作时会产生问题吗?


这俩解决的不是一个问题,ESLint 主要解决的是代码质量问题;Prettier主要解决的是代码风格问题。两者在一起会产生问题。

33.如何调试 Node.js 代码?如何调试 Node.js TypeScript 代码?在浏览器中如何调试 Node.js 代码?


从nodejs8开始,node去掉了_debugger , 内部集成了inspect , 以往使用node-inspect实现的在线调试不再可用.node8开始要用新方法了。

  • 在服务端用inspect模式运行nodejs

node --inspect-brk=0.0.0.0:8080 index.js

  • 打开chrome浏览器 地址栏输入chrome://inspect,在弹出的界面中输入ip:port即可调试。

34.CDN 服务如何实现网络加速?


CDN的工作原理就是将您源站的资源缓存到位于全球各地的CDN节点上,用户请求资源时,就近返回节点上缓存的资源,而不需要每个用户的请求都回您的源站获取,避免网络拥塞、缓解源站压力,保证用户访问资源的速度和体验。

35.WebSocket 使用的是 TCP 还是 UDP 协议?


是基于TCP的,websocket的协议是在TCP/IP协议簇的应用层,和http在同一层。

36.什么是单工、半双工和全双工通信?


  • 单工数据传输只支持数据在一个方向上传输;

  • 半双工数据传输允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;

  • 全双工数据通信允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。

37.简单描述 HTTP 协议发送一个带域名的 URL 请求的协议传输过程?(DNS、TCP、IP、链路)


38.输入地址回车后


  • 浏览器通过请求得到一个HTML文本

  • 渲染进程解析HTML文本,构建DOM树

  • 解析HTML的同时,如果遇到内联样式或者样式脚本,则下载并构建样式规则(stytle rules),若遇到JavaScript脚本,则会下载执行脚本。

  • DOM树和样式规则构建完成之后,渲染进程将两者合并成渲染树(render tree)

  • 渲染进程开始对渲染树进行布局,生成布局树(layout tree)

  • 渲染进程对布局树进行绘制,生成绘制记录

  • 渲染进程的对布局树进行分层,分别栅格化每一层,并得到合成帧

  • 渲染进程将合成帧信息发送给GPU进程显示到页面中

39.Cookie 可以在服务端生成吗?Cookie 在服务端生成后的工作流程是什么样的?


可以。HTTP 协议中的 Cookie 包括 Web Cookie 和浏览器 Cookie,它是服务器发送到 Web 浏览器的一小块数据。服务器发送到浏览器的 Cookie,浏览器会进行存储,并与下一个请求一起发送到服务器。通常,它用于判断两个请求是否来自于同一个浏览器,例如用户保持登录状态。

40.Session、Cookie 的区别和关联?如何进行临时性和永久性的 Session 存储?


  • Session

客户端请求服务端,服务端会为这次请求开辟一块内存空间,这个对象便是 Session 对象,存储结构为 ConcurrentHashMap。Session 弥补了 HTTP 无状态特性,服务器可以利用 Session 存储客户端在同一个会话期间的一些操作记录。

  • Cookies

HTTP 协议中的 Cookie 包括 Web Cookie 和浏览器 Cookie,它是服务器发送到 Web 浏览器的一小块数据。服务器发送到浏览器的 Cookie,浏览器会进行存储,并与下一个请求一起发送到服务器。通常,它用于判断两个请求是否来自于同一个浏览器,例如用户保持登录状态。

服务器端session,如果你不指定session的存储时间,在你打开的浏览器中存储的值,是可以在新打开的框口内得到的,关闭后就自动消失(消失的其实是session_id,因为session的机制是依赖于cookie的(还可以依赖其他的)。

41.设置 Cookie 时候如何防止 XSS 攻击?


在服务器端设置cookie的时候设置 http-only, 这样就可以防止用户通过JS获取cookie。对cookie的读写或发送一般有如下字段进行设置:

  • http-only: 只允许http或https请求读取cookie、JS代码是无法读取cookie的(document.cookie会显示http-only的cookie项被自动过滤掉)。发送请求时自动发送cookie.

  • secure-only: 只允许https请求读取,发送请求时自动发送cookie。

  • host-only: 只允许主机域名与domain设置完成一致的网站才能访问该cookie。

设置Cookie,可以防止攻击者拿到正常用户的Cookie冒充身份非法调用网站接口。

42.简单描述一下用户免登陆的实现过程?可能会出现哪些安全性问题?一般如何对用户登录的密码进行加密?


在用户第一次登录成功的时候,后端会返回一个 Token,这个值Token 主要的作用就是用于识别用户的身份。相当于账号密码。正常情况下,前端给后端发送请求的时候,后端都需要先判断用户的身份,来返回相应的数据给用户。获取到Token后,你需要把 Token 存在 Cookie中。接着向服务器发送请求时,你从 Cookie 中取出 Token,在请求头中携带上 Token 。Token过期时间设置足够长,只要token没过期,这段时间用户都是免登录。

安全问题:其他人使用本机,实现免登录,无法在每次使用应用时验证用户的身份。提供了便捷,失去了安全校验。

对用户登录的密码进行加密,密码MD5化,不使用明文传输。

43.HTTP 中提升传输速率的方式有哪些?常用的内容编码方式有哪些?


  • 使用压缩技术把实体主体压小,在客户端再把数据解析。

  • 使用分块传输编码,将实体主体分块传输,当浏览器解析到实体主体就能够显示了。

常用的内容编码方式:

  • 非归零码

  • 曼彻斯特编码

  • 差分曼彻斯特编码

44.传输图片的过程中如果突然中断,如何在恢复后从之前的中断中恢复传输?


文件的断点续传,

前端工作

  • 为每一个文件切割块添加不同的标识

  • 当上传成功的之后,记录上传成功的标识

  • 当我们暂停或者发送失败后,可以重新发送没有上传成功的切割文件

后端工作

  • 接收每一个切割文件,并在接收成功后,存到指定位置,并告诉前端接收成功

  • 收到合并信号,将所有的切割文件排序,合并,生成最终的大文件,然后删除切割小文件,并告知前端大文件的地址

45.什么是代理?什么是网关?代理和网关的作用是什么?


代理是中间人,使用代理的主机发出的IP报文的目的IP是代理的,但是会在应用层里明确告诉代理,自己真实需求是什么。网关即Gateway,它是连接基于不同通信协议的网络的设备,使文件可以在这些网络之间传输。

46.HTTPS 相比 HTTP 为什么更加安全可靠?


因为 HTTPS 保证了传输安全,防止传输过程被监听、防止数据被窃取,可以确认网站的真实性(具体细节二面再说)。不过需要注意的是,即便使用 HTTPS 仍可能会被抓包,因为HTTPS 只防止用户在不知情的情况下通信被监听,如果用户主动授信,是可以构建“中间人”网络,代理软件可以对传输内容进行解密。

47.什么是对称密钥(共享密钥)加密?什么是非对称密钥(公开密钥)加密?哪个更加安全?


传统的对称式加密需要通讯双方都保存同一份密钥,通过这份密钥进行加密和解密。所以非对称加密也称为单密钥加密。在非对称加密中,加密和解密使用的是不同的密钥。非对称加密中的密钥分为公钥和私钥。公钥顾名思义就是公开的,任何人都可以通过公钥进行信息加密,但是只有用户私钥的人才能完成信息解密。非对称加密带来了一个好处,避免了对称式加密需要传输和保存同一份密钥的痛苦。

非对称加密一定比对称加密机密性更高吗? 不一定, 因为机密性高低是根据秘钥长度而变化的。而且非对称加密最大的问题,就是性能较差,无法应用于长期的通信。

48.你觉得 HTTP 协议目前存在哪些缺点?


HTTP不具备必要的安全功能,与最初的设计相比,现今的Web网站应用的HTTP协议的使用方式已发生了翻天覆地的变化。几乎现今所有的Web网站都会使用会话(session)管理、加密处理等安全性方面的功能,而HTTP协议内并不具备这些功能。

从整体上看,HTTP就是一个通用的单纯协议机制。因此它具备较多优势,但是在安全性方面则呈劣势。就拿远程登录时会用到的SSH协议来说,SSH具备协议级别的认证及会话管理等功能,HTTP协议则没有。另外在架设SSH服务方面,任何人都可以轻易地创建安全等级高的服务,而HTTP即使已架设好服务器,但若想提供服务器基础上的Web应用,很多情况下都需要重新开发。

因此,开发者需要自行设计并开发认证及会话管理功能来满足Web应用的安全。而自行设计就意味着会出现各种形形色色的实现。结果,安全等级并不完备,可仍在运作的Web应用背后却隐藏着各种容易被攻击者滥用的安全漏洞的Bug。

49.Webpack 中的插件机制是如何设计的?


Webpack 插件机制的目的是为了增强 Webpack 在项目自动化构建方面的能力。在webpack中 Loader 就是负责完成项目中各种各样资源模块的加载,从而实现整体项目的模块化,而 Plugin 则是用来解决项目中除了资源模块打包以外的其他自动化工作,对比 Loader 只是在模块的加载环节工作,而插件的作用范围几乎可以触及 Webpack 工作的每一个环节。

Webpack 的插件机制就是我们在软件开发中最常见的钩子机制。钩子机制也特别容易理解,它有点类似于 Web 中的事件。在 Webpack 整个工作过程会有很多环节,为了便于插件的扩展,Webpack 几乎在每一个环节都埋下了一个钩子。这样我们在开发插件的时候,通过往这些不同节点上挂载不同的任务,就可以轻松扩展 Webpack 的能力。

50.如何提升 Node.js 代码的运行稳定性?


  • 保障进程安全

由于一个用户的异常访问或者数据异常,加上没有做好异常处理和安全保护,直接导致了整个 Node.js 服务重启了,从而中断了所有人的请求,用户体验非常差。①由于 Node.js 使用的是 JavaScript,而JavaScript 是一个弱类型语言,因此在现网经常会引发一些由代码逻辑的异常导致的进程异常退出。②其次在 Node.js 中也经常会因为内存的使用不当,导致内存泄漏,当在 64 位系统中达到 1.4 G(32 位系统 0.7 G)时,Node.js 就会异常崩溃。③再而由于Node.js 的 I/O 较多也较为频繁,当启用较多 I/O 句柄,但是没有及时释放,同样会引发进程问题。

  • parameters error

关于 JSON.parse 很多时候我们都比较自然地将其他接口或者第三方的数据拿来解析,但是这里往往会忽略其非 JSON 字符串的问题,在这里需要进行try catch 异常判断。

  • other errors

当前 Node.js 的 Promise 应用越来越广泛了,因此对于 Promise 的 catch 也应该多进行重视,对于每个 Promise 都应该要处理其异常 catch 逻辑,不然系统会提示 warning 信息。还有一些常见的长连接的服务,比如 Socket、Redis、Memcache 等等,我们需要在连接异常时进行处理,如果没有处理同样会导致异常,比如 Socket 提供了 Socket.on(‘error’) 的监听。

  • 注意服务异常方面的内存泄露

设置最大临时缓存数,超出则不使用缓存;设置最大缓存句柄数,超出则不使用缓存;定时清理当前的临时缓存和句柄缓存。

  • 避免全局变量

一般情况下不建议使用全局变量,全局变量必须要有一定的上限和清理规则才能保证服务的安全。

  • 避免单例模块中的变量内存泄漏

要注意一个点,有些模块我们使用单例的模式,就是在每次 require 后都返回这个对象,这种情况也比较容易引发内存泄漏的问题。因为单例模式会引发每个用户访问的数据的叠加。

  • 主动关闭打开文件后未关闭的情况

一般打开文件句柄后,我们都应该主动关闭,如果未主动关闭,就会导致文件句柄越来越多,从而引发句柄泄漏问题。

51.Vue SSR 的工作原理?Vuex 的数据如何同构渲染?


在Vue SSR中,创建Vue实例、创建store和创建router都是套了一层工厂函数的,目的就是避免数据的交叉污染。在服务端只能执行生命周期中的created和beforeCreate,原因是在服务端是无法操纵dom。服务端渲染和客户端渲染不同,需要创建两个entry分别跑在服务端和客户端,并且需要webpack对其分别打包;SSR服务端请求不带cookie,需要手动拿到浏览器的cookie传给服务端的请求。SSR要求dom结构规范,因为浏览器会自动给HTML添加一些结构比如tbody,但是客户端进行混淆服务端放回的HTML时,不会添加这些标签,导致混淆后的HTML和浏览器渲染的HTML不匹配。

对于同构应用来说,我们必须实现客户端与服务端的路由、模型组件、数据模型的共享。Vuex是实现我们客户端和服务端的状态共享的关键,我们可以不使用vuex,但是我们得去实现一套数据预取的逻辑;可以尝试封装一个可以给组件们共享的EventBus,在main.js中export出我们的EventBus以便两个entry使用,接下来是我们的两个entry了。server用来匹配我们的组件并调用组件的asyncData方法去获取数据,client用来将预渲染的数据存储到我们eventBus中的data中。这样就相当于实现类Vuex的功能。

52.SSR 技术和 SPA 技术的各自的优缺点是什么?


SSR:

  • 更利于SEO。

  • 更利于首屏渲染

  • 服务端压力较大

SPA:

  • 页面之间的切换非常快

  • 一定程度上减少了后端服务器的压力(不用管页面逻辑和渲染)

  • 后端程序只需要提供API,完全不用管客户端到底是Web界面还是手机等

  • 不利于SEO

  • 首屏加载压力大

53.什么是单点登录?如何做单点登录?


单点登录是指在同一帐号平台下的多个应用系统中,用户只需登录一次,就可访问所有相互信任的应用系统。比如你在网页中登录了百度云盘,随后你再去贴吧发帖 是不需要二次登录的。

单点登录的本质就是在多个应用系统中共享登录状态。如果用户的登录状态是记录在 Session 中的,要实现共享登录状态,就要先共享 Session,比如可以将 Session 序列化到 Redis 中,让多个应用系统共享同一个 Redis,直接读取 Redis 来获取 Session。

因为不同的应用系统有着不同的域名,尽管 Session 共享了,但是一个企业不同应用的域名不同,依然可能出现跨站or跨域。

前端方面的实现方式:

  • 父域 Cookie

  • 认证中心

  • LocalStorage 跨域

手写

=================================================================

01.数组扁平化


const arr = [1, [2, [3, [4, 5]]], 6];

方法一:使用flat()

const res1 = arr.flat(Infinity);

方法二:使用reduce

const flatten = arr => {

return arr.reduce((pre, cur) => {

return pre.concat(Array.isArray(cur) ? flatten(cur) : cur);

}, [])

}

const res4 = flatten(arr);

方法五:函数递归

const res5 = [];

const fn = arr => {

for (let i = 0; i < arr.length; i++) {

if (Array.isArray(arr[i])) {

fn(arr[i]);

} else {

res5.push(arr[i]);

}

}

}

fn(arr);

02.数组去重


const arr = [1, 1, '1', 17, true, true, false, false, 'true', 'a', {}, {}];

方法一:利用Set

const res1 = Array.from(**new** Set(arr));

方法二:两层for循环+splice

const unique1 = arr => {

let len = arr.length;

for (let i = 0; i < len; i++) {

for (let j = i + 1; j < len; j++) {

if (arr[i] === arr[j]) {

arr.splice(j, 1);

// 每删除一个树,j–保证j的值经过自加后不变。同时,len–,减少循环次数提升性能

len–;

j–;

}

}

}

return arr;

}

方法三:利用indexOf

const unique2 = arr => {

const res = [];

for (let i = 0; i < arr.length; i++) {

if (res.indexOf(arr[i]) === -1) res.push(arr[i]);

}

return res;

}

复制代码

当然也可以用include、filter,思路大同小异。

方法四:利用include

const unique3 = arr => {

const res = [];

for (let i = 0; i < arr.length; i++) {

if (!res.includes(arr[i])) res.push(arr[i]);

}

return res;

}

复制代码

方法五:利用filter

const unique4 = arr => {

return arr.filter((item, index) => {

return arr.indexOf(item) === index;

});

}

复制代码

方法六:利用Map

const unique5 = arr => {

const map = new Map();

const res = [];

for (let i = 0; i < arr.length; i++) {

if (!map.has(arr[i])) {

map.set(arr[i], true)

res.push(arr[i]);

}

}

return res;

}

03.类数组转化为数组


类数组是具有length属性,但不具有数组原型上的方法。常见的类数组有arguments、DOM操作方法返回的结果。

方法一:Array.from

Array.from(document.querySelectorAll(‘div’))

方法二:Array.prototype.slice.call()

Array.prototype.slice.call(document.querySelectorAll(‘div’))

方法三:扩展运算符

[…document.querySelectorAll(‘div’)]

方法四:利用concat

Array.prototype.concat.apply([], document.querySelectorAll(‘div’));

04.Array.prototype.filter()


img

Array.prototype.filter = function(callback, thisArg) {

if (this == undefined) {

throw new TypeError(‘this is null or not undefined’);

}

if (typeof callback !== ‘function’) {

throw new TypeError(callback + ‘is not a function’);

}

const res = [];

// 让O成为回调函数的对象传递(强制转换对象)

const O = Object(this);

// >>>0 保证len为number,且为正整数

const len = O.length >>> 0;

for (let i = 0; i < len; i++) {

// 检查i是否在O的属性(会检查原型链)

if (i in O) {

// 回调函数调用传参

if (callback.call(thisArg, O[i], i, O)) {

res.push(O[i]);

}

}

}

return res;

}

05.Array.prototype.map()


img

Array.prototype.map = function(callback, thisArg) {

if (this == undefined) {

throw new TypeError(‘this is null or not defined’);

}

if (typeof callback !== ‘function’) {

throw new TypeError(callback + ’ is not a function’);

}

const res = [];

// 同理

const O = Object(this);

const len = O.length >>> 0;

for (let i = 0; i < len; i++) {

if (i in O) {

// 调用回调函数并传入新数组

res[i] = callback.call(thisArg, O[i], i, this);

}

}

return res;

}

06.Array.prototype.forEach()


img

Array.prototype.forEach = function(callback, thisArg) {

if (this == null) {

throw new TypeError(‘this is null or not defined’);

}

if (typeof callback !== “function”) {

throw new TypeError(callback + ’ is not a function’);

}

const O = Object(this);

const len = O.length >>> 0;

let k = 0;

while (k < len) {

if (k in O) {

callback.call(thisArg, O[k], k, O);

}

k++;

}

}

07.Array.prototype.reduce()


img

Array.prototype.reduce = function(callback, initialValue) {

if (this == undefined) {

throw new TypeError(‘this is null or not defined’);

}

if (typeof callback !== ‘function’) {

throw new TypeError(callbackfn + ’ is not a function’);

}

const O = Object(this);

const len = this.length >>> 0;

let accumulator = initialValue;

let k = 0;

// 如果第二个参数为undefined的情况下

// 则数组的第一个有效值作为累加器的初始值

if (accumulator === undefined) {

while (k < len && !(k in O)) {

k++;

}

// 如果超出数组界限还没有找到累加器的初始值,则TypeError

if (k >= len) {

throw new TypeError(‘Reduce of empty array with no initial value’);

}

accumulator = O[k++];

}

while (k < len) {

if (k in O) {

accumulator = callback.call(undefined, accumulator, O[k], k, O);

}

k++;

}

return accumulator;

}

08.Function.prototype.apply()


第一个参数是绑定的this,默认为window,第二个参数是数组或类数组

Function.prototype.apply = function(context = window, args) {

if (typeof this !== ‘function’) {

throw new TypeError(‘Type Error’);

}

const fn = Symbol(‘fn’);

context[fn] = this;

const res = contextfn;

delete context[fn];

return res;

}

09.Function.prototype.call


call唯一不同的是,call()方法接受的是一个参数列表

Function.prototype.call = function(context = window, …args) {

if (typeof this !== ‘function’) {

throw new TypeError(‘Type Error’);

}

const fn = Symbol(‘fn’);

context[fn] = this;

const res = contextfn;

delete context[fn];

return res;

}

10.Function.prototype.bind


Function.prototype.bind = function(context, …args) {

if (typeof this !== ‘function’) {

throw new Error(“Type Error”);

}

// 保存this的值

var self = this;

return function F() {

// 考虑new的情况

if(this instanceof F) {

return new self(…args, …arguments)

}

return self.apply(context, […args, …arguments])

}

}

11.debounce(防抖)


触发高频时间后n秒内函数只会执行一次,如果n秒内高频时间再次触发,则重新计算时间。

const debounce = (fn, time) => {

let timeout = null;

return function() {

clearTimeout(timeout)

timeout = setTimeout(() => {

fn.apply(this, arguments);

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Web前端开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
img

下面是我在学习HTML和CSS的时候整理的一些笔记,有兴趣的可以看下:

HTML、CSS部分截图

进阶阶段

进阶阶段,开始攻 JS,对于刚接触 JS 的初学者,确实比学习 HTML 和 CSS 有难度,但是只要肯下功夫,这部分对于你来说,也不是什么大问题。

JS 内容涉及到的知识点较多,看到网上有很多人建议你从头到尾抱着那本《JavaScript高级程序设计》学,我是不建议的,毕竟刚接触 JS 谁能看得下去,当时我也不能,也没那样做。

我这部分的学习技巧是,增加次数,减少单次看的内容。就是说,第一遍学习 JS 走马观花的看,看个大概,去找视频以及网站学习,不建议直接看书。因为看书看不下去的时候很打击你学下去的信心。

然后通过一些网站的小例子,开始动手敲代码,一定要去实践、实践、实践,这一遍是为了更好的去熟悉 JS 的语法。别只顾着来回的看知识点,眼高手低可不是个好习惯,我在这吃过亏,你懂的。

1、JavaScript 和 ES6

在这个过程你会发现,有很多 JS 知识点你并不能更好的理解为什么这么设计,以及这样设计的好处是什么,这就逼着让你去学习这单个知识点的来龙去脉,去哪学?第一,书籍,我知道你不喜欢看,我最近通过刷大厂面试题整理了一份前端核心知识笔记,比较书籍更精简,一句废话都没有,这份笔记也让我通过跳槽从8k涨成20k。

JavaScript部分截图

2、前端框架

前端框架太多了,真的学不动了,别慌,其实对于前端的三大马车,Angular、React、Vue 只要把其中一种框架学明白,底层原理实现,其他两个学起来不会很吃力,这也取决于你以后就职的公司要求你会哪一个框架了,当然,会的越多越好,但是往往每个人的时间是有限的,对于自学的学生,或者即将面试找工作的人,当然要选择一门框架深挖原理。

以 Vue 为例,我整理了如下的面试题。

Vue部分截图

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img

6432)]
[外链图片转存中…(img-NqBW9ql2-1712944196433)]
[外链图片转存中…(img-CgvwaEgL-1712944196433)]
[外链图片转存中…(img-r2kMN1ue-1712944196433)]
[外链图片转存中…(img-hS3SEVYG-1712944196434)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上前端开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024c (备注前端)
[外链图片转存中…(img-EOaqtNvi-1712944196434)]

下面是我在学习HTML和CSS的时候整理的一些笔记,有兴趣的可以看下:

HTML、CSS部分截图

进阶阶段

进阶阶段,开始攻 JS,对于刚接触 JS 的初学者,确实比学习 HTML 和 CSS 有难度,但是只要肯下功夫,这部分对于你来说,也不是什么大问题。

JS 内容涉及到的知识点较多,看到网上有很多人建议你从头到尾抱着那本《JavaScript高级程序设计》学,我是不建议的,毕竟刚接触 JS 谁能看得下去,当时我也不能,也没那样做。

我这部分的学习技巧是,增加次数,减少单次看的内容。就是说,第一遍学习 JS 走马观花的看,看个大概,去找视频以及网站学习,不建议直接看书。因为看书看不下去的时候很打击你学下去的信心。

然后通过一些网站的小例子,开始动手敲代码,一定要去实践、实践、实践,这一遍是为了更好的去熟悉 JS 的语法。别只顾着来回的看知识点,眼高手低可不是个好习惯,我在这吃过亏,你懂的。

1、JavaScript 和 ES6

在这个过程你会发现,有很多 JS 知识点你并不能更好的理解为什么这么设计,以及这样设计的好处是什么,这就逼着让你去学习这单个知识点的来龙去脉,去哪学?第一,书籍,我知道你不喜欢看,我最近通过刷大厂面试题整理了一份前端核心知识笔记,比较书籍更精简,一句废话都没有,这份笔记也让我通过跳槽从8k涨成20k。

JavaScript部分截图

2、前端框架

前端框架太多了,真的学不动了,别慌,其实对于前端的三大马车,Angular、React、Vue 只要把其中一种框架学明白,底层原理实现,其他两个学起来不会很吃力,这也取决于你以后就职的公司要求你会哪一个框架了,当然,会的越多越好,但是往往每个人的时间是有限的,对于自学的学生,或者即将面试找工作的人,当然要选择一门框架深挖原理。

以 Vue 为例,我整理了如下的面试题。

Vue部分截图

一个人可以走的很快,但一群人才能走的更远。不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎扫码加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
[外链图片转存中…(img-MjkHIiwC-1712944196434)]

  • 22
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值