🔒 期中考试

link标签的media属性
script标签的charset属性
使用svg标签画图

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

要求:

  1. 页面标题为「我的页面」
  • 页面中引入了一个外部 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
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
    <meta charset="UTF-8">
    <title>我的页面</title>
    <link rel="stylesheet" href="style.css">
    <link media="print" rel="stylesheet" href="print.css">
    <link media="all and (max-width:500px)" rel="stylesheet" href="mobile.css">
    </head>
    <body>
    <svg version="1.1" baseProfile="full" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
    <circle cx="100" cy="100" r="100" fill="green" />
    </svg>
    <script src="main.js"></script>
    <script charset="GBK" src="gbk.js"></script>
    </body>
    </html>

移动端是怎么做适配的?

2016年腾讯前端面试题:移动端是怎么做适配的?

回答要点:

  • meta viewport
  • 媒体查询(教程
  • 动态 rem 方案(教程
  1. 使用meta标签的viewport能优化移动浏览器的显示

<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">

  1. 使用媒体查询可以针对不同的媒体类型定义不同的样式。
    举个例子:如果浏览器窗口小于 500px, 就让背景变为蓝色:
    1
    2
    3
    4
    5
    6
    7
    <style>
    @media all and (max-width: 500px) {
    body {
    background-color: blue;
    }
    }
    </style>

你也可以利用link标签的media属性,针对不同的媒体使用不同的样式表 :
<link media="all and (max-width:500px)" rel="stylesheet" href="mobile.css">

  1. 动态rem方案
    通过js,动态设置html的font-size,让它的字号与页面宽度建立联系(比如html的字号等于页面宽度的十分之一)
    1
    2
    3
    4
    5
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <script>
    var pageWidth = document.documentElement.clientWidth;
    document.documentElement.style.fontSize = pageWidth/10+'px';
    </script>

此时,1rem就等于页面宽度的十分之一


css3圆角矩形和阴影怎么做?

2017年腾讯前端实习面试题(二面)
用过CSS3吗? 实现圆角矩形和阴影怎么做?

1
2
3
4
5
圆角矩形:border-radius
阴影分为盒子阴影和文字阴影:
盒子阴影:box-shadow
文字阴影:text-shadow


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

2017年腾讯前端实习面试题(二面)
什么是闭包,闭包的用途是什么?

1
2
3
4
5
6
(function (){
var local = '变量';
function fn(){
console.log(local);
}
})();

「函数」和「函数内部能访问到的变量」的总和,就是一个闭包。
上面代码中的函数fn,它里面可以访问到 local 变量,那么函数fn和local变量形成一个闭包。

闭包的作用是用来「间接访问一个变量」。利用闭包可以将函数内部的变量传递到外部,从而实现在外部访问另一个函数内部的局部变量。


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

2017年腾讯前端实习面试题(二面)
call、apply、bind 的用法分别是什么?
利用call、apply、bind这三个方法,可以改变this的指向,使它指向我们期望的对象。

1
2
3
var n = 123;
var o ={n: 234};
function a() {console.log(this.n)};

call:
格式
fn.call(thisValue, arg1, arg2, ...)
第一个参数是this要指向的那个对象,后面的参数是调用时所需要的参数
用法

1
2
3
4
5
6
a.call() //123
a.call(null) //123
a.call(undefined) //123
a.call(window) //123
a.call(o) //234
可以看到,如果call方法没有参数,或者参数为nullundefined,则this指向全局对象

call()方法可以传递两个参数。第一个参数是指定函数内部中this的指向(也就是函数执行时所在的作用域),第二个参数是函数调用时需要传递的参数。

1
2
3
4
function add(a, b) {
console.log(a + b);
}
add.call(null, 1, 2); //3

第一个参数是必须的,可以是null,undefined,this,但是不能为空。设置为null,undefined,this表明函数add此时处于全局作用域。第二个参数中必须一个个添加。而在apply中必须以数组的形式添加。


apply方法与call方法类似,使用格式如下:
func.apply(thisValue, [arg1, arg2, ...])
apply方法的第一个参数也是this所要指向的那个对象,如果没有第一个参数,或者设为null或undefined,则等同于指定全局对象。第二个参数则是一个数组,该数组的所有成员依次作为参数,传入原函数。
用法

1
2
3
4
5
a.apply() // 123
a.apply(null) //123
a.apply(undefined) //123
a.apply(window) //123
a.apply(o) //234

call的第二部分参数要一个一个传,apply要把这些参数放到数组中。这就是他们的区别,真的就这么点区别!!!

1
2
3
4
5
function add(a, b) {
console.log(a + b);
}
add.call(null, 2, 3); //5
add.apply(null, [2, 3]); //5

然后,不得不说的一点:它们的第二个参数都可以传arguments。


bind()和call与apply不同。bind方法用于指定函数内部的this指向(执行时所在的作用域),然后返回一个新函数。bind方法并非立即执行一个函数。call和apply方法都是在调用之后立即执行的。而bind调用之后返回一个函数,需要再调用一次才行

格式:
fn.bind(thisValue, arg1, arg2, ...])

用法

1
2
3
4
5
6
a.bind() //返回一个改变了上下文的函数
a.bind()(); // 123
a.bind(null)(); // 123
a.bind(undefined)(); // 123
a.bind(window)(); // 123
a.bind(o)(); // 234

同样,我们也可以给bind方法传递参数,第一个参数如果为null或者undefined,会将函数内部的this对象指向全局环境;第二个为调用时需要的参数,并且传递参数的形式与call方法相同,一个一个传入。

1
2
3
4
5
6
7
function add(a, b) {
return a + b;
}
console.log(add.apply(null,[1,4])); //5
console.log(add.call(null,1,4)); //5
console.log(add.bind(null, 1, 4)); //add()
console.log(add.bind(null, 1, 4)()); //5

bind方法除了绑定this以外,还可以绑定原函数的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
var add = function (x,y) {
return x*this.m + y*this.n;
}
var obj = {
m: 2,
n: 2
};
var newAdd = add.bind(obj, 5);//add()函数的第一次参数x绑定为5,如果给了两个参数,则同时给定了x、y的值
newAdd(3); //16 add()函数的参数y绑定3
等同于add.bind(obj)(5,3)

找出数组最大元素

1
2
3
var a = [2, 4, 5, 7, 8, 10];
console.log(Math.max.apply(null, a)); //10
console.log(Math.max.call(null,2, 4, 5, 7, 8, 10)); //10

将数组里的空元素变为undefined

通过apply方法,利用Array构造函数将数组的空元素变成undefined。

1
console.log( Array.apply(null, [1, , 3])); // [1, undefined, 3]

空元素和undefined的差别在于,数组的foreach方法会跳过空元素,但是不会跳过undefined,因此遍历内部元素的时候,会得到不同的结果

1
2
3
4
5
6
7
var a = [1, , 3];
a.forEach(function(index) {
console.log(index); //1,3 ,跳过了空元素。
})
Array.apply(null,a).forEach(function(index){
console.log(index); ////1,undefined,3 ,将空元素设置为undefined
})

类数组变成数组

利用数组对象的slice方法,可以将一个类似数组的对象(比如arguments对象)转为真正的数组。
被处理的对象必须有length属性,以及相对应的数字键。

arr.slice()用于提取数组中的元素,当不传入参数时,则提取所有的元素

1
2
3
4
5
6
7
8
Array.prototype.slice.apply({0:1,length:1})
// [1]
Array.prototype.slice.apply({0:1})
// []
Array.prototype.slice.apply({0:1,lengt:2})
// [1, undefined]
Array.prototype.slice.apply({length:1})
// []

总结

call,apply,bind方法的联系和区别

  1. 第一个参数都是指定函数内部中this的指向(函数执行时所在的作用域),然后根据指定的作用域,调用该函数。
  2. 都可以在函数调用时传递参数。call,bind方法需要直接传入,而apply方法需要以数组的形式传入。
  3. call,apply方法是在调用之后立即执行函数,而bind方法没有立即执行,需要将函数再执行一遍。有点闭包的味道。
  4. 改变this对象的指向问题不仅有call,apply,bind方法,也可以使用that变量来固定this的指向。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var a = 1;
    var b = 2;
    var obj={a:3, b:4};
    function add(x,y){
    return this.a*x + this.b*y;
    }
    add(5,6); // 1*5+2*6=17
    add.call(null,5,6) // 1*5+2*6=17, this指向window
    add.call(obj,5,6) // 3*5+4*6=39 ,this指向obj
    add.apply(obj,[5,6]) // 3*5+4*6=39 ,this指向obj,apply的参数以数组形式传入
    add.bind(obj,5,6)() // 3*5+4*6=39 ,this指向obj,bind方法并非立即执行一个函数,需要再次调用

关于javascript的call,apply,bind,bind()与前两种的区别?
js中的bind、call、apply组合使用


HTTP 状态码

2017年腾讯前端实习面试题(二面)
请说出至少 8 个 HTTP 状态码,并描述各状态码的意义。
参考菜鸟教程资料:http://www.runoob.com/http/http-tutorial.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
200 OK:请求成功
201 created:已创建。成功请求并创建了新的资源。一般POST时返回该状态码
301 Moved Permanently:永久重定向
302 Found:临时重定向
304 未修改Not Modified:所请求的资源在上次请求之后没有任何修改(这通常用于浏览器的缓存机制,使用GET请求时尤其需要注意)。服务器返回此状态码时不会返回任何资源。
400:无法找到请求的资源。
401:访问资源的权限不够。 一般登陆时用户名和密码不对会返回401
404 Not Found :请求的资源(网页)不存在。
403 Forbidden :没有权限访问资源。
405:需要访问的资源被禁止。
407:访问的资源需要代理身份验证。
414:请求的URL太长。
500 Internal Server Error:服务器内部错误,无法完成请求
502 Bad Gateway :充当网关或代理的服务器,从远端服务器接收到了一个无效的请求(比如服务器关了)


HTTP post 请求的4部分

2017年腾讯前端实习面试题(二面)
请写出一个 HTTP post 请求的内容,包括四部分。
其中
第四部分的内容是 username=ff&password=123
第二部分必须含有 Content-Type 字段
请求的路径为 /path
参考菜鸟教程资料:http://www.runoob.com/http/http-tutorial.html

1
2
3
4
5
6
7
POST /path HTTP/1.1
Host: www.baidu.com
User-Agent: curl/7.54.0
Accept: */*
Content-Type: application/x-www-form-urlencoded
username=ff&password=123


说出三种排序

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

  1. O(n²)
  2. O(n log2 n)
  3. O(n + max)

https://blog.csdn.net/gane_cheng/article/details/52652705
https://blog.csdn.net/supercoooooder/article/details/52153923
https://www.cnblogs.com/Unknw/p/6346681.html
http://bubkoo.com/2014/01/17/sort-algorithm/archives/

冒泡排序 O(n²)

原理:对数组进行遍历,相邻元素根据大小进行交换,每次遍历将最小值推至最前方,然后对剩下的值再次进行比较
以数组 arr = [5, 1, 4, 2, 8] 为例说明,加粗的数字表示每次循环要比较的两个数字:

第一次外循环

( 5 1 4 2 8 ) → ( 1 5 4 2 8 ), 5 > 1 交换位置
( 1 5 4 2 8 ) → ( 1 4 5 2 8 ), 5 > 4 交换位置
( 1 4 5 2 8 ) → ( 1 4 2 5 8 ), 5 > 2 交换位置
( 1 4 2 5 8 ) → ( 1 4 2 5 8 ), 5 < 8 位置不变

第二次外循环(除开最后一个元素8,对剩余的序列)

( 1 4 2 5 8 ) → ( 1 4 2 5 8 ), 1 < 4 位置不变
( 1 4 2 5 8 ) → ( 1 2 4 5 8 ), 4 > 2 交换位置
( 1 2 4 5 8 ) → ( 1 2 4 5 8 ), 4 < 5 位置不变

第三次外循环(除开已经排序好的最后两个元素,可以注意到上面的数组其实已经排序完成,但是程序本身并不知道,所以还要进行后续的循环,直到剩余的序列为 1)

( 1 2 4 5 8 ) → ( 1 2 4 5 8 )
( 1 2 4 5 8 ) → ( 1 2 4 5 8 )

第四次外循环(最后一次)
( 1 2 4 5 8 ) → ( 1 2 4 5 8 )

快速排序 O(n log2 n)

原理:从数组中取一个值为基准值,并将剩下的值与之比较,小于基准值的放到左边,大于基准值的放到右边,并再次对左右两边进行快速排序,直至左右两边只剩一个元素。
以数组 arr = [5, 2, 1, 4, 8, 6] 为例
取第一个数5为基准值,小于基准值的数放在基准值左边,大于基准值的数放在右边

1
2
3
基准值
2 1 4 [5] 8 6

然后分别对左右两边进行快速排序,左边以第一个数2为基准值,右边以第一个数8为基准值

1
2
3
左基准值 右基准值
↓ ↓
1 2 4 [5] 6 8

当左右基准值的两边都只剩一个元素时,快排结束。

桶排序 O(n + max) 【计数排序也是O(n + max),max表示桶的数量】

原理:将数组分到有限数量的桶里,然后对每个桶再分别排序(有可能再使用别的排序算法),最后将各个桶中的数据有序的合并起来。
以数组 array = [29, 25, 3, 49, 9, 37, 21, 43]为例,数组中最大数为 49,先设置 5个桶,然后分别将这些数放入自己所属的桶

1
2
3
4
5
第1个桶的范围 0~9: 3, 9
第2个桶的范围 10~19:
第3个桶的范围 20~29: 29, 25, 21
第4个桶的范围 30~39: 37
第5个桶的范围 40~49: 49, 43

然后,分别对每个桶里面的数进行排序

1
2
3
4
5
第1个桶的范围 0~9: 3, 9
第2个桶的范围 10~19:
第3个桶的范围 20~29: 21, 25, 29
第4个桶的范围 30~39: 37
第5个桶的范围 40~49: 43, 49

最后,将各个桶中的数据有序的合并起来

1
3, 9, 21, 25, 29, 37, 43, 49


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

这一题是在挖掘你的知识边界,所以你知道多少就要答多少。
可以先查阅一些资料再查,但是不要把自己不懂的东西放在答案里,面试官会追问的。
答:

  1. 输入URL地址
  2. DNS查询:浏览器通过DNS服务器查找对应的 IP 地址(比如 www.baidu.com(百度域名) 对应的一个IP地址是 220.181.112.244)
  3. 建立TCP连接 —— TCP三次握手
    知道了服务器的 IP 地址,下面便开始与服务器建立TCP连接了。建立需要经历以下三个过程:
    浏览器向服务器发送一个建立连接的请求(你好,我可以连你吗?);
    服务器接到请求后发送同意连接的信号(好的,你来连我吧);
    浏览器接到同意连接的信号后,再次向服务器发送了确认信号(那我连你咯!),自此,浏览器与服务器两者建立了连接。
  4. 当TCP连接建立完成以后,浏览器向服务器发送 HTTP 请求
    4.1 请求最多包含四部分,最少包含三部分。(也就是说第四部分可以为空)
    4.2 第三部分永远都是一个回车
    4.3 第4部分是要上传的数据
    4.4 第 2 部分中的 Content-Type 标注了第 4 部分的格式

    1
    2
    3
    4
    5
    6
    7
    1 POST / HTTP/1.1
    2 Host: www.baidu.com
    2 User-Agent: curl/7.54.0
    2 Accept: */*
    2 Content-Type: application/x-www-form-urlencoded
    3
    4 1234567890
  5. 服务器接收、处理请求

  6. 服务器返回 HTTP 响应,响应由4部分组成
    6.1 第1部分表示 协议/版本号 状态码 状态解释
    6.2 第 2 部分中的 Content-Type 标注了第 4 部分的格式
    6.3 第3部分永远是个回车
    6.4 第4部分是要下载的HTML文件内容

    1
    2
    3
    4
    5
    6
    1 HTTP/1.1 200 OK
    2 Content-Type: text/html
    2 Content-Length: 17931
    3
    4 <!DOCTYPE html>
    <!--STATUS OK--><html> <head> 后面太长,省略了……
  7. 浏览器得到 HTML 文件

  8. 浏览器开始对 HTML文件 进行加载、解析、渲染
    8.1 加载:浏览器对一个html页面的加载顺序是从上而下的,并在加载过程并行进行解析渲染处理。
    8.2 浏览器发送静态资源请求:在加载过程中遇到link标签、image标签、script标签时,浏览器会再次向服务器发送请求获取css文件、图片资源、js文件,并执行js代码,同步进行加载解析
    8.3 浏览器发送异步请求(Ajax)
    8.4 解析、渲染: 解析的过程,其实就是生成dom树。dom树是由dom元素及属性节点组成,加上css解析的样式和js解析后的动作实现。而渲染,就是将DOM树进行可视化表示。下一步就来到了绘制网页的工作阶段

  9. 浏览器通过上面步骤计算得到渲染树,构建渲染树使页面以正确的顺序绘制出来,经过一系列的渲染工作,最终完成了页面展示

  10. 断开TCP连接 —— TCP四次挥手
    ○ 主机向服务器发送一个断开连接的请求(你把我断开吧);
    ○ 服务器接到请求后发送确认收到请求的信号(知道了);
    ○ 服务器向主机发送断开通知(那我断开咯?);
    ○ 主机接到断开通知后断开连接并反馈一个确认信号(嗯,你断开吧),服务器收到确认信号后断开连接;
    为什么服务器在接到断开请求时不立即同意断开:当服务器收到断开连接的请求时,可能仍然有数据未发送完毕,所以服务器先发送确认信号,等所有数据发送完毕后再同意断开。

What really happens when you navigate to a URL
知乎:从输入 URL 到页面加载完成的过程中都发生了什么

【第8步补充】:

  • 根据HTML结构生成DOM Tree
  • 根据css生成 CSSOM
  • 将DOM和CSSOM整合成Render Tree(渲染树)
  • 浏览器根据 渲染树 开始渲染(Painting)和展示(Display)
  • 遇到script标签时,浏览器会阻塞渲染【所以script要放在尾部。1.这样可以让页面先渲染出来;2.这样js才能获取到所有的元素】
  • img发送异步请求,不会阻塞下面的代码渲染

如何实现数组去重?

假设有数组 arr = [1,5,2,3,4,2,3,1,3,4]
你要写一个函数 unique,使得
unique(arr) 的值为 [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
    20
    21
    22
    23
    24
    ES5:
    function unique(arr){
    return arr.filter(function (value, index) {
    return arr.indexOf(value) === index;
    });
    }
    //上面的方法不满足要求,因为filter和indexOf算作两次遍历
    //更新如下方法↓
    function unique(arr){
    var hash=[];
    for (var i = 0; i < arr.length; i++) {
    if(hash.indexOf(arr[i])==-1){
    hash.push(arr[i]);
    }
    }
    return hash;
    }
    ES6:
    function unique4(arr){
    return [...new Set(arr)];
    }
-------------本文结束感谢您的阅读-------------