面试题

面试题

一、移动web

1、flex:1 具体含义

flex:1 实际代表的是三个属性的简写:

  • flex-grow是用来增大盒子的,比如:当父盒子的宽度大于子盒子的宽度,父盒子的剩余空间可以利用flex-grow来设置子盒子增大的占比

    <style>
      * {
        margin: 0;
        padding: 0;
      }
    
      .box {
        display: flex;
        width: 800px;
        height: 150px;
        border: 2px solid purple;
      }
    
      .box p {
        width: 200px;
        height: 150px;
        text-align: center;
        line-height: 150px;
        font-size: 30px;
        color: #fff;
        background-color: orange;
      }
    
      /* 将剩余的宽度全部分配给第一个 p 标签 */
      .box p:nth-child(1) {
        flex-grow: 1;
      }
    style>
    
    <body>
      <div class="box">
        <p>1p>
        <p>2p>
        <p>3p>
      div>
    body>
    
  • flex-shrink

    是用来设置子盒子超过父盒子的宽度后,超出部分进行缩小的取值比例

    <style>
      * {
        margin: 0;
        padding: 0;
      }
    
      .box {
        display: flex;
        width: 800px;
        height: 150px;
        border: 2px solid purple;
      }
    
      .box p {
        width: 300px;
        height: 150px;
        text-align: center;
        line-height: 150px;
        font-size: 30px;
        color: #fff;
        background-color: orange;
      }
    
      /* 超出部分将按照比例分配给各个弹性盒子 */
      .box p:nth-child(1) {
        flex-shrink: 1;
      }
    
      .box p:nth-child(2) {
        flex-shrink: 2;
      }
    
      .box p:nth-child(3) {
        flex-shrink: 1;
      }
    style>
    
    <body>
      <div class="box">
        <p>1p>
        <p>2p>
        <p>3p>
      div>
    body>
    
  • flex-basis是用来设置盒子的基准宽度,并且basis和width同时存在basis会把width干掉

    <style>
      * {
        margin: 0;
        padding: 0;
      }
    
      .box {
        display: flex;
        width: 800px;
        height: 150px;
        border: 2px solid purple;
      }
    
      .box p {
        width: 100px;
        /* 覆盖掉 width 属性 */
        flex-basis: 200px;
        height: 150px;
        text-align: center;
        line-height: 150px;
        font-size: 30px;
        color: #fff;
        background-color: orange;
      }
    style>
    
    <body>
      <div class="box">
        <p>1p>
        <p>2p>
        <p>3p>
      div>
    body>
    
2、bfc概念/触发bfc/应用

回顾常见布局方案:

  • 普通流
  • 浮动流
  • 定位流

BFC概念: BFC 即 Block Formatting Contexts (块级格式化上下文), 是 W3C CSS2.1 规范中的一个概念。属于普通流布局方案

BFC特性: 具有 BFC 特性的元素可以看作是隔离的独立容器,容器里面的元素不会在布局上影响到外面的元素。

简单理解: BFC 是一个封闭的大箱子,箱子内部的元素无论如何变换都不会影响到箱子外边的元素

如何触发BFC:

  • body根元素
  • float属性不为none
  • position为absolute或fixed
  • display为inline-block, table-cell, table-caption, flex, inline-flex
  • overflow不为visible

BFC应用场景:

1、清除盒子垂直方向上外边距合并,同一个 BFC 下垂直方向外边距会发生折叠

<style>
  p {
    width: 100px;
    height: 100px;
    background-color: purple;
    margin: 100px 0;
  }
style>

<body>
  <p>p>
  <p>p>
body>

解决方案:可以给其中一个盒子再包裹一个盒子父元素,并触发其BFC功能(例如添加overflow:hidden;)这样垂直方向的两个盒子就不在同一个BFC中了,因此也不会发生垂直外边距合并的问题了。

<style>
  div {
    overflow: hidden;
  }
  p {
    width: 100px;
    height: 100px;
    background-color: purple;
    margin: 100px 0;
  }
style>
<body>
  <div>
    <p>p>
  div>
  <div>
    <p>p>
  div>
body>

2、在子元素设置成浮动元素的时候,会产生父元素高度塌陷的问题

解决方案:给父元素设置overflow:hidden;的时候会产生BFC。由于在计算BFC高度时,自然也会检测浮动的子盒子高度。所以当子盒子有高度但是浮动的时候,通过激发父盒子的BFC功能,会产生清除浮动的效果。

<style>
  ul {
    border: 1px solid purple;
    padding: 0;
    overflow: hidden;
  }

  ul li {
    float: left;
    margin-right: 30px;
    list-style: none;
    width: 100px;
    height: 100px;
    background: orange;
  }
style>

<body>
  <ul>
    <li>li>
    <li>li>
    <li>li>
  ul>
body>
3、盒子居中方式

方式一:flex布局

<style>
  * {
    margin: 0;
    padding: 0;
  }

  .box {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 800px;
    height: 500px;
    margin: 100px auto;
    border: 2px solid purple;
  }

  .minibox {
    width: 300px;
    height: 200px;
    background-color: purple;
  }
style>

<body>
  <div class="box">
    <div class="minibox">div>
  div>
body>

方式二:flex + margin

原理:传统的display: block BFC(块格式化上下文)下,margin: auto 在水平方向可以居中元素在垂直方向不行。要使单个元素使用 margin: auto 在垂直方向上能够居中元素,需要让该元素处于 FFC(flex formatting context),或者 GFC(grid formatting context) 上下文中

<style>
  * {
    margin: 0;
    padding: 0;
  }

  .box {
    display: flex;
    width: 800px;
    height: 500px;
    margin: 100px auto;
    border: 2px solid purple;
  }

  .minibox {
    margin: auto;
    width: 300px;
    height: 200px;
    background-color: purple;
  }
style>

<body>
  <div class="box">
    <div class="minibox">div>
  div>
body>

方式三:定位 + margin

<style>
  * {
    margin: 0;
    padding: 0;
  }

  .box {
    position: relative;
    width: 800px;
    height: 500px;
    margin: 100px auto;
    border: 2px solid purple;
  }

  .minibox {
    position: absolute;
    left: 50%;
    top: 50%;
    margin-left: -150px;
    margin-top: -100px;
    width: 300px;
    height: 200px;
    background-color: purple;
  }
style>

<body>
  <div class="box">
    <div class="minibox">div>
  div>
body>

方式四:定位 + translate

<style>
  * {
    margin: 0;
    padding: 0;
  }

  .box {
    position: relative;
    width: 800px;
    height: 500px;
    margin: 100px auto;
    border: 2px solid purple;
  }

  .minibox {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 300px;
    height: 200px;
    background-color: purple;
  }
style>

<body>
  <div class="box">
    <div class="minibox">div>
  div>
body>
4、盒子模型

盒子模型组成:

  • 内容
  • 内边距
  • 边框
  • 外边距

盒子模型分类:

  • 标准盒模型:默认就是 content-box,也就是标准盒模型,标准盒模型 width 设置了内容的宽,所以盒子实际的大小要加上 padding 和 border
  • ie盒模型/怪异盒模型/c3盒模型:通过设置 box-sizing: border-box; 的盒模型为ie盒模型,也称为怪异盒模型,设置了 width 后,实际盒子的宽度就固定为该宽度,包含了 内容+padding+border。ie盒模型主要表现在ie浏览器,当然其他浏览器也保留了ie盒模型的支持
5、css3 新特性

css3中新增的属性有(常用):

  • css3 盒子模型 box-sizing
  • Flex 布局
  • transition 过度
  • transform2D转换
  • background-size 背景图片尺寸缩放
  • border-radius 圆角
  • animation 动画
6、vw/vh/px/em/rem/vmin区别

px: 长度单位,是相对于显示器的屏幕分辨率而言的

em: 相对单位,基准点为父节点字体的大小

rem: 相对单位,可理解为”root em”,相对根节点html的字体大小来计算

vw: viewpoint width,视窗宽度,1vw等于浏览器窗口宽度的1%

vh: viewpoint height,视窗高度,1vh等于浏览器窗口高度的1%

vmin: vw和vh中较小的那个

vmax: vw和vh中较大的那个

7、绘制0.5px的线

方法一: 定位+缩放

<style>
  .box {
    position: relative;
  }

  .box::after {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 1px;
    background-color: red;
    transform: scale(1, 0.5);
  }
style>

 <body>
    <div class="box">div>
  body>

方式二: 线性渐变 linear-gradient,(会有分辨率问题导致显示不出来)

<style>
  .box {
    margin-top: 20px;
    height: 1px;
    background: linear-gradient(#f00 50%, transparent 50%);
  }
style>

<body>
  <div class="box">div>
body>
8、rem 适配原理

rem 是 相对长度单位。相对于根元素(即html元素)font-size 计算值的倍数的一个css单位

rem的移动适配原理:

在移动端的页面开发中,需要根据不同的手机去适配页面,让页面可以自适应的展示。
也就是说根据屏幕宽度的大小,改变元素和字体的大小,屏幕越宽元素和字体越大。
这个时候我们通常会用到rem作为单位,rem用作非根元素的时候,是相对于根元素设定的字体大小,用于根元素的时候,相对于初始字体的大小

9、移动端网页/移动端app/原生app/混合app/内嵌h5 是什么意思?

移动端app / 移动端网页: 都是需要用到网络的,它们利用设备商的浏览器(比如iPhone的safari)来运行,不需要在设备上下载后安装。

原生app: 是专门针对某一类移动设备而生的,它们都是被直接安装到设备里,而用户一般也是通过网络商店或者卖场来获取,开发起来不支持跨平台,每种平台得单独开发相同应用。

混合app / 内嵌h5: 就是介于 移动app原生app 之间的折中方案。在许多情况下,它能集两者之长,再通过中间件包装成一个可发布到应用商店的应用程序。

10、让Chrome支持小于12px 的文字方式有哪些?区别?

方式一:zoom

<style>
  p {
    font-size: 12px;
    zoom: 0.8;
  }
style>

方式二:transform: scale()

<style>
  p {
    font-size: 12px;
    transform-origin: left top;
    transform: scale(0.8);
  }
style>

两者区别:

  • 兼容性的差异:zoom为非标准属性,除firefox浏览器已在其他浏览器中得到了良好支持,scale已经是标准属性除IE8-外现代浏览器均能较好的支持
  • 缩放中心点差异:zoom缩放中心点为左上角,而scale默认为中心点但可以通过transform-origin进行改变
  • 重绘差异:zoom的缩放改变了元素占据空间的大小会引起整个页面的重排而scale缩放所占据的原始尺寸不变,只在当前元素进行重绘
  • 取值差异:zoom的合法值可以为数值、百分比以及normal而scale则只能为数值
11、移动端适配方案
  • rem

  • viewport(vw/vh)

  • 媒体查询

二、javascript 基础

1、js的数据类型,如何检测数据类型

数据类型分类:

基本数据类型:undefined - - (未定义)、null- - (空的)、number - - (数字)、boolean- - (布尔值)、string- - (字符串)、Symbol - - (符号)、BigInt- -(大数字);

引用数据类型(对象类型):Object- - (对象),比如:array - - (数组)、function - - (函数)、date - - (时间)等;

检测数据类型:

  • typeof 检测一些基本的数据类型

    let num = 1;
    console.log(typeof num); // number
    
  • instanceof 一般用来检测引用数据类型。注:undefined和null无法检测。

    let arr = [];
    console.log(arr instanceof Array); // true
    
  • constructor 用于检测引用数据类型。注:undefined和null没有constructor属性,无法判断。

    let arr = [];
    console.log(arr.constructor === Array); // true
    
  • Object.prototype.toString.call() 适用于所有类型的判断检测

    let arr = [];
    console.log(Object.prototype.toString.call(arr)); // [object Array]
    
2、为什么0.1+0.2 不等于0.3,以及如何解决

问题:

0.1 + 0.2 !== 0.3 这个属于JS运算中 精度 的缺失问题。这两个数的二进制都是无限循环的数。JavaScript使用Number类型表示数字(整数和浮点数),它的实现遵循IEEE754标准,在 IEEE754 标准中常见的浮点数数值表示有:单精准度(32位)和双精准度(64位),而JS采用的是双精度版本,也就是通过64位来表示一个数字;在二进制科学表示法中,双精度浮点数的小数部分最多只能保留52位,再加上前面的1,其实就是保留53位有效数字,剩余的舍去,遵从“0舍1入”的原则。根据这个原则,0.1和0.2的二进制数相加,再转化为十进制数就是:0.30000000000000004。

解决方法:

  • toFixed() 保留一位小数
  • 转换为正数计算
  • 第三方库:Math.js、big.js
3、作用域和作用域链

作用域: 作用域就是变量的可用性的代码范围,就叫做这个变量的作用域。简单理解,就是在这个范围内,变量是可以使用的,超过这个范围,变量就无法使用,这个范围就是作用域。

  • 全局作用域:顾名思义,全局作用域就是能够在全局使用,可以在代码的任何地方被调用。
  • 局部作用域:局部作用域只能作用于局部的代码片段,常见于函数内部,即函数内创建的变量,只能作用于函数内部,函数外部无法使用函数内部创建的变量。
  • 块级作用域:块级作用域是es6新增的,使用let关键字创建变量、const关键字创建常量(当然let、const也会有自己的语法规范,这里不过多展开),作用域只存在于{}花括号内。

作用域链: 当你要访问一个变量时,首先会在当前作用域下查找,如果当前作用域下没有查找到,则返回上一级作用域进行查找,直到找到全局作用域,这个查找过程形成的链条叫做作用域链。

4、var/let/const的区别

作用域:

  • let 和 **const **具有块级作用域,var 不存在块级作用域,可以跨块访问,不能跨函数访问
  • var 出来的变量是全局的,但是不能跨函数访问

变量提升:

变量能在声明之前使用,就是变量提升

  • var 存在变量提升,let 和 const 不存在变量提升

    console.log(num);
    var num = 10;
    // 转换为
    var num
    console.log(num);
    num = 10;
    

全局属性:

浏览器的全局对象是window

  • var 声明的变量为全局变量,并且会将该变量添加为全局对象的属性,但是 let 和 const 不会

**重复声明: **

  • var 声明变量时,可以重复声明变量,后声明的同名变量会覆盖之前声明的遍历。const 和 let 不允许重复声明变量。

  • var 声明的变量同名只会打印最后一次声明的值

  • let 和 const 同一个作用域下不能重名

暂时性死区:

  • 在使用 let、const 命令声明变量之前,该变量都是不可用的。这在语法上,称为 暂时性死区
  • 使用 var 声明的变量不存在暂时性死区。

初始值设置:

  • 在变量声明时,var 和 let 可以不用设置初始值。而const声明变量必须设置初始值。

指针指向:

  • let和const都是ES6新增的用于创建变量的语法。 let创建的变量是可以更改指针指向(可以重新赋值)。但const声明的变量是不允许改变指针的指向。

应用场景:

  • 在开发当中尽量使用 let 和 const 来声明

三、webAPI

1、Javascript本地存储的方式有哪些?区别及应用场景?

cookie:

  • 不超过4kb
  • 在过期时间之前一直有效,即使会话或者浏览器关闭
  • 会自动将数据传递到服务器,服务器也可以写cookie到客户端

localstorage:

  • 优点:

    • 存储大小可以达到5M
    • 只要不主动删除,数据永久储存
    • 不会将数据发送给服务器,仅在本地储存
    • 存储信息在同一域中是共享的,受同源策略的限制
  • 缺点:

    • 无法像 cookie一样设置过期时间

    • 只能存入字符串,无法直接 存入对象

sessionStorage:

  • 存储大小可以达到5M 页面关闭
  • sessionStorage将会删除数据 不会将数据发送给服务器
  • 仅在本地储存
  • sessionStorage也具有上述相同的属性和方法

注意:localstorage、sessionStorage存储对象或数组时,需要将其更换为JSON字符串,然后再进行存储。

indexDB(了解):

  • 优点:
    • 储存量理论上没有上限
    • 所有操作都是异步的,相比 LocalStorage 同步操作性能更高,尤其是数据量较大时
    • 原生支持储存JS的对象
    • 是个正经的数据库,意味着数据库能干的事它都能干
  • 缺点:
    • 操作非常繁琐
    • 本身有一定门槛

区别:

  • 存储大小:cookie数据大小不能超过4k,sessionStorage和localStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大
  • 有效时间:localStorage存储持久数据,浏览器关闭后数据不丢失除非主动删除数据; sessionStorage数据在当前浏览器窗口关闭后自动删除;cookie设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
  • 数据与服务器的交互方式:cookie的数据会自动的传递到服务器,服务器端也可以写cookie到客户端; sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存

应用场景:

  • 标记用户与跟踪用户行为的情况,推荐使用cookie
  • 适合长期保存在本地额度数据(令牌),推荐使用localstorage
  • 敏感账号一次性登录,推荐使用sessionStorage
  • 存储大量数据的情况、在线文档保存编辑历史的情况,使用indexDB
2、说说你对事件循环的理解

JavaScript 在设计之初便是单线程,即指程序运行时,只有一个线程存在,同一时间只能做一件事

为什么要这么设计,跟JavaScript的应用场景有关

JavaScript 初期作为一门浏览器脚本语言,通常用于操作 DOM ,如果是多线程,一个线程进行了删除 DOM ,另一个添加 DOM,此时浏览器将无法处理

为了解决单线程运行阻塞问题,JavaScript用到了计算机系统的一种运行机制,这种机制就叫做事件循环(Event Loop)

JavaScript中,所有的任务都可以分为:

  • 同步任务:立即执行的任务,同步任务一般会直接进入到主线程中执行
  • 异步任务(耗时任务):异步执行的任务,比如ajax网络请求,setTimeout定时函数等,这些任务会交给 宿主环境 来执行,将执行完成的回调函数交给主线程执行
3、说说你对BOM的理解,常见的BOM对象你了解哪些?

BOM (Browser Object Model,浏览器对象模型,提供了独立于内容与浏览器窗口进行交互的对象

其作用就是跟浏览器做一些交互效果,比如如何进行页面的后退,前进,刷新,浏览器的窗口发生变化,滚动条的滚动,以及获取客户的一些信息如:浏览器品牌版本,屏幕分辨率

常见BOM对象:

  • window:Bom的核心对象是window,它表示浏览器的一个实例
  • location:主要操作浏览器地址栏参数 URl
  • navigator:主要用来获取浏览器的属性,区分浏览器类型。属性较多,且兼容性比较复杂
  • screen:保存的纯粹是客户端能力信息,也就是浏览器窗口外面的客户端显示器的信息,比如像素宽度和像素高度
  • history:主要用来操作浏览器URL的历史记录,可以通过参数向前,向后,或者向指定URL跳转
4、说一下预解析

预解析:提前解析代码

**变量提升:**即将变量声明提升到它所在作用域的最开始的部分,会在代码执行之前将变量的声明提升

**函数提升:**函数声明式会在代码执行之前将函数的声明提升,不会提升调用。函数表达式可以理解为一个普通变量的提升,在js代码执行之前会把fun提升带最前面,在函数赋值之前,fun是undefined,如果调用fun(),将会报错。

5、能修改原数组的方法有哪些?
  • pop():删除数组最后一个元素,并返回该元素
  • push():在数组尾部添加元素,并返回更新后的数组长度
  • shift():删除数组的第一个元素,并返回该元素
  • unshift():在数组第一位添加元素,并返回更新后的数组长度
  • sort():对数组排序(按字符ASCII进行排序),也可添加回调函数按照想要的规则排序
  • reverse():数组反转
  • splice():返回被删除元素所组成的数组。
  • fill(): 填充数组
6、Set和Map的区别和作用?

Set和Map都是es6新增的 数据结构

Set:

  • Set 对象是一个类数组对象,它长得就很像数组。
  • Set 对象存储的值是不重复的,所以我们通常使用它来实现数组去重。
  • Set 对象存储的数据不是键值对的形式,而且它可以存储任何类型的数据。

Map:

  • Map 对象这种数据结构和和对象类似,都已键值对的形式存储数据,即 key-vlue 形式。
  • Map 对象存储的数据是有序的,而我们平常使用的对象是无序的,所以通常当我们需要使用对象形式(键值对)存储数据且需要有序时,采用 Map 对象进行存储。
  • Map 对象的键值可以是任意类型,我们平时使用的对象只能使用字符串作为键。

Map和Set区别:

  • Map和Set查找速度都非常快,时间复杂度为O(1),而数组查找的时间复杂度为O(n)。
  • Map对象初始化的值为一个二维数组,Set对象初始化的值为一维数组。
  • Map对象和Set对象都不允许键重复(可以将Set对象的键想象成值)。
  • Map对象的键是不能改的,但是值能改,Set对象只能通过迭代器来更改值。

作用:

  • Set: 数组去重
  • Map: 数字类型充当键、按照顺序存储对象、对象也可以作为键
7、forin/forof的区别

for of 用法:

// 遍历数组
const arr = [1, 2, 3, 4, 5, 6, 7];
for (const item of arr) {
  console.log(item);
}

// 遍历对象
const obj = {
  uname: "张三",
  age: 18,
};
const ks = Object.keys(obj)
for (const item of ks) {
  console.log(item);
}

区别:

  • 推荐在遍历对象的时候使用for in ,在遍历数组的时候使用for of 。
  • for in 循环出的是key(并且key的类型是string),for of 循环出的是value。
  • for of 是es6引新引入的特性,修复了es5引入的for in 的不足。
  • for of 不能循环普通的对象,需要通过Object.keys搭配使用。
8、中断循环的方式,如何中断forEach
  • for:break退出循环,continue 退出本次循环

  • forEach:用return、break、continue的方式都不能终止forEach循环,return在forEach里相当于for循环里的continue,能够退出本次循环,可以使用try...catch终止foreach循环

    例:

    try{
      var array = ["first","second","third","fourth"];
      // 执行到第3次,结束循环
      array.forEach(function(item,index) {
        if(item === "third"){
          throw new Error("EndIterative");
        }
    
        console.log(item); // first second
      });
    }catch(e){
      if(e.message != "EndIterative") throw e;
    }
    // 下面的代码不影响继续执行
    console.log("继续执行。。。");
    
  • map:终止map循环的方式和forEach相同

  • for in:break退出循环,continue 退出本次循环

  • for of:break退出循环,continue 退出本次循环

  • some:相当于或,只要有一个满足条件,就return true

  • every:相当于且,只要有一个不满足条件,就return false,只有都满足条件才会返回true

9、数组去重的实现方式有哪些?

方式一:利用 Set() + Array.from()

const arr = [1, 2, 3, 5, 3, 2, 5];
const res = Array.from(new Set(arr));
console.log(res);

**注意:**以上去方式对NaN和undefined类型去重也是有效的,是因为NaN和undefined都可以被存储在Set中, NaN之间被视为相同的值

方式二:利用两层循环 + 数组的splice方法,此方法对NaN是无法进行去重的,因为进行比较时NaN !== NaN

// 通过两层循环对数组元素进行逐一比较,然后通过splice方法来删除重复的元素。
function removeDuplicate(arr) {
  let len = arr.length;
  for (let i = 0; i < len; i++) {
    for (let j = i + 1; j < len; j++) {
      if (arr[i] === arr[j]) {
        arr.splice(j, 1);
        len--; // 减少循环次数提高性能
        j--; // 保证j的值自加后不变
      }
    }
  }
  return arr;
}

方式三:利用数组的 indexOf 方法,此方法也无法对NaN去重

// 新建一个空数组,遍历需要去重的数组,将数组元素存入新数组中,存放前判断数组中是否已经含有当前元素,没有则存入。
function removeDuplicate(arr) {
  const newArr = [];
  arr.forEach((item) => {
    if (newArr.indexOf(item) === -1) {
      newArr.push(item);
    }
  });
  return newArr; // 返回一个新数组
}

方式四:利用数组的 includes 方法,可以对 NaN 去重

// 原理和 方式三 一至
function removeDuplicate(arr) {
  const newArr = [];
  arr.forEach((item) => {
    if (!newArr.includes(item)) {
      newArr.push(item);
    }
  });
  return newArr;
}

// 注意:为什么includes能够检测到数组中包含NaN,其涉及到includes底层的实现。
const testArr = [1, 'a', NaN]
console.log(testArr.includes(NaN)) // true

方式五:利用数组的 filter() + indexOf(),此方法也无法对NaN去重

function removeDuplicate(arr) {
  return arr.filter((item, index) => {
    return arr.indexOf(item) === index;
  });
}

方式六:利用 Map(),可以对 NaN 去重

function removeDuplicate(arr) {
  const map = new Map();
  const newArr = [];
  arr.forEach((item) => {
    if (!map.has(item)) {
      // has()用于判断map是否包为item的属性值
      map.set(item, true); // 使用set()将item设置到map中,并设置其属性值为true
      newArr.push(item);
    }
  });
  return newArr;
}

**注意:**使用Map()也可对NaN去重,原因是Map进行判断时认为NaN是与NaN相等的,剩下所有其它的值是根据 === 运算符的结果判断是否相等。

方式七:利用对象,实现方式和 Map() 差不多

function removeDuplicate(arr) {
  const newArr = [];
  const obj = {};
  arr.forEach((item) => {
    if (!obj[item]) {
      newArr.push(item);
      obj[item] = true;
    }
  });

  return newArr;
}
10、如何判断后台返回的数据是一个空对象

方式一:将对象转换成字符串,再判断是否等于“{}”

let obj={};
console.log(JSON.stringify(obj)==="{}");

方式二:for in循环

let result = function (obj) {
  // 如果是空对象则不会执行循环
  for (let key in obj) {
    return false; //若不为空,可遍历,返回false
  }
  return true;
};
console.log(result({}));

方式三:Object.keys()方法,返回对象的属性名组成的一个数组,若长度为0,则为空对象(ES6的写法)

console.log(Object.keys(obj).length==0);

方式四:Object.getOwnPropertyNames() 方法获取对象的属性名,存到数组中,若长度为0,则为空对象

console.log(Object.getOwnPropertyNames(obj).length==0);

四、js 进阶

1、聊一聊闭包和垃圾回收机制

闭包概念:有权访问另一个函数作用域中变量的函数,闭包 = 内层函数 + 外层函数的变量

闭包作用: 延长变量作用范围

闭包的特性:

  • 函数嵌套函数
  • 函数内部可以引用函数外部的参数和变量
  • 参数和变量不会被垃圾回收机制回收

垃圾回收算法说明

所谓垃圾回收,核心思想就是如何判断内存是否已经不再会被使用了,如果是,就视为垃圾,释放掉

下面介绍两种常见的浏览器垃圾回收算法: 引用计数法标记清除法

引用计数

IE采用的引用计数算法, 定义“内存不再使用”的标准很简单,就是看一个对象是否有指向它的引用。

算法:

  • 跟踪记录每个值被引用的次数。
  • 如果这个值的被引用了一次,那么就记录次数1
  • 多次引用会累加。
  • 如果减少一个引用就减1。
  • 如果引用次数是0 ,则释放内存。

标记清除法

现代的浏览器已经不再使用引用计数算法了。

现代浏览器通用的大多是基于标记清除算法的某些改进算法,总体思想都是一致的。

核心:

  • 标记清除算法将“不再使用的对象”定义为“无法达到的对象”。

  • 就是从根部(在JS中就是全局对象)出发定时扫描内存中的对象。 凡是能从根部到达的对象,都是还需要使用的。

  • 那些无法由根部出发触及到的对象被标记为不再使用,稍后进行回收。

2、数组解构,对象解构如何实现

https://blog.csdn.net/xuanzhuan365/article/details/109481552

3、箭头函数有哪些特点?

箭头函数的特点:

  • 相比普通函数,箭头函数有更加简洁的语法。

  • 箭头函数不绑定this,会捕获其所在上下文的this,作为自己的this。

  • 箭头函数是匿名函数,不能作为构造函数,不可以使用new命令,否则后抛出错误。

  • 箭头函数不绑定arguments,可以使用剩余参数

  • 使用call,apply,bind并不会改变箭头函数中的this指向。

  • 箭头函数没有原型对象prototype这个属性

  • 不能使用yield关键字,不能用作Generator(生成器)函数

箭头函数的优点:

  • 简洁的语法
  • 只有一个参数可以省略小括号
  • 如果函数体只有一行代码,可以写到一行上,并且无需写 return 直接返回值
  • 箭头函数不会创建自己的this,它只会从自己的作用域链的上一层沿用this。
4、常用的数组方法,对象方法

数组方法:

一、 改变原数组的方法 (常用)

  • push : 尾部追加 (向数组的尾部添加一个或多个元素,返回值是数组的长度)
  • unshift : 头部添加 (向数组的头部添加一个或多个元素,并返回数组长度)
  • pop : 尾部删除 (删除数组最后一个元素)
  • shift : 头部删除 (删除数组第一个元素)
  • sort: : 排序 (对数组元素进行排序)
  • reverse : 反转 (将数组进行倒序)
  • splice :删除元素或者添加元素,如:splice(‘从哪里’,‘删几位’,‘添加的元素’)

二、其他数组方法(常用)

  • join : 分隔 (将数组的每一项通过自己指定的字符进行拼接、默认连接为 “,”)
  • map(): 该方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值、原数组不变
  • forEach(): 用于循环调用数组中的每个元素,并将元素传回给回调函数、原数组不变
  • every(): 对数组中每一项进行判断,若每一项都返回true、则返回true,有一个为false,则返回false,并停止遍历,原数组不变
  • some(): 对数组每一项进行判断,如果有一个元素满足条件,则返回true , 并停止遍历,如果没有满足条件的元素,则返回false,原数组不变
  • filter(): 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素、原数组不变
  • find(): 当数组中的元素在测试条件时返回 true 时, 返回符合条件的元素,之后的值不会再调用执行函数,如果没有符合条件的元素返回 undefined、原数组不变
  • findIndex(): 当数组中的元素返回 true 时, 该方法会返回符合条件的元素的索引位置,之后的值不会再调用执行函数,如果没有符合条件的元素返回 -1、原数组不变
  • slice() : 当有两个参数 如 slice(‘起始位置的下标’,‘到哪里结束’) 如果只有一个参数 返回的是从该指定位置到数组末尾的所有项,不改变原数组

对象方法(常用):

  • Object.keys():返回一个由一个给定对象的自身可枚举 属性 组成的数组
  • Object.create():创建一个新对象
  • Object.assign():进行对象浅拷贝
  • Object.values():返回一个由一个给定对象的自身可枚举 属性值 组成的数组
  • Object.defineProperty():劫持变量的set和get方法,将属性添加到对象,或修改现有属性的特性
5、构造函数/实例/原型对象三者之间的关系

构造函数:有 prototype 属性指向原型对象,可以通过 new 得到实例对象

原型对象:原型对象用来共享属性和方法,原型对象上有 constructor 属性指向构造函数

实例对象:通过 new 构造函数来得到实例对象,实例对象身上有 __proto__ 属性指向原型对象

6、说一说原型链?

原型链:就是实例对象和原型对象之间的链接,每一个对象都有原型,原型本身又是对象,原型又有原型,以此类推形成一个链式结构称为原型链。

原型链提供了对象属性和方法的查找规则,先查看自身有没有,如果没有会按照原型链向上查找

7、说一下继承的实现方式有哪些?

https://blog.csdn.net/wuliyouMaozhi/article/details/125905733

8、new的过程
  • 创建一个空对象
  • 将构造函数中的this指向这个空对象
  • 给对象中添加属性和方法
  • 返回这个对象
9、this的指向,call,apply,bind三者的区别和用法

相同点:

  • 都可以改变函数内部的this指向

区别点:

  • call 和 apply 会调用函数,并且改变函数内部this指向

  • call 和 apply 传递的参数不一样,call 传递参数 aru1, aru2… 形式 apply 必须数组形式[arg]

  • bind 不会调用函数,可以改变函数内部this指向

主要应用场景:

  • call 调用函数并且可以传递参数

  • apply 经常跟数组有关系,比如借助于数学对象实现数组最大值最小值

  • bind 不调用函数,但是还想改变this指向。比如改变定时器内部的this指向

10、深浅拷贝

**浅拷贝: ** 浅拷贝只会拷贝对象的第一层属性,如果这些属性是对象,则不会对这些对象进行拷贝,而是直接复制对象的引用。这意味着,对于浅拷贝后的对象,如果原对象的属性值发生了变化,浅拷贝后的对象的属性值也会跟着发生变化。

深拷贝: 在进行深拷贝时,会拷贝所有的属性,并且如果这些属性是对象,也会对这些对象进行深拷贝,直到最底层的基本数据类型为止。这意味着,对于深拷贝后的对象,即使原对象的属性值发生了变化,深拷贝后的对象的属性值也不会受到影响。

11、递归函数

一个函数在它的函数体内调用它自身称为递归调用,这种函数称为递归函数。执行递归函数将反复调用其自身,每调用一次就进入新的一层,当最内层的函数执行完毕后,再一层一层地由里到外退出。

12、节流防抖

所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间,短时间高频率触发只有最后一次触发成功

**开发使用场景: **搜索框防抖

所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数

开发使用场景:小米轮播图点击效果、鼠标移动、页面尺寸缩放 resize、滚动条滚动就可以加节流

13、用过哪些es6语法
  • 新增了块级作用域(let,const)

  • 提供了定义类的语法糖(class)

  • 新增了一种基本数据类型(Symbol)

  • 新增了变量的解构赋值

  • 函数参数允许设置默认值,引入了rest参数(剩余参数),新增了箭头函数。

  • 数组新增了一些API,如isArray / from / of 方法;数组实例新增了 entries(),keys() 和 values() 等方法。

  • 对象和数组新增了扩展运算符

  • ES6新增了模块化(import / export)

  • ES6新增了Set和Map数据结构。

  • ES6原生提供Proxy构造函数,用来生成Proxy实例

  • ES6新增了生成器(Generator)和遍历器(Iterator)

14、forEach和map的区别?some和every的区别?(数组循环方法通透)

foreach和map的区别:

相同点:

  • 都是循环遍历数组中的每一项。

  • 每次执行匿名函数都支持三个参数,参数分别为item(当前每一项),index(索引值),arr(原数组)。

  • 匿名函数中的this都是指向window。

  • 只能遍历数组。

不同点:

  • map()会分配内存空间存储新数组并返回,forEach()不会返回数据。

  • forEach()允许callback更改原始数组的元素。map()返回新的数组。

some和every的区别:

相同点:

  • some和every都有三个参数,item为当前项,index为当前项的索引值,arr为数组本身;

  • 都可循环遍历数组

不同点:

  • every相当于逻辑关系中的且(&&),只有所有参数满足条件的时候,才会返回true,如果有一个不满足,就会逻辑中断,返回false,

  • some相当于逻辑关系中的或(||),只要有一个参数满足条件,就会中断逻辑,返回true,遍历结束,没有找到合适的参数,就返回false

  • 通俗说:every就是找假,一假则假;some就是找真,一真则真

五、数据可视化

1、echarts的使用是否熟练

熟练使用

步骤:

  • 引入echarts.js文件
  • 在绘图前需要为 ECharts 准备一个定义了高宽的 DOM 容器
  • 通过 echarts.init 方法初始化一个 echarts 实例
  • 指定配置项和数据(option)
  • 将配置项设置给echarts实例对象
2、echarts有哪些常用的属性
  • 标题:title
  • 图例:legend
  • 网格:grid
  • x 轴:xAxis
  • y轴:yAxis
  • 提示框:tooltip
  • 图标类型设置:series
  • 默认色盘:color

六、Ajax

1、http状态码有哪些及分别代表什么意思?
  • 1xx:这一类型的状态码,代表请求已被接受,需要继续处理。这类响应是临时响应,只包含状态行和某些可选的响应头信息,并以空行结束。

  • 2xx:这一类型的状态码,代表请求已成功被服务器接收、理解、并接受。

    • 200 OK:服务器成功处理了请求(这个是我们见到最多的)
  • 3xx:这类状态码代表需要客户端采取进一步的操作才能完成请求。通常,这些状态码用来重定向,后续的请求地址(重定向目标)在本次响应的location域中指明。

    • 301 Moved Permanently:资源移动。所请求资源自动到新的URL,浏览器自动跳转到新的URL
    • 304 Not Modified:服务端的资源与客户端上一次请求的一致,不需要重新传输,客户端使用本地缓存的即可
  • 4xx:这类的状态码代表了客户端看起来可能发生了错误,妨碍了服务器的处理。

    • 400 Bad Request:用于告诉客户端它发送了一个错误的请求
    • 404 Not Found:(页面丢失)未找到资源
  • 5xx:这类状态码代表了服务器在处理请求的过程中有错误或者异常状态发生,也有可能是服务器意识到以当前的软硬件资源无法完成对请求的处理。

    • 500 Internal Server Error:服务器内部出现了错误
    • 501 Internal Server Error:服务器遇到一个错误,使其无法对请求提供服务
2、axios原理

axios是一个基于Promise的方法,可以发送get、post等请求,并且前后端都可以使用。

axios可以用在浏览器和 node.js 中是因为,它会自动判断当前环境是什么,如果是浏览器,就会基于XMLHttpRequests实现axios。如果是node.js环境,就会基于node内置核心模块http实现axios简单来说,axios的基本原理就是

  • axios还是属于 XMLHttpRequest, 因此需要实现一个ajax。或者基于http 。

  • 还需要一个promise对象来对结果进行处理。

3、async/await/promise/generator

promise:

  • promise是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果
  • 从语法上说,promise 是一个对象,从它可以获取异步操作的的最终状态(成功或失败)。
  • Promise是一个构造函数,这个回调函数中放的是异步的操作,对外提供统一的 API,自己身上有all、reject、resolve等方法,原型上有then、catch等方法。
  • 主要是用来解决异步问题以及回调地狱

async/await:

  • 异步终极解决方案,promise语法糖
  • async的用法,它作为一个关键字放到函数前面,这样普通函数就变为了异步函数;
  • 异步async函数调用,跟普通函数的使用方式一样
  • 异步async函数返回一个promise对象
  • async函数配合await关键字使用(阻塞代码往下执行)是异步方法,但是阻塞式的

generator:

  • ES6 新引入了 Generator 函数,可以通过 yield 关键字,把函数的执行流挂起,为改变执行流程提供了可能,从而为异步编程提供解决方案。
  • 调用 Generator 函数和调用普通函数一样,在函数名后面加上()即可,但是 Generator 函数不会像普通函数一样立即执行,而是返回一个指向内部状态对象的指针,所以要调用遍历器对象Iterator 的 next 方法,指针就会从函数头部或者上一次停下来的地方开始执行。
// 其中 * 用来表示函数为 Generator 函数,yield 用来定义函数内部的状态。
function* fn() {
  console.log("one");
  yield "1";
  console.log("two");
  yield "2";
  console.log("three");
  yield "3";
}
4、如何二次封装aioxs
import axios from 'axios'
import store from '@/store'
import router from '@/router'
// baseURL 超时时间配置
const instance = axios.create({
  // 设置请求的响应时间,超时直接结束
  timeout: 5000,
  // 设置请求的基本地址  
  baseURL: 'http://pcapi-xiaotuxian-front-devtest.itheima.net'
})

// 全局注入token
// 请求拦截器=》发请求前
instance.interceptors.request.use(config => {
  // 在请求头统一添加token
  const { token } = store.state.user.profile
  if (token) {
    config.headers.Authorization = `Bearer ${token}`
  }
  return config
}, e => Promise.reject(e))

// 处理返回数据 token失效跳回到登录页
// 响应拦截器=》成功请求
instance.interceptors.response.use(
  (response) => {
    // 请求200进入到这里
    // 把data数据返回给页面,剥离数据
    return response.data
  },
  (error) => {
    // 200以外进入
    // 处理401
    if (error?.response.status === 401) {
      /**
       * 1. 获取当前出现401的页面路径(目的:成功登陆之后,回到上次访问的页面)
       * 2. 跳回登录页带上401页面的地址
       */
      const redirectUrl = router.currentRoute.value.fullPath
      router.replace(`/login?redirectUrl=${redirectUrl}`)
    }
    return Promise.reject(error)
  }
)
5、axios请求拦截器和响应拦截器如何使用?

请求拦截器:

// use(两个参数)
axios.interceptors.request.use(req => {
  // 在发送请求前要做的事儿
  ...
  return req
}, err => {
  // 在请求错误时要做的事儿
  ...
  // 该返回的数据则是axios.catch(err)中接收的数据
  return Promise.reject(err)
})

响应拦截器:

// use(两个参数)
axios.interceptors.reponse.use(res => {
  // 请求成功对响应数据做处理
  ...
  // 该返回的数据则是axios.then(res)中接收的数据
  return res
}, err => {
  // 在请求错误时要做的事儿
  ...
  // 该返回的数据则是axios.catch(err)中接收的数据
  return Promise.reject(err)
})
6、聊一聊异步

Javascript语言的执行环境是"单线程"(一次只能完成一件任务。如果有多个任务,就必须排队,前面一个任务完成,再执行后面一个任务,以此类推)。

这种模式的好处是实现起来比较简单,执行环境相对单纯;坏处是只要有一个任务耗时很长,后面的任务都必须排队等着,会拖延整个程序的执行。常见的浏览器无响应(假死),往往就是因为某一段Javascript代码长时间运行(比如死循环),导致整个页面卡在这个地方,其他任务无法执行。这样设计本身是因为操作dom的需要。

为了解决这个问题,Javascript语言将任务的执行模式分成两种:同步和异步。

“同步模式" 就是上一段的模式,后一个任务等待前一个任务结束,然后再执行,程序的执行顺序与任务的排列顺序是一致的、同步的;"异步模式"则完全不同,每一个任务有一个或多个回调函数(callback),前一个任务结束后,不是执行后一个任务,而是执行回调函数,后一个任务则是不等前一个任务结束就执行,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。

“异步模式" 非常重要。在浏览器端,耗时很长的操作都应该异步执行,避免浏览器失去响应,最好的例子就是Ajax操作。在服务器端,"异步模式"甚至是唯一的模式,因为执行环境是单线程的,如果允许同步执行所有http请求,服务器性能会急剧下降,很快就会失去响应。

7、各个请求方式的区别
  • get 发送一个请求常用来获取服务器资源
  • post 向URL指定的资源提交数据或附加新的数据
  • put 跟POST方法很像,也是像服务器提交数据进行处理请求。但是,它们之间有不同。PUT指定了资源在服务器上的位置,而POST没有。一般用于修改资源
  • delete 请求服务器删除指定的资源

最常见的就是post与get方法,下面详细介绍一下二者的区别:

1、URL形式
get将表单中数据按照name=value的形式,添加到action 所指向的URL 后面,并且两者使用”?”连接,而各个变量之间使用”&”连接

post请求:post请求会把请求的数据放置在HTTP请求包的包体中,传递到action所指向URL。上面的item=bandsaw就是实际的传输数据。

因此,get请求的数据会暴露在地址栏中,而POST请求则不会。

get请求用来从服务器上获得资源,而post是用来向服务器提交数据;

2、传输数据的大小
在HTTP规范中,没有对URL的长度和传输的数据大小进行限制。但是在实际开发过程中,对于get,特定的浏览器和服务器对URL的长度有限制。因此,在使用get请求时,传输数据会受到URL长度的限制。

对于post,由于不是URL传值,理论上是不会受限制的,上传文件通常要使用post方式;但是实际上各个服务器会规定对POST提交数据大小进行限制,Apache、IIS都有各自的配置。

3、安全性
post的安全性比get的高。这里的安全是指真正的安全,而不同于上面get提到的安全方法中的安全,上面提到的安全仅仅是不修改服务器的数据。比如,在进行登录操作,通过get请求,用户名和密码都会暴露再URL上,因为登录页面有可能被浏览器缓存以及其他人查看浏览器的历史记录的原因,此时的用户名和密码就很容易被他人拿到了。除此之外,get请求提交的数据还可能会造成Cross-site request frogery攻击。

如果这些数据不是敏感数据,那么可以使用get;对于敏感数据还是应用使用post;

8、即时通信功能如何实现?客服聊天如何实现

即时通信:

WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信,即允许服务器主动发送信息给客户端。因此,在WebSocket中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输,客户端和服务器之间的数据交换变得更加简单。

9、传统api和restfulapi的区别

例:

传统模式:

api/getstate.aspx- 获取状态信息
api/updatestate.aspx - 更新状态信息
api/deletestate.aspx - 删除该状态的数据

RESTful模式:

api/state 只需要这一个接口

GET 方式请求 api/state- 获取该状态的数据
POST 方式请求 api/state- 更新该状态的数据

更多内容:https://worktile.com/kb/ask/22890.html

10、如何实现取消请求

axios官网:https://www.axios-http.cn/docs/cancellation

11、浏览器缓存

https://blog.csdn.net/jiang_ziY/article/details/123818243

12、如何进行接口联调?

https://www.shuzhiduo.com/A/q4zVbNvGzK/

13、http/https的区别
  • HTTPS 协议需要到 CA (Certificate Authority,证书颁发机构)申请证书,一般免费证书较少,因而需要一定费用。(以前的网易官网是http,而网易邮箱是 https 。)
  • HTTP 是超文本传输协议,信息是明文传输,HTTPS 则是具有安全性的 SSL 加密传输协议。
  • HTTP 和 HTTPS 使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
  • HTTP 的连接很简单,是无状态的。HTTPS 协议是由 SSL+HTTP 协议构建的可进行加密传输、身份认证的网络协议,比 HTTP 协议安全。(无状态的意思是其数据包的发送、传输和接收都是相互独立的。无连接的意思是指通信双方都不长久的维持对方的任何信息。)
14、开发时,如果接口还没提供该如何处理?

在开发的过程中,会遇到后端文档出来了但接口没出来,或者是联调的时候接口有问题,那么前端的调试就有困难了。这个时候需要进行 mock 数据(自己实现一些测试数据)

15、mockjs的简单使用

官网:http://mockjs.com/

const Mock = require("mockjs");
var Random = Mock.Random;
const res = Mock.mock({
  // 属性 list 的值是一个数组,其中含有 1 到 10 个元素
  "list|1-10": [
    {
      // 属性 id 是一个自增数,起始值为 1,每次增 1
      "id|+1": 1,
      "username": Random.cname(),
      "createTime": Random.date()
    },
  ],
});

console.log(res);
16、原生js如何实现发送请求

get请求:

//1、创建一个 xhr 的对象
let xhr = new XMLHttpRequest()
//2、调用xhr中的open()函数,创建一个Ajax的请求
xhr.open('GET', 'http://www.liulongbin.top:3006/api/getbooks')
//3、调用xhr的send函数,发起请求
xhr.send()
//4、监听 onreadystatechange 事件
xhr.onreadystatechange = function () {
  if (xhr.readyState === 4 && xhr.status === 200) {  //固定写法
    //数据获取成功,获取服务器响应的数据 
    console.log(xhr.responseText)
  }
}

Post请求:

//1、创建xhr的对象
let xhr = new XMLHttpRequest()
//2、调用open函数('请求类型','url')
xhr.open('POST', 'http://www.liulongbin.top:3006/api/addbook')
//3、设置 Content-Type属性(固定写法)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
//4、调用send函数
xhr.send('bookname=落日听风&author=我我我&publisher=个人出版社')
//5、监听事件
xhr.onreadystatechange = function () {
  if (xhr.readyState === 4 && xhr.status === 200) {
    console.log(xhr.responseText)
  }
}
17、为什么会跨域,以及解决方案

跨域: 出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议主机和端口号。

解决方案:

  • 反向代理服务器(服务器转发)
  • CORS(后端开启)
  • jsonp(几乎不用,只支持get请求)

七、git

1、git的常见命令
命令 说明
git init 初始化git仓库
git clone 克隆远程仓库项目
git config --list 查看git配置信息
git add 跟踪文件或将文件加入暂存区
git commit -m [message] 提交暂存区到仓库区
git branch 查看所有本地分支
git branch [branch-name] 创建新分支
git checkout -b [branch] 创建并切换分支
git merge [branch] 合并指定分支到当前分支
git push 向远程推送代码
git pull 拉取远程代码
git status 查看文件状态
git log 查看提交日志
2、你们公司的git的规范是怎么样的

http://jianshu.io/p/e1086dcd6b42

3、git分支规范

http://jianshu.io/p/e1086dcd6b42

4、git中merge和rebase的区别

相同点:

  • 两者都可以合并代码。

不同点:

  • 比如现在在某个子分支执行git rebase(merge) master操作。

  • merge:将在子分支的所有提交记录成一次commit,保留在记录中。

  • rebase:不会保留commit记录,直接将分支中的内容排到master的记录之后。

  • 最明显的特点就是rebase是一条直线,merge是很多条分支合并在一起。

https://blog.csdn.net/qq_48106051/article/details/127065222

5、企业代码管理

云效:云效,创立于2012年,是阿里巴巴旗下一站式研发提效产品。通过项目流程管理和专项提效自动化工具,真正实现24小时持续集成持续交付。

gitlab:GitLab是由GitLabInc.开发,使用MIT许可证的基于网络的Git仓库管理工具,且具有wiki和issue跟踪功能。使用Git作为代码管理工具,并在此基础上搭建起来的web服务。

6、git pull 和 git fetch

git fetch:是将远程主机的最新内容拉到本地,用户在检查了以后决定是否合并到工作本机分支中。
git pull: 则是将远程主机的最新内容拉下来后直接合并,即:git pull = git fetch + git merge,这样可能会产生冲突,需要手动解决。

八、node

1、 promise A+ 规范

https://zhuanlan.zhihu.com/p/414171010

2、宏任务和微任务

Javascript 把异步任务又做了进一步的划分,异步任务又分为两类,分别是:宏任务 和 微任务

执行顺序:每一个宏任务执行完之后,都会检查是否存在待执行的微任务,如果有,则执行完所有微任务之后,再继续执行下一个宏任务

分类

宏任务:

  • ajax请求
  • setTimeout、setInterval
  • 文件操作

微任务:

  • Promise.then()、.catch()、finally()
  • Process.nextTick
3、promise All 源码

Promise.all 方法

// 实现 Promise.all() 方法
const myAll = (arr) => {
  // 存放结果集,按照顺序存放
  const resArr = [];
  let i = 0;

  // 处理结果
  const result = (res, index, resolve) => {
    // index 记录传入数组中 promise 对象的位置
    resArr[index] = res;
    i++;
    if (i === arr.length) return resolve(resArr);
  };

  return new Promise((resolve, reject) => {
    if (!Array.isArray(arr)) return reject('参数必须是数组');
    arr.forEach((item, index) => {
      item.then(
        (res) => {
          // 拿到的只是结果,要等结果全部出现,才能 resolve
          // resArr.push(res);
          // if (resArr.length === arr.length) return resolve(resArr);
          // console.log(res)
          // resArr[index] = res;
          // console.log(resArr, index);
          // if (resArr.length === arr.length) return resolve(resArr);
          result(res, index, resolve);
        },
        (err) => {
          reject(err);
        }
      );
    });
  });
};

Promise.race 方法

// 实现 Promise.race() 方法
// Promise.race() 方法会发起并行的 Promise 异步操作,只要任何一个异步操作完成,就会立即执行下一步的 .then 操作(赛跑机制)
const myRace = (arr) => {
  return new Promise((resolve, reject) => {
    if (!Array.isArray(arr)) return reject('参数必须是数组');
    // 遍历arr, 看谁先满足条件, 谁先满足条件, 就先让外层的promise resolve
    // promise的状态只能被修改一次, 只要第一个改了, 就成功, 后续再改, 也无效了
    arr.forEach((item) => {
      item.then(
        (res) => {
          resolve(res);
        },
        (err) => {
          reject(err);
        }
      );
    });
  });
};
4、es6模块化和commonjs模块化的区别

语法上:

  • CommonJS 使用的是 module.exports = {} 导出一个模块对象,require(‘file_path’) 引入模块对象
  • ES6使用的是 export 导出指定数据, import 引入具体数据。

导出值类型:

  • CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用
  • CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。
  • ES6 Modules 的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。

加载时机:

  • CommonJS 模块是运行时加载,ES6 模块是编译时加载
  • 运行时加载:CommonJS 模块就是对象;即在输入时是先加载整个模块,生成一个对象,然后再从这个对象上面读取方法,这种加载称为“运行时加载”。
  • 编译时加载:ES6 模块不是对象,而是通过 export 命令显式指定输出的代码,import时采用静态命令的形式。即在import时可以指定加载某个输出值,而不是加载整个模块,这种加载称为“编译时加载”
5、模块化的作用

模块化是指解决一个复杂问题时自顶向下逐层把系统划分成若干模块的过程,有多种属性,分别反映其内部特性。

模块化的好处:

  • 模块间解耦,复用。
  • 可维护成本低:可分单元测试,方便单个模块功能调试、升级。
  • 生产效率高:灵活架构,焦点分离,多人协作互不干扰,方便模块间组合、分解。
6、webpack的作用

WebPack 是一个模块打包工具,你可以使用WebPack管理你的模块依赖,并编绎输出模块们所需的静态文件。它能够很好地管理、打包Web开发中所用到的HTML、JavaScript、CSS以及各种静态文件(图片、字体等),让开发过程更加高效。对于不同类型的资源,webpack有对应的模块加载器。webpack模块打包器会分析模块间的依赖关系,最后 生成了优化且合并后的静态资源。

7、webpack中babel、loader、plugin的区别

Babel: Babel是一个工具链,主要用于将ECMAScript 2015+版本的代码转换为向后兼容的JavaScript代码,使之可以运行在各种环境中

loader: loader可以让webpack能够处理那些非js文件(webpack自身只理解js、json,现webpack5可以处理图片资源了~)

plugin: 插件plugins可以用于执行范围更广的任务。插件的范围包括:从打包优化和压缩、一直到重新定义环境中的变量 【

你可能感兴趣的:(前端)