2017年前端面试经历-2

第二个面试是对我打击最大的今日头条。

今日头条近一年风头正劲,发展迅速,前端需求量很大。本来抱着很大希望去面试,结果收到的打击也最大。

不过站在现在回顾那个面试,虽然打击最大,给我的帮助和提高也是最大的。

夸张一点说,what doesn’t kill you makes stronger


应该是又挂了。面试从下午四点开始,做笔试题,然后一面,等待,然后二面,结束的时候已经8点半了

跑回公司打卡时已经9点多了,心情特别沮丧。面试的内容接近80%是我不清楚或者没接触过的,95%都是我不确定的。

我也知道自己做前端不过区区九个月,自己是有些心急了,但是每次面试被问的不得不一遍又一遍承认“这个我不了解”、“这个我不熟悉”的时候,都为自己的无能、无知和蠢笨而懊恼和沮丧。

可能现在去大公司确实超出了自己的能力范围,换句话说在能力不够的时候,想要去超出自己能力范围的地方,只能看运气。

浮躁了。

也是由于自己目前的工作没有办法提供更多的学习机会了,所以着急。今天就去找公司的人谈换项目的事,看会有什么结果。

1、box-sizing

CSS属性box-sizing的值有哪些?分别有什么含义?

  • content-box: 宽度、高度之外绘制元素的padding和border
  • border-box: 宽度、高度之内绘制元素的padding和border

==和margin没有关系==!!!

2、在HTTP响应Header中,Set-Cookie的选项有哪些?分别是什么含义?
  • tt_webid=6507009217324615181: 设置 name 和 value, 必选参数,其他参数为可选
  • Path=/:控制那些访问能够触发cookie的发送,/表示根路径下的文件有权限读取该cookie,只可写,不可读,path 权限有继承性
  • Domain: cookie 有效的域名,.toutiao.com的设置表明在 toutiao.com 的所有域名中生效,如果www.toutiao.com仅仅在www.toutiao.com子域名中生效
  • expire: 规定cookie的过期时间,是一个绝对时间,如果没设置,cookie将在session结束后(即浏览器关闭后)失效
  • Max-Age: 规定web文件被用户请求后的存活时间,是一个相对值,单位是秒
  • secure:规定是否需要在HTTPS链接传输cookie,如果需要设置为true,默认为false
3、for…in、Object.keys和Object.getOwnPropertyNames的区别
  • for...in: 遍历自身原型中所有可枚举的属性
  • Object.keys: 遍历自身可枚举的属性
  • Object.getOwnPropertyNames: 遍历自身所有属性,包括可枚举属性不可枚举属性

可枚举是有属性的enumerable值决定的,生成不可枚举的属性使用Object.defineProerties方法

var obj1 = {};
Object.defineProperties(obj1, {
  name: {
    value: "张三",
    enumerable: false
  }
});
4、判断数组

五种方法:

$.isArray([]); // true

[].constructor === Array; // true

[] instanceof Array; // true

typeof [] === 'object' && [].length === 0 // true

Array.isArray([]); // true
5、关于跨域

何为跨域?

跨域是指从一个域名的网页去请求另一个域名的资源。协议(http&https)、端口(80&81)、域名(baidu&google)、二级域名(news&sports)不相同,都为跨域。

跨域请求数据有哪几种方式?

  1. iframe + window.name
  2. iframe + window.postMessage
  3. JSONP
  4. CORS(header:(Access-Control-Allow-Origin : *)
  5. Nginx反向代理

图片/脚本等资源有什么跨域问题?

图片、脚本不存在跨域问题

跨域请求如何携带cookie

第一种方法:nginx反向代理

第二种方法:[JSONP]方式可以携带cookie,但是只能是GET方法

第三种方法:CORS

HTTPS相关知识

简要描述HTTPS的安全机制

建立在SSL/TLS协议上,采用了公钥加密法,基本过程是:

  1. 客户端向服务器端索要并验证公钥。
  2. 双方协商生成”对话密钥”。
  3. 双方采用”对话密钥”进行加密通信。

前两步未握手阶段,详细过程是:

1、客户端先要服务器索要并验证公钥

2、服务器收到客户端请求后,向客户端做出回应, 内容包括服务器生成的两个随机数、加密方法、服务器证书等

3、客户端收到回应后,首先验证服务器证书,证书可信的话客户端就会从证书中取出服务器的公钥,利用预先约定好的加密方法生成“会话秘钥”,生成第三个随机数

4、服务器收到客户端的第三个随机数,计算生成本次的对话秘钥,握手阶段结束,接下来客户端和服务器进入加密通信,使用的就是HTTP协议,只不过用对话秘钥加密内容

HTTPS在WEB服务工程实践中需要注意的问题

HTTPS在未经优化的情况下速度比HTTP慢几百毫秒以上吗,影响主要来源于两方面:1、协议交互增加的网络延时;2、加解密相关的计算耗时

HTTP2和HTTPS的关系

HTTP2是在HTTPS协议的基础上实现的。HTTPS是HTTP1.1的补充,加入了SSL曾,增加其安全基础,HTTP2是HTTP1.1的全面升级。HTTP2目前在实际使用中,只用于HTTPS协议场景下,所以目前HTTP2的使用场景,都是默认安全加密的。

HTTP2是一个彻底的二进制协议,头信息和数据体都是二进制。HTTP2复用TCP链接,实现了双向的、实时的多工通信,HTTP2允许服务器推送

点击劫持

点击劫持是一种视觉欺骗,用透明的iframe或者图片覆盖页面,诱导用户点击,访问其他页面

预防方法是前端可以对当前页面地址进行判断,如果加载了iframe则重置location,更可靠的防御方法是在服务端设置HTTP头信息的X-FRAME-OPTION属性,属性值有DENY/SAMEORIGIN/ALLOWFROM

XSS跨站脚本攻击,用户输入非法字符,向页面植入用户代码,防护方式是用户的输入进行过滤和处理,对标签进行转换,避免使用用户输入作为代码,做到数据与代码分离

CSRF(CORSS SITE REQUEST FORGEY):跨站伪造请求,是用户在登陆的不安全的网站后,此网站伪造用户向目标网站发出请求(携带cookie),防御方法是用户提交请求时增加随机数或验证码,服务器进行验证

TCP三次握手

第一次:建立连接时,客户端发送SYN包到服务器,等待服务器确认。

SYN:同步序列编号(Synchronize Sequence Numbers)

第二次:服务器收到SYN包,确认后发送SYN + AGK

第三次:客户端收到服务器的SYN + AGK包后,向服务器发送确认包ACK,成功建立连接

首屏性能优化

是一个很大很深的课题,现在简单总结一下:

  • 页面模块化加载
    • 考虑将DOM树简化,内容放在localStorage中,通过前端缓存加异步加载加快首页加载速度。
    • 把需要请求的路径写在dom上(例如:data-tpl="elevator_tpl"),用户滚动时,一旦该模块进入了视窗,则请求dom上对应的data-tpl地址,拿到渲染这个模块所需要的脚本和数据,不过这中间还有一层本地缓存localstorage,如果在本地缓存中匹配到了对应的hash string内容,则直接渲染,否则请求到数据之后更新本地缓存。localstorage中的version会在页面加载时候,与后端文件hash相对比,hash不变直接取localstorage中的内容(当然也可以使用cookie判断版本)
  • 图片懒加载,节省流量的同时,也能减少请求数
  • webpack代码分割,按需加载JS模块
  • 服务端开启gzip压缩
  • 合理使用缓存
  • CSS雪碧图
  • 减少不必要的301/302跳转,减少跳转等待时间
  • 减少cookie体积,加快请求时间

TCP与HTTP的关系

TCP是传输层,HTTP是应用层,HTTP是基于TCP基础之上的。TCP就是单纯的建立连接,不涉及任何实际数据,HTTP是用来传输数据,是用于实际应用的。

TCP是底层通讯协议,定义的是数据传输和连接方式的规范

HTTP是应用层协议,定义的是传输数据的内容的规范

window.onload

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>DOM加载顺序</title>
  <script src="../libs/jquery.min.js"></script>
</head>
<body>
<p>1</p>
<script>
  document.write('2')
</script>
<p>3</p>
<script>
  window.onload = function () {
    document.write('4');
    document.write('5');
    setTimeout(function () {
      document.write('8')
    }, 1000)
  };
  setTimeout(function () {
    document.write('6')
  }, 0);
  setTimeout(function () {
    document.write('7')
  }, 1000)
</script>
</body>
</html>

最后页面展现的是:45678

分析:
123的顺序很好理解,这时候window.load函数还没有执行,但是在第二段脚本中,setTimeOutwindow.onload都是在DOM完全加载完毕后执行,document.write相当重新书写了页面,导致123被取消,在页面上消失

这里indow.onloaddocument.ready造成的效果是相同的。

九宫格布局,要求hover时单元格边框变色

解决思路:

1 用table布局, border-collapse: collapse;,然后hover时利用td内部spanborder盖住tdborder

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>九宫格</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    .wrapper {
      margin: 50px;
    }
    .table {
      border-collapse: collapse;
    }
    .table td {
      text-align: center;
      vertical-align: middle;
      border-collapse: collapse;
      border: 5px solid black;
      position: relative;
    }
    .table td span {
      position: relative;
      display: block;
      width: 50px;
      height: 50px;
      line-height: 50px;
    }
    .table td span:hover {
      position: absolute;
      left: -5px;
      top: -5px;
      border: 5px solid red;
    }
  </style>
</head>
<body>
<div class="wrapper">
  <table class="table">
    <tr>
      <td><span>1</span></td>
      <td><span>2</span></td>
      <td><span>3</span></td>
    </tr>
    <tr>
      <td><span>4</span></td>
      <td><span>5</span></td>
      <td><span>6</span></td>
    </tr>
    <tr>
      <td><span>7</span></td>
      <td><span>8</span></td>
      <td><span>9</span></td>
    </tr>
  </table>
</div>
</body>
</html>

2 用flex布局,用margin为复制盖住重复的边框,hover时改变对应的z-index

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>九宫格</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    .wrapper {
      margin: 50px;
      float: left
    }
    .flex {
      display: flex;
      width: 165px;
      height: 165px;
      flex-wrap: wrap;
      justify-content: center;
      align-items: center;
    }
    .flex-cell {
      flex: 0 0 50px;
      height: 50px;
      line-height: 50px;
      margin: -5px 0 0 -5px;
      text-align: center;
      border: 5px solid black;
      z-index: 1;
    }
    .flex-cell:hover {
      border: 5px solid red;
      z-index: 2;
    }
  </style>
</head>
<body>
<div class="wrapper">
</div>
<div class="wrapper">
  <div class="flex">
    <div class="flex-cell">1</div>
    <div class="flex-cell">2</div>
    <div class="flex-cell">3</div>
    <div class="flex-cell">4</div>
    <div class="flex-cell">5</div>
    <div class="flex-cell">6</div>
    <div class="flex-cell">7</div>
    <div class="flex-cell">8</div>
    <div class="flex-cell">9</div>
  </div>
</div>
</body>
</html>

3 任意布局,外围容器有左、上边框, 内部cell有右下边框, hover时用:after伪元素添加元素

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>九宫格</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    .wrapper2 {
      width: 165px;
      height: 165px;
      border-style: solid;
      border-color: black;
      border-width: 5px 0 0 5px;
    }
    .cell {
      float: left;
      width: 50px;
      height: 50px;
      line-height: 50px;
      border-style: solid;
      border-color: black;
      border-width: 0 5px 5px 0;
      text-align: center;
      position: relative;
    }
    .cell:hover:after {
      content: '';
      display: block;
      position: absolute;
      left: -5px;
      top: -5px;
      width: 100%;
      height: 100%;
      border: 5px solid red;
    }
  </style>
</head>
<body>
<div class="wrapper">
  <div class="wrapper2">
    <div class="cell">1</div>
    <div class="cell">2</div>
    <div class="cell">3</div>
    <div class="cell">4</div>
    <div class="cell">5</div>
    <div class="cell">6</div>
    <div class="cell">7</div>
    <div class="cell">8</div>
    <div class="cell">9</div>
  </div>
</div>
</body>
</html>

5 用grid布局

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>九宫格</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }
    .wrapper {
      margin: 50px;
      float: left
    }
    .grid{
      display: grid;
      width: 165px;
      height: 165px;
      grid-template-columns: 1fr 1fr 1fr;
      grid-template-rows: 1fr 1fr 1fr;
    }
    .grid-cell{
      display: grid;
      align-items: center;
      justify-content: center;
      vertical-align: middle;
      margin:-5px 0 0 -5px;
      border: 5px solid black;
      z-index: 1;
    }
    .grid-cell:hover{
      border: 5px solid red;
      z-index: 2;
    }
  </style>
</head>
<body>
<div class="wrapper">
  <div class="grid">
    <div class="grid-cell">1</div>
    <div class="grid-cell">2</div>
    <div class="grid-cell">3</div>
    <div class="grid-cell">4</div>
    <div class="grid-cell">5</div>
    <div class="grid-cell">6</div>
    <div class="grid-cell">7</div>
    <div class="grid-cell">8</div>
    <div class="grid-cell">9</div>
  </div>
</div>
</body>
</html>
原生AJAX请求
let xhr = new XMLHttpRequest();
xhr.open('GET', 'www.baidu.com');
xhr.send(null);
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4 && xhr.status === 200) {
    console.log(xhr.responseText)
  }
}

将原生的ajax请求改造为Promise请求

function succeedFunc(res) {
  console.log(res);
}

function failFunc(err) {
  console.log(err)
}

let xhr = new XMLHttpRequest();
let promise = new Promise(function(resolve, reject) {
  xhr.open('GET', 'test.txt');
  xhr.send(null);
  xhr.onreadystatechange = function() {
    if (xhr.readyState !== 4) {
      return;
    }
    if (xhr.status === 200) {
      resolve(xhr.responseText)
    } else {
      reject(new Error(xhr.responseText))
    }
  };
});
promise.then(function(value) {
  succeedFunc(value)
}, function(err) {
  failFunc(err)
})
在一个数组中按顺序取指定数目的最小数

思路还是需要两层嵌套的循环,根据内部循环的结果返回到外层循环,再改变内层循环的指标:

let arr = [2, 3, 5, 7, 2, 1, 2, 5, 2, 5, 5];

function getMin(arr, length) {
  let startIndex = 0, endIndex = arr.length - length;
  let result = [];
  let tempMin;
  for (let i = 0; i < arr.length; i++) {
    tempMin = arr[++startIndex];
    for (let j = startIndex; j <= endIndex; j++) {
      if (arr[j] < tempMin) {
        tempMin = arr[j];
        startIndex = j;
      }
    }
    result.push(tempMin);
    endIndex++;
    if (result.length === length) {
      break;
    }
  }
  return result;
}
console.log(getMin(arr, 3))
九宫格异步获取数据,要求尽快,并且按顺序展示

思路就是异步操作的promise请求要同时发出,但是写入事件的回调(await)按顺序执行

同时发出,可以不加await直接发出请求,在写入的时候await promise的结果,也可以将请求放在Promise.all中,写入时直接写入

假设异步操作设这样的:

function time(ms, message, index) {
  console.log(index);
  return new Promise(function (resolve) {
    setTimeout(resolve, ms * 1000, message)
  })
}

第一种写法:

async function fetch1() {
  let result1 = time(2, `${1} is complete`, `${1} is start`);
  let result2 = time(4, `${2} is complete`, `${2} is start`);
  console.log( await result1);
  console.log( await result2);
}

第二种写法:

async function fetch2() {
  console.time(1);
  let [result1, result2] = await Promise.all([time(2, `${1} is complete`, `${1} is start`),  time(4, `${2} is complete`, `${2} is start`)])
  console.log(result1);
  console.log(result2);
  console.timeEnd(1)
}

利用循环的话,使用for循环

async function fetch() {
  console.time(1);
  let result = [];
  for (let i = 1; i < 4; i++) {
    let ms = 5;
    result[i] = time(ms, `${i} is complete`, `${i} is start`);
  }
  for (let i = 1; i < 4; i++) {
    console.log(await result[i] )
  }
  console.timeEnd(1);
}

和下面的题目是一个知识点

假设wait(n)是一个耗时n秒的异步操作,判断总耗时
let w1 = await wait(3);
let w2 = await wait(2);

w1;
w2

因为请求是依次发出的,所以总耗时是5s

let w1 = wait(3);
let w2 = wait(2);

await w1;
await w2

异步操作请求是同时发出的,在等待w1的3s时w2请求已经完成,在w1()执行后立刻就可以w2(),所以总耗时3s

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值