【前端面试题(3)】

前端面试题大全(3)


一、说说AMD、CMD、commonJS模块化规范的区别 ?

1. CommonJS

CommonJS规范是诞生比较早的。NodeJS就采用了CommonJS。是这样加载模块:

var clock = require('clock');
clock.start();

这种写法适合服务端,因为在服务器读取模块都是在本地磁盘,加载速度很快。但是如果在客户端,加载模块的时候有可能出现“假死”状况。
比如上面的例子中clock的调用必须等待clock.js请求成功,加载完毕。那么,能不能异步加载模块呢?

2. AMD

AMD,即 (Asynchronous Module Definition),这种规范是异步的加载模块,requireJs应用了这一规范。先定义所有依赖,然后在加载完成后的回调函数中执行:
代码如下(示例):

require([module], callback);
//用AMD写一个模块
require(['clock'],function(clock){
  clock.start();
});

AMD虽然实现了异步加载,但是开始就把所有依赖写出来是不符合书写的逻辑顺序的,能不能像commonJS那样用的时候再require,而且还支持异步加载后再执行呢?

3. CMD

CMD (Common Module Definition), 是seajs推崇的规范,CMD则是依赖就近,用的时候再require。它写起来是这样的:

define(function(require, exports, module) {
   var clock = require('clock');
   clock.start();
});

AMD和CMD最大的区别是对依赖模块的执行时机处理不同,而不是加载的时机或者方式不同,二者皆为异步加载模块。
AMD依赖前置,js可以方便知道依赖模块是谁,立即加载;而CMD就近依赖,需要使用把模块变为字符串解析一遍才知道依赖了那些模块,这也是很多人诟病CMD的一点,牺牲性能来带来开发的便利性,实际上解析模块用的时间短到可以忽略。

二、说说package.json中版本号的规则?

^: 只会执行不更改最左边非零数字的更新。 如果写入的是 ^0.13.0,则当运行 npm update 时,可以更新到 0.13.1、0.13.2 等,但不能更新到 0.14.0 或更高版本。 如果写入的是 ^1.13.0,则当运行 npm update 时,可以更新到 1.13.1、1.14.0 等,但不能更新到 2.0.0 或更高版本。
~: 如果写入的是 〜0.13.0,则当运行 npm update 时,会更新到补丁版本:即 0.13.1 可以,但 0.14.0 不可以。
>: 接受高于指定版本的任何版本。
>=: 接受等于或高于指定版本的任何版本。
<=: 接受等于或低于指定版本的任何版本。
<: 接受低于指定版本的任何版本。
=: 接受确切的版本
-: 接受一定范围的版本。例如:2.1.0 - 2.6.2。
||: 组合集合。例如 < 2.1 || > 2.6。
可以合并其中的一些符号,例如 1.0.0 || >=1.1.0 <1.2.0,即使用 1.0.0 或从 1.1.0 开始但低于 1.2.0 的版本。
还有其他的规则:

无符号: 仅接受指定的特定版本(例如 1.2.1)。
latest: 使用可用的最新版本。

三、谈谈对koa中洋葱模型的理解?

洋葱模型示例图

Koa.js

Koa.js 是一个极其精简的 Web 服务框架,主要提供以下功能:

1、HTTP 服务:主要处理 request 和 response
2、中间件数据处理机制(洋葱模型)

什么是 Koa.js 洋葱模型?

洋葱模型就是中间件处理的流程,中间件生命周期大致有:
1、前期处理
2、交给并等待其他中间件处理
3、后期处理
多个中间件处理,就形成了所谓的洋葱模型,它是AOP面向切面编程的一种应用

如何实现洋葱模型?
const App = function () {
  // 中间件公共的处理数据
  let context = {}
  // 中间件队列
  let middlewares = []
  return {
    // 将中间件放入队列中
    use (fn) {
      middlewares.push(fn)
    },
    // 调用中间件
    callback () {
      // 初始调用 middlewares 队列中的第 1 个中间件
      return dispatch(0)
      function dispatch (i) {
        // 获取要执行的中间件函数
        let fn = middlewares[i]
        // 执行中间件函数,回调参数是:公共数据、调用下一个中间件函数
        // 返回一个 Promise 实例
        return Promise.resolve(
          fn(context, function next () { dispatch(i + 1) })
        )
      }
    },
  }
}

上边代码,在不考虑特殊边界情况下,就完成了 Koa2.js 中简易版中间件的封装,让我们来测试一下

// 测试代码

let app = App()

app.use(async (cxt, next) => {
  console.log('middleware_01 start')
  await next()
  console.log('middleware_01 end')
})

app.use(async (cxt, next) => {
  console.log('middleware_02 start')
  await next()
  console.log('middleware_02 end')
})

app.use(async (cxt, next) => {
  console.log('middleware_03 start')
  console.log('middleware_03 end')
})

// Koa2.js 源码中,放在 http.createServer(callback) 回调中调用
// 这里我们直接调用
app.callback()

// 输出如下:

middleware_01 start
middleware_02 start
middleware_03 start
middleware_03 end
middleware_02 end
middleware_01 end

四、说说你对webSocket的理解?

WebSocket,是一种网络传输协议,位于OSI模型的应用层。可在单个TCP连接上进行全双工通信,能更好的节省服务器资源和带宽并达到实时通迅
客户端与服务器只需要完成一次握手,两者之间就可以创建持久双向数据传输
websocket
从上图可见,websocket服务器与客户端通过握手连接,连接成功后,两者都能主动的向对方发送或接受数据

而在websocket出现之前,开发实时web应用的方式为轮询

不停地向服务器发送 HTTP 请求,问有没有数据,有数据的话服务器就用响应报文回应。如果轮询的频率比较高,那么就可以近似地实现“实时通信”的效果

轮询的缺点也很明显,反复发送无效查询请求耗费了大量的带宽CPU资源

1、特点

1. 全双工

通信允许数据在两个方向上同时传输,它在能力上相当于两个单工通信方式的结合

例如指 A→B 的同时 B→A ,是瞬时同步的

2.二进制帧

采用了二进制帧结构,语法、语义与 HTTP 完全不兼容,相比http/2,WebSocket更侧重于“实时通信”,而HTTP/2 更侧重于提高传输效率,所以两者的帧结构也有很大的区别

不像 HTTP/2 那样定义流,也就不存在多路复用、优先级等特性

自身就是全双工,也不需要服务器推送

3.协议名

引入ws和wss分别代表明文和密文的websocket协议,且默认端口使用80或443,几乎与http一致

ws://www.chrono.com
ws://www.chrono.com:8080/srv
wss://www.chrono.com:445/im?user_id=xxx
4.握手

WebSocket也要有一个握手过程,然后才能正式收发数据

客户端发送数据格式如下:

GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13

2、优点

1、较少的控制开销:数据包头部协议较小,不同于http每次请求需要携带完整的头部
2、更强的实时性:相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少
3、保持创连接状态:创建通信后,可省略状态信息,不同于HTTP每次请求需要携带身份验证
4、更好的二进制支持:定义了二进制帧,更好处理二进制内容
支持扩展:用户可以扩展websocket协议、实现部分自定义的子协议
5、更好的压缩效果:Websocket在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著地提高压缩率

五、bind、call、apply 区别?如何实现一个bind?

Call、bind、apply作用都是改变函数执行时的this指向

区别:

1、apply接收两个参数,第一个参数是this指向,第二个参数是函数接收的参数,以数组的形式传入
2、Call方法的第一个参数也是this指向,后面传入的是一个参数列表
3、Bind方法和call相似,第一个参数也是this指向,后边传入的也是一个参数列表(这个列表可以分多次传入),bind是返回绑定this之后的函数,apply和call是立即执行

如何实现一个bind:

修改this指向,动态的传递参数,兼容new关键字

//使用
function.prototype.mybind = function(context){
	//判断调用对象是否为函数
	If(typeof this !==function){throw new TypeError(“error”)}
	//获取参数
	Const args = [...arguments].slice(1)
	Fn = this
	Return function Fn(){
//根据调用方式,传入不同的绑定值
	Return fn.apply(this instanceof Fn ? new fn(...arguments):context,args.concat(...arguments))
}
}

六、什么是防抖和节流?有什么区别?

节流:n秒内只允许一次,如果在n秒内重复触发,只有一次生效
防抖:n秒后在执行该事件,如果在n秒内被重复触发,则重新计时

区别:

1、函数防抖在一段连续操作结束以后,处理回调,利用clearTimeout和setTimeout实现;函数的节流,在一段连续操作中,每一段事件只执行一次,频率较高的事件中使用来提高性能
2、函数防抖关注一定时间连续触发的时间,只在最后执行一次,而函数节流一段时间内只执行一次

七、怎么理解回流跟重绘?什么场景下会触发?

在HTML中,每个元素都可以理解成一个盒子,在浏览器解析过程中,会涉及到回流与重绘:

1、回流:布局引擎会根据各种样式计算每个盒子在页面上的大小与位置

2、重绘:当计算好盒模型的位置、大小及其他属性后,浏览器根据每个盒子特性进行绘制

具体的浏览器解析渲染机制如下所示:
回流重塑

1、解析HTML,生成DOM树,解析CSS,生成CSSOM树
2、将DOM树和CSSOM树结合,生成渲染树(Render Tree)
3、Layout(回流):根据生成的渲染树,进行回流(Layout),得到节点的几何信息(位置,大小)
4、Painting(重绘):根据渲染树以及回流得到的几何信息,得到节点的绝对像素
5、Display:将像素发送给GPU,展示在页面上

如何触发?

回流触发时机:

回流这一阶段主要是计算节点的位置和几何信息,那么当页面布局和几何信息发生变化的时候,就需要回流,如下面情况:

1、添加或删除可见的DOM元素
2、元素的位置发生变化
3、元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
4、内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
5、页面一开始渲染的时候(这避免不了)
6、浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)

重绘触发时机:

触发回流一定会触发重绘

可以把页面理解为一个黑板,黑板上有一朵画好的小花。现在我们要把这朵从左边移到了右边,那我们要先确定好右边的具体位置,画好形状(回流),再画上它原有的颜色(重绘)

除此之外还有一些其他引起重绘行为:

1、颜色的修改
2、文本方向的修改
3、阴影的修改

八、VUE路由的原理?

路由分为两种模式:hash模式history模式

路由参数:

1.默认 hash
2. history。如果浏览器不支持 history 新特性,则采用 hash
3. 如果不在浏览器环境下,就采用 abstract(Node环境下)
vue路由原理

路由区别:

  1. mode:“hash” 多了 “#”
    http://localhost:8080/#/login
  1. mode:“history”
    http://localhost:8080/recommend

Hash:url中的hash值是客户端的一种状态,当向服务器端发送请求时,hash部分不会被发送,hash的改变,都会在浏览器的访问历史中增加一个记录,因此我们可以通过浏览器的回退,前进按钮控制hash的切换,通过改变hash值来进行页面的跳转

History:在history的模式下,前端的url必须和实际向后端发起请求的url一致,pushState和replaceState两个API来操作实现url的变化,可以在页面不刷新的情况下,操作浏览器的历史记录,也可以使用popstate来监听url的变化,从而实现页面的跳转功能

九、说说你对keep-alive的理解?

keepalive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染 。也就是所谓的组件缓存

是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM。

keep-alive 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们。
和 transition 相似,keep-alive 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中。

prop:

1、include: 字符串或正则表达式。只有匹配的组件会被缓存。
2、exclude: 字符串或正则表达式。任何匹配的组件都不会被缓存。

keep-alive的声明周期执行

1、页面第一次进入,钩子的触发顺序 created-> mounted-> activated, 退出时触发 deactivated
2、当再次进入(前进或者后退)时,只触发 activated 事件挂载的方法等,只执行一次的放在 mounted 中;组件每次进去执行的方法放在
activated 中;

基本用法
<!--被keepalive包含的组件会被缓存-->
<keep-alive>
    <component><component />
</keep-alive>

被keepalive包含的组件不会被再次初始化,也就意味着不会重走生命周期函数

activated 当 keepalive 包含的组件再次渲染的时候触发
deactivated 当 keepalive 包含的组件销毁的时候触发

keepalive是一个抽象的组件,缓存的组件不会被 mounted,为此提供activated和deactivated钩子函数

十、什么是响应式设计?响应式设计的基本原理是什么?

响应式布局:指在同一页面在不同屏幕尺寸下有不同的布局。传统的开发方式是PC端开发一套,移动端再开发一套,pad端再开发一套,而使用响应式布局只要开发一套就够了。
响应式网站设计(Responsive Web design)是一种网络页面设计布局,页面的设计与开发应当根据用户行为以及设备环境(系统平台、屏幕尺寸、屏幕定向等)进行相应的响应和调整
响应式设计与自适应设计的区别:

响应式开发一套界面,通过检测视口分辨率,针对不同客户端在客户端做代码处理,来展现不同的布局和内容;
自适应需要开发多套界面,通过检测视口分辨率,来判断当前访问的设备是移动端、PC端、pad端,从而请求服务层,返回不同的页面

优点:

1、用户体验好:响应式设计可以向用户提供友好的Web界面,因为它可以适应几乎所有设备的屏幕,包括智能手机、平板电脑、TV、PC显示器、iPhone和Android手机,包括横向、纵向的屏幕。
2、节省设计开发成本:相对需要开发电脑网站、pad网站、手机网站来说,响应式网站设计更有利于节省设计开发成本。
3、积累分享:响应式Web设计可以让你(作为网站的拥有者)通过单一的URL地址收集所有的社交分享链接。你可以为创建更好、更友好的网站而做出积极贡献。

缺点:

1、对老版IE浏览器兼容性不友好:对于老版本IE(IE6、IE7、IE8)支持不好,这是一个致命的问题。如果你的网站用户大多还采用老版本IE的话,建议不做响应式网页设计。
2、加载变慢:加载需要一定的时间 虽然,它不是一个大问题,在响应式设计中,需要下载一些看起来并不必要的HTML/CSS。除此之外,图片并没有根据设备调整到合适大小,而这正是导致加载时间加倍的原因。
3、 增加开发时间成本:开发响应式网站是一项耗时的工作。如果你计划把一个现有网站转化成响应式网站,可能耗时更多。如果你想要一个响应式网站,最好借助一些原型设计工具,例如Mockplus,从草图开始重新设计。
4、影响布局:响应式Web设计的布局主要是液态的,这也正是设计者对设计样式不好控制的原因。而且眼下正是设计者提前展示各种“复制品”的时候。设计者试图针对移动和桌面布局分别显示线框和设计原型。只有等到这两种布局均得到提高后,响应式Web设计策略才能真正实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值