牛客面经每日一总结(四)

178 阅读8分钟

RSA和DSA的区别

他们都是非对称加密算法。

  • RSA: 他是基于大数分解(两个素数的乘积)实现的。它既可以作为签名(签名数字证书)使用也可以做加密(tls握手)使用。
  • DSA:他是基于整数有限域离散对数难题实现的。只能用于数字签名无法用于加密。

AES和DES区别

他们都是对称加密算法。

AES是DES的代替者,安全性高,性能很好,硬件也会多特殊的优化。

由于对称加密算法只能对特定长度明文加密,所以如果对于长明文,我们需要使用分组加密,然后将加密的秘钥段,连接起来。组成最终的秘钥。

内存泄露的原因

  • 在函数中定义一个未声明的变量,会被放在window中,将一直保存到内存中,知道程序结束。
  • 闭包的大量使用,因为闭包时,当外层函数执行上下文销毁后,内存函数应用的变量会被保存在堆中。
  • 递归,没有设置终止条件。
  • js引用DOM节点。即使节点删除了,这引用也会保存到内存中。

通过JSON实现深拷贝的问题

  • 对于对象的循环引用,会报错
  • 不能处理函数,Symbol等类型。

flex的理解

这里说的flex是内容元素的css样式。由flex-grow, flex-shrink, flex-basis组成。默认值是0 1 auto;

这里值讨论flex-basis的使用。

  • 设置元素主轴的初始大小。
  • 当其他两个属性都生效时,那么flex-basis将会失效。
  • 当width或者height 和 flex-basis同时存在,那么width或者height将会失效。
  • 如果flex-basis:auto, 那么它将使用width或者height的值。如果width或者height也为auto或者未设置,那么它将由内容撑开。
flex: 1 = flex: 1 1 0% 
flex: 2 = flex: 2 1 0% 
flex: auto = flex: 1 1 auto 
flex: none = flex: 0 0 auto,常用于固定尺寸不伸缩

如何阻止表单提交

  • 将input:submit改为input:button。
  • 监听form表单的submit事件,调用event.preventDefault(),或者返回false。

异步异常的捕获

我们知道try catch只能捕获存在于自己上下文的错误。但是异步异常就不能被catch。

但是有很多认为这两种方式也不能被捕获

  • 回调函数中的异常
  • await后的promise抛出的异常。 以上两种方式是可以捕获的。

其实我们捕获异步异常,一般都是在异步函数中捕获,这样我们就可以直接使用try catch,如果不在异步函数中,我们就直接将异步写在promise使用catch进行捕获。

那么如何捕获异步异常呢?

  • 将异步写在promise中使用catch捕获。
  • 但是如果promise中的异步抛出异常,catch可是不可以捕获的,需要使用reject传出异常信息。

这里还需要注意一下catch函数

  • catch只会捕获第一次抛出的异常。
  • 当catch和then方法都抛出异常,那么他只会捕获catch抛出的异常。 他是根据代码执行顺序进行捕获的。
    new Promise((resolve, reject) => {
      reject("====error")
    }).catch(res => {
      console.log("error1:", res) //  ====error
      throw new Error("======error catch")
    }).then(res => {
      throw new Error("=====error then")
    }).catch(res => {
      console.log("error2: ",res) // Error: ======error catch
    })

为什么0.1+0.2=0.30000000000000004

这个错误的根本原因是:大多数十进制无法正确的转换为二进制。 在计算机上计算时,是将十进制转换为二进制后进行计算,并将计算结果从二进制转换为十进制再次显示。

EcmaScrpt规范定义Number的类型遵循了IEEE754-2008中的64位浮点数规则定义的小数后的有效位数至多为52位导致计算出现精度丢失问题!

如何解决这个问题

原生的解决方法

  • 通过toFixed方法:使用定点表示法来格式化一个数值。
  • 该方法接收digits参数。表示小数点后数字的个数。介于 0 到 20(包括)之间,实现环境可能支持更大范围。如果忽略该参数,则默认为 0。
  • 然后返回格式化后的字符串。
    let a = 0.1
    let b = 0.2

    const result = parseFloat((a + b).toFixed(1))

    console.log(typeof result, result) // number 0.3

或者通过 *10 再 ÷10 的操作

    let a = 0.1 + 0.2; // 0.30000000000000004

    a = Math.round (a * 10); // 乘以 10 → 舍入 "3.0000000000000004" → "3"
    a = a / 10; // 3 / 10
    console.log (a); // 0.3

parseFloat()方法对于小数点后全为0的数字会保留整数。

    parseFloat(1.000) // 1

    parseFloat(1.030) // 1.03

伪类选择器

他们一般都是结合父标签使用的。

  • 如果不结合父标签,那么他将会选择符合条件的所有。
  • 如果不结合父标签,那么last-child将没有效果。(不知道为什么,是我测试的有问题吗)
      <style>
        /* 这个必须具有嵌套的元素。 但是last-child就不会有这个限制 */
        p:last-child {
          color: red;
        }
      </style>

    <body>
      <!-- <div> -->
      <p>1</p>
      <p>2</p>
      <p>3</p>
      <p>4</p>
      <p>5</p>
      <p>6</p>
      <p>7</p>
      <p>8</p>
      <p>9</p>
      <p>10</p>
      <!-- </div> -->
    </body>

image.png 如果给p标签加上div父标签,那么p: last-child将生效。 image.png

包含child的伪类受其他元素的影响

  • first-child: 表示选中第一个元素。一般都是组合元素。即前面需要加上父元素标签。 不然对于first-child可以选中很多。而且对于last-child标签而言。他只在嵌套元素下才能生效。
    // 这个选择器就不起作用,因为p不是div中的第一个元素。 
      <style>
        div p:first-child {
          color: red
        }
      </style>
    ​
      <div>
        <span>0</span>
        <p>1</p>
        <p>2</p>
        <p>3</p>
      </div>
  • nth-child(数字 / odd / even / 表达式):
    • 数字从1开始的。
    • 受其他元素影响。如果有其他元素,那么其他元素也参数索引
    • even(2n)表示偶数元素选中,odd(2n + 1)表示奇数元素选中。
    • 表达式:必须是包含n的表达式,并且n是从0开始计算的。
  • nth-last-child(): 表示从最后一个开始查找。
  • only-child。表示父元素中只能有一个标签,而且改标签为伪类选择器指定的标签。 image.png

不受其他元素的影响

  • first-of-type
  • last-of-type。这个并不需要有父元素包裹。
  • nth-of-type(数字 / odd / even / 表达式): 同上面一样
  • nth-last-of-type()
  • only-of-type: 表示父元素内,可以有多种标签,但是只能有唯一一个伪类选择器指定的标签,否则不起作用。 这类选择器,和上面的基本一样,唯一的区别就是他们只参考相同标签的元素。不会管其他类型的元素。

注意使用伪类选择器时,一定要加上父标签。

空标签伪类选择器

empty:标签内什么都没有才可以选中。包括空格。

axios的使用

  • 通过axios.create(config)创建一个实例。并传入一些基本的配置,比如timeout, baseURL等等。
  • 设置请求拦截器。这里一定要返回请求的配置。
    // 1. 请求拦截
      instance.interceptors.request.use(config => {
        // console.log(config);
        // 当请求可以发出时   我们拦截  对其做一些修饰
        // 1. config中的一些信息不符合服务器需求
        // 2  每次发送请求时,都希望有一个loading
        // 3. 某些网络请求都必须携带一些特定信息(token)
        return config;//拦截修改后   ,一定要将config返回   让服务器得到请求   来做出响应
      },err => {
        // console.log(err);
      })
  • 设置响应拦截器。如果后端接口比较规范的话,这里可以通过状态码整理响应数据。
      // 2. 响应拦截
      instance.interceptors.response.use(res => {
        // console.log(res);//此时是服务器返回的数据
        return res.data;//返回数据本身
      },err => {
        // console.log(err);
         return err;
      })
  • 最后返回axios实例对象。

JWT 的原理

JWT生成的Token由三部分组成:

  • header

    • alg:采用的加密算法,默认是 HMAC SHA256(HS256),采用同一个密钥进行加密和解密;
    • typ:JWT,固定值,通常都写成JWT即可;会通过base64Url算法进行编码
  • payload

    • 携带的数据,比如我们可以将用户的id和name放到payload中;
    • 默认也会携带iat(issued at),令牌的签发时间;
    • 我们也可以设置过期时间:exp(expiration time);
    • 会通过base64Url算法进行编码
  • signature

    • 设置一个secretKey,通过将前两个的结果合并后进行HMACSHA256(默认编码)的算法;
    • HMACSHA256(base64Url(header)+.+base64Url(payload), secretKey);
    • 如果secretKey暴露是一件非常危险的事情,因为之后就可以模拟颁发token,也可以解密token;

注意:前两个字段是通过base64编码的,可以反向解码。但是最后一个字段一般不行。

image.png

image.png

http2的主动推送(server push)和websocket有什么区别

  • HTTP2 Server Push,一般用以服务器根据解析 index.html 同时推送 JPG/JS/CSS 等资源,而免了服务器发送多次请求
  • websocket,用以服务器与客户端手动编写代码去推送进行数据通信

http 502和504的区别

  • 502 Bad Gateway。一般表现为你自己写的应用层服务(Java/Go/PHP)挂了,网关层无法接收到响应
  • 504 Gateway Timeout。一般表现为应用层服务 (upstream) 超时,如查库操作耗时十分钟,超过了 Nginx 配置的超时时间

如何中断请求

web新推出的一个api: AbortConroller。具体请参考mdn 他是一个类,通过创建对象获取signal信号量,他的作用是让controller对象和请求相关联,然后通过controller.abort()来中断请求的发送。

    const controller = new AbortController();
    const signal = controller.signal;
    abortBtn.addEventListener('click', function() {
      // 取消发送
      controller.abort();
    });

  // 在配置中传入signal
  fetch(url, {signal}).then(function(response) {
  
  })

并且axios的 v0.22.0 开始支持该api。具体请查看github

    const controller = new AbortController();

    axios.get('/foo/bar', {
       signal: controller.signal
    }).then(function(response) {
       //...
    });
    // cancel the request
    controller.abort()