请写出一个符合 W3C 规范的 HTML 文件

要求

页面标题为「我的页面」

页面中引入了一个外部 CSS 文件,文件路径为 /style.css

页面中引入了另一个外部 CSS 文件,路径为

/print.css,该文件仅在打印时生效

页面中引入了另一个外部 CSS 文件,路径为

/mobile.css,该文件仅在设备宽度小于 500 像素时生效

页面中引入了一个外部 JS 文件,路径为 /main.js

页面中引入了一个外部 JS 文件,路径为 /gbk.js,文件编码为 GBK

页面中有一个 SVG 标签,SVG 里面有一个直径为 100 像素的圆圈,颜色随意
注意题目中的路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>我的页面</title>
<link rel="stylesheet" href="/style.css">
<link rel="stylesheet" href="/print.css" media="print">
<link rel="stylesheet" href="/mobile.css" media="(max-width: 500px)">
<style type="text/css">
*{
padding: 0;
margin: 0;
}
</style>
</head>
<body>
<svg>
<circle cx="100" cy="100" r="50" fill="black">
</svg>
</body>
<script type="text/javascript" src="./main.js"></script>
<script type="text/javascript" src="./gbk.js" charset="GBK"></script>
</html>

移动端是怎么做适配的?

回答要点:

meta viewport

媒体查询

动态 rem 方案

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
1.meta viewport
在head标签内部加上这段代码

<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
该meta标签的作用是让当前viewport的宽度等于设备的宽度,同时不允许用户手动缩放。也许允不允许用户缩放不同的网站有不同的要求,但让viewport的宽度等于设备的宽度。
width=device-width: 让当前viewport宽度等于设备的宽度
user-scalable=no: 禁止用户缩放
initial-scale=1.0: 设置页面的初始缩放值为不缩放
maximum-scale=1.0: 允许用户的最大缩放值为1.0
minimum-scale=1.0: 允许用户的最小缩放值为1.0
2.媒体查询

@media ()and(){}
//满足()里的条件,就执行大括号里css的样式
<style>
@media (max-width:320px){
body{
background: red;
}
}
</style>
当最大宽度分辨率满足,就生效这个红色背景的CSS样式
3.动态 rem 方案
1rem等于根元素html的font-size的值,那么可以调整根元素的font-size值来调整页面缩放后的各个元素的尺寸和定位。

在script标签加入这段代码:

<script>
var pageWidth=window.innerWidth //获取屏幕宽度
document.documentElement.style.fontSize= `${pageWidth/60}px`
</script>
此处,fontSizede的值为屏幕宽的十分之一,那么在写CSS的时候可以这样写:

.xxx{
width:0.4rem;
height:0.2rem;
margin:0.05rem 0.05rem;
float:left;
}
用sass将px转化为rem:

@function px( $px ){
@return $px/$designWidth*10 + rem;
}
$designWidth: 320px;

那么1rem=32px

用过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
用过CSS3。
1.实现圆角
实现圆角矩形
使用 border-radius 属性:

border-radius: 6px;
当使用一个半径时确定一个圆形;当使用两个半径时确定一个椭圆,这个(椭)圆与边框的交集形成圆角效果。
取值:

用 px 等 css 长度单位值来定义圆形半径或椭圆的半长轴,半短轴。不能用负值。
使用百分数定义圆形半径或椭圆的半长轴,半短轴。水平半轴相对于盒模型的宽度;垂直半轴相对于盒模型的高度。不能用负值。
border-radius 属性又可以细分为以下 4 个属性,从左上角开始,逆时针依次为:

border-top-left-radius
border-top-right-radius
border-bottom-right-radius
border-bottom-left-radius
因此,可以为四个角各自单独设置,也可以用简写的 border-radius 属性一起设置。

border-radius: 6px;

/* 相当于 */

border-top-left-radius: 6px;
border-top-right-radius: 6px;
border-bottom-right-radius: 6px;
border-bottom-left-radius: 6px;
和其他简写属性类似,无法为个别值设定为继承,如 border-radius:0 0 inherit inherit,这会覆盖一部分现有定义。在这种情况下只能使用完整属性来指定。
2.阴影
有两种属性可以先实现阴影:

box-shadow 属性和 text-shadow 属性

使用 box-shadow 属性:
box-shadow: inset 2px 2px 2px 1px red;
会生成一个在边框内,水平、竖直偏移量均为 2px,模糊半径为 2px,同时阴影会扩大 1px 的红色阴影。
box-shadow使用一个或多个投影,如果使用多个投影时必须需要用逗号“,”分开。
对象选择器 {box-shadow:inset x-offset y-offset blur-radius spread-radius color}
对象选择器 {box-shadow:投影方式 X轴偏移量 Y轴偏移量 阴影模糊半径 阴影扩展半径 阴影颜色}
为文字添加阴影可以用 text-shadow 属性:
text-shadow: 2px 2px 2px red;
会生成一个水平、竖直偏移量均为 2px,模糊半径为 2px 的红色阴影。
两个属性都可以有多组阴影值,多组阴影值之间用逗号相隔;多个阴影时会从前往后叠加,第一个阴影在最上面。

什么是闭包,闭包的用途是什么?

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
1.什么是闭包?

function f1(){
var n=999;
function f2(){
  alert(n);
    }
    return f2;
  }
上面代码中的f2函数,就是闭包。

闭包就是能够读取其他函数内部变量的函数。

由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。

所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
2.闭包的用途是什么?
用处有两个,一个是前面提到的可以读取函数内部的变量,另一个就是让这些变量的值始终保持在内存中。

function f1() {

var n = 999;

nAdd = function () {
n += 1
}

function f2() {
alert(n);
}

return f2;

}

var result = f1();

result(); // 999

nAdd();

result(); // 1000
在这段代码中,result实际上就是闭包f2函数。它一共运行了两次,第一次的值是999,第二次的值是1000。这证明了,函数f1中的局部变量n一直保存在内存中,并没有在f1调用后被自动清除。

为什么会这样呢?原因就在于f1是f2的父函数,而f2被赋给了一个全局变量,这导致f2始终在内存中,而f2的存在依赖于f1,因此f1也始终在内存中,不会在调用结束后,被垃圾回收机制(garbage collection)回收。

call、apply、bind 的用法分别是什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apply()、call()和bind()方法都是Function.prototype对象中的方法,而所有的函数都是Function的实例。三者都可以改变this的指向,将函数绑定到上下文中。
apply() 方法调用一个函数, 其具有一个指定的this值,以及作为一个数组(或类似数组的对象)提供的参数。 语法 func.apply(thisArg, [argsArray])
call() 方法调用一个函数, 其具有一个指定的this值和分别地提供的参数(参数的列表)。 语法 fun.call(thisArg, arg1, arg2, ...)
bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。 语法 fun.bind(thisArg, 队列or数组)()
这三个方法的用法非常相似,将函数绑定到上下文中,即用来改变函数中this的指向。
function add(a,b){
return a+b;
}
add.call(add, 5, 3); //8
add.apply(add, [5, 3]); //8
bind:bind 接受的参数跟 call 一致,只是 bind 不会立即调用,它会生成一个新的函数,你想什么时候调就什么时候调。如下代码:
function add(a, b){
return a+b;
}
var foo1 = add.bind(add, 5,3);
foo1(); //8
var foo1 = add.bind(add, 5,3);
foo1(); //8

请说出至少 8 个 HTTP 状态码,并描述各状态码的意义。

例如:

状态码 200 表示响应成功。

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
1xx(临时响应)表示临时响应并需要请求者继续执行操作的状态代码。
100 (继续) 请求者应当继续提出请求。 服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。

101 (切换协议) 请求者已要求服务器切换协议,服务器已确认并准备切换。

2xx (成功)表示成功处理了请求的状态代码。
200 (成功) 服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。

201 (已创建) 请求成功并且服务器创建了新的资源。

202 (已接受) 服务器已接受请求,但尚未处理。

203 (非授权信息) 服务器已成功处理了请求,但返回的信息可能来自另一来源。

204 (无内容) 服务器成功处理了请求,但没有返回任何内容。

205 (重置内容) 服务器成功处理了请求,但没有返回任何内容。

206 (部分内容) 服务器成功处理了部分 GET 请求。

3xx (重定向) 表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向。
300 (多种选择) 针对请求,服务器可执行多种操作。 服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。

301 (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。

302 (临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。

303 (查看其他位置) 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。

304 (未修改) 自从上次请求后,请求的网页未修改过。 服务器返回此响应时,不会返回网页内容。

305 (使用代理) 请求者只能使用代理访问请求的网页。 如果服务器返回此响应,还表示请求者应使用代理。

307 (临时重定向) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。

4xx(请求错误) 这些状态代码表示请求可能出错,妨碍了服务器的处理。
400 (错误请求) 服务器不理解请求的语法。

401 (未授权) 请求要求身份验证。 对于需要登录的网页,服务器可能返回此响应。

403 (禁止) 服务器拒绝请求。

404 (未找到) 服务器找不到请求的网页。

405 (方法禁用) 禁用请求中指定的方法。

406 (不接受) 无法使用请求的内容特性响应请求的网页。

407 (需要代理授权) 此状态代码与 401(未授权)类似,但指定请求者应当授权使用代理。

408 (请求超时) 服务器等候请求时发生超时。

409 (冲突) 服务器在完成请求时发生冲突。 服务器必须在响应中包含有关冲突的信息。

410 (已删除) 如果请求的资源已永久删除,服务器就会返回此响应。

411 (需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。

412 (未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。

413 (请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。

414 (请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。

415 (不支持的媒体类型) 请求的格式不受请求页面的支持。

416 (请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态代码。

417 (未满足期望值) 服务器未满足"期望"请求标头字段的要求。

5xx(服务器错误)这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错。
500 (服务器内部错误) 服务器遇到错误,无法完成请求。

501 (尚未实施) 服务器不具备完成请求的功能。 例如,服务器无法识别请求方法时可能会返回此代码。

502 (错误网关) 服务器作为网关或代理,从上游服务器收到无效响应。

503 (服务不可用) 服务器目前无法使用(由于超载或停机维护)。 通常,这只是暂时状态。

504 (网关超时) 服务器作为网关或代理,但是没有及时从上游服务器收到请求。

505 (HTTP 版本不受支持) 服务器不支持请求中所用的 HTTP 协议版本。

请写出一个 HTTP post 请求的内容,包括四部分。

其中
第四部分的内容是 username=ff&password=123

第二部分必须含有 Content-Type 字段

请求的路径为 /path

1
2
3
4
5
6
7
1 POST /path HTTP/1.1
2 Host: www.demo.com
2 Cache-Control: no-cache
2 Postman-Token: 81d7b315-d4be-8ee8-1237-04f3976de032
2 Content-Type: application/x-www-form-urlencoded
3
4 username=ff&password=123

请说出至少三种排序的思路,这三种排序的时间复杂度分别为

O(n*n)

O(n log2 n)

O(n + max)

1
2
3
4
5
6
7
8
9
1.O(n*n)冒泡排序(升序)
选择第1个和第2个数字,如果第1个>第2个则二者交换位置,之后选择第2个和第3个数字,类似交换处理,一轮下来后,最大的数字会冒泡到最后一位。接下来,忽略已经排好的数字,对剩下的数字进行新一轮排序,直到所有数字都排序完成。
2.O(n log2 n)快速排序
从数列中挑出一个元素称为基准;
重新排序数列,所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基准后面(相等的数可以放在任一边);
递归的把小于基准值的子数列和大于基准值的子数列排序;
递归到最底部时,数列的大小是零或一,也就是已经排序好了。
3.O(n + max)基数排序
将所有待比较数值(正整数)统一为同样的数位长度,数位较短的数前面补零。然后,从最低位开始,依次进行一次排序。这样从最低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

一个页面从输入 URL 到页面加载显示完成,这个过程中都发生了什么?

这一题是在挖掘你的知识边界,所以你知道多少就要答多少。

可以先查阅一些资料再查,但是不要把自己不懂的东西放在答案里,面试官会追问的。

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
1.DNS解析
DNS解析的过程就是寻找哪台机器上有你需要资源的过程。当你在浏览器中输入一个地址时,例如www.baidu.com,其实不是百度网站真正意义上的地址。互联网上每一台计算机的唯一标识是它的IP地址,但是IP地址并不方便记忆。用户更喜欢用方便记忆的网址去寻找互联网上的其它计算机,也就是上面提到的百度的网址。所以互联网设计者需要在用户的方便性与可用性方面做一个权衡,这个权衡就是一个网址到IP地址的转换,这个过程就是DNS解析。

2.TCP连接
每次建立连接前,客户端和服务端之前都要先进行三次对话才开始正式传输内容,三次对话大概是这样的:

1. 客户端:我要连接你了,可以吗
2. 服务端:嗯,我准备好了,连接我吧
3. 客户端:那我连接你咯。
4. 开始后面步骤
3.发送HTTP请求
其实这部分又可以称为前端工程师眼中的HTTP,它主要发生在客户端。发送HTTP请求的过程就是构建HTTP请求报文并通过TCP协议中发送到服务器指定端口(HTTP协议80/8080, HTTPS协议443)。HTTP请求报文是由三部分组成: 请求行, 请求报头和请求正文。

1 动词 路径 协议/版本
2 Key1: value1
2 Key2: value2
2 Key3: value3
2 Content-Type: application/x-www-form-urlencoded
2 Host: www.baidu.com
2 User-Agent: curl/7.54.0
3
4 要上传的数据
4.服务器处理请求并返回HTTP报文
HTTP响应报文也是由三部分组成: 状态码, 响应报头和响应报文。
状态码
状态码是由3位数组成,第一个数字定义了响应的类别,且有五种可能取值:

1xx:指示信息–表示请求已接收,继续处理。

2xx:成功–表示请求已被成功接收、理解、接受。

3xx:重定向–要完成请求必须进行更进一步的操作。

4xx:客户端错误–请求有语法错误或请求无法实现。

5xx:服务器端错误–服务器未能实现合法的请求。
平时遇到比较常见的状态码有:200, 204, 301, 302, 304, 400, 401, 403, 404, 422, 500

5.浏览器解析渲染页面
浏览器是一个边解析边渲染的过程。首先浏览器解析HTML文件构建DOM树,然后解析CSS文件构建渲染树,等到渲染树构建完成后,浏览器开始布局渲染树并将其绘制到屏幕上

6.连接结束
通过四次挥手关闭连接。一端断开连接需要两次挥手(请求和回应),两端断开连接就需要四次挥手。


如何实现数组去重?

假设有数组 array = [1,5,2,3,4,2,3,1,3,4]

你要写一个函数 unique,使得
unique(array) 的值为 [1,5,2,3,4]
也就是把重复的值都去掉,只保留不重复的值。

要求:

不要做多重循环,只能遍历一次
请给出两种方案,一种能在 ES 5 环境中运行,一种能在 ES 6 环境中运行(提示 ES 6 环境多了一个 Set 对象)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
ES 5
ES5 提供了 filter 方法,我们可以用来简化外层循环:
比如使用 indexOf 的方法:

function unique(array) {
var res = array.filter(function(item, index, array){
return array.indexOf(item) === index;
})
return res;
}
console.log(unique(array));
排序去重的方法:

function unique(array) {
return array.concat().sort().filter(function(item, index, array){
return !index || item !== array[index - 1]
})
}
console.log(unique(array));
1
2
3
4
5
ES 6

function unique(array) {
return [...new Set(array)];
}