前端面试问题总结

HTML

html5的新特性

  • 文件类型声明(<!DOCTYPE>)仅有一型:<!DOCTYPE HTML>。

  • 新的解析顺序:不再基于SGML。

  • 绘画 canvas;

  • 用于媒介回放的 video 和 audio 元素;

  • 语意化更好的内容元素:article、footer、header、nav、section;

  • 表单控件:calendar、date、time、email、url、search;

  • input元素的新类型:date, email, url等。

  • 新的技术:webworker, websocket, Geolocation;

  • 新的属性:ping(用于a与area), charset(用于meta), async(用于script)。

  • 全域属性:id, tabindex, repeat。

  • 新的全域属性:contenteditable, contextmenu, draggable, dropzone, hidden, spellcheck。

  • 新应用程序接口:

    • HTML Geolocation
    • HTML Drag and Drop
    • HTML Local Storage
    • HTML Application Cache
    • HTML Web Workers
    • HTML SSE
    • HTML Canvas/WebGL
    • HTML Audio/Video
  • 移除的元素:

    • 纯表现的元素:basefont,big,center,font, s,strike,tt,u;
    • 对可用性产生负面影响的元素:frame,frameset,noframes;

Web Worker

Web Worker的基本原理就是在当前javascript的主线程中,使用Worker类加载一个javascript文件来开辟一个新的线程,起到互不阻塞执行的效果,并且提供主线程和新线程之间数据交换的接口: postMessageonmessage

JS : worker.js


var math =function(n) {
   //肥肠复杂的数学计算
};
onmessage =function(evt) {
    var d = evt.data;
    postMessage(d);
};

HTML:

<!DOCTYPE HTML>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
 <script type="text/javascript">
//WEB页主线程
var worker =new Worker("worker.js");
//创建一个Worker对象并向它传递将在新线程中执行的脚本的URL
var data = ... //要计算的数据
 worker.postMessage(data);
//向worker发送数据
 worker.onmessage =function(evt){
//接收worker传过来的数据函数
   console.log(evt.data);
//输出worker发送来的数据
 }
 </script>
 </head>
 <body></body>
</html>

input元素常见类型

  • button
  • checkbox
  • file
  • hidden
  • image
  • password
  • radio
  • reset
  • submit
  • text

CSS

盒模型

IE 盒子模型、W3C 盒子模型;

区 别: IE的content部分把 border 和 padding计算了进去;

content-box:让元素维持W3C的标准盒模型。

布局所占宽度Width:

Width = width + padding-left + padding-right + border-left + border-right

布局所占高度Height:

Height = height + padding-top + padding-bottom + border-top + border-bottom

border-box:让元素维持IE传统盒模型(IE6以下版本和IE6~7的怪异模式)。

布局所占宽度Width:

Width = width(包含padding-left + padding-right + border-left + border-right)

布局所占高度Height:

Height = height(包含padding-top + padding-bottom + border-top + border-bottom)

position属性

  • static:默认的属性值,按照标准流(包括浮动方式)进行布局。
  • relative:称为相对定位,使用相对的盒子的位置常以标准量的排版方式为基础,然后使盒子相对于它在原本的标准位置偏移指定的距离.相对定位仍在标准流中,它对父块和兄弟块盒子没有任何影响。
  • absolute:绝对定位,盒子的位置以它的包含框为基准进行偏移。绝对定位从标准流中脱离,并且以它最近的一个已经定位祖先元素为基准进行定位。没有已经定位的祖先元素,则以浏览器窗口为基准进行定位。
  • inherit:规定从父元素继承 position 属性的值。
  • fixed:固定定位,与绝对定位类似,以浏览器窗口为基准进行定位,拖动浏览器窗口的滚动条时,位置保持不变。

fixed实例

HTML:

<body>
  <div id="a">
    <div id="c">
        <br>
        <br>
        <br>
    </div>
  </div>
</body>

CSS:

#a{
    height: 300px;
    width: 500px;
    background-color: #7c82ab;
  }
#c{
    width:500px;
    height:auto;
    background-color:#ccc;
    postion:fixed;
    bottom:0px;
}

diplay常用属性

  • block 像块类型元素一样显示。
  • none 缺省值。像行内元素类型一样显示。不保留位置,会引起reflow回流和repaint重绘。
  • inline-block 像行内元素一样显示,但其内容象块类型元素一样显示。
  • list-item 像块类型元素一样显示,并添加样式列表标记。
  • table 此元素会作为块级表格来显示
  • inherit 规定应该从父元素继承 display 属性的值

清除浮动

1.父级div定义 overflow: auto;

HTML:


<div class="outer over-flow">
    <div class="div1">1</div>
    <div class="div2">2</div>
    <div class="div3">3</div>
</div>

CSS:


.over-flow{
    overflow: auto;
    zoom: 1; /*zoom: 1;for IE6/7 Maxthon2*/
}

2.clear:both;

div{
    float:left;
    clear:both;
}

3.after 方法

.outer {
    zoom:1; /*zoom: 1;for IE6/7 Maxthon2*/
}
.outer:after {
    clear:both;
    content:".";
    display:block; /*for FF/chrome/opera/IE8*/
    width: 0;
    height: 0;
    visibility:hidden;
    }

CSS选择器

  • id选择器( # myid)
  • 类选择器(.myclassname)
  • 标签选择器(div, h1, p)
  • 相邻选择器(h1 + p)
  • 子选择器(ul > li)
  • 后代选择器(li a)
  • 通配符选择器( * )
  • 属性选择器(a[rel = "external"])
  • 伪类选择器(a:hover, li:nth-child)

CSS3新增伪类:

  • 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(2) 选择属于其父元素的第二个子元素的每个p元素。
  • :enabled :disabled 控制表单控件的禁用状态。
  • :checked 单选框或复选框被选中。

响应式布局的原理

  • Meta标签定义

    • 使用 viewport meta 标签在手机浏览器上控制布局

      <meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1" />

    • 通过快捷方式打开时全屏显示

      <meta name="apple-mobile-web-app-capable" content="yes" />

  • 隐藏状态栏

    <meta name="apple-mobile-web-app-status-bar-style" content="blank" />

  • iPhone会将看起来像电话号码的数字添加电话连接,应当关闭

    <meta name="format-detection" content="telephone=no" />

  • 使用Media Queries适配对应样式

    常用于布局的CSS Media Queries有以下几种:

    • 设备类型(media type):

      • all所有设备;
      • screen 电脑显示器;
      • print打印用纸或打印预览视图;
      • handheld便携设备;
      • tv电视机类型的设备;
      • speech语意和音频盒成器;
      • braille盲人用点字法触觉回馈设备;
      • embossed盲文打印机;
      • projection各种投影设备;
      • tty使用固定密度字母栅格的媒介,比如电传打字机和终端。
    • 设备特性(media feature):

      • width浏览器宽度;
      • height浏览器高度;
      • device-width设备屏幕分辨率的宽度值;
      • device-height设备屏幕分辨率的高度值;
      • orientation浏览器窗口的方向纵向还是横向,当窗口的高度值大于等于宽度时该特性值为portrait,否则为landscape;
      • aspect-ratio比例值,浏览器的纵横比;
      • device-aspect-ratio比例值,屏幕的纵横比。
  • 设置多种视图宽度

@media only screen and (min-width:768px)and(max-width:1024px){}

@media only screen and (width:320px)and (width:768px){}
  • 百分比布局
    • 宽度不固定,可以使用百分比
    #head{width:100%;}
    #content{width:50%;}
    
    • 响应式图片
    #wrap img{
      max-width:100%;
      height:auto;
    

}

* 字体设置

  一个响应式的字体应关联它的父容器的宽度,这样才能适应客户端屏幕。css3引入了新的单位叫做rem,和em类似但对于Html元素,rem更方便使用。em是相对于根元素的,需重置根元素字体大小:

  ```css
  html{font-size:100%;}
完成后,可以定义响应式字体:
@media (min-width:640px){body{font-size:1rem;}}
@media (min-width:960px){body{font-size:1.2rem;}}
@media (min-width:1200px){body{font-size:2rem;}}

absolute和relative的差别

  • relative

    • 生成相对定位的元素,通过top,bottom,left,right的设置相对于其正常位置进行定位。可通过z-index进行层次分级。
    • 定位为relative的元素脱离正常的文本流中,但其在文本流中的位置依然存在。
    • relative定位的层总是相对于其最近的父元素,无论其父元素是何种定位方式。
  • absolute

    • 生成绝对定位的元素,相对于static定位以外的第一个父元素进行定位。元素的位置通过"left","top","right"以及"bottom"属性进行规定。可通过z-index进行层次分级。
    • 定位为absolute的层脱离正常文本流,但与relative的区别是其在正常流中的位置不在存在。
    • 对于absolute定位的层总是相对于其最近的定义为absolute或relative的父层,而这个父层并不一定是其直接父层。如果其父层中都未定义absolute或relative,则其将相对body进行定位。

隐藏元素

  1. overflow
  2. opacity
  3. visibility
  4. display
  5. postion
  6. clip/clip-path
  7. z-index

布局

水平垂直居中

链接:https://juejin.im/post/5d5a39b66fb9a06afc2540ea

Flex 布局

链接:https://zhuanlan.zhihu.com/p/25303493

Grid 布局

链接:https://juejin.im/entry/5894135c8fd9c5a19507f6a1

瀑布流布局

链接:
https://juejin.im/post/5d365a65e51d454d1d6285eb

BFC

Block formatting context直译为"块级格式化上下文"。(普通流)具有BFC特性的元素可以看做是隔离了的独立容器,容器里面的元素不会再布局上影响到外面的元素,并且BFC具有普通容器所没有的一些特性。

BFC 布局规则
  • 内部的Box会在垂直方向,一个接一个地放置。
  • Box垂直方向的距离由margin决定。属于同一个BFC的两个相邻Box的margin会发生重叠
  • 每个元素的margin box的左边, 与包含块border box的左边相接触(对于从左往右的格式化,否则相反)。即使存在浮动也是如此。
  • BFC的区域不会与float box重叠。
  • BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素。反之也如此。
  • 计算BFC的高度时,浮动元素也参与计算
触发BFC

只要元素满足下面任一条件即可触发BFC特性:

  • float属性不为none.
  • position属性不为static和relative.
  • display属性为下列之一:table-cell,table-caption,inline-block,flex,or inline-flex.
  • overflow属性不为visible.

HTTP

状态码

1. 常见状态码

  • 200 - 请求成功
  • 301 - 资源(网页等)被永久转移到其它URL
  • 304 - Not Modified,客户端则直接从本地缓存中将页面调取
  • 404 - 请求的资源(网页等)不存在
  • 500 - 内部服务器错误

2. 状态码分类

  • 1** 信息,服务器收到请求,需要请求者继续执行操作
  • 2** 成功,操作被成功接收并处理
  • 3** 重定向,需要进一步的操作以完成请求
  • 4** 客户端错误,请求包含语法错误或无法完成请求
  • 5** 服务器错误,服务器在处理请求的过程中发生了错误

请求方式

  • GET:GET是http的默认请求方式, 一般用来获取数据。
  • HEAD:HEAD方法与GET方法一样,都是向服务器发出指定资源的请求。但是,服务器在响应HEAD请求时不会回传资源的内容部分,即:响应主体。这样,我们可以不传输全部内容的情况下,就可以获取服务器的响应头信息。HEAD方法常被用于客户端查看服务器的性能。
  • POST:POST请求会向指定资源提交数据,请求服务器进行处理。如:表单提交、文件上传。
  • PUT:PUT请求会身向指定资源位置上传其最新内容,通过该方法客户端可以将指定资源的最新数据传送给服务器取代指定的资源的内容。
  • DELETE:DELETE请求用于请求服务器删除所请求URI所标识的资源。DELETE请求后指定资源会被删除。
  • TRACE:返回接受到的请求,用来查看数据经过中间服务器时发生了哪些变动。
  • OPTIONS:OPTIONS请求与HEAD类似,一般也是用于客户端查看服务器的性能。 这个方法会请求服务器返回该资源所支持的所有HTTP请求方法,该方法会用'*'来代替资源名称,向服务器发送OPTIONS请求,可以测试服务器功能是否正常。JavaScript的XMLHttpRequest对象进行CORS跨域资源共享时,就是使用OPTIONS方法发送嗅探请求,以判断是否有对指定资源的访问权限。
  • CONNECT:要求使用SSL和TLS进行TCP通信。
  • PATCH:请求修改局部数据

RESTful架构

REST是一种架构风格:无状态,以资源为中心,充分利用HTTP协议和URI协议,提供统一的接口定义,使得它作为一种设计Web服务的方法而变得流行。在某种意义上,通过强调URI和HTTP等早期Internet标准,REST是对大型应用程序服务器时代之前的Web方式的回归。

架构约束:

  • 客户-服务器:通信只能由客户端单方面发起,表现为请求-响应的形式。
  • 无状态:通信的会话状态(Session State)应该全部由客户端负责维护。
  • 缓存:响应内容可以在通信链的某处被缓存,以改善网络效率。
  • 统一接口:通信链的组件之间通过统一的接口相互通信,以提高交互的可见性。
  • 分层系统:通过限制组件的行为(即,每个组件只能"看到"与其交互的紧邻层),将架构分解为若干等级的层。
  • 按需代码:支持通过下载并执行一些代码(例如Java Applet、Flash或JavaScript),对客户端的功能进行扩展。

主要特征:

  • 面向资源(Resource Oriented)
  • 可寻址(Addressability)
  • 连通性(Connectedness)
  • 无状态(Statelessness)
  • 统一接口(Uniform Interface)
  • 超文本驱动(Hypertext Driven)

WebSocket原理

Websocket是应用层第七层上的一个应用层协议,它必须依赖 HTTP 协议进行一次握手 ,握手成功后,数据就直接从 TCP 通道传输,与 HTTP 无关了。

Websocket的数据传输是frame形式传输的,比如会将一条消息分为几个frame,按照先后顺序传输出去。这样做会有几个好处:

1 大数据的传输可以分片传输,不用考虑到数据大小导致的长度标志位不足够的情况。

2 和http的chunk一样,可以边生成数据边传递消息,即提高传输效率。

HTTP2新特性

链接:https://juejin.im/post/5b88a4f56fb9a01a0b31a67e
来源:掘金

HTTP/2的通过支持请求与响应的多路复用来减少延迟,通过压缩HTTP首部字段将协议开销降至最低,同时增加对请求优先级和服务器端推送的支持。

1. 二进制分帧

HTTP/2 采用二进制格式传输数据,而非 HTTP 1.x 的文本格式,二进制协议解析起来更高效。 HTTP / 1 的请求和响应报文,都是由起始行,首部和实体正文(可选)组成,各部分之间以文本换行符分隔。HTTP/2 将请求和响应数据分割为更小的帧,并且它们采用二进制编码。
HTTP/2 中,同域名下所有通信都在单个连接上完成,该连接可以承载任意数量的双向数据流。每个数据流都以消息的形式发送,而消息又由一个或多个帧组成。多个帧之间可以乱序发送,根据帧首部的流标识可以重新组装。

2. 多路复用

多路复用,代替原来的序列和阻塞机制。所有就是请求的都是通过一个 TCP连接并发完成。 HTTP 1.x 中,如果想并发多个请求,必须使用多个 TCP 链接,且浏览器为了控制资源,还会对单个域名有 6-8个的TCP链接请求限制。
在 HTTP/2 中,有了二进制分帧之后,HTTP /2 不再依赖 TCP 链接去实现多流并行了,在 HTTP/2中:

  • 同域名下所有通信都在单个连接上完成。
  • 单个连接可以承载任意数量的双向数据流。
  • 数据流以消息的形式发送,而消息又由一个或多个帧组成,多个帧之间可以乱序发送,因为根据帧首部的流标识可以重新组装。
    这一特性,使性能有了极大提升:
  • 同个域名只需要占用一个 TCP 连接,消除了因多个 TCP 连接而带来的延时和内存消耗。
  • 单个连接上可以并行交错的请求和响应,之间互不干扰。
  • 在HTTP/2中,每个请求都可以带一个31bit的优先值,0表示最高优先级, 数值越大优先级越低。有了这个优先值,客户端和服务器就可以在处理不同的流时采取不同的策略,以最优的方式发送流、消息和帧。
3. 服务器推送

服务端可以在发送页面HTML时主动推送其它资源,而不用等到浏览器解析到相应位置,发起请求再响应。例如服务端可以主动把JS和CSS文件推送给客户端,而不需要客户端解析HTML时再发送这些请求。
服务端可以主动推送,客户端也有权利选择是否接收。如果服务端推送的资源已经被浏览器缓存过,浏览器可以通过发送RST_STREAM帧来拒收。主动推送也遵守同源策略,服务器不会随便推送第三方资源给客户端。

4. 头部压缩

HTTP 1.1请求的大小变得越来越大,有时甚至会大于TCP窗口的初始大小,因为它们需要等待带着ACK的响应回来以后才能继续被发送。HTTP/2对消息头采用HPACK(专为http/2头部设计的压缩格式)进行压缩传输,能够节省消息头占用的网络的流量。而HTTP/1.x每次请求,都会携带大量冗余头信息,浪费了很多带宽资源。
为了减少这块的资源消耗并提升性能, HTTP/2对这些首部采取了压缩策略:

  • HTTP/2在客户端和服务器端使用“首部表”来跟踪和存储之前发送的键-值对,对于相同的数据,不再通过每次请求和响应发送;
  • 首部表在HTTP/2的连接存续期内始终存在,由客户端和服务器共同渐进地更新;
  • 每个新的首部键-值对要么被追加到当前表的末尾,要么替换表中之前的值。

5. 应用层的重置连接

对于 HTTP/1 来说,是通过设置 tcp segment 里的 reset flag 来通知对端关闭连接的。这种方式会直接断开连接,下次再发请求就必须重新建立连接。HTTP/2 引入 RST_STREAM 类型的 frame,可以在不断开连接的前提下取消某个 request 的 stream,表现更好。

6. 请求优先级设置

HTTP/2 里的每个 stream 都可以设置依赖 (Dependency) 和权重,可以按依赖树分配优先级,解决了关键请求被阻塞的问题

7. 流量控制

每个 http2 流都拥有自己的公示的流量窗口,它可以限制另一端发送数据。对于每个流来说,两端都必须告诉对方自己还有足够的空间来处理新的数据,而在该窗口被扩大前,另一端只被允许发送这么多数据。

关于流量控制详见: How does it work ?- 流量控制

8. HTTP/1 的几种优化可以弃用

合并文件、内联资源、雪碧图、域名分片对于 HTTP/2 来说是不必要的,使用 h2 尽可能将资源细粒化,文件分解地尽可能散,不用担心请求数多

浏览器缓存机制

链接: https://www.jianshu.com/p/54cc04190252
来源:简书

localStorage, sessionStorage, Cookie, Session

特性 Cookie localStorage sessionStorage
数据的生命期 一般由服务器生成,可设置失效时间。如果在浏览器端生成Cookie,默认是关闭浏览器后失效 除非被清除,否则永久保存 仅在当前会话下有效,关闭页面或浏览器后被清除
存放数据大小 4K左右,很多浏览器都限制一个站点最多保存20个Cookie 一般为5MB 一 般为5MB
与服务器端通信 每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题 仅在客户端(即浏览器)中保存,不参与和服务器的通信 仅在客户端(即浏览器)中保存,不参与和服务器的通信
易用性 需要程序员自己封装,源生的Cookie接口不友好 源生接口可以接受,亦可再次封装来对Object和Array有更好的支持 源生接口可以接受,亦可再次封装来对Object和Array有更好的支持

前端模块化

链接:https://juejin.im/post/5aaa37c8f265da23945f365c
来源:掘金

前端安全

链接: https://zhuanlan.zhihu.com/p/83865185
来源:知乎

DNS解析

原理

https://juejin.im/post/5b0a32a36fb9a07ab979f0b4
原理链接:
来源: 掘金

基于的协议:

区域传送时使用TCP,主要有一下两点考虑:
1.辅域名服务器会定时(一般时3小时)向主域名服务器进行查询以便了解数据是否有变动。如有变动,则会执行一次区域传送,进行数据同步。区域传送将使用TCP而不是UDP,因为数据同步传送的数据量比一个请求和应答的数据量要多得多。
2.TCP是一种可靠的连接,保证了数据的准确性。

域名解析时使用UDP协议:
客户端向DNS服务器查询域名,一般返回的内容都不超过512字节,用UDP传输即可。不用经过TCP三次握手,这样DNS服务器负载更低,响应更快。虽然从理论上说,客户端也可以指定向DNS服务器查询的时候使用TCP,但事实上,很多DNS服务器进行配置的时候,仅支持UDP查询包。

Vue

vue面试题:

  1. https://github.com/fengshi123/blog
    来源:GitHub

  2. https://segmentfault.com/a/1190000016344599
    来源:segmentfault

Vue数据双向绑定机制

链接:https://segmentfault.com/a/1190000006599500
来源:segmentfault

虚拟DOM

链接:https://juejin.im/post/5d36cc575188257aea108a74
来源:掘金

Vuex和Vue-bus的区别

https://juejin.im/post/5c09cb73518825159512778b
来源:掘金

Vue 的diff算法https://juejin.im/post/5ce4c113518825526b293de1

https://juejin.im/post/5ad6182df265da23906c8627
来源:掘金

组件化

链接:https://juejin.im/post/5ce4c113518825526b293de1

来源:掘金

JavaScript

基本数据类型

值类型(基本类型):字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。
引用数据类型:对象(Object)、数组(Array)、函数(Function)。

引用变量和数值变量

  • 基本类型值 简单的数据段,保存在栈内存中;typeof检测。
  • 引用类型值 可能有多个值构成的对象,保存在堆内存中;instanceof检测。

与其他语言不用,JavaScript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。也就是说包含引用类型值的变量实际上包含的并不是对象本身,而是一个指向该对象的指针。

  • 按值访问相当于是将原数据的值进行一次拷贝,给新的变量,原变量发生改变后,按值访问的不会变化。一般是string,number这样的基本类型。

    var a = 1;
    var b = a;
    alert(a+";"+b);//1;1
    a = 2;
    alert(a+";"+b);//2;1  b不会发生改变,因为是按值访问
    
  • 按引用是指在内存区内只有一份,新的变量只是拥有一个指向它的指针,一旦内存区内的内容发生变化,所有指向它的引用都将发生变化,一般是对象,包括用户自定义对象和内置对象,Array和Function。

    var a = {name: "Zoe"};
    var b = a;
    console.log(a.name);//Zoe
    console.log(b.name);//Zoe
    
    a.name = "Alex"; 
    console.log(a.name);//Alex
    console.log(b.name);//Alex 按引用访问,指针指向的区域已经被更改
    

变量提升

JavaScript 中,函数及变量的声明都将被提升到函数的最顶部。
JavaScript 中,变量可以在使用后声明,也就是变量可以先使用再声明。

var变量提升

console.log(a);
var a =1;

// 等价于

var a ;
console.log(a); // 1
a = 1; 

function提升

a(); // 1

function a() {
    console.log(1);
}

JavaScript 只有声明的变量会提升,初始化的不会。

var x = 5; // 初始化 x

elem = document.getElementById("demo"); // 查找元素
elem.innerHTML = x + " " + y;           // 显示 x 和 undefined

var y = 7; // 初始化 y

JavaScript引擎的工作方式是,先解析代码,获取所有被声明的变量,然后再一行一行地运行。这造成的结果,就是所有的变量的声明语句,都会被提升到代码的头部,叫做变量提升(hoisting)。可以用let来约束。let 声明的变量的作用域是块级的。

闭包

JavaScript 变量属于本地或全局作用域。当一个内部函数被其外部函数之外的变量引用时,就形成了一个闭包。
全局变量能够通过闭包实现局部(私有)。

var cat = (function(){
  var name = 'secret'; //name变量私有化,外部无法访问
  return {
    get_name: function() {
      return name;
    },
    set_name: function(new_name) {
      name = new_name;
    }
  }
}());
cat.get_name (); //得到'secret'
cat.name; //Type error
cat.set_name('m');
cat.get_name(); // 'm'

多人合作的项目中如何解决命名空间冲突

  • 防止全局声明的修改
  • 防止其他来源代码的修改
  • 模块化开发
  • 命名空间
  var ValidateUtil = {
    type1 : function(){};
    type2: function(){};
  };

Promise

  • 对象的状态不受外界影响。有三种状态:padding(进行中)、fulfilled(成功)、rejected(失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
  • 一旦状态改变,就不会再变,任何时候都可以得到这个结果。三个状态只有从padding到fulfilled或者从padding到rejected。状态只有从padding改变到fulfilled或者refected,两种改变。
//基本用法
 new Promise(function (resolve,reject) {
        console.log('promise准备阶段');
        resolve("成功!");
        reject("失败!");
    })

//实例
 function asyncPro(msg){
        return new Promise(function (resolve,reject) {
            console.log(msg+':promise准备阶段');
            resolve(msg+'成功!');
            reject(msg+"失败!");
        });
    }
    asyncPro('第一步').then(function (msg) {
        console.log(msg);
        return asyncPro('第二步');
    }).then(function (msg) {
        console.log(msg);
        return asyncPro('第三步');
    }).then(function(msg){
        console.log(msg);
    });

原生ajax

  //1. 创建ajax对象
  var xhr = null;
  if(window.XMLHttpRequest){
      xhr = new XMLHttpRequest();
  } else {
      //为了兼容IE6
      xhr = new ActiveXObject('Microsoft.XMLHTTP');
  }

  //2. 连接服务器open(方法GET/POST,请求地址, 异步传输)
  xhr.open('GET',  'data.txt',  true);

  //3. 发送请求
  xhr.send();

  //4.处理返回数据
  /*
  ** 每当readyState改变时,就会触发onreadystatechange事件
  ** readyState属性存储有XMLHttpRequest的状态信息
  ** 0 :请求未初始化
  ** 1 :服务器连接已建立
  ** 2 :请求已接受
  ** 3 : 请求处理中
  ** 4 :请求已完成,且相应就绪
  */
  xhr.onreadystatechange = function(){
      if(xhr.readyState == 4){
          /*
          ** Http状态码
          ** 1xx :信息展示
          ** 2xx :成功
          ** 3xx :重定向
          ** 4xx : 客户端错误
          ** 5xx :服务器端错误
          */
          if(xhr.status == 200){
              success(xhr.responseText);
          } else {
              if(failed){
                  failed(xhr.status);
              }
          }
      }
  }

什么是内存泄漏

JavaScript中最常用的垃圾收集方式是标记清除(mark-and-sweep)。当变量进入环境(例如,在函数中声明一个变量)时,就将这个变量标记为“进入环境”。从逻辑上讲,永远不能释放进入环境的变量所占的内存,因为只要执行流进入相应的环境,就可能用到它们。而当变量离开环境时,这将其 标记为“离开环境”。
虽然JavaScript 会自动垃圾收集,但是如果我们的代码写法不当,会让变量一直处于“进入环境”的状态,无法被回收。

常见内存泄漏的原因

  • 循环引用
function cycle() {
    var o1 = {};
    var o2 = {};
    o1.a = o2;
    o2.a = o1; 

    return "Cycle reference!"
}
cycle();
  • 全局变量引起的内存泄漏

    function yyy(){
      yyy = 'xxxxxx';//yyy 成为一个全局变量,不会被回收
    }
    
  • 闭包引起的内存泄漏

      var yyy = (function(){
          var yyy = 'xxxxxx';// 被闭包所引用,不会被回收
          return function(){
              console.log(yyy);
          }
      })()
    
  • dom清空或删除时,事件未清除导致的内存泄漏

      <div id="container">
      </div>
      $('#container').bind('click', function(){
          console.log('click');
      }).remove();
      //把事件清除了,即可从内存中移除
      <div id="container">
      </div>
      $('#container').bind('click', function(){
          console.log('click');
      }).off('click').remove();
    

清空数组的常用方法

  • 将数组 length 赋值为0
  • 将数组赋值为[ ]
  • splice()删除数组元素arr.splice(0, arr.length);

bind,call,apply的用法

  • Function.prototype.call()和Function.prototype.apply()

call()和apply()可以看作为某个对象的方法,通过调用方法的形式来间接调用函数。 它们的第一个参数是要调用函数的母对象,它是调用上下文,在函数体内通过this来获得对它的引用。 apply()方法和call()方法的作用相同,只不过函数传递的方式不一样,它的实参都放入在一个数组中。

    var n = {};
   
   function f(a, b) {
     return a + b;
   }
   
   f.call(n, 1, 2);        // 将函数f作为n的方法,实际上就是重新设置函数f的上下文
   f.apply(n, [1, 2]);
  • Function.prototype.bind()

bind()是在ES5中新增的方法,从名字可以看出,这个方法的主要作用就是将函数绑定到某个对象。 当在函数f()上调用bind()方法并后传入一个对象n作为参数,这个方法将返回一个新函数: (以函数调用的方式)调用新的函数将会把原始的函数f()作为n的方法来调用。例如:

```js
function f(y) {
  return this.x + y;
}

var a = {
  x: 1
};

var m = f.bind(a);  // 通过调用 g(x) 来调用 a.f(x)
m(2); // 3
```

实现bind()方法:

```js
// 返回一个函数,通过调用它来调用n中的方法f(),传递它所有的实参
function bind(f, n) {
  if (f.bind) return f.bind(n); // 如果bind()方法存在,使用bind()方法
  else return function () {
    return f.apply(n, arguments);
  }
}
```

$(document).ready() 与window.onload的区别

  • 执行时间不同
    window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行。
    $(document).ready()是DOM结构绘制完毕后就执行,不必等到加载完毕。

  • 编写个数不同

    window.onload不能同时编写多个,如果有多个window.onload方法,只会执行一个
    $(document).ready()可以同时编写多个,并且都可以得到执行

  • 简化写法

    window.onload没有简化写法
    (document).ready(function(){})可以简写成(function(){});

事件监听

  • element.addEventListener(type, listener[, useCapture]); // IE6~8不支持
  • element.attachEvent('on' + type, listener); // IE6~10,IE11不支持
  • element['on' + type] = function(){} // 所有浏览器

DEMO:

function test() {
    console.log(1);
    }
element.addEventListener('click', test, false);
element.attachEvent('onclick', test);
element.onclick = test;

原型链

在JavaScript中,每个对象都有一个指向它的原型对象的内部链接。这个原型对象又有自己的原型,直到某个对象的原型为null为止,组成这条链的最后一环。这种一级一级的链结构就成为原型链。

ES6写法:

class a {
    constructor(name) {
    this.name = name;
    }
speak() {
    console.log(this.name + ' lalala');
    }
}
class aa extends a {
    speak() {
    console.log(this.name + ' hahaha');
     }
}

字符串反转

JS方法:

  var reverseString = function(string) {
     string = string.split('').reverse().join('');
     return string;
  };

CSS方法:

  p{
      direction: rtl;
      unicode-bidi: bidi-override;
  }

滚动条监听

浏览器事件循环

链接:https://juejin.im/post/5afbc62151882542af04112d

function a () {
  console.log('---1---');
  setTimeout(() => {
    console.log('---2---');
    Promise.resolve().then(() => {
      console.log('-----3------');
    });
  }, 0);

  setTimeout(() => {
    console.log('---4---');
  }, 0);

  Promise.resolve().then(() => {
    console.log('---5---');

    return Promise.resolve().then(() => {
      console.log('---6---');
    });
  }).then(() => {
    console.log('---7---');
  });
}

/** 输出
* ---1---
* ---5---
* ---6---
* ---7---
* undefined
* ---2---
* ---3---
*  ---4---
*/

跨域常用解决方案

  • JSONP
    利用<script>标签没有跨域限制的“漏洞”来达到与第三方通讯的目的。当需要通讯时,本站脚本创建一个<script>元素,地址指向第三方的API网址,形如:<script src="http://www.example.net/api?param1=1&param2=2"></script> 并提供一个回调函数来接收数据(函数名可约定,或通过地址参数传递)。
    第三方产生的响应为json数据的包装(故称之为jsonp,即json padding),形如: callback({"name":"hax","gender":"Male"}) 这样浏览器会调用callback函数,并传递解析后json对象作为参数。本站脚本可在callback函数里处理所传入的数据。

  • CORS 通过设置响应头的 Access-Control-Allow-Origin

  • window.name

  • window.postMessage() HTML5新特性

  • location.hash

  • document.domain

同源策略: 域名,协议,端口相同。

事件委托

对“事件处理程序过多” 问题的解决方案就是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理某一类的所有事件。例如,click事件会一直冒泡到document层次,所以我们可以为整个页面制定一个onclick事件处理程序,而不必给每个可单机的元素分别添加事件处理程序。

HTML

<ul id="myLinks">
  <li id="a"></li>
  <li id="b"></li>
  <li id="c"></li>
</ul>

JavaScript

  var list = document.getElementById("myLinks");

  EventUtil.addHandler(list, "click", function(event){
    event = EventUtil.getEvent(event);

    switch(target.id){
      case "a":
        console.log("1");
        break;

      case "b":
        console.log("2");
        break;

      case "c":
        console.log("3"):
        break;
    }
  });

原生模态框

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <style type="text/css">
.lightbox {
  display: none;
}

/* Opened lightbox */
.lightbox:target {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Lightbox content */
.lightbox figcaption {
  width: 25rem;
  position: relative;
  padding: 1.5em;
  background-color: #fff;
}

/* Close button */
.lightbox .close {
  position: relative;
  display: block;
}

.lightbox .close::after {
  right: -1rem;
  top: -1rem;
  width: 2rem;
  height: 2rem;
  position: absolute;
  display: flex;
  z-index: 1;
  align-items: center;
  justify-content: center;
  background-color: black;
  border-radius: 50%;
  color: white;
  content: "×";
}

/* Lightbox overlay */
.lightbox .close::before {
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  position: fixed;
  background-color: rgba(0,0,0,.7);
  content: "";
  cursor: default;
}
    </style>
  </head>
  <body>
    <a href="#example">open</a>
    <div class="lightbox" id="example">
      <figure>
        <a href="#" class="close"></a>
        <figcaption>test</figcaption>
      </figure>
    </div>
  </body>
</html>

跑马灯

链接: https://segmentfault.com/a/1190000016903385
来源:segment fault

Tab

链接:https://www.jianshu.com/p/168fa8cc7e7b

轮播图

链接: https://www.jianshu.com/p/d3c650a5c994

函数节流和函数防抖

函数防抖(debounce):在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。即:只有任务触发的间隔超过指定间隔的时候,任务才会执行。
函数防抖原理:通过闭包保存一个标记来保存 setTimeout 返回的值,每当用户输入的时候把前一个 setTimeout clear 掉,然后又创建一个新的 setTimeout,这样就能保证输入字符后的 interval 间隔内如果还有字符输入的话,就不会执行 fn 函数了。

function debounce(fn, interval) {
    let timeout = null;
    return function () {
        clearTimeout(timeout);
        timeout = setTimeout(() => {
            fn.apply(this, arguments);
        }, interval);
    };
}

函数节流(throttle) :规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
函数节流原理:函数的节流就是通过闭包保存一个标记(canRun = true),在函数的开头判断这个标记是否为 true,如果为 true 的话就继续执行函数,否则则 return 掉,判断完标记后立即把这个标记设为 false,然后把外部传入的函数的执行包在一个 setTimeout 中,最后在 setTimeout 执行完毕后再把标记设置为 true(这里很关键),表示可以执行下一次的循环了。当 setTimeout 还未执行的时候,canRun 这个标记始终为 false,在开头的判断中被 return 掉。

function throttle(fn, interval = 300) {
   let canRun = true;
   return function () {
       if (!canRun) return;
       canRun = false;
       setTimeout(() => {
           fn.apply(this, arguments);
           canRun = true;
       }, interval);
   };
}

应用场景
  • debounce

    • search搜索联想,用户在不断输入值时,用防抖来节约请求资源。
    • window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
  • throttle

    • 鼠标不断点击触发,mousedown(单位时间内只触发一次)
    • 监听滚动事件,比如是否滑到底部自动加载更多,用throttle来判断

大数相加

Number类型的精度是2的53次方。

function add(n, m) {
  // 操作数类型判断, 要求为字符串。不满足条件则抛出异常。
  if (typeof n !== 'string' || typeof m !== 'string') {
    throw new Error('数据类型错误, 大数相加操作数为字符串!');
  }

  // 数据反转, 方便后面的遍历求和
  n = n.split('').reverse();
  m = m.split('').reverse();

  // 获取较长的位数, 并作为后面对应位数遍历的最大值
  const maxLength = Math.max(n.length, m.length);

  // 计算过程中, 临时变量
  let tempN = 0; // 临时存储第1个操作数
  let tempM = 0; // 临时存储第2个操作数
  let tempAdd = 0; // 临时存储对应位上的数相加的和
  let extNum = 0; // 满10进1,保存进的值(1 或 0)

  // 计算结果
  const res = []; // 应位上的书相加的和

  // 遍历每一位上的数字,并求和。记录满十进一
  for (let index = 0; index < maxLength; index++) {
    // 缺位补0
    tempN = n[index] || 0;
    tempM = m[index] || 0;

    // 对应位上的数字求和
    tempAdd = Number(tempN) + Number(tempM);

    // 进一(extNum 为进 1)
    if (extNum) {
      tempAdd += extNum;
    }

    // 满十(存储需要进的 1)
    extNum = tempAdd >= 10 ? 1 : 0;

    // 最后一位满十进的一直接保存在当前求得的和中, 非最后一位则取 %10 后的值
    if (index === (maxLength - 1) && extNum) {
      res.push(tempAdd);
    } else {
      res.push(tempAdd % 10);
    }
  }

  // 返回计算后的数时注意翻转
  return res.reverse().join('');
}

大数相减

大数相乘

大数相除

解决 0.1 + 0.2 != 0.3

在JavaScript中的二进制的浮点数0.1和0.2并不是十分精确,在他们相加的结果并非正好等于0.3,而是一个比较接近的数字 0.30000000000000004 ,所以条件判断结果为 false。

    function numbersequal(a,b){
        return Math.abs(a-b)<Number.EPSILON;
    }
    
    var a=0.1 + 0.2;
    var b=0.3;
    console.log(numbersequal(a,b));  //true

算法

二叉树递归遍历

链接:https://www.jianshu.com/p/72ea83e2feab
来源:简书

二叉树非递归遍历

链接:https://juejin.im/post/5e1181445188253a5b3cd5cf

链表

链接:https://juejin.im/post/5b87c60c6fb9a019fa06495b
来源:掘金

查找URL中的参数

  1. 指定参数名称,返回该参数的值或者空字符串
  2. 不指定参数名称,返回全部的参数对象或者{}
  3. 如果存在多个同名参数,则返回数组
function getUrlParam(sUrl,sKey){
    var result = {};
    sUrl.replace(/\??(\w+)=(\w+)&?/g,function(a,k,v){
        if(result[k] !== void 0){
            var t = result[k];
            result[k] = [].concat(t,v);
        }else{
            result[k] = v;
        }
    });
    if(sKey === void 0){
        return result;
    }else{
        return result[sKey] || '';
    }
}

斐波那契数列

用 JavaScript 实现斐波那契数列函数,返回第n个斐波那契数。 f(1) = 1, f(2) = 1 等

//递归
function fibonacci(n) {
    if(n<0){
        return -1;
    }else if(n < 2){
        return n;
    }else{
       return arguments.callee(n-1) +  arguments.callee(n-2);
    }
}

//非递归
function getNthFibonacci(count) {
    if(count<0) return 0;
    if(count<=1) return 1;
    var first = 1;
    var second = 1;
    var third = 0;
    for(var i = 2; i <= count; i++) {
        third = first + second;
        first = second;
        second = third;
    }
    return third;
}

返回斐波那契数列函数

输入大于0的整数n返回长度为n的斐波那契数列。

function fibonacci(n) {
  var result = [1,1];
    if(n <= 0){
        return -1;
    }else if(n == 1){
      result.pop(1);
    }else {
       for(var i = 2; i < n; i++){
         result.push(result[i-1] + result[i-2]);
       }
    }
    return result;
}

修改 this 指向

题目描述

封装函数 f,使 f 的 this 指向指定的对象
输入例子:

bindThis(function(a, b){return this.test + a + b}, {test: 1})(2, 3)

输出例子:

6

function bindThis(f, oTarget) {
    return f.bind(oTarget);
}

实现函数add

\* add(2,3);//5
   add(2)(3);//5
*\
function add(a) {
    if(arguments.length > 1){
      return arguments[0] + arguments[1];
        }else {
    return (function (b){return a + b});
    }
}

add(2,3);//5
add(2)(3);//5

十大经典排序算法

链接:https://sort.hust.cc/

快速排序

var quickSort = function(arr) {
  if (arr.length <= 1) { return arr; }
  var pivotIndex = Math.floor(arr.length / 2);
  var pivot = arr.splice(pivotIndex, 1)[0];
  var left = [];
  var right = [];
  for (var i = 0; i < arr.length; i++){
    if (arr[i] < pivot) {
      left.push(arr[i]);
    } else {
      right.push(arr[i]);
    }
  }
  return quickSort(left).concat([pivot], quickSort(right));
};

实现深度克隆

//JSON.parse
const newObj = JSON.parse(JSON.stringify(oldObj));


function deepClone(obj) {
    
    if(typeof obj !== 'object') {
        return -1;
    } else {
      var res = obj.constructor === Array ? [] : {};
       for (var k in obj) {
           if(typeof obj[k] === 'object') {
               res[k] = deepClone(obj[k]);
           } else {
                res[k] = obj[k];
           }
            
       }
    }
    return res;

}

 

String Shifting (赛码网)

我们规定对一个字符串的shift操作如下:

shift(“ABCD”, 0) = “ABCD”

shift(“ABCD”, 1) = “BCDA”

shift(“ABCD”, 2) = “CDAB”

换言之, 我们把最左侧的N个字符剪切下来, 按序附加到了右侧。

给定一个长度为n的字符串,我们规定最多可以进行n次向左的循环shift操作。如果shift(string, x) = string (0<= x <n), 我们称其为一次匹配(match)。求在shift过程中出现匹配的次数。

var line = "";
while(str = read_line().trim()) {
    line += str;
}
var n = line.length;
var result = 0;
if(n > 500000) {
    print(1);
}
else {
  for(var i = 0; i < n; i ++) {
      if(line.substr(i) + line.substr(0, i) === line) {
          result ++;   
       }        
  }
   print(result);
}    

数组拍平

\\ 输入 var arr = [1,2,[3,4,5,[6,[7,8],9],10,[11,12]];
\\ 输出 arr = [1,2,3,4,5,6,7,8,9,10,11,12]

\\ 递归
function flat(arr) {
    if(!Array.isArray(arr)) return false;
    res = [];
    for(var i = 0; i < arr.length; i++) {
        if(Array.isArray(arr[i])) {
            res = res.concat(flat(arr[i]));
        } else {
            res.push(arr[i]);
        }
    }
    return res;
}

\\toString
function flat(arr) {
    if(!Array.isArray(arr)) return false;
    return arr.toString().split(',').map((v) => {
        return parseInt(v);
    });
}

统计字符串出现次数最多的字母

function findMost(str) {
    var container = {};
    var arr = str.split('');
    for(var i = 0; i < arr.length; i++) {
        if(!container[arr[i]]) {
            container[arr[i]] = 1;
        } else {
            container[arr[i]] += 1;
        }
    }
    var maxKey = 0;
    var maxValue = '';
    for(var k in container) {
        if(container[k] >= maxKey) {
            maxKey = container[k];
            maxValue = k;
        }
    }
    return maxValue;
}

两个单向链表找相交结点

手写代码常用函数总结

链接:https://juejin.im/post/5e57048b6fb9a07cc845a9ef#heading-38
来源: 掘金

补充

常考算法

  1. 链接:https://juejin.im/post/5aa7c2306fb9a028c14a24b8
  2. 链接 https://segmentfault.com/a/1190000020230669
    3.(全) http://obkoro1.com/web_accumulate/algorithm/

全面总结

链接:https://juejin.im/post/5aae076d6fb9a028cc6100a9
来源:掘金

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,001评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,210评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,874评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,001评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,022评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,005评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,929评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,742评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,193评论 1 309
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,427评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,583评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,305评论 5 342
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,911评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,564评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,731评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,581评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,478评论 2 352

推荐阅读更多精彩内容

  • 概要 64学时 3.5学分 章节安排 电子商务网站概况 HTML5+CSS3 JavaScript Node 电子...
    阿啊阿吖丁阅读 9,180评论 0 3
  • 前端开发面试题 面试题目: 根据你的等级和职位的变化,入门级到专家级,广度和深度都会有所增加。 题目类型: 理论知...
    怡宝丶阅读 2,578评论 0 7
  • 面试题一:https://github.com/jimuyouyou/node-interview-questio...
    R_X阅读 1,618评论 0 5
  • 前端面试题的简单整理,都只是大概回答,具体某些问题的具体理解后续会补上。 前端页面有哪三层构成,分别是什么?作用是...
    李欢li阅读 481评论 0 2
  • 一、理论基础知识部分 1.1、讲讲输入完网址按下回车,到看到网页这个过程中发生了什么 a. 域名解析 b. 发起T...
    我家媳妇蠢蠢哒阅读 3,123评论 2 106