前端面试题大全

一、 计算机网络

1. 网络体系结构


TCP/IP协议体系中各协议的关系:



2. HTTP协议头包含哪些重要部分,HTTP状态码


包括通用头、请求头、响应头、实体头四部分

200成功、302重定向、304使用缓存、404未找到、503服务器故障

3. 网络url输入到输出都做了什么?


  1. 输入网址www.baidu.com

  2. 查询缓存

  • 浏览器查找自身缓存,如果有域名的IP地址则返回,没有则继续查找

  • 系统查找自身缓存……

  • 路由器查找自身缓存……

  1. 获取IP
  • 本地域名服务器采用迭代查询,先向一个根域名服务器进行查询

  • 根域名服务器告诉本地域名服务器,下一次查询的顶级域名服务器dns.com的IP地址

  • 本地域名服务器向顶级域名服务器dns.com进行查询

  • 顶级域名服务器dns.com告诉本地域名服务器,下一次查询的权限域名服务baidu.dns.com的IP地址

  • 本地域名服务器向权限域名服务器baidu.dns.com进行查询

  • 权限域名服务器告诉本地域名服务器,所查询的主机www.baidu.com的IP地址

  • 本地域名服务器最后把IP地址告诉主机

  1. 三次握手
  • 浏览器所在客户机向服务器发出连接请求报文

  • 服务器接收报文之后,同意建立连接,向客户机发送确认报文

  • 客户机接收到确认报文之后,再次向服务器发出报文,确认已接收到报文

  • 此时客户机与服务器之间的TCP连接已建立完成,开始通信

  1. 获取资源
  • 浏览器发出取文件命令:GET

  • 服务器给出响应,将指定文件发送给浏览器

  • 浏览器释放TCP连接

  • 浏览器向服务器发出连接释放报文,然后停止发送数据

  • 服务器接收到释放报文后,向客户机发送确认报文,然后将未传送完的数据发送完

  • 服务器数据传输完毕之后,向客户机发送连接释放报文

  • 客户机接收到报文后,发出确认,然后等待一段时间,释放连接

  1. 浏览器解析资源并显示到窗口中

4. 为什么说性能优化就要减少HTTP的访问次数?


  • 每次请求,请求头都会带上一些额外的数据

  • 每次请求,都需要经过一系列解析和连接操作


5. 描述一下HTTP的请求过程和原理


过程:

  • 域名解析

  • 发起TCP3次握手

  • 建立TCP连接后发起http请求

  • 服务器响应http请求,浏览器获得html代码

  • 浏览器解析html代码,并请求html中的资源(js、css、图片等)

  • 浏览器对页面进行渲染并呈现给客户

原理:HTTP协议是应用层的一种协议,是一种C/S架构服务,基于TCP/IP协议进行通信,监听在TCP的80端口,HTTP协议实现的是的客户端可以向服务端获得web资源


6. https有几次握手和挥手?https的原理是什么?


https是三次握手四次挥手,和http是一样的

原理:https在传输之前需要客户端和服务器进行一次握手,在握手过程中确立双方加密传输数据的密码信息,TLS/SSL协议是一套加密传输协议,使用非对称加密,对称加密,以及HASH算法


7. TLS的中文名是什么?TLS在网络的哪一层?


TLS:安全传输层协议,在传输层


8. TCP的连接特点是什么?TCP如何保证连接安全可靠?


TCP的可靠性是通过顺序编号和确认(ACK)来实现的,TCP接收端必须丢弃重复的数据,并且TCP提供流量控制,连接的每一个地方都有固定大小的缓冲空间


9. 为什么TCP连接需要三次握手?


三次握手为了确认客户端跟服务端都能接受到双方的信息,两次的话服务器不能确认客户端能否接收自己发的包

第一次握手,客户端给服务端发包。服务端确认自己可以接收客户端的包,客户端不确认服务端是否接收到自己的包

第二次握手,服务端回复客户端。此时客户端确认自己发的包被服务端接收到,也确认自己可以正常接收服务端的包,客户端对此次连接没有疑问了。此时服务端确认自己能接收到客户端的包,但不能确认客户端能否接收到自己的包

第三次握手,客户端回复服务端。客户端已经没有疑问,服务端也确认刚刚客户端收到了自己的包,两边都没有问题,开始通信


10. 为什么TCP连接需要三次握手四次挥手?


为什么是三次握手:

为了防止已失效的连接请求报文突然发送到服务器,导致服务器建立了无效连接,浪费资源。

假设只有两次握手,客户端发出的第一个请求报文在某个网络节点长时间滞留,以致延误到连接释放后才打到服务器。服务器收到失效的连接请求报文段后,同意连接,并向客户发出确认报文。这样服务器的资源就白白浪费了。

为什么是四次挥手:

TCP协议是全双工通信,这意味着客户端和服务端都可以向彼此发送数据,所以关闭连接是双方需要确认的共同行为。假设只有三次挥手,

首先释放了客户到服务端的连接,此时TCP连接处于半关闭状态,这是客户不能想服务端发送数据,而服务器可以向客户端发送数据。如果此时客户端一接收到服务端的报文,就立刻发送确认报文,这样会导致服务端向客户端的连接被关闭,服务端的尚未传输完成的数据被中断,客户端就无法接收到完整的数据


11. TCP的三次握手和四次挥手绘图(写出ACK和SEQ的值)


三次握手:

其中的ack是请求报文中Seq+1

四次挥手:


12. TCP和UDP的区别有哪些?


TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议

UDP(User Datagram Protocol 用户数据协议)是OSI(Open System
Interconnection
开放式系统互联)参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务

TCP报文的头部开销20字节,UDP头部8字节

TCP是全双工可靠信道,UDP则是不可靠信道

UDP没有拥塞机制,因此网络出现拥堵不会使源主机的发送效率降低(适合用于实时会议视频)

TCP只支持点对点,UDP支持一对一、多对一、多对多的交互通信


13. Get和Post的区别是什么?什么情况下用到?


区别:
  • Get使用URL或Cookie传参,而Post将数据放在Body中

  • Get的URL会有长度限制,而Post的数据则可以非常大

  • Post比Get更安全,因为数据在地址栏不可见


使用场景:Get用来从服务器获得数据,Post用来向服务器添加数据


14. HTTP2/HTTP1之间的区别是什么?


  • http2采用二进制格式而非文本格式,二进制更加高效,而且错误更少

  • http2只需要一个连接即可实现多路复用,同时处理多个消息的请求和响应。http1是一个连接只能提交一个请求的效率比较高,多了会变慢

  • 使用报头压缩,http2降低了开销,http1的消息头有很大冗余。

  • http2可以主动将资源推送给客户端,例如js、css等文件,而不用等待html被解析


15. 介绍一下websocket


websocket是一种网络通信协议,是HTML5提供的一种在单个TCP连接上进行的全双工通信协议。而http是一种无状态、无连接、单向的应用层协议,在http协议下,服务器不能主动向客户端推送数据。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

var ws = new WebSocket(\'ws://localhost:9998/echo\')

ws.onopen = function() {

ws.send(\'发送数据\')

}

// 接收消息

ws.onmessage = function(evt) {

var receive_msg = evt.data

}

// 断开连接

ws.onclose = function() {}

16. HTTP Response的Header里面都有什么?


  1. Cache-Control:告诉所有缓存机制是否可以缓存及哪种类型

  2. Content-Length:响应体长度

  3. Content-Type:返回内容的MIME类型,如jpg就是图片

  4. Expires:响应过期期限

  5. Set-Cookie:设置Http Cookie



二、 浏览器


1. 你了解浏览器的标准模式和怪异模式吗?


现代浏览器都有两种渲染方式:标准模式和怪异模式。

在标准模式下,浏览器按照HTML和CSS标准对文档进行解析和渲染;

在怪异模式下,浏览器按照非标准的实现方式对文档进行解析和渲染。

这样的话,对于旧有的网页,浏览器就会启动怪异模式,使得旧网页能够正常显示。

而对于新网页,浏览器就会启用标准模式,使得新网页能够使用HTML和CSS的标准特性。

区别:


2. 为什么会有跨域问题?


浏览器会阻止同一个域去访问另一个域的js脚本,防止来自其他域的恶意脚本攻击。

其中的域指相同的协议、相同的主机以及相同的端口。


3. 前端安全XSS,CSRF这些是什么?


xss:跨站脚本攻击。xss攻击的主要目的是获取目标攻击网站的Cookie,因为有了Cookie相当于session。恶意攻击者往Web页面中插入恶意Script代码,当用户浏览该网页之时,嵌入Web里面的恶意代码会被执行,从而达到恶意攻击用户的目的,避免措施:编码、过滤、校验

CSRF:跨站点伪装请求。CSRF攻击者在用户已经登录目标网站之后,诱使用户访问一个攻击网站,利用目标网站对用户的信任,以用户身份在攻击页面对目标网站伪造用户操作的请求,达到攻击目的。防御手段:使用Post,显示Get。加验证码


4. 浏览器如何加载页面,script脚本阻塞有什么解决方法,defer和async的区别是什么?


加载页面:

通过DNS查询到域名对应的IP地址,向IP地址发起连接请求。连接成功后,通过http协议向服务器请求html,服务器返回html代码,浏览器解析html代码,并加载html中相关的js和css等资源

阻塞:

  1. 推迟加载
  • 页面的初始渲染并不依赖js或css,就可以放到最后加载。
  1. defer延迟加载
  • <script src="" defer></script>在文档解析完成后执行,并且在DOMContentLoaded事件之前执行完成,效果和放在</body>前面一样

    注意:用了defer不要使用document.write()方法。使用defer时最好不要加载样式信息,因为样式表可能尚未加载,浏览器会禁止脚本等待样式表加载完成,相当于样式表阻塞脚本加载

  1. 异步加载
  • async异步加载就是告诉浏览器不必等到加载完外部文件,可以边渲染边下载,什么时候渲染完什么时候执行。
1
<script type="text/javascript" src="a.js" async></script>

5. 浏览器强制缓存和协商缓存是什么?


强制缓存:利用http返回头中的Expires和Cache-Control两个字段来控制,用来表示资源的缓存时间

协商缓存:就是由服务器来确定缓存资源是否可用,所以客户端和服务端要通过某种标识来进行通信,从而让服务器判断请求资源是否可以缓存访问。第一次请求的响应头带上某个字段(Last-Modified或者Etag),则后续请求则会带上对应的请求字段(If-Modified-Since或If-None-Match)。


6. 浏览器的全局变量有哪些?


window、navigator、location、alert()、setTimeout()


7. 浏览器同一时间能够从一个域名下载多少个资源?


一般是限制在10个以内


8. Web存储,Cookies,localStorage等的使用规则和区别


Cookie在浏览器和服务器之间来回传递,在过期时间之前都有效,即使关闭窗口或浏览器,cookie数据不超过4k

web存储指本地存储,包括localStorage和sessionStorage。

其中sessionStorage仅在窗口开启时有效

localStorage则长期保存在本地,最高可以达到5M


9. 浏览器内核你都知道有哪些?


  • 火狐:Gecko

  • Safari:webkit

  • 搜狗:兼容模式(IE:Trident)和高速模式(webkit)

  • 傲游:兼容模式(IE:Trident)和高速模式(webkit)

  • QQ:兼容模式(IE:Trident)和高速模式(webkit)

  • 360极速:基于谷歌(Chromuim)和IE内核

  • 360安全:IE内核


10. 什么是预加载,什么是懒加载?


预加载:提前加载图片,当用户查看时可以从本地缓存直接渲染

懒加载:也就是延迟加载,先把img元素替换成一张1x1的占位图,等到图片出现在可视区域时,才去请求图片,让真正的图片显示出来。


11. 一个XMLHttpRequest实例有几种状态,分别代表什么?


  • 0:对象没有完全初始化

  • 1:对象开始发送请求

  • 2:对象请求发送完成

  • 3:对象开始读取服务器响应

  • 4:对象读取服务器响应结束


12. 服务器如何识别是你在操作,说说思路


  1. 当浏览器首次访问服务器时,服务器会为客户端创建一个session(每个用户独有的房间,用来存放这个用户的相关信息和内容),并通过特殊算法算出一个sessionID(类似于双方都知道的唯一暗号),用来标识sesion对象。

  2. 当浏览器再次(session还在有效时间内)向服务器请求资源时,浏览器将sessionID和请求内容一起发送到服务端。服务端通过对比自身存储的sessionID来判断用户之前是否存在,并返回对应的内容给不同用户

  3. 因为标识符存在内存里,所以当浏览器关闭时,浏览器保存的sessionID就会消失,服务器将匹配失败,默认该用户为新用户


13. 浏览器的渲染过程你了解吗?


  1. 解析HTML文件,创建DOM树

  2. 解析CSS

  3. CSS与DOM树合并,构建渲染树

  4. 布局和绘制,重绘(repaint)和重排(reflow)


14. 介绍几个IE浏览器的兼容问题


  1. 块属性标签float之后,又有横向的margin值,在IE6中显示会比设置的大(IE6双边距bug)

  2. 设置较小的高度标签(一般小于10px),在IE6,IE7会超出自己设置的高度。

  3. 图片默认有间距。解决方案:使用float来为img布局

  4. 给一个元素设置高度和宽度的同时,还为其设置margin和padding值,会改变该元素的实际大小。解决办法:在需要加margin和padding的div内部加一个div,在这个div设置margin和padding


15. 拆解一个URL的各个部分,分别是什么意思?


例:

1
scheme://host:port/path?query#fragment
  • scheme指通信协议,如http、ftp

  • host:主机,域名或IP地址

  • port:端口,http默认80

  • path:文件目录或文件地址

  • query:查询参数,用&隔开,用=赋值

  • fragment:锚点


16. 网页的重绘与重排


重绘:元素外观的改变所触发的浏览器行为,例如改变visibility、outline、背景色等属性。浏览器会根据元素的新属性重新绘制,使元素呈现新的外观。重绘不会带来重新布局,并不一定伴随重排。

重排:是更明显的一种改变,可以理解为渲染树需要重新计算。将对性能产生很大影响。

下面是常见的触发重排的操作:

  1. DOM元素的几何属性变化

  2. DOM树的结构变化

  3. 获取某些属性

  4. 改变元素的某些样式,浏览器窗口大小调整

三、 Html


1. HTML5的特性有哪些?语义化的做法有哪些?具体指什么?


  1. 新特性
  • 多媒体,用于媒介回放的video和audio元素

  • 图像效果,用于绘画的canvas和svg元素

  • 离线&存储,对本地离线存储有更好的支持,比如Cookies、localStorage等

  • 设备兼容特性,HTML5提供了前所未有的数据与应用接入接口,使外部应用可以直接和浏览器内部数据相连

  • 连接特性,更有效的连接工作效率,使得基于页面的实时聊天,更快速的网页游戏体验,更优化的在线交流得到了实现,同时拥有更有效的服务器推送技术,Server-Sent
    Event和WebSockets就是其中两个特性,这两个特性能够帮助我们实现将服务器数据推送到客户端的功能

  • 性能与集成特征,HTML5会通过XML
    HttpRequest2等技术,帮助您的Web应用和网站在多样化的环境中更快速的工作。


  1. 新标签
  • 多媒体:<video><audio><source><embed><track>

  • 新表单元素:<datalist><output><keygen>

  • 新文档节段和纲要:<header>页面头部 <section>章节 <aside>边栏
    <article>文档内容 <footer>页面底部


  1. 语义化
  • 语义化的好处:

    • 更好地呈现内容结构,让源码具有可读性

    • 利于SEO

    • 方便团队的开发与维护

    • 遵循W3C标准的团队都遵循这个标准,减少差异化,有利于规范化

    • 方便其他设备解析,如屏幕阅读器、盲人阅读器、移动设备等

  • 语义化的做法:

    • 语义特性:添加<header></header><footer></footer>等标签

    • 添加title、alt属性,用于解释名词和图片信息


2. XHTML与HTML有什么区别?


  1. XHTML元素必须被正确嵌套

  2. XHTML元素必须关闭

  3. 标签名必须用小写字母

  4. XHTML文档必须有根元素


3. 为什么要在标签上使用data-,它有什么好处?


  1. html规范中规定自定义属性需要添加data-前缀,目的是提供与渲染无关的信息

  2. 使用getAttribute()和setAttribute()方法操作自定义属性

  3. 使用dataset操作自定义属性

  4. dataset属性的兼容性问题可以参考CanIUse

  1. 使用data-属性选择器的好处:绑定DOM强相关数据,JS传递数据

4. Meta特性都有一些什么特性,有什么作用?


  1. 什么是meta标签
  • <meta>标签提供关于HTML文档的元数据,它不会显示在页面上,但是对于机器是可读的,可用于浏览器(如何显示内容或重新加载页面),搜索引擎(关键词)等
  1. meta的作用
  • meta里的数据供机器解读,告诉机器如何解析这个页面

  • 添加服务器发送到浏览器的HTTP头部内容

  1. 常用meta标签
  • Charset:声明文档使用的字符编码,以防乱码,一定要写在第一行

  • Viewport:影响移动端页面布局


5. 什么是Canvas,你可以用它做什么需求?


Canvas元素是HTML5的一部分,允许脚本语言动态渲染位图像。

能应对的需求:

  1. 游戏

  2. 图表制作:echarts.js跟heightchart.js都是基于canvas的

  3. banner广告


6. HTML废弃的标签有哪些?举几个例子


  • em代替i,让文字斜体显示

  • ins代替u,让文字有下划线

  • del代替s,让文字有删除线

  • strong代替b,让文字粗体


7. 工作中你都兼容哪些浏览器?实际开发中你遇到过哪些兼容问题?


  1. Input按钮在Android和iOS中的样式兼容问题
1
2
-webkit-appearance:none;
height: 4rem;
  1. [滚动穿透](https://www.cnblogs.com/qianxiaox/p/13834725. html)问题
1
2
3
4
body.modal-open {
position: fixed;
width: 100%
}

8. CSS/JS引入的位置一般在哪里?为什么


  • JS应该放在</body>标签前面,避免出现页面加载空白的问题

  • CSS应该放在head标签之中,因为如果放在body标签中,等DOM树构建完成了,渲染树才构建,那么当渲染树构建完成之后,浏览器将不得不重新渲染整个页面,这样造成了资源的浪费,效率也不高。而放在head之中,浏览器就会边构建变渲染,这样效率就高多了


9. 什么是渐进式渲染?


指先加载首屏内容,之后再随着时间或滚动的页面才进行后面的加载


10. Meta viewport的原理是什么?


手机浏览器是把页面放到一个虚拟的”窗口”(viewport)中,通常这个虚拟的”窗口”(viewport)比屏幕宽,这样就不用把每个网页都挤到很小的窗口中(这样会破坏没有针对手机浏览器优化的网页的布局),用户可以通过平移和缩放来看网页的不同部分。移动设备默认的viewport是layout
viewport,也就是那个比屏幕宽的viewport。但我们进行移动设备网站开发的时候,需要的是ideal
viewport。

详细内容可以参考深入浅出移动端适配(总结版)Web移动端最强适配方案总结,没想到这么好用!

四、 Javascript


1. js的基本类型有哪些?引用类型有哪些?null和undefined的区别


  1. 基本数据类型
  • undefined

  • null

  • boolean

  • number

  • string

  1. 引用数据类型
  • function

  • object

  • array

  1. null和undefined的区别
  • undefined表示变量声明但未初始化时的值
  • null表示准备用来保存对象,还没有真正保存对象的值。从逻辑角度来讲,null表示一个空对象指针

2. 如何判断一个变量是Array类型?如何判断一个变量是Number类型?


  1. Array类型
  • 从原型入手:
    1
    Array.prototype.isPrototypeOf(obj)
  • 从构造函数入手:
    1
    obj instanceof Array
  • Array的方法
    1
    Array.isArray(obj)
  1. Number类型
  • typeof

  • isNaN


3. 引用类型跟基本数据类型有什么区别?堆栈关系了解吗?


基本类型 引用类型
访问方式 操作和保存的是实际变量的值 保存在内存中,js不许直接访问内存,操作的是对象的引用
存储位置

4. JS常用的DOM操作API


  1. 查询
  • getElementById

  • getElementsByClassName

  • getElementsByTagName

  • getElementsByName

  • querySelector

  • querySelectorAll

  • forms 获取当前页面所有form,返回一个HTMLCollection

  1. 创建
  • createElement

  • createTextNode

  • createDocumentFragment
    创建一个DocumentFragment,也就是文档碎片,它表示一种轻量级文档,主要用来临时存储节点,大量操作DOM时使用它可以大大提升性能

  1. 复制
  • cloneNode

5. 事件委托(手写),什么是事件冒泡和事件捕获,如何阻止冒泡,如何阻止默认事件?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var toolbar = document.querySelector(\'.toolbar\')

toolbar.addEventListener(\'click\', e => {

var btn = e.target

if (!btn.classList.contains(\'active\')) {

btn.classList.add(\'active\')

}

else {

btn.classList.remove(\'active\')

}

})

当触发事件时,触发操作将会一层层向元素内部传递,被各级元素捕获,这就是事件捕获。之后每一层元素会触发对应的事件,从内往外一级级
触发,这就是事件冒泡。

阻止冒泡:stopPropagation

阻止捕获:preventDefault


6. 对闭包的理解?什么时候构成闭包?闭包的实现方法?闭包的优缺点?


闭包函数内部可以访问全局变量,函数外部无法读取函数内部的局部变量。

构成闭包的条件:内部函数对外部函数的变量有引用关系

实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
function outer() {

let bar = \'hello\'

function inner() {

console.log(bar)

}

inner()

}

用处:

  • 读取函数内部变量

  • 让这些变量始终保持在内存中

  • 问题:

  • 耗费内存,引起内存泄漏


7. this有哪些使用场景?跟C,JAVA中的this有什么区别?如何改变this的指向?


关于this的指向问题可以参考JavaScript 的 this原理

this大部分指向其调用者,但有两个特例并不如此,

一个是箭头函数,它本身不会修改this指向,而是从作用域链的上一层继承。

一个是setTimout和setInterval,它们是异步函数,会创建一个完全隔离的环境,这个环境中调用function,其实就相当于window.function,其调用者是window,所以this就指向了window。要解决这一问题,可以使用箭头函数,如上所述,箭头函数本身没有this,它的this是从上一层继承过来的,所以自然指向上一层。


8. call,apply,bind有什么区别?


call和apply的第一个参数都是一样的,就是指定this的对象

call第一个后面的参数都是传入参数,函数调用的时候会接收这些参数

apply只有两个参数,第二个参数是用数组的方式传入函数所需的参数

bind调用之后不会立即执行函数,而是返回一个绑定了对象与传入的参数的函数,其参数跟call是一样的


9. 显式原型和隐式原型,手绘原型链,原型链是什么?为什么要有原型链?


在JS中万物皆对象,方法(Function)是对象,方法的原型(Function.prototype)是对象。对象具有属性(__proto__)成为隐式原型。对象的隐式原型指向构造该对象的构造函数的显式原型。原型对象只存在于函数对象。也就是本质上只要通过new
Function创建的函数对象都会有一个原型对象。

五条原型原则:

  1. 所有引用类型(数组、对象、函数),都具有对象属性,都可以自由拓展属性,null除外。
1
2
3
4
5
6
7
8
9
var obj = {}; obj.a = 100
var arr = \[\]; arr.a = 100
function fn() {}
fn.a = 100
console.log(obj.\_\_proto\_\_)
console.log(arr.\_\_proto\_\_)
console.log(fn.\_\_proto\_\_)
console.log(fn.prototype)
console.log(obj.\_\_proto\_\_ === Object.prototype)
  1. 所有引用类型(数组、对象、函数)都有一个__proto__属性,属性值是一个普通对象。__proto__的含义是隐式原型

  2. 所有引用类型(数组、对象、函数)都有一个prototype属性,属性值是一个普通对象。prototype的含义是显式原型

  3. 所有引用类型(数组、对象、函数),__proto__属性都指向它的构造函数的prototype值。

  4. 当试图获取一个对象的某个属性时,如果这个对象本身没有这个属性,那么就会去它的__proto__中寻找(即它构造函数的prototype)

  • 什么是原型链?

  • 原型链就是实例对象跟原型对象之间的链接。

  • 为什么要使用原型链?

  • 为了实现继承,简化代码,实现代码的重用

  • 只要是这个链条上的属性,都可以被访问到


10. 你知道哪几种创建对象的方式?


  1. 工厂模式
1
2
3
4
5
6
7
8
9
10
11
function createPerson(name, age, job) {
var o = new Object()
o.name = name
o.age = age
o.job = job
o.sayName = function() {
console.log(this.name)
}
}
let p1 = createPerson(\'Mike\', 32, \'teacher\')
let p2 = createPerson(\'Sarah\', 13, \'student\')
  1. 构造函数模式
1
2
3
4
5
6
7
8
9
10
function Person(name, age, job) {
this.name = name
this.age = age
this.job = job
this.sayName = function() {
console.log(this.name)
}
}
let p1 = new Person(\'Mike\', 32, \'teacher\')
let p2 = new Person (\'Sarah\', 13, \'student\')
  1. 原型模式
1
2
3
4
5
6
function Person() {}
Person.prototype.name = \'Mike\'
Person.prototype.age = 32
Person.prototype.job = \'teacher\'
Perons.prototype.sayName = function() { console.log(this.name) }
let p = new Person()
  1. 组合使用构造模式和原型模式
1
2
3
4
5
6
7
8
9
10
function Person(name, age, job) {
this.name = name
this.age = age
this.job = job
}
Person.prototype = {
constructor: Person,
sayName: function() { console.log(this.name) }
}
let p = new Person(\'Mike\', 32, \'teacher\')

11. 实现继承有哪些方式?它的优缺点是什么?


  1. 原型继承
  • 优点:父类方法得到了复用
  • 缺点:同理父类的属性也得到了复用,即子类实例没有自己的属性,修改不同实例中的父属性会相互影响
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Person(name, age) {
this.name = name
this.age = age
this.play = [1, 2, 3]
this.setName = function() {}
}
Person.prototype.setAge = function() {}
function Student(price) {
this.price = price
this.setStore = function() {}
}
Student.prototype = new Person()
let v1 = new Student(15000)
let v2 = new Student(14000)
v1.play = [1]
console.log(v2.play) // [1]
  1. 构造函数继承
  • 优点:子类的每个实例都有自己的属性,互不影响
  • 缺点:没有实现父原型方法和属性的复用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function Person(name, age) {
    this.name = name
    this.age = age
    this.setName = function() {}
    }
    Person.prototype.setAge = function() {}
    function Student(name, age, price) {
    Person.call(this, name, age)
    this.price = price
    }
    let s1= new Student('Tom', 20, 15000)
    console.log(s1.setAge()) // undefined
  1. 组合式继承
  • 优点:继承上述两种方式的优点,摈弃了缺点
  • 缺点:因为父类构造函数被执行了两次,子类的原型对象(Sub.prototype)中也有一份父类的实例属性,而且这些属性会被子类实例(sub1,sub2)的属性覆盖掉,也存在内存浪费
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Person(name, age) {
this.name = name
this.age = age
this.setAge = function() {}
}
Person.prototype.setName = function() {
console.log('111')
}
function Student(name, age, price) {
Person.call(this, name, age)
this.price = price
this.setScore = function() {}
}
Student.prototype = new Person()
Student.prototype.constructor = Student // 不指定的话,构造函数是Person
Student.prototype.sayHello = function() {}
let s1 = new Student('Tom', 20, 15000)
let s2 = new Student('Jack', 21, 16000)
  1. 寄生组合式继承
  • 优点:以上优点均有
  • 缺点:继承父类方法时调用了父类构造函数,从而造成了内存浪费。可以使用Object.create来解决这个问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Person(name, age) {
this.name = name
this.age = age
}
Person.prototype.setAge = function() {
console.log('111')
}
function Student(name, age, price) {
Person.call(this, name, age)
this.price = price
this.setScroce = function() {}
}
Student.prototype = Object.create(Person.prototype)
Student.prototype.constructor = Student
let s1 = new Student('Mike', 40, 15000)
console.log(s1 instanceof Student, s1 instanceof Person)
console.log(s1.constructor)
console.log(s1)

12. new一个对象具体做了什么?


  1. 创建一个新对象,如:var person = {}

  2. 新对象的__proto__属性指向构造函数的原型对象

  3. 将构造函数的作用域赋值给新对象。(也就是this对象指向新对象)

  4. 执行构造函数内部代码,将属性添加给person中的this对象

  5. 返回新对象person


13. 请写出ajax,或者说出流程


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
function ajax(url, fnSucc, fnFail) {

let xmlHttp = null

if(window.XMLHttpRequest) {

xml = new window.XMLHttpRequest() //IE6以上不兼容

}

else {

xml = new ActiveXObject(\'Microsoft,XMLHTTP\')

}

xmlHttp.open(\'GET\', url, true)

xmlHttp.send()

xmlHttp.onreadystatechange = function() {

if (xmlHttp.readyState == 4) {

if (xmlHttp.status == 200) {

fnSucc(xmlHttp.responseText)

}

else {

if (fnFail) fnFail()

}

}

}

}

XMLHttpRequest返回值:

  • responseText:获得字符串形式的响应数据

  • responseXML:获得XML形式的响应数据

  • status、statusText:以数字和文本形式返回状态码

  • getAllResponseHeader():获得所有响应

  • getResponseHeader():查询响应中某个字段的值

  • readyState属性:

  • 0:未初始化,还没调用open方法

  • 1:载入,已经调用send方法,正在发送请求

  • 2:载入完成,send方法已完成,收到回应

  • 3:解析,正在解析响应内容

  • 4:完成,响应内容已经解析完成,可在客户端调用


14. 变量提升如何理解?


  1. 使用var声明的变量会被提前声明
1
2
console.log(a) //undefined
var a = 10
  1. 没有使用var声明的变量不会被提前声明
1
2
console.log(a) //Uncaught ReferenceError: a is not defined
a = 10
  1. 用function声明的函数也有提前
1
2
3
4
func1() // 1
function func1() {
console.log(\'1\')
}
  1. 形参相当于var声明
1
2
3
4
function func1(e) {
console.log(e)
}
func1() //undefined

15. 举例说明一个匿名函数的典型用例?


1
2
3
4
5
(function(o) {

console.log(o)

})()

16. 指出JS的内置对象和原生对象的区别?为什么扩张JS内置对象是不提倡的做法?有哪些内置对象和函数,举几个例子


  1. 区别
  • 内置(build-in)对象总是在引擎初始化的阶段就被创建好了,是原生对象的一个子集。
  • 而原生(Native)对象包括了一些运行过程中动态创建的对象。
  • 宿主对象是由宿主框架通过某种机制注册到Javascript引擎中的对象,BOM和DOM都是宿主对象。
  1. 为什么不提倡
  • 主要是担心Javascript官方哪天会实现该方法,导致逻辑冲突了
  1. 有哪些
  • 图片描述

17. Document load和document DOMContentLoaded两个事件之间的区别


区别:触发时机不一样,先触发DOMContentLoaded,再出发load

DOM文档加载的步骤:

  1. 解析HTML结构

  2. 加载外部脚本和样式表文件

  3. 解析并执行脚本代码

  4. DOM树构建完成,触发DOMContentLoaded

  5. 加载图片等外部文件

  6. 页面加载完毕,触发load


18. ===和==的区别


===是全等号,在==基础上增加了对数据类型的判断

19. typeof能够得到哪些值


number、string、boolean、undefined、object、function

20. 什么是”use strict”,好处和坏处是什么?


ECMAscript5新增的”严格模式”,可以让Javascript在更严格的环境下运行

  1. 好处:
  • 消除Javascript语法中一些不合理,不严谨的地方,减少怪异行为

  • 消除代码中运行的一些不安全之处,保证代码运行安全

  • 提高编译器效率,增加运行速度

  • 为未来新版本的Javascript做铺垫

  1. 坏处:
  • IE6789不支持

  • 有些库用了严格模式,有些没有,打包的时候如果合并到一个文件中,就会失效,并且造成字节浪费


21. 函数的作用域是什么?JS的作用域你了解吗?


属于这个函数作用域的全部变量都可以在整个函数范围内使用及复用(事实上在嵌套的作用域中也可以使用)。

全局变量有两种,一种是在函数外部声明的变量,另一种是函数内部没有用var、let声明的变量

局部变量指函数内用var或let声明的变量

其中用var声明的变量会出现变量提升

函数作用域会让内部的局部变量无法被外部访问

JS在ES6之前没有块作用域的概念,ES6之后加入了let关键字,可以声明只能在块里面使用的变量。


22. JS如何实现重载和多态?


  1. 多态

指在一个虚方法中实现不同功能

1
2
3
4
5
6
7
8
9
let makeSound = function(animal) {
animal.sound()
}
let Dusk = function() {}
Dusk.prototype.sound = function() { console.log('gaga') }
let Chicken = function() {}
Chicken.prototype.sound = function() { console.log('gege') }
makeSound(new Dusk())
makeSound(new Chicken())
  1. 重载
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
function override(obj, name, func) {
let old = obj[name]
obj[name] = function() {
if (arguments.length === func.length) {
func.apply(this, arguments)
}
else if(typeof old === 'function') {
old.apply(this.arguments)
}
}
}
var people = {
values: ['Zhang san', 'Li si']
}
override(people, 'find', function() {
console.log('无参数')
return this.values
})
override(people, 'find', function(firstname) {
let ret = []
for(let i = 0; i < this.values.length; i ++) {
if (this.values[i].indexOf(firstname) === 0) {
ret.push(this.values[i])
}
}
return ret
})
override(people, 'find', function(firstname, lastname) {
let ret = []
for (let i = 0; i < this.values.length; i ++) {
if (this.values[i] === firstname + ' ' + lastname) {
ret.push(this.values[i])
}
}
return ret
})
console.log(people.find())
console.log(people.find('Zhang'))
console.log(people.find('Li', 'si'))

本质上就是利用闭包强行将func保存在堆栈中,然后借助old用类似递归的方式找到对应的func,具体原理参考js如何实现重载


23. 什么是柯里化函数?如何实现?有什么好处?有什么缺点?


柯里化函数就是把接收多个参数的函数变成接收单一参数的函数的一种技术,bind的本质就是柯里化函数

最简单的实现有:

1
2
3
4
5
6
7
8
9
function curryAdd(x) {

return function(y) {

return x + y

}

}

通用的封装实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
function createCurry(func, args) {

let that = this

let len = func.length

let args = args || []

return function() {

let _args = [...args, ...arguments]

if (_args.length < len) {

return createCurry.call(that, func, _args)

}

return func.apply(this, _args)

}

}

function check(reg, targetStr) {

return reg.test(targetStr)

}

let _check = createCurry(check)

let checkPhone = _check(/^1[34578]d{9}$/)

console.log(checkPhone('18338384756'))

具体参考前端基础进阶(十):深入详解函数的柯里化

好处是可以实现参数复用、提前确认、延迟运行

坏处是用了闭包,容易造成内存消耗


24. 什么是惰性函数?如何实现?有什么好处?


惰性函数可以在执行一次分支之后,就无需再次进行判断的技术
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
(function addEvent(type, element, fun) {

if (window.addEventListener) {

addEvent = function(type, element, fun) {

element.addEventListener(type, fun, false)

}

}

else if (window.attachEvent) {

addEvent = function(type, element, fun) {

element.attachEvent('on' + type, fun)

}

}

else {

addEvent = function(type, element, fun) {

element['on' + type] = fun

}

}

})()

具体参考js对惰性函数的理解


25. 常用的数组API,字符串API有哪些?


数组API参考JavaScript数组参考手册

字符串API参考JavaScript String对象


26. 原生事件绑定(跨浏览器),下面案例中dom0和dom2的区别是什么?


以下属于dom0级的事件绑定:
1
2
3
<button class="btn" onclick="console.log('Hello')" />

document.getElementByClass('btn').onclick(() => console.log('Hi'))

以下属于dom2级的事件绑定:

1
document.getElementByClass('btn').addEventListener('click', () => console.log('Hey'))

区别:

dom0的事件会被覆盖

dom2的事件会全部触发,不会覆盖


27. 给定一个元素获取它相对于视图窗口的坐标?


  1. clientWidth和clientHeight,指
    元素内容+padding的大小,不包括border、margin、滚动条

  2. offsetHeight和offsetWidth,指 元素内容+padding+border
    的大小,不包括margin和滚动条

  3. clientTop和clientLeft,指 border宽度

  4. offsetTop和offsetLeft,指border外边缘与offsetParent对象的距离

  5. offsetParent指元素最近定位(relative、absolute)的祖先元素,如果没有则返回null

  6. getBoundingClientRect方法,返回一个left、right、top、bottom对象,分别表示四个位置相对于视窗的坐标,不包含margin


28. 深拷贝原理是什么,请简要描述过程?


深拷贝就是把引用数据类型中的数据都拷贝一份,得到一个完全独立于原对象的新对象,两个对象之间的引用数据不共享

实现:

  1. 正常实现
1
2
3
4
5
6
7
8
function deepCopy(obj) {
let newObj = {}
if (typeof obj != 'object') return obj
for (var attr in obj) {
newObj[attr] = deepCopy(obj[attr])
}
return newObj
}
  1. 借助Json的stringify和parse

29. 浏览器(web端)的Cookie如何设置跟获取?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function setCookie(cname, cvalue, exdays) {

let d = new Date()

d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000))

let expires = "expires=" + d.toGMTString()

document.cookie = cname + "=" + cvalue + ";" + expires

}

function getCookie(cname) {

let name = cname + "="

let ca = document.cookie.split(";")

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

var c = ca[i].trim()

if (c.indexOf(name) === 0) return c.substring(name.length, c.length)

}

return ""

}

30. setTimeout和Promise的执行顺序是什么?


异步任务分为宏任务和微任务

宏任务包括setTimeout、setInterval、setImmediate、I/O、UI rendering

微任务包括process.nextTick、Promise、MutationObserver

微任务首先执行,所有微任务执行完之后,再去取一个宏任务执行,如此往复。

因此Promise会在setTimeout之前执行


31. JS的事件流模型都有什么?


冒泡流、捕获流、DOM中的事件流(捕获+冒泡)

32. navigator对象,location和history你了解多少?


  1. navigator
  • back():后退

  • forward():前进

  • go():前往具体某个页面

  1. location
  • 包含当前URL的信息,可通过window.location

  • 方法:

  • hash 设置或返回从井号(#)开始的URL

  • host 设置或返回主机名和端口号

  • hostname 设置或返回当前主机名

  • href 设置或返回完整URL

  • pathname 设置或返回路径部分

  • port 设置或返回端口号

  • protocol 设置或返回URL协议

  • search 设置或返回问号(?)开始的部分

  • assign() 加载新的文档

  • reload() 重新加载当前文档

  • replace() 用新的文档替换当前文档

  1. history
  • 包含用户在浏览器窗口中访问过的URL,通过window.history访问

33. JS的垃圾回收机制


实现思路:
  1. 引用计数
  • 给所有对象进行引用计数,计数为0的对象会被当作垃圾回收
  • 缺陷:互相引用的对象会被不停地计数
1
2
3
4
var obj1 = {}
var obj2 = {}
obj1.x = obj2
obj2.x = obj1
  1. 标记清除
  • 垃圾回收器获取到根并标记它

  • 然后访问它的所有子对象,逐一标记

  • 继续访问子对象的子对象,标记,知道没有引用,保证同一个对象以后不会访问第二次

  • 没有被标记到的对象全部删除

  • 参考彻底掌握js内存泄漏以及如何避免


34. 说一下内存泄漏的原因和场景


不会再被用的对象没有被垃圾回收机制清理掉,就会造成内存泄漏。

如何分析内存泄漏可以参考深入了解 JavaScript
内存泄露

场景:

  1. 引用计数下对象互相引用

  2. 在函数中声明全局变量

1
2
3
function foo() {
bar = 'hello world'
}
  1. 被遗忘的定时器
1
2
3
4
var superBigData = {}
setInterval(function() {
console.log(supderBigData)
}, 200)
  1. 被遗忘的事件监听器

一般指挂在在window下的事件监听器忘了移除监听,如resize事件

1
window.addEventListener('resize', function() {})

35. DOM事件中的target和currentTarget有什么区别?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<ul>

<li>1</li>

<li>2</li>

<li>3</li>

<li>4</li>

<li>5</li>

</ul>

ul.addEventListener('click', function(e) {

console.log(e.target) // li

console.log(e.currentTarget) // ul

})

e.target指向触发事件的对象

e.currentTarget指向监听事件的对象


36. typeof和instanceof区别,instanceof的原理是什么?


  1. typeof
  • 返回值是一个字符串,说明该变量的类型
  1. instanceof
  • 用于判断是否某个对象的实例
  • 原理是查看对象B的prototype指向的对象是否在对象A的[[prototype]]链上

37. JS动画和CSS3动画有什么区别?


CSS3简单,但JS足够灵活

38. JS实现一个简单的倒计时程序


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var t = 10

var timer = setTimeout(function() {

t --

if (t <= 0) {

//doSomething

clearTimeout(timer)

}

}, 1000)

39. JS处理异常的语句有哪些?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
try {

// doSomething

}

catch(err) {

console.log(err)

}

finally {

//alway come in

}

40. JS的设计模式有哪些?


  1. 工厂模式

  2. 单例模式

  3. 模块模式

  4. 代理模式


41. 手指点击触控屏幕是什么事件


touch


42. JS代码调试


  1. 代码中加入debugger

  2. 可以在chrome中设置DOM节点变化的监听断点

  3. Ajax断点(XHR断点),可以监听网络传输

  4. 在chrome的开发者工具中可以使用Emulation标签来模拟手机尺寸

  5. 开发者工具中有个Audits插件,可以帮助你快速分析你的网站


43. 防抖函数和节流函数的实现,都适合什么场景?


  1. 防抖
  • 在多次触发事件的操作停止之后,才开始计时,必须等到计时完成才执行事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function debounce(func, wait, immediate) {
var timer
return function() {
if (timer) clearTimeout(timer)
if (immediate) {
var callNow = !timer
timer = setTimeout(() => timer = null, wait)
if (callNow) func.apply(this, arguments)
}
else {
timer = setTimeout(() => func.apply(this, arguments), wait)
}
}
}
  • 使用场景:

  • 登录、发短信等按钮

  • 调整窗口大小

  • 文本编辑器实时保存

  1. 节流
  • 不管期间触发了多少次操作,每个一段时间触发一次事件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
function trottle(func, wait, options) {

var timer, context, args

var previous = 0

if (!options) options = {}

var later = function() {

previous = !options.leading ? 0 : new Date().getTime()

timer = null

func.apply(context, args)

if (!timer) context = args = null

}

var trottled = function() {

var now = new Date().getTime()

// previous=now时,事件不执行

if (!previous && !options.leading) previous = now

var remaining = wait - (now - previous)

context = this

args = arguments

if (remaining <= 0 || remaining > wait) {

if (timer) {

clearTimeout(timer)

timer = null

}

previous = now

func.apply(context, args)

if (!timer) context = args = null

}

else if (!timer && options.trailing) {

timer = setTimeout(later, remaining)

}

}

}

使用场景:

  • 提交按钮

44. 如何实现一个拖拽,说一下思路


具体实现参考JavaScript进阶之实现拖拽(上)


45. 轮播图组件开发


具体实现参考offset相关属性和匀速动画(含轮播图的实现).docx

五、 ES6


1. 聊聊promise?


promise用于解决回调地狱的问题

promise有三种状态,Fullfilled代表成功,Rejected代表失败,Pending代表进行中

实现异步读文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import fs from 'fs'

function getFile(path) {

return new Promise((resolve, reject) => {

fs.readFile(fPath, 'utf-8', (err, dataStr) => {

if (err) return reject(err)

return resolve(dataStr)

})

})

}

getFile('01. txt')

.then(dataStr => console.log(dataStr))

.catch(err => console.log(err))

2. ES6特性你了解多少?如果遇到一个东西不知道是ES6还是ES5,你该如何区分?


  1. let和const

  2. iterable类型

  • Array、Map、Set都属于iterable类型,可以用for...of遍历
  1. 解构赋值

  2. 箭头函数

  3. 字符串模板


3. ES6的继承和ES5的继承有什么区别?


es5通过原型或构造函数来实现

es6用class关键字定义,类之间用extends继承,子类必须在constructor方法中调用super方法


4. Promise如何封装一个Ajax?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
function ajax(optionsOverride) {

var options = {}

// ajaxOptions为ajax的默认配置

for (var k in ajaxOptions) {

options[k] = optionsOverride[k] || ajaxOptions[k]

}

options.async = !options.async ? false: true

var xhr = options.xhr || new XMLHttpRequest()

return new Promise((resolve, reject) => {

xhr.open(options.method, options.url, options.async)

xhr.timeout = options.timeout

for (var k in options.headers) {

xhr.setRequestHeader(k, options.headers[k])

}

xhr.onprogress = options.onprogress

xhr.upload.progress = options.onuploadprogress

xhr.responseType = options.dataType

xhr.onabort = function() {

reject(new Error({

errorType: 'abort_error',

xhr: xhr

}))

}

xhr.ontimeout = function() {

reject(new Error({

errorType: 'timeout_error',

xhr: xhr

}))

}

xhr.onerror = function() {

reject(new Error({

errorType: 'onerror',

xhr: xhr

}))

}

xhr.onloadend = function() {

if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304)
return resolve(xhr)

reject(new Error({

errorType: 'status_error',

xhr: xhr

}))

}

try {

xhr.send(options.data)

}

catch(e) {

reject(new Error({

errorType: 'send_error',

error: e

}))

}

})

}

5. let和const的优点?


let和const有跨级作用域,不会变量提升


6. ES6 generator是什么,await/async的实现原理


generator函数是一个封装的异步任务,定义时只需要在function后面加个星号(*)即可,函数内部要用yield关键字来定义异步操作,执行它会返回一个遍历器对象,通过next或throw方法执行下一个异步操作。

async的内部实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
function spawn(gen) {

const it = gen()

!function step(nextFn) {

try {

var { data, done } = nextFn()

}

catch(e) {

return reject(e)

}

if (done) return resolve(data)

Promise.resolve(data)

.then(value => step(() => it.next(value)))

.catch(value => step(() => it.throw(value)))

}(() => it.next(undefined))

}

function* gen() {

try {

var a = yield new Promise((resolve, reject) => setTimeout(() => reject(100), 1000))

}

catch(e) {

a = e

}

let b = yield new Promise((resolve, reject) => setTimeout(() => resolve(102), 1000))

return a + b

}

async function asyncDemo() {

try {

var a = await new Promise((resolve, reject) => setTimeout(() => reject(100), 1000))

}

catch(e) {

a = e

}

let b = await new Promise((resolve, reject) => setTimeout(() => resolve(102), 1000))

return a + b

}

spawn(gen)

.then(value => console.log('spawn --> onFulfilled:', value))

.catch(value => console.log('spawn --> onRejected:', value))

asyncDemo()

.then(value => console.log('asyncDemo --> onFulfilled:', value))

.catch(value => console.log('asyncDemo --> onRejected:', value))

具体参考:[generator 到 async
的简单理解。](https://www.cnblogs.com/luoxiaoer/p/11735768. html)


7. ES6和node的commonjs模块化规范的区别


  • ES6是js的语法规范

  • commonjs主要解决js文件之间的依赖和引用问题,是一个包管理规范

六、 CSS


1. 盒模型的组成是什么?box-sizing有什么作用?


盒模型由margin(外边距)border(边框)padding(内边距)content(内容)组成

box-sizing有以下三个属性:

  1. content-box,以content为盒子的宽度和高度

  2. border-box,盒子的宽高包括边框和内边距,内容真正宽高会根据边框和内边距进行调整

  3. inherit,从父元素继承值


2. CSS3的新特性有哪些?伪类、伪元素、锚伪类分别有哪些?


  1. 新特性
  • CSS实现圆角(border-radius)、阴影(box-shadow)、边框图片(border-image)

  • 对字体加特效(text-shadow)、强制文本换行(word-wrap)、线性渐变(linear-gradient)

  • 旋转,缩放,定位,倾斜:transform: rotate(90deg) scale(.85, .9)
    translate(0px, -30px) skew(-9deg, 0deg)

  • 增加了更多的CSS选择器,多背景,rgba()

  • 在CSS3中唯一引入的伪元素是::selection;

  • 媒体查询(@media),多栏布局(flex)

  1. 伪类:用于向某些选择器添加效果
  • :hover 将样式添加到鼠标悬浮的元素上

  • :active 将样式添加到被激活的元素上

  • :focus 将样式添加到获得焦点的元素上

  • :link 将样式添加到未被访问过的元素上

  • :visited 将样式添加到被访问过的元素上

  • :first-child 将样式添加到元素的第一个子元素

  • :lang 定义指定的元素中使用的语言

  1. 伪元素:代表某个元素的子元素,这个子元素虽然在逻辑上存在,但不存在于文档树之中
  • ::first-letter 将样式添加到文本的首字母

  • ::first-line 将样式添加到文本的首行

  • ::before 在某元素之前插入某些内容

  • ::after 在某元素之后插入某些内容

  1. 新增伪类
  • p:first-of-type 选择<p>元素中首个<p>元素

  • p:last-of-type 选择<p>元素中最后一个<p>元素

  • p:only-of-type
    选择某个父元素中有且只有一个<p>元素的元素(允许非p元素存在)

  • p:only-child
    选择某个父元素中有且只有一个<p>元素的元素(不允许任何元素存在)

  • p:nth-child(n) 选择第n个元素,并且这个元素的类型是p

  • p:nth-last-child(n)
    选择某个父元素中倒数第n个<p>元素,并且这个元素的类型是p

  • p

  • p:nth-of-type(n) 选择p元素中第n个元素

  • p:nth-of-last-type(n) 选择p元素中倒数第n个元素

  • p:last-child 选择最后一个元素,且这个元素是p

  • p:empty 选择没有子元素的p元素

  • p:target 选择当前活动中的p元素

  • :not(p) 选择所有非p元素

  • :enabled 控制表单控件的可用状态

  • :disabled 控制表单控件的不可用状态


3. 使用CSS3实现隐藏元素的方式有几种?


  1. 通过opacity设置元素的透明度
1
.hide { opacity: 0; }
  1. visibility
1
.hide { visibility: hidden; }
  1. display
1
.hide { display: none; }
  1. position
1
.hide { position: absolute; top: -9999px; left: -9999px; }
  1. clip-path
1
.hide { clip-path: polygon(0px, 0px, 0px, 0px, 0px, 0px, 0px, 0px); }

4. 如何实现盒子在页面水平和垂直居中?


水平居中

  1. 行内元素
1
text-align: center;
  1. 顶宽块状元素
1
margin: 0 auto;
  1. 不顶宽块状元素
  • 在元素外加入table标签,该元素写在td之中,然后设置margin的左右为auto

  • 给元素设置display: inline,将元素转变成行内元素,然后使用text-align:
    center

  • 父元素设置position: relative; display: float; left:
    50%,该元素设置position: relative; left: -50%;

垂直居中:

  1. 父元素高度确定的单行文本,设置line-height等于父元素的height

  2. 父元素高度确定的多行文本

  • 父元素嵌入到table中,然后设置vertical-align: middle;

  • 先设置display: table-cell; 然后设置vertical-align: middle;

其他解决方案:

  1. 使用transform
1
2
3
4
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%)
  1. 使用flex
1
2
3
display: flex;
justify-content: center;
align-item: center;

5. 详细描述一下position和display?


  1. position
  • absolute

    • 绝对定位,相对于static定位以外的第一个父级元素左上角定位,脱离正常文档流
  • fixed

    • 固定定位,相对于浏览器窗口左上角定位,脱离正常文档流
  • relative

    • 相对定位,相对于其父元素定位,不脱离正常文档流
  • sticky

    • 粘性定位,会根据滚动条改变展示效果,比如设置top: 0时,当元素未滚动到页面顶端,元素为relative定位;当元素滚动到页面顶端时,元素变为fixed定位
  • static

    • 默认值,没有相对定位,在正常文档流之中
  • inherit

    • 继承父级元素的定位
  1. display
  • none

    • 不显示元素
  • block

    • 显示为块级元素,前后有换行符
  • inline

    • 行内元素
  • inline-block

    • 结合了inline和block的特点,既可以设置长宽、margin、padding,又能跟其他行内元素并排

6. 浮动元素引起的问题和解决办法


  1. 引起的问题:
  • 浮动元素脱离文档流,导致父级元素无法被撑开,影响其他同级元素

  • 与浮动元素同级的非浮动元素会跟随其后,脱离文档流

  • 如果浮动元素不是同级元素的第一个,那么在它之前的元素也应该浮动,否则影响显示

  1. 解决办法
  • 额外标签法(隔墙法)

  • 在旁边增加一个<br class="clear" />

  • 设置.clear { clear: both; }

  • 使用伪类after,本质上就是隔墙法的一种变异

  • 在父元素中添加clearfix类,在clearfix做如下设置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    .clearfix:after {
    clear: both;
    content: "";
    visibility: hidden;
    height: 0;
    display: block
    }
    .clearfix {
    /* 触发hasLayout */
    zoom: 1;
    }
  • 设置高度或者使用overflow:hidden/auto;

  • 浮动外部元素(会影响布局,不推荐)


7. link和@import引入CSS的区别


  1. 适用范围不同
  • @import可以在网页中使用,也能在css文件中使用,用来将多个css文件整合到一个css文件中;而link只能在网页中使用
  1. 功能范围不同
  • link是一种XHTML标签,除了加载CSS,还能定义RSS,定义ref连接属性等
  • @import是CSS提供的一种方式,只能加载CSS
  1. 加载顺序不同
  • 当一个页面被加载时,link引用的CSS会被同时加载,而@import引用的CSS会等到页面加载完之后再加载,所以网速慢的时候,使用@import会出现闪烁的情况
  1. 兼容性差别
  • @import是在CSS2.1之后提出的,所以老的浏览器不支持。link则没有这个问题
  1. 控制样式时差别
  • 使用link方式可以让用户切换CSS样式

8. 解释一下css3的flexbox,以及适用场景


弹性布局的主要思想是让容器有能力来改变元素的宽度和高度,以填满可用空间(主要是为了容纳所有类型的显示设备和屏幕尺寸)的能力。


9. 哪些是块级元素哪些是行级元素,各有什么特点?


行内元素 块级元素
a、b、em、font、i、img、input、br、label、span、small、select、textarea address、dl、div、form、h1-h6、hr、menu、ol、p
行内元素不会独占一行,相邻的行内元素会排在同一行,一行排不下会自动换行,其宽度随元素的内容变化而变化 块级元素会独占一行,其宽度自动填满其父元素宽度
行内元素的padding-top/bottom,margin-top/bottom都不能产生边距效果,无法设置width和height 块级元素可以设置margin和padding,也可以设置宽高

10. 网格布局(grid)了解吗


Grid布局又称"网格",是一个基于二维网格布局的系统,但Grid布局目前应用得不是很广泛,也没有企业级的实现案例,原因可能是flex布局已经满足日常需要,并且很多移动端的内置浏览器对其支持性不太好

11. 传统表格布局了解吗?


Table用于布局,主要用来批量显示数据。但Table有一个缺点,就是加载页面的时候,需要将全部数据都请求到才显示页面,否则就是一片空白,所以现在一般不用Table布局。但其稳定性非常优秀,一般在管理系统类项目中用的比较多。

12. 实现两栏布局你知道有哪些办法?


  1. 左边float: left; 右边margin-left
1
2
3
4
5
6
7
.left {
float: left;
width: 200px;
}
.right {
margin-left: 200px;
}
  1. 左边float: left; 右边overflow
1
2
3
4
5
6
7
.left {
float: left;
width: 200px;
}
.right {
overflow: hidden;
}
  1. 使用absolute
1
2
3
4
5
6
7
8
9
10
11
.wrap {
position: relative;
}
.left {
width: 200px;
}
.right {
position: absolute;
left: 200px;
right: 0; // 限制右边块级元素的宽度
}
  1. 使用table
1
2
3
4
5
6
7
8
9
10
.wrap {
display: table;
}
.left {
display: table-cell;
width: 200px;
}
.right {
display: table-cell;
}
  1. 使用inline-block和calc函数
1
2
3
4
5
6
7
8
.left {
float: left;
width: 200px;
}
.right {
float: left;
width: calc(100% 200px)
}
  1. 使用flex
1
2
3
4
5
6
7
8
9
.wrap {
display: flex;
}
.left {
flex: 0 0 200px;
}
.right {
flex: 1;
}

13. DPI是什么


每英寸包含点的数量(dots per inch)

普通屏幕通常是96DPI,一般将2倍于此的屏幕叫做高分屏,即大于等于192DPI,比如Mac的视网膜屏就达到192DPI,打印时需要更大的DPI


14. Attribute跟Property有什么区别


Property是DOM中的属性,是Javascript里边对象

Attribute是HTML标签的特性,它的值只能够是字符串


15. css布局问题,css实现三列布局怎么做?如果中间是自适应又该怎么做?


  1. 绝对定位

中间不给宽度,左右绝对定位left和right实现自适应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
.wrap {
position: relative;
}
.left {
position: absolute;
left: 0;
width: 100px;
}
.right {
position: absolute;
right: 0;
width: 200px;
}
.middle {
position: absolute;
left: 100px;
right: 200px;
}
  1. 两侧浮动+中间自动撑开
1
2
3
4
5
6
7
8
.left {
width: 100px;
float: left;
}
.right {
width: 150;
float: right;
}

中间自适应的方案有很多,可以直接设置display:
block,或使用calc计算出宽度,或者给左右设置固定的margin

1
2
3
.middle {
display: block;
}
  1. 圣杯布局和双飞翼布局

通过设置负值margin来覆盖middle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
<div class="wrap">
<div class="middle">middle</div>
<div class="left">left</div>
<div class="right">right</div>
</div>
.wrap {
overflow: hidden;
}
.middle {
width: 100%;
background: green;
height: 100px;
float: left;
}
.left {
float: left;
margin-left: -100%;
width: 100px;
height: 100px;
background: red;
}
.right {
float: left;
margin-left: -150px;
width: 150px;
height: 100px;
background: blue;
}

但这样写,middle的内容会被left的内容挡住,如图:

圣杯布局:给wrap设置padding往中间收,left和right则设置负值挂在两边

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<div class="wrap">
<div class="middle">middle</div>
<div class="left">left</div>
<div class="right">right</div>
</div>
.wrap {
padding: 0 150px 0 100px;
overflow: hidden;
}
.middle {
position: relative;
width: 100%;
background: green;
height: 100px;
float: left;
}
.left {
position: relative;
float: left;
margin-left: -100%;
width: 100px;
height: 100px;
background: red;
left: -100px;
}
.right {
position: relative;
float: left;
margin-left: -150px;
width: 150px;
height: 100px;
background: blue;
right: -150px;
}

双飞翼布局:给middle加一个inner,用margin与left跟right分隔开

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<div class="wrap">
<div class="middle">
<div class="inner">middle</class>
</div>
<div class="left">left</div>
<div class="right">right</div>
</div>
.wrap {
overflow: hidden;
}
.inner {
margin: 0 150px 0 100px;
}
.middle {
width: 100%;
background: green;
height: 100px;
float: left;
}
.left {
float: left;
margin-left: -100%;
width: 100px;
height: 100px;
background: red;
}
.right {
float: left;
margin-left: -150px;
width: 150px;
height: 100px;
background: blue;
}

双飞翼跟圣杯的区别是双飞翼的middle的宽度是囊括left和right两部分的,只是中间的inner不被left和right
挡住。

  1. flex布局

16. 流式布局如何实现,响应式布局如何实现?


  1. 流式布局

宽度使用百分比来定义的布局,会随着屏幕宽度增减来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<body>
<header>header</header>
<nav>nav</nav>
<section>
<aside>aside</aside>
<article>article</article>
</section>
<footer>footer</footer>
</body>
body > * {
width: 95%;
height: auto;
margin: 0 auto;
margin-top: 10px;
border: 1px;
solid: #000;
padding: 5px;
}
header {
height: 50px;
}
section {
height: 300px;
}
footer {
height: 30px;
}
section > * {
height: 100%;
border: 1px solid #000;
float: left;
}
aside {
width: 25%;
}
article {
width: 73%;
margin-left: 1%;
}
  1. 响应式布局
  • 在meta标签中通过媒体查询识别不同平台,给它们配对不同的CSS布局

具体实践可以参考前端响应式布局原理与实践


17. 瀑布流如何实现?


可以借助插件Mansory


18. transition和animation的区别,animation的属性有什么


  1. transition
  • transition:

  • 过渡属性 过渡所需要时间 过渡动画函数 过渡延迟时间

  • 优点:简单易用

  • 缺点:

  • 需要事件触发,所以没法在网页加载时自动发生

  • 是一次性的,不能重复发生,除非一再触发

  • 只能定义开始状态和结束状态,没有中间状态

  • 一条transition规则只能定义一个属性的变化,不能涉及多个属性

  1. animation
  • animation:

  • 动画名称 动画周期 动画函数 等待时间 播放次数 是否倒放 动画状态

  • 动画前后操作

  • animation制作动画主要包括两个部分:

  • 用关键帧声明一个动画

  • 在animation中调用关键帧声明的动画,@keyframes就是关键帧,一个@keyframes中的样式规则可以由多个百分比构成,通过定义每个百分比的具体行为,实现多变的动画效果。另外,增加webkit前缀可以让兼容性更好?

  1. 区别
  • transition需要触发一个事件才会随着时间改变其CSS属性;animation则不需要

19. 请写出使用CSS3旋转图片的代码片段


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<!DOCTYPE html>

<html lang="zh-CN">

<head>

<meta charset="UTF-8" />

<title>Rotation</title>

<style type="text/css">

#img {

width: 280px;

height: 280px;

background: url('shishi.png') no-repeat;

border-radius: 50%;

-webkit-animation: run 6s linear 0s infinite;

}

#img: hover {

-webkit-animation-play-state: paused;

}

@-webkit-keyframes run {

from { -webkit-transform: rotate(0deg); }

to { -webkit-transform: rotate(360deg); }

}

</style>

</head>

<body>

<div id="img"></div>

</body>

</html>

20. 对移动端开发了解多少?


  1. 响应式布局(@media)

  2. Zepto是移动端的jQuery,使用也不怎么广泛

  3. viewport

  4. js正则判断平台


21. 什么是BFC,如何去创建BFC?它能解决什么问题?


BFC的设计目的可以参考:深度剖析Margin塌陷,BFC,Containing Block之间的关系

BFC的使用场景可以参考:CSS: What is Block Formatting Context (BFC)?

定义:
BFC即块级格式化上下文,它规定了内部的Block-level Box如何布局,并且与这个区域外部毫不相干。

布局规则:

  • 内部的Box会在垂直方向上一个接一个布置
  • Box垂直方向的距离是由margin决定的,属于同一个BFC的两个相邻Box的margin会发生重叠

如何创建BFC:

  • float不为none

  • overflow不为visible

  • display为table-cell、table-caption、inline-block

  • position是absolute或fixed


22. CSS中的长度单位有哪些?


  1. 绝对长度单位
  • px:代表一个像素单位

  • in:英寸,1in = 96px

  • cm:厘米,1cm = 37. 8px

  • mm:毫米

  1. 相对长度单位
  • em:根据父级的fontsize来定义的

  • rem:根据根元素的fontsize来定义的

  • pt:1pt = 1/72in

  • pc:1pc = 12pt

  • ex:基于当前字体的x字母高度来度量的

  • ch:基于当前字体的0字符来度量的

  1. 可视区百分比长度单位
  • vw:可视区的宽度,1vw等于可视区宽度的百分之一,vw单位跟百分比相似

23. CSS中选择器的优先级?如何计算权重?


!important > 行内样式 > ID选择器 > 类选择器 > 标签 > 通配符 > 继承 > 浏览器默认属性

如下例:

#box .box2 p {} // 1个ID选择器,1个类选择器,1个标签,最终值是1,1,1

div div #box3 p {} // 1个ID选择器,0个类选择器,3个标签,最终值是1,0,3

div.box1 div.box2 div.box3 p {} // 0个ID选择器,3个类选择器,4个标签,最终值是0,3,4

因此优先级最高的是第一个


24. CSS中哪些属性会被继承,哪些不会?


关于字体样式的属性,都具有继承性,包括:color、text-*、line-*、font-*

盒子、定位、布局的属性都不会继承


25. 雪碧图(精灵图)?


把网站中使用的图片整合到一张图片中,通过background-position来定位图片,十分适合用来整合小图标。优点是大幅减少对服务器的HTTP请求数量

26. 什么是SVG,它能做什么?


SVG是一种可伸缩的矢量图形,用来定义网络基于矢量的图形,图形在放大或者改变尺寸时,其图形质量不会有所损失

27. CSS的加载是异步的吗?它表现在什么地方?


在link元素中添加media属性,并为media添加一个浏览器不支持的值,如none。即可实现CSS的异步加载。同理可用来延迟加载JS

28. 工作中遇到的浏览器兼容问题有哪些?你知道哪些常用的HACK技巧?


  1. 不同浏览器的默认初始值不一样
  • 最简单的实现是:
1
2
3
4
* {
margin: 0;
padding: 0;
}
  • 更加细节的设置可以使用插件,webpack等构建工具已经自带了这类插件
  1. IE相关的问题基本可以不管

29. 请解释一下”::before”和”:before”中双冒号跟单冒号的区别


单冒号兼容IE浏览器

30. 用CSS定义p标签,要求实现以下效果:字体颜色在IE6下为黑色(#000),IE7下为红色(#f00),而其他浏览器为绿色(#0f0)


1
2
3
4
5
6
7
8
9
p {

color: green;

*color: blue;

_color: red;

}

31. rgba()和opacity的透明效果有什么不同?


opacity作用于元素,元素内所有内容都会透明

rgba()只作用于元素的颜色或者背景色,子元素不会继承透明效果。

七、 框架 / 类库


1. jQuery源码如何实现选择题,为什么$取得的对象要设计成数组的形式,这样设计有什么目的?


jQuery内部采用一种”类数组对象”的存储结构,既可以像对象一样处理jQuery操作,也可以像数组一样使用push、pop、shift、sort、each、map等类数组方法操作jQuery对象。


2. jQuery如何绑定事件,有几种类型和区别?


on,其他的都被废除了。


3. 什么是MVVM,MVC,MVP?


  1. MVC:M(Model 模型)数据保存,V(View 视图)展示html页面,C(Control
    控制器)业务逻辑,视图的改变会通过控制器要求数据层改变状态,然后反馈会视图层

  2. MVVM:是Model-View-ViewModel的缩写,View可以独立于Model的变化和修改

  3. MVP:将Control改为Presenter,View和Model不发生联系,都通过Presenter传递,所有交互都发生在Presenter内部,而在MVC中View会直接从Model中读取数据,而不通过Control


4. Vue和Angular的双向数据绑定原理


vue将普通对象的属性通过Object.defineProperty转换为ES5特性之一getter/setter,模版中每个指令/数据绑定都有一个对应的watcher对象,当修改对象值时,首先会触发属性setter,在setter被调用时,会触发watcher重新计算,也就会导致它的关联指令更新DOM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function defineReactive(obj, key, value) {

var dep = new Dep()

Object.defineProperty(obj, key, {

enumerable: true,

configurable: true,

get: function reactiveGetter() {

if (Dep.target) dep.depend()

return value

},

set: function reactiveSetter(newVal) {

if (value === newVal) return

value = newVal

dep.notify()

}

})

}

angular.js是通过脏值检测的方式查看数据是否变更,最简单的办法是通过setInterval()定时循环检测数据变化


5. Vue组件通信以及路由原理


  1. 使用prop和emit

  2. 将组件封装成template,提高上一级

  3. 使用vuex

  4. 使用eventBus,不推荐,会让数据变乱

八、 NodeJs


1. 对node.js有没有了解


node.js既是平台,也是运行环境,也是新的语言。它本身是基于google的javascript
v8引擎开发的,它实际上是一种服务端开发+运行的JS语言,有一点类似Perl+PHP或者Python的概念,它本身可以作为HTTP
Server,也可以当作TCP Server


2. Express和Koa有什么关系,有什么区别?


Koa是由Express原班人马打造,致力于一个更小、更富有表现力、更健壮的Web身份。

使用Koa编写web应用,通过组合不同的generator,可以免除重复繁琐的回调函数嵌套,并极大地提升错误处理效率。

Koa只提供一个框架,需要什么都可以DIY。而Express则啥都有。


3. node.js适合做什么业务?


node.js是单线程,非阻塞I/O,事件驱动,它的特性决定它适合做一些大量I/O的东西,比如:聊天室、表单提交等不需要大量计算的功能。


4. node.js中的Stream和Buffer有什么区别?


Buffer:为数据缓冲对象,是一个类似数组结构的对象,可以通过指定开始写入的位置及写入的数据长度,往其中写入二进制数据

Stream:是对Buffer对象的高级封装,其操作的底层是Buffer对象,Stream可以设置为可读、可写,或者即可读也可写,在node.js中继承了EventEmitter接口,可以监听写入、读入的过程。具体实现有文件流,httpresponse等


5. node的异步问题是如何解决


使用async/await

九、 前端工程化


1. webpack,gulp,grunt等构建工具了解多少,有什么区别?


webpack与gulo、grunt没什么可比性,webpack可以看作模块打包机,通过分析你的项目结构,找到js模块以及其他一些浏览器不能直接运行的拓展语言(Scss、Typescript等),并将其转换和打包为合适的格式供浏览器使用。主要用于预编译方案、模块化方案。

glup是工具链、构建工具,可以配合各种插件做js压缩、css压缩、less编译。替代手工实现自动化工作。相对于grunp频繁的IO操作,glup的流操作更快捷方便


2. webpack的入口文件如何配置


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
const path = require('path')

module.exports = {

entry: {

entry: './src/entry.js'

},

output: {

path: path.resolve(__dirname, 'dist')

filename: 'bundle.js'

},

// 模块:例如解读css,图片如何转换,压缩

module: {},

plugins: [],

devServer: {}

}

3. webpack的loader和plugins的区别


loader用于加载被打包的资源,plugin用于扩展webpack

十、 模块化


1. 对AMD,CMD,commonJs有什么理解?


  1. AMD规范即异步模块加载机制。ADM规范其实只有一个主要接口define(id,
    dependencies,
    factory),它要在声明模块的时候指定所有依赖dependencies,并且还要当作形参传到factory中
1
2
3
4
define("module", ["dep1", "dep2"], function(d1, d2) {
return someExportedValue
})
require(["module", "../file"], function(module, file) {})
  • 优点:1. 适合在浏览器环境异步加载 2. 并行加载多个模块
  • 缺点:1. 提高开发成本,代码书写和阅读困难 2.
  • 不符合通用的模块思维,是一种妥协的实现
  1. CMD规范与AMD类似,尽量保持简单。另外它CommonJS、NodeJS的Modules规范保持很大的兼容性。在CMD中,一个模块就是一个文件,格式为:define(factory)
  • 优点:1. 依赖就近,延迟执行 2. 很容易在Node中运行
  • 缺点:以来SPM打包,模块加载逻辑偏重
  1. CommonJS是以在浏览器环境之外构建JS生态系统为目标的项目,比如在服务器和桌面环境中。CommonJS规范是为了解决JS的作用域问题而定义的模块形式,可以使模块在自身命名空间中执行。该规范的主要内容是:模块必须通过module.exports导出对外的变量或接口,通过require()来导入其他模块的输出到当前模块。
1
2
3
4
5
6
7
// moduleA.js
module.exports = function(value) {
return value * 2
}
// moduleB.js
var multiBy2 = require('./moduleA.js')
var result = multiBy2(4)

CommonJS是同步加载模块,一个单独的文件就是一个模块。但其实也有浏览器端的实现,其原理是将所有模块都定义好,并通过id进行索引。

优点:1. 服务器端便于重用 2. NPM中已经有将近20W个模块包 3.
简单并容易使用

缺点:
1.同步的模块方式不适合在浏览器环境中,同步意味着阻塞加载,浏览器的资源是异步加载的
2.不能非阻塞地并行加载多个模块


2. 为什么要模块化?不用的时候和用requireJS的时候代码该如何书写?


  1. 方便大量的js脚本代码的管理维护以及团队配合开发

  2. 有效解决命名空间冲突以及文件依赖加载顺序问题

  3. 有利于模块的版本管理,提高可维护性,有利于前端优化,跨环境共享模块


3. 分别说说同步和异步模块化的应用场景,说一下AMD异步模块化的实现原理


引入JS可以用异步加载,借助require.async即可实现

十一、数据结构相关


1. 基本数据结构:(数组、队列、链表、堆、二叉树、哈希表等)


  1. 数组
  • 数组是最基本的数据结构,使用一块连续的内存空间保存数据
  1. 队列
  • 是一种先入后出的逻辑结构,对于元素的操作分别在队头和队尾,元素插入在队尾,元素的删除在队头。
  1. 链表
  • 存储的数据在地址空间上可连续,可不连续,链表中每一个节点包括数据和指向下一个地址的指针,查找数据的时间复杂度O(n),方便数据增删
  • 栈是一种先入后出的逻辑结构,每次加入新的元素和拿走元素都在顶部操作
  1. 二叉树
  • 每个节点至多只有两个子树的结构,在父节点中有指向左右子节点的指针

  • 先序遍历:根-左-右,中序遍历:左-根-右,后序遍历:左-右-根

  • 查找二叉树:左子树的值小于根节点的值,右子树的值大于根节点的值,在插入数据时,从根节点开始往下比较,小于比较值则放在左边,大于比较值就放在右边。插入一个值的时间复杂度是O(logn)

  • 平衡二叉树:左右子树的高度差绝对值不超过1

  1. 哈希表

2. 8种排序算法,原理,适用场景以及复杂度


注:基数排序的复杂度中,r代表关键字的基数,d代表长度,n代表关键字的个数

具体原理参考:八大常用排序算法详细分析
包括复杂度,原理和实现


3. 说出费波拉切数列的实现方法,越多越好


  1. 递归
1
2
3
4
5
function fib(n) {
if (n == 1 || n == 2) return 1
return fbnq(n 1) + fbnq(n 2)
}
fbnq(10)
  1. 非递归
1
2
3
4
5
6
7
8
9
10
11
function fb(n) {
var a, b, res
a = b = 1
for (var i = 3; i <= n; i ++) {
res = a + b
a = b
b = res
}
return res
}
fb(10)

十二、性能优化


1. CDN的用法是什么?什么时候用到


CDN即内容分发网络。CDN的原理是广泛采用各种缓存服务器,将这些缓存服务器分布到用户访问相对集中的地区或网络中,在用户访问网站时,利用全局负载技术将用户的访问指向距离最近的工作正常的缓存服务器上,由缓存服务器直接响应用户请求。

  • CDN的适用场景:
  • 解决因分布、带宽、服务器性能带来的访问延迟问题,适用于网站站点/应用加速、点播、直播、视音频点播、大文件下载分发加速、移动应用加速等场景

2. 说说一些常见的性能优化手段


  1. CSS放在head中,JS放在</body>前

  2. 不要使用css表达式,css的表达式一方面是兼容性问题,虽然看起来比较强大,但实际性能开销很大,因为它实际的执行效率是远远超出预期的,如果使用css表达式,会导致页面卡顿

  3. 用外链引用css和js,可以有效减少HTML体积,并且外链之后,css和js作为静态资源可以给他设置合适的缓存的响应头,能够利用浏览器的缓存

  4. 让Ajax请求可缓存,Get请求可以缓存

  5. 组件延迟加载,保证页面关键的静态资源有限加载

  6. 减少DOM节点数,如果DOM结构非常复杂,那么浏览器在解析的时候,进行布局、渲染时计算量更大。

  7. 避免在页面中使用frame类(包括iframe和frameset),因为iframe会阻塞父文档的onload,即使它是空白的。

  8. 要减少Cookie的体积

  9. 静态资源加载不用带上Cookie

  10. 减少js对DOM访问,缓存在变量中。另外还可以利用DocumentFragment

  11. 利用冒泡机制来绑定事件,然后在事件中区分target对象,而不是给每个target都绑定事件

  12. 常用的压缩图片的工具:”PNGCrush”、”JPEGTRAN”、”PNGQUANT”

  13. 不要在HTML中缩放图片,会额外增加渲染开销

  14. 不要让图片SRC留空,会引发额外的请求

  15. 任何资源尽量控制在25k以内,因为iPhone无法缓存25k以上的资源

  16. DNS优化、CDN优化、http优化,减少域名解析事件,增多域名提高并发


3. 如何优化DOM操作的性能


  1. 查找元素优化。查找速度:ID > 类 > 属性

  2. 减少操作元素

  3. 减少通过DOM修改样式,修改样式也会导致浏览器重新渲染。

  4. 批量修改DOM时从文档流中摘除该元素,对其应用多重改变,将元素带回文档中,这样可以最小化重绘和重排版

  • 具体方法:

  • 隐藏元素,进行修改,然后显示它

  • 将原始元素拷贝到一个脱离文档的节点中,修改副本,然后覆盖原始元素

  1. 减少iframe,iframe需要消耗

  2. 多次访问同一DOM,要用局部变量暂存


4. 单页面应用有什么SEO方案?


  1. 采用history模式

  2. 用后端做一套页面,内容和前端一摸一样,即所谓的静态化,sail框架、Node.js中的express框架、php都可以实现

  3. 用nginx做代理跳转,将搜索引擎识别后将流量引到后端的端口上,预先渲染给搜索引擎看的页面,还有history模式自带的404问题也需要在nginx里将404转index.html或者rewrite

  4. 服务端渲染首屏

  5. 让服务器把首屏数据渲染到页面上

  6. 进行基本的css模版js的编译合并

  7. 减少请求次数,借助gulp工具把css和js分别打包成一个文件

  8. 代码分块,如果首屏不需要的块,就不用加载了

  9. 路由组件懒加载

  10. 大量图片懒加载

十三、其他


1. 前端渲染和后端渲染的区别


  • 前端渲染:

指的是后端只返回JSON数据,前端利用预先写的html模版,循环读取JSON数据,拼接字符串(es6的模版字符串特性大大减少了拼接字符串的成本),并插入页面。

好处:网络传输数据量小,不占用服务端运算资源(解析模版),模版在前端(很可能仅部分在前端),改结构变交互都前端自己来,改完自己调就行。

坏处:前端耗时较多,对前端工作人员要求比较高,前端代码多,因为部分以前在后台处理的交互逻辑交给了前端处理,占用少部分客户端运算资源用于解析资源

  • 后端渲染:

  • 前端请求,后端用后台模版引擎直接生成html,前端接受数据后,直接插入页面。

  • 好处:前端耗时少,即减少首屏时间,模版统一在后端,前端(相对)省事,不占用客户端运算资源(解析模版)

  • 坏处:占用服务器资源

  • 对比

前端渲染 后端渲染
页面呈现速度 主要受限于带宽和客户端的性能,优化得好,可以逐步动态展开内容,感觉上会更好一点 快,受限于用户的带宽
流量消耗 多一点点(一个前端框架大概50KB) 少一点点(可以省去前端框架部分的代码)
可维护性 好,前后端分离,各施其职,一目了然 差(前后端东西放在一起,掐架多年,早就闹分手了)
SEO友好度 差,大量使用ajax,多数浏览器不能抓去ajax数据
编码效率 高,前后端只做自己的事情 低(不同团队可能有不同效率)

2. 数据库的四大特性,什么是原子性,表的关系


四大特性:原子性、一致性、分离型、持久性

  • 原子性

  • 事务中包含的程序作为数据库的逻辑工作单位,它所做的对数据操作修改要么全部执行,要么全部不执行,这种特性称为原子性。

  • 假设用户在一个事务内完成了对数据库的更新,这时所有的更新对外部世界必须是可见的,或者完全没有更新。前者称事务已提交,后者称事务已撤销(或流产)。DBMS必须确保成功提交事务在数据库内有完全的反应,而失败的数据库对数据完全没有影响。

  • 一致性

  • 指的是一个事务执行之前和执行之后数据库都必须处于一致性状态。加入数据库的状态满足所有完整性约束,就说数据库是一致的。

  • 例如,当数据库处于一执行状态S1时,对数据库执行一个事务,在事务执行期间假定数据库的状态不一致,当事务执行结束时,数据库处于一致性状态S2

  • 分离型

  • 并发的事务是相互隔离的。即一个事务内部的操作及正在操作的数据必须封锁起来,不被其他企图进行修改的事务看到。

  • 分离型是DBMS针对并发事务间的冲突提供安全保证。DBMS可以通过加锁在并发事务之间提供不同级别的分离。

  • 持久性

  • 一旦一个事务提交,DBMS保证它对数据库中数据的改变是持久性的,耐得住任何系统故障。持久性通过数据库备份和恢复来保证


3. SEO


SEO即Search(搜索)Engine(引擎)Optimization(优化)。

网站的结构优化:

  1. 控制首页链接数量
  • 网站首页是权重最高的地方,如果首页链接过少,爬。虫不能继续往下爬到内页,直接影响网页收录的数量。但是首页链接不能太多,一旦太多,没有实质性链接,很容易影响用户体验,也会降低网站首页的权重。
  • 因此对于中小型网站,建议首页链接控制在100个以内,链接性质可以包括页面导航、底部导航、锚文字链接等等,注意链接要建立在用户的良好体验和引导用户获取信息的基础上。
  1. 扁平化的目录层次
  • 尽量让一个”蜘蛛”只要跳转3次,就能达到网站内每一个内页。
  • 代码优化:
  1. <title>标题:只强调重点即可,尽量把重要的关键词放在前面,关键词不要重复。

  2. <meta keywords>标签:关键词,列举出几个页面的重要关键字即可

  3. <meta description>标签:网页描述,需要高度梗概内容,不要过长。

其他SEO策略可以参考网站:https://www.xminseo.com/


4. mySql和MongoDB有什么区别


  1. mySql

    • 关系型数据库

    • 在不同引擎上有不同的存储方式

    • 查询语句是使用传统的sql语句,拥有成熟的体系

    • 开源数据库的份额不断增加,mysql的份额页也在持续增长

    • 缺点就是在海量数据处理的时候效率会显著变慢

  2. MongoDB

  • 非关系型数据库(NoSql),属于文档型数据库,可用xml、json、bson(Binary-JSON)格式存放数据,这些数据具备自述性(self-describing),呈现分层的树状数据结构,数据结构由键值对(key

  • => value)组成。

  • MongoDB是有C++语言编写的,主要是在为web应用提供可扩展的高性能数据存储解决方案。

  • 存储方式:虚拟内存+持久化

  • 查询语句:是独特的MongoDB查询方式

  • 适合场景:事件的记录,内容管理或者博客平台等等。

  • 架构特点:可以通过副本集,以及分片来实现高可用

  • 数据处理:数据是存储在硬盘上,只不过需要经常读取的数据会被加载到内存中,将数据存储在物理内存中,从而达到高速读写。

  • 成熟度与广泛度:新型数据库,成熟度较低,Nosql中最为接近关系型数据库,比较完善的DB,使用人群在不断增长。

  • 优点:

    • 快速!在适量级的内存的MongoDB的性能非常迅速,它将热数据存储在物理内存中,使得热数据的读写非常快。

    • 高扩展

    • 自身的Failover的机制

    • json的存储格式

    • 内置GridFS,支持大容量的存储

    • 内置Sharding,分片简单

    • 海量数据下,性能优越

    • 支持自动故障恢复(复制集)

  • 缺点:

    • 不支持事务操作

    • 占用空间过大

    • MongoDB没有如mySql成熟的维护工具

    • 无法进行关联表的查询,不适用于关系多的数据

    • 复杂聚合操作通过mapreduce创建,速度慢

    • 模式自由,自由灵活的文件存储格式带来的数据错误


5. click在ios上有300ms的延迟,是什么原因,如何解决


原因:2007年初,苹果公司在发布首款iPhone前夕,遇到了一个问题——当时的网站都是为大屏幕设备设计的。于是苹果的工程师做了一些约定,应对iPhone这种小屏幕浏览桌面端站点的问题。这当中最出名的,当属双击缩放(double
tap to zoom)。这也是上述会有300毫秒延迟的原因。

当用户一次点击屏幕之后,浏览器并不能立刻判断用户是要进行双击缩放,还是要进行单击操作。因此,iOS
Safari就等待300毫秒,以判断用户是否再次点击

解决:FastClick是FTLabs专门为解决移动端浏览器300毫秒点击延迟问题所开发的一个轻量级的库。简而言之,FastClick在检测到touchend事件后,会通过DOM自定义事件立即触发一个模拟click的click事件(自定义事件),并把浏览器在300毫秒之后真正触发click事件阻止掉。


6. 移动端的手势和事件


触摸事件:

  • touchstart:当手指放在屏幕上触发

  • touchmove:当手指在屏幕上滑动时,连续地触发

  • touchend:当手指从屏幕上离开

  • touchcabcel:当系统停止跟踪时触发

  • 注:event.preventDefault()可以阻止屏幕的默认滚动

除了DOM属性,还有以下三个用于跟踪触摸的属性

  • touches:标签当前跟踪的触摸操作的touch对象数组

  • 当一个手指在触屏上时,event.touches.length = 1

  • 当两个手指时,event.touches.length = 2

  • targetTouches:特定于事件目标的touch对象数组

  • 因为touch事件是会冒泡,所以利用这个属性指出目标对象

  • changedTouches:表示自上次触摸以来发生了什么改变的touch对象数组

  • 每个touch对象都包含下列几个属性:

  • clientX:触摸目标在视口中的x坐标

  • 使用clientX……时,必须要指明具体的touch对象event.touches[0],而不要直接指明数组。

  • 在touched

  • clientY:触摸目标在视口中的y坐标

  • identifier:标识触摸的唯一ID

  • pageX:触摸目标在页面中的x坐标

  • pageY:触摸目标在页面中的y坐标

  • screenX:触摸目标在屏幕中的x坐标

  • screenY:触摸目标在屏幕中的y坐标

  • target:触摸的DOM节点目标

  • 手势事件:

  • gesturestart:当一个手指已经按在屏幕上,而另一个手指又触摸在屏幕时触发

  • gesturechange:当触摸屏幕的任何一根手指的位置发生变化时触发

  • gestureend:当任何一个手指从屏幕上面移开时触发

  • 手势属性:

  • rotation:表示手指变化引起的旋转角度,负值表示逆时针,正值表示顺时针,从零开始

  • scale:表示两根手指之间的距离

  • 触摸与手势的关系:

  • 当手指放在屏幕上时,会触发touchstart。此时如果第二根手指放到屏幕上,就会触发gesturestart事件,随后又触发了第二根手指touchstart事件

  • 如果一根或两根手指在屏幕上滑动,将会触发gesturechange事件。但只要一根手指移出屏幕,则会触发gestureend事件,接着又会触发touchend事件


7. unicode,utf-8,gbk编码的了解,乱码的解决


  1. unicode:国际唯一标准编码,收录了所有语言的文字

  2. utf-8:针对Unicode的可变长度字符编码,又称万国码。

  3. gbk是为了汉字而制定的编码,由中华人民共和国全国信息技术标准化技术委员会1995年12月1日制订

  4. 乱码:


十四、反向面试

问技术:

  1. 我的工作内容是什么?
  2. 团队有多少人?前端又有多少人?
  3. 公司的发展情况?
  4. 公司的技术栈?
  5. 目前在做什么类型的项目?
  6. 公司的未来规划?
  7. 公司受疫情影响大不大?
  8. 你觉得你的Boss怎么样?

问人事:
0. 上下班时间,一周工作几天?

  1. 五险一金有吗?缴纳基数是多少?
  2. 薪酬结构是怎么样的?
  3. 其他福利待遇
  4. 公司的晋升机制
  5. 公司如何评估绩效?
  6. 公司的调薪制度



参考:
浅谈html+css流式布局
JS创建对象的几种方法
JavaScript常见的六种继承方式
技术面试最后反问面试官的话