【24秋招冲刺】前端面经

作者碎碎念:

        经历过一场场面试,然后又一场场被挂,小编就算是个铁人也会流泪滴!!!但是秋招还是会继续,家里没矿,所以继续受虐,在此记录面试的高频考点,巩固基础,屡败屡战!!!!(SOS什么毒鸡汤???!!!)


如何实现垂直居中对齐(2次,高频)

<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    /* 绝对定位 1.*/
    #parent {
      position: relative;
      width: 500px;
      height: 500px;
      background-color: aqua;
    }

    #center {
      position: absolute;
      width: 100px;
      height: 100px;
      line-height: 100px;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      text-align: center;
      background-color: brown;
    }

    /* 绝对定位 2.*/
    /* #parent {
      position: relative;
      width: 500px;
      height: 500px;
      background-color: aqua;
    }

    #center {
      position: absolute;
      width: 100px;
      height: 100px;
      line-height: 100px;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      margin: auto;
      text-align: center;
      background-color: brown;
    } */

    /* flex布局 */
    /* #parent {
      display: flex;
      justify-content: center;
      align-items: center;
      width: 500px;
      height: 500px;
      background-color: aqua;
    }

    #center {
      width: 100px;
      height: 100px;
      line-height: 100px;
      text-align: center;
      background-color: brown;
    } */
  </style>
</head>
<body>
  <!-- 实现三栏布局 -->
  <div id="parent">
    <div id="center">center</div>
  </div>
</body>

</html>

效果图如下:

 延伸:说一下flex布局(3次)

说一下flex怎么布局的,然后说一下常用属性的用法,让面试官觉得你会;

如何实现三栏布局(笔试1次,面试1次,CSS基础)

 flex、绝对定位、浮动、双飞翼、圣杯(后两者布局还没理解到)

<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    /* flex布局 */
    #parent {
      width: 1000px;
      height: 100px;
      display: flex;
    }

    #left {
      width: 100px;
      text-align: center;
      background-color: palegoldenrod;
    }

    #right {
      width: 200px;
      text-align: center;
      background-color: blue;
    }

    #center {
      flex: 1;
      text-align: center;
      background-color: brown;
    }

    /* 绝对定位
    #parent {
      position: relative;
      width: 1000px;
      height: 100px;
    }

    #left {
      position: absolute;
      height: 100px;
      width: 100px;
      text-align: center;
      background-color: palegoldenrod;
    }

    #right {
      position: absolute;
      width: 200px;
      height: 100px;
      top: 0;
      right: 0;
      text-align: center;
      background-color: blue;
    }

    #center {
      height: 100%;
      margin-left: 100px;
      margin-right: 200px;
      text-align: center;
      background-color: brown;
    } */

    /* 浮动:注意中间元素center要在末尾 */
    /* #parent {
      width: 1000px;
      height: 100px;
    }

    #left {
      float: left;
      height: 100px;
      width: 100px;
      text-align: center;
      background-color: palegoldenrod;
    }

    #right {
      float: right;
      width: 200px;
      height: 100px;
      top: 0;
      right: 0;
      text-align: center;
      background-color: blue;
    }

    #center {
      height: 100%;
      margin-left: 100px;
      margin-right: 200px;
      text-align: center;
      background-color: brown;
    } */
  </style>
</head>
<body>
    <!-- 实现三栏布局 -->
    <div id="parent">
      <div id="left">left</div>
      <div id="center">center</div>
      <div id="right">right</div>
    </div>
</body>

</html>

效果图都是这样,最好自己动手实操,加深印象~

对BFC的理解,如何创建BFC(2次)

MDN区块格式化上下文(Block Formatting Context,BFC)是 Web 页面的可视 CSS 渲染的一部分,是块级盒子的布局过程发生的区域,也是浮动元素与其他元素交互的区域。

通俗来讲:BFC是一个独立的布局环境,可以理解为一个容器,在这个容器中按照一定规则进行物品摆放,并且不会影响其它环境中的物品。如果一个元素符合触发BFC的条件,则BFC中的元素布局不受外部影响。

创建BFC的条件:

  • 根元素:body;
  • 元素设置浮动:float 除 none 以外的值;
  • 元素设置绝对定位:position (absolute、fixed);
  • display 值为:inline-block、table-cell、table-caption、flex等;
  • overflow 值为:hidden、auto、scroll;

盒子模型(2次)

width和height属性的范围:

  • box-sizing: content-box,标准盒子模型:content
  • box-sizing: border-box,IE(怪异)盒子模型:content + padding + border

原型和原型链(2次,重点!)

原型:每一个函数都有prototype属性,称为原型(原型对象),原型有属性和方法与实例对象共享,可以继承

原型链:对象都有__proto__属性,指向它的原型对象,原型对象也是对象,也有__proto__属性,指向原型对象的原型对象,这样一层一层形成的链式结构称原型链(最顶层为null)

画图加深记忆(理解理解才能吸收!!)

ES6新特性(n次,必背必背!!!)

Symbol、BigInt数据类型

新增let、const关键字

var、let、const区别:

  • var没有块级作用域,let、const有(块级作用域 : { } )
  • var存在变量提升(变量只能在声明之后使用,否在会报错),let、const没有
  • var可以重复声明,let、const不可以
  • var、let不用设置初始值,const必须设置
  • let创建的变量可以重新赋值,const不可以

箭头函数()=>{}

箭头函数和普通函数的区别:

  • 箭头函数更简洁
  • 箭头函数不绑定this,会捕获其所在上下文的this,作为自己的this。箭头函数中this的指向在它在定义时已经确定了,不会改变。普通函数的this指向调用者(谁调用就指向谁)。
  • 箭头函数不能作为构造函数使用(如上因为不能绑定this)
  • call()、apply()、bind()等方法不能改变箭头函数中this的指向
  • 箭头函数没有prototype,当然就不存在原型;没有自己的arguments对象
  • 箭头函数不能用作Generator函数,不能使用yeild关键字(作者自己标红,还不懂呜呜呜呜)

 扩展运算符

解构赋值

新增Map、Set数据结构

Map、Set、json区别:

  • JSON 对象在 JavaScript 中以键值对的形式表示,但键必须是字符串,且整个 JSON 对象必须是一个字符串。
  • Map存储键值对,任何值(对象或者原始值)都可以作为一个键或一个值,可迭代(用于 for...of 循环)。
  • Set存储唯一的值,可迭代(用于 for...of 循环)。

Map和weakMap区别:待续...

Set和weakSet区别:待续...

默认参数

即给函数设置默认参数

function greet(name, message = "Hello") {
  console.log(`${message}, ${name}!`);
}

 Promise

Promise是异步编程的一种解决方案,它是一个对象,可以获取异步操作的消息,改善了回调地狱

如何捕获Promise中的错误信息(1次)

try/catch,Promise.catch(),Promise.finally()(无论成功失败都会执行)

Promise实例的三个状态(1次)

  • Pending(进行中)
  • Fulfilled(已完成)
  • Rejected(已拒绝)

两个过程(pending起手)

  • pending -> fulfilled : Resolved(已完成)
  • pending -> rejected:Rejected(已拒绝)

注意:一旦从进行状态变成为其他状态就永远不能更改状态了。

Promise.all()(1次)

this/call/apply/bind区别(4次,背背背!!!)

这三个方法都显式指定调用函数的 this 指向

  • call,第一个参数this绑定的对象,其余参数需要依次列举出来,仅定义未执行
  • apply,第一个参数this绑定的对象,第二个传参数数组,仅定义未执行
  • bind,第一个参数this绑定的对象,第二个传参数对象立即执行

使用这些方法改变this指向

事件循环(3次)

JS是单线程的(why?设计为多线程如果同时添加删除DOM节点该怎么办?会出问题),为了防止阻塞,将代码分为同步and异步

常见宏任务:script(代码块),setTimeout/setInterval,setImmediate定时器

常见微任务:Promise.then()/catch(),ASync/Await,Object.observe,process.nextTick(node)

 执行顺序:执行栈中的同步代码 -> 微任务队列(直到没有微任务) -> 宏任务队列

 说完概念面试官一般会让你做一道关于时间循环的题(穿插seetTimeout、Promise),我的建议是多看多练,就会对事件循环理解更深刻。

先自己做一下哦~

setTimeout(() => {
  console.log('setTimeout');

  Promise.resolve().then(() => {
    console.log('setPro1');
  }).then(() => {
    console.log('setPro2');
  })
}, 0);

setTimeout(() => {
  console.log('set');
}, 0)

Promise.resolve().then(() => {
  console.log('then1');
}).then(() => {
  console.log('then2');
}).then(() => {
  console.log('then3');
})

console.log('same');

 公布答案啦~

 下面出一个纯Promise的,很绕很绕,直接晕厥

Promise.resolve().then(() => {
      console.log(0);
      return Promise.resolve(4);
}).then(res => {
      console.log(res);
})
Promise.resolve().then(() => {
      console.log(1);
}).then(() => {
      console.log(2);
}).then(() => {
      console.log(3);
}).then(() => {
      console.log(5);
})

闭包(2次)

MDN:闭包(closure)是一个函数以及其捆绑的周边环境状态(lexical environment词法环境)的引用的组合。

内部函数可以访问外部函数作用域就形成闭包,闭包可以使变量私有(不会造成变量污染)

经典面试题:循环中使用闭包解决 var 定义函数的问题

for (var i = 1; i <= 5; i++) {
  ;(function(j) {
    setTimeout(function timer() {
      console.log(j)
    }, j * 1000)
  })(i)
}

首先使用了立即执行函数(5次)将 i 传入函数内部,这个时候值就被固定在了参数 j 上面不会改变(j取到的值都是对应循环中的i值),当下次执行 timer 这个闭包的时候,就可以使用外部函数的变量 j,从而达到目的。

弊端:闭包可能会造成内存泄漏

注意:内存泄漏可能会延伸垃圾回收机制(V8)

浏览器的跨域问题

跨域问题其实就是浏览器的同源策略造成的。同源策略是浏览器的一个用于隔离潜在恶意文件的重要的安全机制。同源指的是:协议端口号域名必须一致。

如何解决跨域问题

 跨域问题设计后端,建议找视频看看,文字内容比较抽象实践一下印象更深;

(1)CORS(跨域资源共享),CORS需要浏览器和服务器同时支持,整个CORS过程都是浏览器完成的,无需用户参与。因此实现CORS的关键就是服务器,只要服务器实现了CORS请求,就可以跨源通信了。

浏览器将CORS分为简单请求非简单请求

简单请求(不会触发预检请求OPTIONS):请求方法:HEAD/GET/POST,请求头信息默认不改变

浏览器会直接发出CORS请求,它会在请求的头信息中增加一个Origin(协议+域名+端口)字段, 如果Orign指定的域名在许可范围之内,服务器返回的响应头字段中至少有Access-Control-Allow-Origin(和Origin字段存储的数据相等)

非简单请求:简单请求的要求之外的情况,非简单请求的CORS请求会在正式通信之前进行一次HTTP查询请求,称为预检请求。预检请求使用的请求方法是OPTIONS,他的头信息中的关键字段有OriginAccess-Control-Request-Method,Access-Control-Request-Headers,服务器在收到浏览器的预检请求之后,会根据头信息的三个字段来进行判断,如果返回的头信息在中有Access-Control-Allow-Origin这个字段就是允许跨域请求,如果没有,就是不同意这个预检请求,就会报错。

(2)nginx反向代理接口跨域;

(3)JSONP(已过时):利用<script>标签没有跨域限制,通过<script>标签src属性,发送带有callback参数的GET(只能是GET)请求,服务端将接口返回数据拼凑到callback函数中,返回给浏览器,浏览器解析执行,从而前端拿到callback函数返回的数据。

 什么是XSS攻击(2次待更新...)

当输入一个网址按下Enter键会发生什么(美团一面)

 重排一定会触发重绘,重绘不一定触发重排

布局没有发生变化,跳过layout+layer阶段,直接进行paint(绘制)阶段

触发回流(重排):

  • 首次渲染页面
  • 添加/删除元素
  • 改变元素大小/位置/内容、字体大小
  • 调整浏览器窗口大小
  • 查询某些属性或调用某些方法(clientWidth/clientLeft/clientHeight..., getcomputerdStyle(),getBoundingClientReact())

如何避免回流:避免频繁操作样式、DOM(脱离文档流,隐藏修改再显示)、transform/opacity/filters/will-change不会引起回流重绘

触发重绘:没有出现几何图形的变化的CSS样式

浏览器缓存机制(百度一面,浏览器原理必需知道)

我将缓存机制分为四种类型

浏览器首次加载资源,服务器返回 200,浏览器从服务器下载资源文件,并缓存资源文件与 response header(响应头),以供下次加载时对比使用;

  • cache-control: max-age;请求数据时,响应头中的cache-control字段,表示有效时间内的重复请求浏览器无需再次访问服务器,直接使用缓存资源;
  • expires:指定过期时间,同样是服务端的响应头字段,在有效的时间点之前,浏览器无需再次访问服务端,直接使用缓存资源;
  • Etag(服务端)/If-None-Match(客户端):首次请求资源时,服务端将缓存结果签名并设置在响应头的Etag字段中发送给客户端,客户端缓存Etag和结果数据,并在下一次请求时将Etag设置在请求头的If-None-Match字段中,服务端接收请求会比较Etag和If-None-Match是否一致, 若一致,返回304告诉客户端资源没有发生变化,客户端接收304状态码直接访问之前缓存的结果数据;
  • Last-Modified(服务端)/If-Modified-Since(客户端):首次请求资源时,服务端将缓存Last-Modified(结果数据最新的更改时间)并设置在响应头的Last-Modified字段中发送给客户端,客户端缓存Last-Modified和结果数据,并在下一次请求时将Last-Modified设置在请求头的If-Modified-Since字段中,服务端接收请求比较Last-Modified和If-Modified-Since,如果Last-Modified < If-Modified-Since(请求资源的时间在结果数据变化之后,资源是最新的),说明结果数据并没有发生变化,返回304告诉客户端资源没有发生变化,客户端接收304状态码直接访问之前缓存的结果数据;

 REACT的diff算法(2次,待更新...)

 V8的垃圾回收机制——GC算法分代式垃圾回收机制

V8将内存(堆)分为新生代老生代

新生代中的对象一般存活时间较短,使用 Scavenge GC 算法。在新生代空间中,内存空间分为两部分,分别为 From 空间和 To 空间。在这两个空间中,必定有一个空间是使用的,另一个空间是空闲的。新分配的对象会被放入 From 空间中,当 From 空间被占满时,新生代 GC 就会启动了。算法会检查 From 空间中存活的对象并复制到 To 空间中,如果有失活的对象就会销毁。当复制完成后将 From 空间和 To 空间互换,这样 GC 就结束了。

老生代中的对象一般存活时间较长且数量也多,使用了两个算法,分别是标记清除算法标记压缩算法

对象会出现在老生代空间中的情况:

  • 新生代中的对象是否已经经历过一次 Scavenge 算法,如果经历过的话,会将对象从新生代空间移到老生代空间中。
  • To 空间的对象占比大小超过 25 %。在这种情况下,为了不影响到内存分配,会将对象从新生代空间移到老生代空间中。

在这个阶段中,会遍历堆中所有的对象,然后标记活的对象,在标记完成后,销毁所有没有被标记的对象。在标记大型对内存时,可能需要几百毫秒才能完成一次标记。这就会导致一些性能上的问题。为了解决这个问题,2011 年,V8 从 stop-the-world 标记切换到增量标志。在增量标记期间,GC 将标记工作分解为更小的模块,可以让 JS 应用逻辑在模块间隙执行一会,从而不至于让应用出现停顿情况。但在 2018 年,GC 技术又有了一个重大突破,这项技术名为并发标记。该技术可以让 GC 扫描和标记对象时,同时允许 JS 运行。

清除对象后会造成堆内存出现碎片的情况,当碎片超过一定限制后会启动压缩算法。在压缩过程中,将活的对象向一端移动,直到所有对象都移动完成然后清理掉不需要的内存。

手写代码篇

数组去重(还没问过但是很基础)

// 数组去重的方法
 const equal = function (list) {
      // 1.利用Set特性
      // let _list = [...new Set(list)];

      
      // 2.数组indexOf、includes方法
      // for (let i = 0; i < list.length; i++) {
      //   // if (_list.indexOf(list[i]) < 0) {

      //   if (!_list.includes(list[i])) {
      //     _list.push(list[i]);
      //   }
      // }

      // 3.数组filter方法和indexOf组合技
      // let _list = list.filter((item, index, array) => {
      //   return array.indexOf(item) === index;
      // })

      // 4.数组reduce和indexOf/includes组合技
      let _list = list.reduce((pre, cur) => {
        if (!pre.includes(cur)) {
          pre.push(cur);
        }
        return pre;
      }, [])


      return _list;
    }

console.log(equal([1, 2, 3, 4, 5, 23, 1, 2, 3, 4, 5]));

总的来说,就是设置资源过期时间和判断结果数据是否发生变化两种方式,理解记忆哦~

先这样吧,洗洗睡咯...

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值