百度前端面试题分享,带答案

这是我参与更文挑战的第7天,活动详情查看:更文挑战css

码字不易,您的赞是我持续更新创做的动力。html

在此次找工做的过程当中,百度总体的流程仍是比较规范的,虽然由于第一次去百度大厦的时候被HR告知一面面试官由于会议缘由要临时取消面试,改约其余时间。可是以后来到和全部的面试官聊天的过程当中,仍是感觉到了大厂范儿。前端

相较于其余公司喜欢问原理、问机制,百度的几面中更关注的是你在工做中是如何运用你所掌握的框架知识的,工做中是如何平衡业务和技术的,会经过一些工做中很实际的问题来一层层的深刻讨论,这点我以为很是好。webpack

下面主要看一下百度线下测试题部分,看看百度更关注一个前端的基本素养是什么。web

样式相关

1.1 假设有以下的 DOM 结构 & 样式 ( ⼩提示, 能够先往下看, 而后再回来看这⼀⼤坨 css )

<style> body { background: #fff !important; } .root { border: 3px #000 solid; width: 200px; } .root div { box-sizing: border-box; border: 1px #000 solid; background-color: #fff; } .div-a { position: relative; z-index: 100; top: 50px; width: 200px; height: 100px; } .div-b { position: absolute; z-index: 300; top: 80px; width: 100px; height: 50px; } .div-c { position: absolute; z-index: 200; width: 50px; height: 100px; } </style>

<div class="root"> 
  <div class="div-a"> 
    <div class="div-b"></div>
  </div>
  <div class="div-c"></div>
</div>
复制代码

问题

  • 请问以上 HTML ⽚段, 对应如下的哪⼀个渲染效果?
  • 请简要分析⼀下你的推导思路?
    • 提示, 这个⼩问是必答的, 咱们须要参考你的实际推导依据

img img img img

做答

选B。面试

⾸先,针对 root ⾼度,因为 root 下的元素只有 div-a 是 relative ,在⽂档流中;⼜由于全部 div 的盒模型是使⽤的标准盒模型,因此 root 的⾼度就等于 div-a 的⾼度 200px + 其上下边框的⾼度 3px*2 = 206px ;ajax

而后, div-a 相对其正常位置向下偏移 50px (top: 50px) , div-b 是绝对定位,其定位是相对于⽗级 div-a 进⾏的,向下偏移 80px (top:80px) ,由此能够排除C、D选项。算法

A、B选项中的不一样点在于针对 div-c 和 div-b 的 z-index ,因为 div-b 的⽗级元素 div-a 的 z-index 为 100px ,根据从⽗规则,因此 div-b 的 z-index 会被降级,⽽ div-c 的 z-index 值⼤于 div-a 的 z-index ,因此 div-c 在 div-b 的上⾯。故选B。跨域

1.2 简要介绍⼀下, 你在项⽬中, 如何管理各个元素的 z-index ?

  • 制定使⽤z-index的规范,⽐如 popover,modal,colorpicker 之类的组件,按照组件特性指定其层级的⾼低规范。另外业务布局中若是⽤到了z-index,尽可能控制其层级为较低的规范内,如布局中的z-index尽可能使⽤1xx,弹出层类的组件使⽤2xx等。
  • 全局维护⼀个获取z-index的⽅法,每次调⽤时数值递增1

1.3 简要介绍⼀下, 你如何在项⽬中管理样式的? 如何避免不一样⻚⾯ / 模块中, 样式的互相影响 ?

  • ⽬前项⽬中使⽤的是 BEM 规则,经过区分模块和元素来进⾏样式命名。
  • 经过 css modules 将css进⾏分模块管理。

⽹络相关

2.1 : 什么是同源策略和跨域? 解决跨域的⽅法有哪些 ?

同源策略是指协议、端⼝、域名相同,也就是在同⼀个域中。数组

⾮同源受到的限制有:cookie⽆法读取、dom⽆法获取、ajax请求⽆法发送。

跨域:两个不一样域(协议、端⼝、域名不一样)之间进⾏请求。

解决跨域的⽅法:

  • JSONP,经过动态建立⼀个script标签,script标签的src属性是没有跨域的限制的。
  • cors,服务端在response时增长⼀些头信息:

必需项, 值为请求头中的 Origin 的值.

  • Access-Control-Allow-Credentials:true

可选项, 值为boolean, 表示是否容许浏览器发送cookie, 须要在服务器配置.

  • Access-Control-Allow-Methods:

必需项, 容许跨域请求的请求⽅式.

  • Nginx作反向代理
  • 开发环境跨域使⽤ webpack-dev-server 的 proxy

2.2 : 列举⼀下 HTTP 中关于 "资源缓存" 的头部指令 (Head) 有哪些 ? 并简要介绍⼀下设置的规则 ?

强制缓存

  • Expires 指定⼀个缓存的过时时间,若是当次请求的资源在该过时时间以前,则命中缓存。缺点是

由于这个时间是⼀个绝对时间,因此当客户端本地时间被修改后,服务器与客户端时间误差变⼤会 致使缓存混乱。

  • Cache-Control ⼀般经过 max-age 指定⼀个相对时间,单位是秒。优先级⾼于 Expires 。其余常⽤

的取值有:

  • public 表示响应能够被任何对象缓存
  • private 表示只能被单个⽤户缓存,⾮共享的,不能被代理服务器缓存
  • no-cache 强制全部缓存了该响应的⽤户,在使⽤已缓存的数据钱,发送待验证器的请求到服务器。
  • No-store 禁⽌缓存

协商缓存

若未命中强缓存,则浏览器会将请求发送⾄服务器。服务器根据http头信息中的Last-Modify/If-ModifySince或Etag/If-None-Match来判断是否命中协商缓存。若是命中,则http返回码为304,浏览器从缓存 中加载资源。

  • Last-Modify/If-Modify-Since 浏览器第⼀次请求⼀个资源的时候,服务器返回的header中会加上Last-Modify,Last-modify是⼀个时间标识该资源的最后修改时间,当浏览器再次请求该资源时,发送的请求头中会包含If-Modify-Since,该值为缓存以前返回的Last-Modify。服务器收到IfModify-Since后,根据资源的最后修改时间判断是否命中缓存。
  • ETag/If-None-Match ETag能够保证每⼀个资源是惟⼀的,资源变化都会致使ETag变化。ETag值的变动则说明资源状态已经被修改。服务器根据浏览器上发送的If-None-Match值来判断是否命中缓存。

2.3 : 简要解释⼀下 301, 302, 304 的区别 ?

301 永久性重定向。该状态码表示请求的资源已经被分配了新的URI,而且之后使⽤资源如今所指的URI。而且根据请求的⽅法有不一样的处理⽅式。

302 临时性重定向。该状态码表示请求的资源已被分配了新的URI,但愿⽤户本次能使⽤新的URI访问。

304 该状态码表示客户端发送附带条件请求时,服务器端容许请求访问资源,但未满⾜条件的状况。

304状态码返回时,不包含任何响应的主题部分。附带条件的请求指的是采⽤GET⽅法的请求头中包含:If-Match、If-Modified-Since、If-None-Match、If-Range、If-Unmodified-Since中任⼀⾸部。

JS & 算法相关

3.1 : 请说明如下程序打印出什么结果, 并简要说明推导依据

const result = ['1', '3', '10'].map(parseInt);
// 这⾥会打印出什么呢? 
console.log( result );
复制代码

做答

打印结果是[1, NaN, 2] 由于map的参数是

function(current, index, arr) { // 当前元素值,当前元素索引值,数组自己
}
复制代码

parseInt的参数是:

parseInt(str, radix) // 解析的字符串,⼏进制(若省略或为0,则以10进⾏解析,若⼩于2或者⼤于36,则返回NaN)
复制代码

因此该题展开来写:

const result = ['1', '3', '10'].map(function(cur, index, arr) {
return parseInt(cur, index);
});
// 执⾏过程:
// parseInt('1', 0) -> 1
// parseInt('3', 1) -> NaN
// parseInt('10', 2) -> 2
复制代码

3.2 : 请修改如下代码, 使最后能顺序打印出 1, 2, 3, 4, 5

for (var i = 0; i < 5; i++) {
  setTimeout(function () {
    console.log(i);
  }, 1000);
}
复制代码
  • 要求: 每一个数字之间, 间隔时间为 1秒(提示, 好好审题哟)

做答:

const myPromise = num => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(num)
      }, 1000)
    })
 }

async function test() {
  for (let i = 0; i < 5;) {
    i++;
    console.log(await myPromise(i))
  }
 }
test();
复制代码

3.3 : 按照以下要求实现 process ⽅法

  • 取得两个数组⾥相同的部分, 并去重
  • 而后按照从⼩到⼤顺序排序, 最后结果返回 (注意, 是返回结果, 不是把结果打印出来)
const arrayA = [4, 2, 1, 2, 5];
const arrayB = [2, 3, 1, 6];
function process(arrayA, arrayB) {
// 这⾥是你实现代码的地⽅
}
/* 应该返回 [1, 2] */
process(arrayA, arrayB);
复制代码

做答部分

第一种:

function process(arrayA, arrayB){
  return arrayA
    .filter((v) => arrayB.includes(v))
    .filter((v, i, arr) => arr.indexOf(v) === i )
    .sort((a, b) => a-b);
}
复制代码

第⼆种:

function process(arrayA, arrayB) {
  const set = new Set();
  while(arrayA.length > 0) {
    const ele = arrayA.pop();
    if (arrayB.includes(ele)) {
      set.add(ele);
    }
  }
  return [...set].sort((a,b) => a - b);
}
复制代码

3.4 (附加题) : ⼩明要上⼀个⻓阶梯, 这个阶梯共有 N 个台阶, 假设⼩明每次能上⼀个台阶, 也能上两个台阶, 请问⼩明上这个阶梯, 总共有⼏种⾛法?

  • 你的⽬标是实现⼀个⽅法
  • 输⼊是⼀个 "数字 n (有⼏个台阶)"
  • 输出是⼀个 "数字 ( 表明总共有⼏种⾛法)"
/* 例如, n = 1, return 1 (⽅法1: 1台阶) n = 2, return 2 (⽅法1: 1台阶&1台阶, ⽅法2: 2台阶) n = 3, return 3 (⽅法1: 1台阶*3次, ⽅法2: 1台阶&2台阶, ⽅法3: 2台阶&1台阶) */
function step(n) {
// 这⾥是你实现代码的地⽅
}
复制代码

做答

(典型的斐波那契数列)

递归解法:

function step(n) {
  if (n <= 0) {
    throw new Error("param err");
    return -1;
  }
  if (n == 1) return 1;
  if (n == 2) return 2;
  return step(n - 1) + step(n - 2);
}
复制代码

⾮递归解法:

function step(n) {
  if (n <= 0) {
    throw new Error("param err");
    return -1;
  }

  if (n === 1) return 1;
  if (n === 2) return 2;

  let nMinusOne = 2,
  nMinusTwo = 1,
  timeN = 0;

  for (let i = 3; i <= n; ++i) {
    timeN = nMinusOne + nMinusTwo;
    nMinusTwo = nMinusOne;
    nMinusOne = timeN;
  }
  return timeN;
}
复制代码

综合来看,百度对前端的要求其实更看重的是解决问题的能力以及一些很基础的前段知识。面试的过程,其实也是复盘本身的过程,经过一次次的复盘来更加清楚本身的优劣势,明确本身的定位,这样才能在之后的工做中扬长补短,逐渐完善本身的知识体系。