慕课网《前端跳槽面试必备技巧》——关于基础面

本篇介绍的是面试的一/二面,即基础面需要准备的内容。原课程链接:前端跳槽面试必备技巧

一面/二面(基础知识面)

这一面的面试技巧:

  • 准备要充分
  • 知识要系统
  • 沟通要简洁
  • 内心要诚实
  • 态度要谦虚
  • 回答要灵活

切忌:

  1. 基础面相对答案相对统一,所以要简洁回答;而相比于第二/三面,可以多回答一点,但是要注意成体系,有逻辑性。

  2. 诚实的回答,不要自己说“我看过,我忘记了”这种,不会就是不会,可以去请教面试官。

  3. 关于知识,不要说话太死或者太满,评价一个事情的时候,由于我们往往认识不足,才会得到一个片面的观点。

页面布局

题目:假设调试已知,请写出三栏布局,其中左栏、右栏宽度各为300px,中间自适应。

布局题

回答技巧:

  1. 题干的要求真的是这么简单吗?

    解析:浮动+绝对定位是基础答案。加分项:第三种是Flex布局,第四种是Table布局,第五种网格布局Grid布局。

  2. 这道题的答案应该怎么写?技巧在哪里?

  3. 如果我要证明我的实力,我应该答上几种答案。

下面是答案:

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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style media="screen">
html * {
padding: 0;
margin: 0;
}

.layout article div {
min-height: 100px;
}

.layout {
margin-top: 10px;
}
</style>
</head>

<body>
<!-- 浮动 -->
<section class="layout float">
<style media="screen">
.layout.float .left {
float: left;
width: 300px;
background: red;
}

.layout.float .right {
float: right;
width: 300px;
background: blue;
}

.layout.float .center {
background: yellow;
}
</style>
<article class="left-right-center">
<div class="left"></div>
<div class="right"></div>
<div class="center">
<h1>浮动解决方案</h1>
1. 这是三栏布局中间部分
2. 这是三栏布局中间部分
</div>
</article>
</section>
<!-- 绝对定位 -->
<section class="layout absolute">
<article class="left-center-right">
<style media="screen">
.layout.absolute .left-center-right>div {
position: absolute;
}

.layout.absolute .center {
left: 300px;
right: 300px;
background: yellow;
}

.layout.absolute .left {
left: 0;
width: 300px;
background: red;
}

.layout.absolute .right {
right: 0;
width: 300px;
background: blue
}
</style>
<div class="left"></div>
<div class="right"></div>
<div class="center">
<h2>这是绝对定位的解决方案</h2>
1. 这是三栏布局绝对定位中间部分
2. 这是三栏布局绝对定位中间部分
</div>
</article>
</section>
<!-- flex布局 -->
<section class="layout flexbox">
<style media="screen">
.layout.flexbox {
margin-top: 120px;
}

.layout.flexbox .left-center-right {
display: flex;
}

.layout.flexbox .left {
width: 300px;
background: red;
}

.layout.flexbox .center {
flex: 1;
background: yellow;
}

.layout.flexbox .right {
width: 300px;
background: blue;
}
</style>
<article class="left-center-right">
<div class="left"></div>
<div class="center">
<h2>这是flex布局的解决方案</h2>
1. 这是三栏布局flex中间部分
2. 这是三栏布局flex中间部分
</div>
<div class="right"></div>
</article>
</section>

<!-- 表格布局 -->
<section class="layout table">
<style media="screen">
.layout.table .left-center-right {
width: 100%;
display: table;
height: 100px;
}
.layout.table .left-center-right > div {
display: table-cell;
}
.layout.table .left {
width: 300px;
background: red;
}
.layout.table .center {
background: yellow;
}
.layout.table .right {
width: 300px;
background: blue;
}
</style>
<articcle class="left-center-right">
<div class="left"></div>
<div class="center">
<h2>这是table布局的解决方案</h2>
1. 这是三栏布局table中间部分
2. 这是三栏布局table中间部分
</div>
<div class="right"></div>
</articcle>
</section>

<!-- grid布局 -->
<section class="layout grid">
<style media="screen">
.layout.grid .left-center-right {
display: grid;
width: 100%;
grid-template-rows: 100px;
grid-template-columns: 300px auto 300px;
}
.layout.grid .left {
background: red;
}
.layout.grid .right {
background: blue;
}
.layout.grid .center {
background: yellow;
}
</style>
<article class="left-center-right">
<div class="left"></div>
<div class="center">
<h2>网络布局解决方案</h2>
1. 这是三栏布局grid中间部分
2. 这是三栏布局grid中间部分
</div>
<div class="right"></div>
</article>
</section>
</body>
</html>

答完题之后,面试可能最会问的是:

  1. 怎么延伸,这一种方案的优缺点;

  2. 把高度去掉,中间的高度比较高,需要左右一样会撑开。

    • Table、Flex布局可以自适应。
  3. 兼容性怎么样。

    • 对于浮动缺点:常见需要清除浮动;优点,兼容性比较好。
    • 绝对定位缺点:脱离了文档流;优点:快捷;
    • flex布局:在移动端适配比较好;
    • 表格布局:优点,对于高度的适应比较好,兼容性比较好;缺点:当其中一个单元格高度超出了之后,会改变其他的单元格的高度;
    • 网格布局:优点代码量简化;缺点:兼容性对于IE不是友好。
  4. 浮动解决方案,为什么中间内容比较高,超出了左侧元素后,为什么会浮动到左侧? 使用浮动布局的时候,不让元素超出自己的边界,自动延伸(答案:创建BFC,见CSS盒模型

页面布局小结

  1. 语义化掌握到位(不要通篇DIV)
  2. 页面布局理解深刻(理解原理)
  3. CSS基础知识扎实(table, flex, grid基础知识)
  4. 思维灵活且积极上进
  5. 代码书写规范

页面布局的变通/变种

  1. 三栏布局

    • 左右宽度固定,中间自适应
    • 上下高度固定,中间自适应
  2. 两栏布局

    • 左宽度固定,右自适应
    • 右宽度固定,左自适应
    • 上高度固定,下自适应
    • 下高度固定,上自适应

只有多思考,多准备,才能建立知识体系。

CSS盒模型

题目:谈谈你对CSS盒模型的认识

准备的知识:

  1. 基本概念:标准模型 + IE模型
  2. 标准模型与IE模型的区别(宽高不同)
  3. CSS如何设置这两种模型
  4. JS如何设置获取盒模型对应的宽和高
  5. 实例题(根据盒模型解释边距重叠)
  6. BFC(Block Formatting Context-块级格式化上下文,边距重叠解决方案) IFC(Inline Formatting Context-行级格式化上下文)

BFC布局规则:

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

IFC布局规则:

  1. 框会从包含块的顶部开始,一个接一个地水平摆放。
  2. 摆放这些框的时候,它们在水平方向上的外边距、边框、内边距所占用的空间都会被考虑在内。在垂直方向上,这些框可能会以不同形式来对齐:它们可能会把底部或顶部对齐,也可能把其内部的文本基线对齐。能把在一行上的框都完全包含进去的一个矩形区域,被称为该行的行框。水平的margin、padding、border有效,垂直无效。不能指定宽高。
  3. 行框的宽度是由包含块和存在的浮动来决定。行框的高度由行高计算这一章所描述的规则来决定。

回答技巧:

  1. 基本概念:
标准模型 IE模型
  1. 标准模型与IE模型的区别,IE模型包含Padding进行计算Content内部部分的宽;

  2. 设置模型的方式:

    1
    2
    3
    box-sizing: content-box; # 标准模型(浏览器默认)

    box-sizing: border-box; # IE模型
  3. JS有几种方式:

    1
    2
    3
    4
    5
    6
    7
    dom.style.width/height,取的是内联属性,如果是link的样式取不到的。

    dom.currentStyle.width/height 只有IE支持

    window.getComputedStyle(dom).width/height

    dom.getBoundingClientRect().width/height
  4. 实例题:

    元素重叠要注意:

    • 兄弟元素的重叠,重叠的原则取最大值
    • 空元素,取margin-top,margin-bottom一个最大值作为边距
  5. BFC解决边距重叠解决方案:

    • BFC基本概念
    • BFC原理(垂直方向会重叠,不会清除FLEX布局,不会影响外面的元素,Float元素会参与计算)
    • 如何创建BFC(overflow:hidden/visible,float不为None,position值不为relative或者static,display属性table/table-cell)
    • BFC使用场景
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
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
html * {
padding: 0;
margin: 0;
}
</style>
</head>
<body>
<section id="sec">
<style media="screen">
#sec {
background: red;
/* overflow: hidden; */
}
.child {
height: 100px;
margin-top: 10px;
background: yellow;
}
</style>
<article class="child"></article>
</section>

<!-- 例子2,关于Margin -->
<section id="margin">
<style>
#margin {
background: pink;
overflow: hidden;
}
#margin > p {
margin: 5px auto 25px;
background: red;
}
</style>
<p>1</p>
<p>2</p>
<p>3</p>
---------
<p>1</p>
<!-- 套一个DIV,使用BFC方式 -->
<div style="overflow:hidden">
<p>2</p>
</div>
<p>3</p>
</section>

<!-- BFC的应用 -->
<section id="layout">
<style>
#layout {
background: red;
}
#layout .left {
float: left;
width: 100px;
height: 100px;
background: pink;
}
#layout .right {
height: 110px;
background: gray;
overflow: auto; # 这一行,使right的元素可以向下延伸,而不会向左进行延伸
}
</style>
<div class="left"></div>
<div class="right"></div>
</section>

<!-- BFC子元素,即使是float也会参与高度计算 -->
<section id="float">
<style>
#float {
background: red;
/* overflow: auto; */
/* float: none; */
}

#float .float{
float: left;
}
</style>
<div class="float">
我是浮动元素
</div>
</div>
</body>
</html>

DOM事件

  1. 基本概念:DOM事件的级别;
DOM事件类 事件级别
DOM0 element.onclick=function(){}
DOM2 element.addEventListener(‘click’, function(){}, false)
DOM3 element.addEventListener(‘keyup’,function(){}, false)

IE中attachListener;

DOM3增加了一些事件类型,鼠标、键盘事件;

  1. 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
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Event</title>
    </head>
    <body>
    <div id="ev">
    <style>
    #ev {
    width: 300px;
    height: 100px;
    background: red;
    color: #fff;
    text-align: center;
    line-height: 100px;
    }
    </style>
    目标元素
    </div>
    <script>
    var ev = document.getElementById('ev')

    window.addEventListener('click', function(){
    console.log('window capture')
    }, true)

    document.addEventListener('click', function(){
    console.log('document capture')
    }, true)

    document.documentElement.addEventListener('click', function(){
    console.log('html capture')
    }, true)

    document.body.addEventListener('click', function(){
    console.log('body capture')
    }, true)

    ev.addEventListener('click', function(){
    console.log('ev capture')
    }, true)
    </script>
    </body>

    console里面打印的信息:

    1
    2
    3
    4
    5
    window capture
    document capture
    html capture
    body capture
    ev capture

    上面的输出顺序不受定义先后顺序的影响,说明捕获的流程是从上至下,一层又一层。冒泡是相反的,可以把true全改成false来试验一下。

  2. DOM事件流;

    事件流是指用户侧触发了事件之后,事件是如何传递并最终在目标对象上触发相应的操作的。

    一个完整的事件流包含:1. 捕获阶段;2. 目标阶段;3. 冒泡阶段

  3. 描述DOM事件捕获的具体流程;

    window -> document -> html标签 -> body -> 父元素 -> 子元素 -> 目标元素

  4. Event对象的常见应用

  • event.preventDefault()阻止默认事件

  • event.stopPropagation() 阻止冒泡

  • event.stopImmediatePropagation() 事件响应优先级,A,B同时绑定在某元素上,如果在A触发中,加入该方法,即B元素上的事件就不会触发

  • event.currentTarget事件委托,多个元素,给父级元素绑定事件的时候,currentTarget代表的是绑定事件的父级元素

  • event.target获取被点击的元素

    参考资料1:

    the currentTarget refers to the element that the event listener directly attached to while the target still refers to the specific <a> we clicked.

    JavaScript Event Delegation, and event.target vs. event.currentTarget

    参考资料2:

    e.target = The thing under the mouse (as ben says… the thing that triggers the event).

    e.currentTarget = The thing before the dot… (see below)

    Difference between e.target and e.currentTarget

  1. 自定义事件

    1
    2
    3
    4
    5
    var eve = new Event('customEventName')
    elem.addEventListener('customEventName', function(){
    console.log('customEventName')
    })
    elem.dispatchEvent(eve)

    Event对象可以指定事件名,但是当需要给事件再传递一些数据的时候使用CustomEvent对象;

HTTP协议

  1. HTTP协议的主要特点

    • 简单快速:UII统一资源符,资源是是固定的
    • 灵活:HTTP头部分有数据类型,通过HTTP协议可以完成不同类型的数据传输
    • 无连接:连接一次就会断掉
    • 无状态:客户端与服务端是相对独立的,服务端没有记录客户的状态的

    服务端通过session的方式来记录用户信息与HTTP协议本身无关,HTTP协议未记录客户端的相关信息

  2. HTTP报文的组成部分

    HTTP报文组成有请求报文 + 响应报文;
    请求报文有请求行(HTTP方法、页面地址、HTTP协议及版本)、请求头(key-value值及类型)、空行、请求体;
    响应报文有状态行、响应头、空行、响应 体;

  3. HTTP方法

    • GET 获取资源
    • POST 传输资源
    • PUT 更新资源
    • DELETE 删除资源
    • HEAD 获得报文首部
  4. POST和GET的区别

  • GET在浏览器回退时无害的,而POST会再次请求
  • GET产生的URL地址可以被收藏,而POST不可以
  • GET请求会被浏览器主动缓存,而POST不会,除非手动设置
  • GET请求只能URL编码,而POST支持多种编码方式
  • GET请求参数会完整保留在浏览器历史记录里,而POST中的参数不会被保留
  • GET请求在URL中传递的参数有长度限制(基本是2KB),而POST没有限制
  • 对参数的数据类型,GET只接受ASCII字符,而POST没有限制
  • GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息
  • GET参数通过URL传递,POST放在Request Body中
  1. HTTP状态码
  • 1xx: 指示信息-表示请求已接收,继续处理
  • 2xx:成功-表示请求已被成功接收
  • 3xx:重定向-要完成请求必须进行更进一步的操作
  • 4xx:客户端错误-请求有语法错误或请求无法实现
  • 5xx:服务器错误-服务器未能实现合法的请求

常见的状态码:

200 OK:客户端请求成功
206 Partial Content:客户发送了一个带有Range头的GET请求,服务器完成了它
301 Moved Permanently:所请求的页面已经转移至新的URL
302 Found:所请求的页面已经临时转移至新的URL
304 Not Modified:客户端有缓冲的文档并发出了一个条件性的请求,服务器告诉客户,原来缓冲的文档还可以继续使用
400 Bad Request:客户端请求有语法错误,不能被服务器所理解
401 Unauthorized:请求未经制空权,这个 状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden:对被请求的页面被禁止
404 Not Found: 请求资源不存在
500 Internal Server Error:服务器发生不可预期的错误原来缓冲的文档还可以继续使用
503 Server Unavailable:请求未完成,服务器临时过载或当机,一段时间可能恢复正常

  1. 什么是持久连接

    HTTP协议采用“请求-应用”模式,当使用普通模式,即非Keep-Alive模式时,每个请求/应答客户和服务器都要新建立一个连接,完成之后立即断开连接(HTTP协议为无连接的协议)

    当使用Keep-Alive模式(又称持久连接、连接重用)时,Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接。

    HTTP协议1.1版本才开始支持Keep-Alive模式

  2. 什么是管线化

    在使用持久连接的情况下,某个连接上的消息的传递类似于:

    请求1->响应1->请求2->响应2->请求3->响应3

    某个连接上的消息变成了类似这样

    请求1->请求2->请求3->响应1->响应2->响应3

    管线化的特点:

    • 管线化机制通过持久连接完成,仅HTTP/1.1支持此技术
    • 只有GET和HEAD请求可以进行管线化,而POST则有所限制
    • 初次创建连接时,不应启动管线机制,因为对方(服务器)不一定支持HTTP/1.1版本的协议
    • 管线化不会影响响应到来的顺序,如上面的例子所示,响应返回的顺序并未改变
    • HTTP/1.1 要求服务器端支持管线化,但并不要求服务器端也对响应进行管线化处理,只是要求对于管线化的请求不失败即可
    • 由于上面提到的服务端问题,开启管线化很可能并不会带来大幅度的性能提升,而且很多服务器端和代理程序对管线化的支持并不好,因为现代浏览器如Chrome和Firefox默认并未开启管线化支持

面向对象内容部分

原型链

  1. 创建对象有几种方法

    方法一:

    1
    2
    var o1 = { name: 'o1'}
    var o11 = new Object({ name: 'o11'})

    方法二:

    1
    2
    var M = function(){this.name = 'o2'}
    var o2 = new M()

    方法三:(这个是很多同学答不上来的一种方法)

    1
    var P = { name: 'o3' }
  2. 原型、构造函数、实例、原型链

    • 任何函数都可以当作是构造函数
    • 只要是函数被new使用了,后面的就是一个构造函数
    • 构造函数可以通过New来生成一个实例
    • 函数都有一个prototype属性,这个是JS引擎给函数初始化的一个属性。

    原型链的基本功能:任何一个实例对象,通过原型链找到它上面的原型对象的方法和属性都是被实例所共享的。

    一个简单的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <script>
    var M = function(name){this.name= name}
    var o3 = new M('o3')

    M.prototype.say = function() {
    console.log('say hi')
    }

    var o5 = new M('o5')
    </script>

    函数才有prototype,对象是没有prototype的;只有实例对象才有__proto__对象。

  3. instanceof的原理

    上面实例中的例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    o3 instanceof M 
    返回true,原因,o3是M的是一实例。
    o3 instanceof Object
    返回true,原因,只要是原型链上的构造函数,都被看成是o3的一个构造函数
    o3.__proto === M.prototype
    返回true
    M.prototype.__proto__ === Object.prototype
    返回true
    o3.__proto__.constructor === M
    返回true
    o3.__proto__.contructor === Object
    返回false
  4. new运算符

    new原理

    按照New原理,写一个New2方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    var new2 = function(func){
    var o = Object.create(func.prototype)
    var k = func.call(o)
    if (typeof k === 'object') {
    return k
    } else {
    return o
    }
    }

    Console里面试验一下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    o6 = new2(M)
    这里的M.__proto__: Object
    o6 instanceof M
    返回true,o6是M的一个实例
    o6 instanceof Object
    返回true
    o6.__proto__.constructor === M
    返回true
    M.prototype.walk = function(){console.log('walk')}
    o6.walk()
    返回walk
    o3.walk()
    返回walk

面向对象类

  1. 类与实例

    • 类的声明
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    /**
    * 类的声明
    */
    function Animal () {
    this.name = 'name'
    }

    /**
    * ES6中的Class的声明
    */
    class Animal2 {
    constructor () {
    this.name = name;
    }
    }
    • 生成实例
    1
    2
    3
    4
    /**
    * 实例化
    */
    console.log(new Animal(), new Animal2())
  2. 类与继承

    • 如何实现继承
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    /**
    * 借助构造函数实现继承
    */
    function Parent1 () {
    this.name = 'parent1'
    this.play = [1,2,3]
    }
    Parent1.prototype.say = function () {
    console.log('say Parent')
    }
    function Child1 () {
    Parent1.call(this) // apply 改变了函数执行的上下文
    this.type = 'child1'
    }
    console.log(new Child1())

    var s1 = new Child2()
    var s2 = new Child2()
    console.log(s1.play, s2.play)
    s1.play.push(4)
    console.log(s1.play, s2,play)
    输出[1,2,3,4]

    使用构造函数实现的继承,缺点:无法继承父类原型对象上的方法,而是只能继承构建函数内的属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /**
    * 借助原型链实现继承
    */
    function Parent2 () {
    this.name = 'parent2'
    }
    function Child2 () {
    this.type = 'child2'
    }
    Child2.prototype = new Parent2()
    console.log(new Child2())

    console中来验证一下:

    1
    new Child2().__proto === Child2.prototype

    缺点:因为子类是继承了父类的prototype,那么当改变父类的原型对象的值的时候,所有的实例都会跟着变化

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /**
    * 组合方式
    */
    function Parent3 () {
    this.name = 'parent3'
    this.play = [1,2,3]
    }
    function Child3 () {
    Parent3.call(this)
    this.type = 'child3'
    }
    Child3.prototype = new Parent3()
    var s3 = new Child3()
    var s4 = new Child3()
    console.log(s3.play, s4.play)
    s3.play.push(4)
    console.log(s3.play, s4.play)

    Console中打印:

    1
    (4) [1, 2, 3, 4] (3) [1, 2, 3]

    思考一下,有什么缺点?

    Child3 new会实例化父类,prototype中又会实例化父类,父类的实例化执行了多次。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    /**
    * 组合继承的优化
    */
    function Parent4 () {
    this.name = 'parent4'
    this.play = [1,2,3]
    }
    function Child4 () {
    Parent4.call(this)
    this.type = 'child4'
    }
    Child4.prototype = Parent4.prototype
    var s5 = new Child4()
    var s6 = new Child4()
    console.log(s5.play, s6.play)
    s5.play.push(4)
    console.log(s5.play, s6.play)

    console.log(s5 instanceof Child4, s5 instanceof Parent4)
    console.log(s5.constructor)

    Console中打印

    1
    2
    (3) [1, 2, 3] (3) [1, 2, 3]
    (4) [1, 2, 3, 4] (3) [1, 2, 3]

    这种方式有没有不足?

    不能通过instanceof来判断s5,s6是Child的实例,还是Parent直接实例出来的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    /**
    * 组合继承优化2
    */
    function Parent5 () {
    this.name = 'parent5'
    this.play = [1,2,3]
    }
    function Child5 () {
    Parent5.call(this)
    this.type = 'child5'
    }
    Child5.prototype = Object.create(Parent5.prototype) // __proto__

    /*这样不仅实现了继承,而且还实现了原型对象的隔离*/
    Child5.prototype.constructor = Child5

    var s7 = new Child5()
    var s8 = new Child5()
    console.log(s7 instanceof Child5, s7 instanceof Parent5)
    console.log(s7.constructor)
    • 继承的几种方式

      构建函数 + 原型链

通信

跨域通信、普通的通信

  1. 什么是同源策略及限制

    同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。

    源:协议 + 域名 + 端口

    • Cookie、LocalStorage和IndexDB无法读取
    • DOM无法获得
    • AJAX请求不能发送
  2. 前后端如何通信

    (1)AJAX

    (2)WebSocket

    (3)CORS “跨域资源共享”(Cross-origin resource sharing)

  3. 如何创建Ajax(Asynchronous JavaScript and XML)

    (1)XMLHttpRequest对象的工作流程

    (2)兼容性处理

    (3)事件的触发条件

    (4)事件的触发顺序

  4. 跨域通信的几种方式

    (1)JSONP

    参考源码:jsonp.js

    原理是什么?怎么实现的?

    主要原理是:客户端告诉服务端Callback(回调函数名称,比如:jsonp),客户端定义一个全局的jsonp函数,通过执行jsonp函数,获取函数里面的数据。

    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
    /**
    * [function jsonp]
    * @param {[type]} url [description]
    * @param {[type]} onsucess [description]
    * @param {[type]} onerror [description]
    * @param {[type]} charset [description]
    * @return {[type]} [description]
    */
    util.jsonp = function (url, onsuccess, onerror, charset) {
    var callbackName = util.getName('tt_player');
    window[callbackName] = function () {
    if (onsuccess && util.isFunction(onsuccess)) {
    onsuccess(arguments[0]);
    }
    };
    var script = util.createScript(url + '&callback=' + callbackName, charset);
    script.onload = script.onreadystatechange = function () {
    if (!script.readyState || /loaded|complete/.test(script.readyState)) {
    script.onload = script.onreadystatechange = null;
    // 移除该script的 DOM 对象
    if (script.parentNode) {
    script.parentNode.removeChild(script);
    }
    // 删除函数或变量
    window[callbackName] = null;
    }
    };
    script.onerror = function () {
    if (onerror && util.isFunction(onerror)) {
    onerror();
    }
    };
    document.getElementsByTagName('head')[0].appendChild(script);
    };

    (2)Hash

    参考源码:Ajax参考

    1
    2
    3
    4
    5
    6
    7
    8
    // 利用hash,场景是当前页面 A 通过iframe或frame嵌入了跨域的页面 B
    // 在A中伪代码如下:
    var B = document.getElementsByTagName('iframe');
    B.src = B.src + '#' + 'data';
    // 在B中的伪代码如下
    window.onhashchange = function () {
    var data = window.location.hash;
    };

    (3)postMessage

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // postMessage
    // 窗口A(http:A.com)向跨域的窗口B(http:B.com)发送信息
    Bwindow.postMessage('data', 'http://B.com');
    // 在窗口B中监听
    Awindow.addEventListener('message', function (event) {
    console.log(event.origin);
    console.log(event.source);
    console.log(event.data);
    }, false);

    (4)Websocket

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // Websocket【参考资料】http://www.ruanyifeng.com/blog/2017/05/websocket.html

    var ws = new WebSocket('wss://echo.websocket.org');

    ws.onopen = function (evt) {
    console.log('Connection open ...');
    ws.send('Hello WebSockets!');
    };

    ws.onmessage = function (evt) {
    console.log('Received Message: ', evt.data);
    ws.close();
    };

    ws.onclose = function (evt) {
    console.log('Connection closed.');
    };

    (5)CORS

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // CORS【参考资料】http://www.ruanyifeng.com/blog/2016/04/cors.html
    // url(必选),options(可选)
    fetch('/some/url/', {
    method: 'get',
    }).then(function (response) {

    }).catch(function (err) {
    // 出错了,等价于 then 的第二个参数,但这样更好用更直观
    });

安全

安全分类分CSRF——跨站请求伪造(英语:Cross-site request forgery), XSS——跨域脚本攻击(英语:Cross-site scripting)

CSRF可能会考到:

  • 基本概念与缩写
  • 攻击原理

  • 防御措施

    (1)Token验证

    (2)Referer验证

    (3)隐藏令牌

XSS可能会考到:

  • 攻击原理
  • 防御措施

参考:Web安全-XSS

XSS是向页面注入JS,让JS去做它想做的事情;CSRF利用漏洞去执行接口,CSRF依赖用户需要登录网站。

算法

基本的算法题:

  • 排序
  • 堆栈、队列、链表
  • 递归
  • 波兰式和逆波兰式

排序

  1. 排序相关资料:

    快速排序

    选择排序

    希尔排序

  2. 递归相关资料:

    递归

  3. 波兰式与逆波兰式

    理论

    源码

  4. 如何准备?

    • 基本功

    • 理解题目(如果不会,可以问问面试官,解释一下题目)

    • 想到哪里写到哪里

    • 如果不会,可以问一下(这里我知道怎么做,需要用XX什么原理,但是我这时不知道接下来怎么做了)