likes
comments
collection
share

2023-04,05面试集合,搞钱要紧

作者站长头像
站长
· 阅读数 15
 // 四月中旬公司裁员,我所在的项目组卡一下全部没了。来公司两年多,期间经历过多次调整,嘴上说已经说了不知道多少次要被裁员了。
    // 但是真到自己身上的时候还是有点难受.
    // 难受的点在这里,应该是周二的下午吧,hr通知说晚上领导请吃饭?我还在想去年就说要请我们项目组的吃饭,今天终于吃上了。嘿嘿
    // 重点在这,饭吃到一半,领导说项目已经卖掉了,
    // 哦豁
    // 公司现在也没有合适的项目安排,要裁员。瞬间碗里的肉不香了...
    // 好了,就这样吧.
    // 回家休息了大半个月,改了简历,看了几个面试题,感觉看不进去,刷了一遍v3的视频,简历评审什么的b站大把,有兴趣的可以去看看。
    // 51之后陆陆续续开始投简历,一开始是在boss上投的,基本都是已读...没有回复
    // 一个星期又过去了,有点慌
    // 5月10号,我把市面上招聘的app全部下载了智联,51,拉钩,boss然后逐一添加,修改简历。海投...
    // 投简历,面试,改简历,投简历,面试。大概两周吧拿了4家的offer,感觉今年的行情真的有点差,压价,大小周,单休,钱少事多...
    // 入职了现在这个离住处近的(15分钟),但是是单休,难受啊
    // 好了,要干活了. 下次再吹水吧

2023-04,05面试集合,搞钱要紧

1.css相关

1.HTML5、CSS3进行符合web标准的语义化开发

HTML5:

  • header, footer, nav, section, article, aside等语义化标签用于描述文档结构。
  • main元素用于表示文档的主要内容区域。
  • h1-h6标签用于表示标题,并且应按照层次结构使用。
  • p标签用于表示段落文本。
  • a标签用于表示超链接。
    • target常用属性: _blank: 在新的窗口或浏览器标签页中打开。
  • img标签用于表示图片,并且可以使用alt属性描述图片。

1.2 CSS3:

  • 1.2.1 bfc 块级格式上下文,也就独立渲染一块区域。也就是说BFC内部的元素和外部的元素不会相互影响。

    • 两个相邻Boxmargin会发生重叠;

    • 当父元素没有添加高度,父元素的高度需要被子元素撑开时,而子元素脱离文档流的时候(脱离文档流:子元素设置了浮动,子元素就会脱离文档流),此时父元素就会失去高度,也就是高度坍塌。

    • 如何解决高度坍塌?开启bfc来解决。如开启bfc?

      • 1.overflow:hidden 开启bfc。
      • 2.给父元素添加伪元素以解决 外边距重叠的问题。
      • :before和:after双伪类元素可以用于在元素前后插入内容,例如:清除浮动的技巧。
         3./* clearfix 这个样式可以同时解决高度塌陷和外边距重叠的问题,当你在遇到这个问题时,
            直接使用clearfix 这个类即可 */
            .clearfix::before,
            .clearfix::after{
              content: '';
              display: table;
              clear:both;
            }
      
  • 1.2.2 盒子模型

    • box-sizing属性可以定义元素的盒模型,标准盒子模型(box-sizing:content-box)和怪异盒模型/IE盒模型(box-sizing:border-box)两种模式。
  • display属性可以定义元素的显示方式,包括block、inline、inline-block等多种类型。

  • position属性可以定义元素的定位方式,包括static、relative、absolute、fixed等多种类型。

  • border-radius属性可以定义元素的圆角半径。

  • flex布局可以用于实现响应式布局,具有强大的伸缩性和对齐功能。

2.3.以下是几个常见的  CSS  面试题及其解答:

1.  什么是  CSS  盒子模型?

  • 答:CSS  盒子模型指元素占用空间的矩形区域,由内容区、内边距、边框和外边距组成。通常有两种盒子模型:W3C  标准盒子模型和  IE  盒子模型。
    • 标准盒模型中,元素的宽度和高度只包括内容区域,不包括边框和内边距.
    • IE 盒模型中,元素的宽度和高度包括内容区、内边距和边框。

2023-04,05面试集合,搞钱要紧

4.  请简述  CSS  动画的实现方式?

  • 答:CSS  动画的实现方式主要有两种:transition  和  animation。其中,transition  通过设置元素属性的变化,触发  CSS  过渡效果;animation  是通过设置指定的帧序列来触发  CSS  动画效果,其中可以设置变化的属性、过渡时间、缓动函数等参数。

5.  如何实现  CSS  Sprites(精灵图)?

  • 答:CSS  Sprites  是将多张图片拼合成一张大图,通过设置元素的  background-position  属性来显示需要的部分。这种技术可以减少  HTTP  请求,提高网站访问速度。可以使用工具将多张图片合成一张大图,然后通过  CSS  设置背景图和  background-position,来具体实现精灵图效果。

6.块状元素,内联元素 2023-04,05面试集合,搞钱要紧

1.3 响应式布局和移动端布局方式

3.1  什么是响应式设计?

  • 答:响应式设计(Responsive  Design)是指为了适应不同设备尺寸(如手机、平板、电脑)而设计的网站或应用程序。核心原则是使用弹性布局、媒体查询和可缩放的图片等技术,使得网站能够根据不同设备的尺寸和分辨率,自适应地调整布局、字体和图片等内容,提高用户体验和访问效果。

  • 响应式布局和移动端布局方式是为了适应不同设备上的屏幕尺寸、分辨率和设备方向而设计的。

  • 响应式布局:指通过使用CSS媒体查询和灵活的网格系统,使网站能够在不同屏幕尺寸和设备上自动调整和适应布局。通俗来说就是只需要开发一套代码,只需要一套代码使页面适应不同的屏幕。

  • 移动端布局:是一种专门针对移动设备设计的网页布局方式,通常采用单栏或双栏布局。相比于响应式布局,移动端布局更加关注用户体验和操作方式,并会根据设备特性进行优化。例如,移动端布局会采用大字体、简洁的设计风格、可点击的元素大小等,以提高移动设备上网站的易用性和可读性。移动端布局通常需要单独为移动设备设计不同的样式表,响应式布局则可以通过CSS媒体查询在一个样式表中实现。

@media screen and (max-width: 1059px){}

  • 响应式布局的主要特点是基于CSS媒体查询技术,根据浏览器窗口大小自适应调整页面布局。一般来说,响应式布局需要先确定设计的断点(breakpoint),即当浏览器宽度达到某个特定值时会对页面进行重新布局。(max-width: 1059px,)常见的断点包括768px(平板电脑)、992px(小型台式机)和1200px(大型台式机)。在每个断点处,可以设置不同的样式规则来优化页面布局,从而使得网站可以针对不同大小的设备提供最佳的浏览体验。响应式布局的经典案例包括:

  • 移动端布局方式主要包括两种:1)流式布局;2)viewport布局。

  1. 流式布局:流式布局是一种相对于浏览器宽度进行调整的移动端布局方式,主要特点是使用百分比来设置元素的宽度,并且在页面缩放时可以自动适应。优点是可以适应各种屏幕大小,但缺点是设计难度较大,需要考虑多种因素来确保页面正常显示。流式布局的经典案例包括:

    • @media screen and (max-width: 768px):这是一种基于CSS媒体查询的流式布局,它可以根据不同的屏幕尺寸调整样式规则,以实现响应式效果。
  2. viewport布局:viewport是浏览器中用于显示网页内容的区域,而viewport布局是指通过手动设置viewport的宽度和高度来适应移动设备的屏幕大小。这种布局方式可以通过设置meta标签来实现,其中包括width、initial-scale和maximum-scale等属性。

// CSS基础相关面试题
1.实现瀑布流

1.P元素和div元素,都是块元素,两者之间有什么区别呢?  
    - p标签通常包裹段落文本而且自带一定到margin属性,
    - div基本可以包裹任何标签元素,而且margin属性为0。
-----------
2.谈谈你对CSS盒子模型的理解?  
- box-sizing:border-box || content-box || inherit(页面将从父元素继承box-sizing的值)
    - 分为**标准盒子模型**(box-sizing:content-box)和怪异模式也称为IE模式(box-sizing:border-box)两种。
    - 区别在于怪异盒子模型的宽高包含了内容宽度+padding+border。标准盒子模型就是内容的宽高。
    -   标准盒模型中,元素的宽度和高度只包括内容区域,不包括边框和内边距.
    -   IE 盒模型中(怪异盒子模型),元素的宽度和高度包括内容区、内边距和边框。
    - 在怪异盒模型中,盒子width=盒子自身的content+padding+border。
    - 在怪异盒模型中,总宽/高=盒子(content宽高+padding+border)+margin。
-----------------
3.如何水平垂直居中一个页面元素?还有什么其他方式吗?  
    1.display: flex; justify-content: center; align-items: center; 
    2.绝对定位配合margin:auto;》父元素绝对定位配合+子元素相对定位,top,left,right,bottom:为0;margin:auto;
    3.绝对地位配合transform实现;》父元素绝对定位配合+子元素相对定位,top,left:为50%;transform: translate(-50%, -50%)。

-----------------
3.1# 请说一下左边固定宽度,右边自适应的布局方法?
    - 1.父元素相对定位,固定元素绝对定位absolute,右边元素添加margin-left为固定宽度。
    -2.父元素添加display:flex;触发弹性盒,flex-direction:row;从左边开始排列。
    -3.左边固定元素家浮动,右边自适应元素margin-left为固定宽度。

-----------------

4.清除浮动的方式有哪些?他们之间有哪些区别?  
    - 1.**使用空标签清除浮动clear:both。**
        - 不推荐,会增加很多空标签。添加一个空div,利用css提高的clear:both清除浮动,让父级div能 自动获取到高度。
    - 2.**父元素添加overflow:hidden**通过触发[BFC]方式,实现清除浮动。
    -3.**使用after伪元素清除浮动**
    -4.**使用before和after双伪元素清除浮动**  推荐使用
    -5**为父元素设置高度**,需要手动添加高度,如何后面的高度发生变化,还要再次修改高度,给后期的维护带来麻烦。
    
 ------------
5.重绘和回流有什么区别?
    - 定义:当JS对页面的节点进行操作时,就会产生回流或重绘。
    - 重绘:颜色等不影响布局改变的就是重绘。
    - 回流/也就是重排**:像水流一样,位置,大小改变就是回流(尺寸、布局、显示(display: none/block)改变。
        - 
    - **注意:回流一定会触发重绘,而重绘不一定会回流**
    
    #### 引起回流的因素:
        - DOM节点增加、删除
        - DOM节点位置变化
        - 元素的尺寸、边距、填充(文字、图片)、边框、宽高
        - DOM节点display显示与否,不包含visibility
        - 页面渲染初始化(第一次加载页面)
        - 浏览器窗口尺寸变化(resize)
        - 向浏览器请求某些样式信息(offset、scroll、client、width/height、getComputedStyle、currentStyle)
        - 除开以上几个因素以外只会引起重绘。

        dom操作之所以消耗性能,就是因为容易引起回流,所以在做dom操作优化的时候就是以减少回流次数为依据来进行优化的,之所以需要缓存、文档碎片就是为了减少回流次数
    
 ------------  
  
5.1说一下浏览器缓存?**合理利用缓存,可以提高页面的打开速度**
    - 当我们访问一个网站时,会加载各种资源,如 HTML文档、JS、CSS、图片等。浏览器会将一些不经常变的资源保存在本地,这样下次访问相同网站时,就直接从本地加载资源,并不通过请求服务器,这就是浏览器缓存。
    - 强缓存与协商缓存相结合的方案。
    - JS、CSS、图片等资源配置强缓存。
        - 如何判断缓存过期?看请求头里的max-age这个相对时间字段(单位秒)
    - 强缓存(也就是本地缓存):第一次访问页面,浏览器会根据服务器返回的 response Header 来判断是否对资源进行缓存,
    // 如果响应头中有 cache-control 或 expires 字段,代表该资源是强缓存。
  - 协商缓存:浏览器携带缓存标识向服务器发送请求,服务器根据缓存标识来决定该资源是否过期,一般用于html资源,验证版本是否更新。
  // -  看请求头里面: Cache-Control 的值为 no-cache (协商缓存)
    -   或者 Cache-Control: max-age=0
  
 ------------      
6.(你说你做过移动端开发,对响应式布局了解吗?)实现响应式布局有哪些方式?  
    - 百分比布局 (要换算,计算困难)
        - 通过百分比单位可以使得浏览器中的组件的宽和高随着浏览器的变化而变化,从而实现响应式的效果.
    - 媒体查询
    - rem响应式布局 
        - rem 是相对于 html 根元素的字体大小的单位.
    - vw、vh响应式布局: 
        - w 和 vh 分别相对的是视图窗口的宽度和视口窗的高度.
        - 100vw = 视图窗宽度 ,100vh = 100 视图窗高度.
        - 利用 vscode 的插件 px to vw 来实现单位的自动转换.
    - Flex弹性布局

    - 参考:https://juejin.cn/post/7172184062226858014

------------
7.有没有用过一些CSS框架?  
    - Bootstrap 
    - 参考 https://www.php.cn/faq/360172.html
8.当我在浏览器中输入URL,一直到页面显示,这个中间过程发生了哪些事情呢?(说的越具体越好  

    1、输入地址
    2、浏览器查找域名的 IP 地址  
    3、浏览器向 web 服务器发送一个 HTTP 请求
    4、服务器的永久重定向响应
    5、浏览器跟踪重定向地址
    6、服务器处理请求
    7、服务器返回一个 HTTP 响应 
    8、浏览器显示 HTML
    9、浏览器发送请求获取嵌入在 HTML 中的资源(如图片、音频、视频、CSS、JS等等)
    
    - 参考1: https://www.cnblogs.com/idenzel/p/6658691.html
    - 参考2: https://juejin.cn/post/7156507687713243172#comment

---------
9.说几条web前端的优化策略吧。
    - 见下文...

----------
10.data为什么是一个函数?
- 会组件可能被用来创建多个实例。
    - 1.是为了在重复创建实例的时候避免共享同一数据造成的数据污染。
    - 2.为了保证这个对象是独立的,如果可以保证对象是惟一的,也可以不写函数直接写对象。
    - 其实归根结底就是为了避免数据污染。

圣杯 & 双飞翼两者均为三栏布局的优化解决方案。

2023-04,05面试集合,搞钱要紧

// 方法1.
<div class="container">
  <div class="left-column"></div>
  <div class="middle-column"></div>
  <div class="right-column"></div>
</div>

.container {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: stretch;
}

.left-column {
  flex-basis: 200px;
  background-color: #ccc;
}

.middle-column {
  flex-basis: calc(100% - 400px);
  background-color: #eee;
}

.right-column {
  flex-basis: 200px;
  background-color: #ccc;
}
container是一个flex容器,flex-wrap属性设置为wrap以使其在需要时换行。justify-content属性设置为space-between以使三个栏目之间有一定的空隙。align-items属性设置为stretch以使三个栏目的高度相等。

// 左栏和右栏使用flex-basis属性设置宽度,中栏使用calc()函数计算宽度,即总宽度减去左栏和右栏的宽度。


// 方法2.
外层容器也就是ul设置display:flex,对项目也就是li设置flex:auto,代表 flex: 1 1 auto。
<style>
        * {
            list-style: none;
            border: 0; 
            padding: 0;
            margin: 0
        }
        ul {
            width: 500px; 
            height: 200px; 
            background: red; 
            display: flex; 
            margin: auto; 
            margin-top: 100px; 
            padding: 0 10px;
            align-items: center;
        }
        li {
            background: green; 
            height: 100px; 
            width: 500px; 
            display: inline-block; 
            margin: 2px;
            line-height: 100px;
            text-align: center;
       flex: auto
        }
 
</style>
// 0.实现三列布局还有很多种方法,比如用时下比较流行的Flex
// 1.常规:让左列left右列right分别左右浮动,然后给主列设置左右外边距margin-leftmargin-right,即可实现主列自适应。
2.圣杯布局:思路是把左列left 右列right 主列main分别浮动,然后用负外边距给左右两列进行定位;

<div class="container">
    <div class="main"></div>
    <div class="left"></div>
    <div class="right"></div>
</div>


 .container{
            padding-left: 120px;
            padding-right: 220px;
        }
        .main{
            float: left;
            width: 100%;
            height: 200px;
            background-color: #01549b;
        }
        .left{
            position: relative;
            left: -120px;
            float: left;
            height: 200px;
            width: 100px;
            margin-left: -100%;
            background-color: #bd4147;
        }
        .right{
            position: relative;
            right: -220px;
            float: left;
            height: 200px;
            width: 200px;
            margin-left: -200px;
            background-color: #419641;
        }
圣杯布局的优点:

-   主列率先加载
-   允许任何列是最高的
-   DOM结构简单

#### 双飞翼布局源自淘宝UED,
- // 第一步和圣杯布局一样,浮动三列,给左右两列设置负外边距;同样会覆盖主列main
// 双飞翼布局的做法是在主列main后面添加了一个宽度为100%div,再设置主列main的左右边距。


<div class="wrap">
    <div class="main"></div>
</div>
    <div class="left"></div>
    <div class="right"></div>

 .wrap{
            float: left;
            width: 100%;
        }
        .main{
            height: 200px;
            margin-left: 110px;
            margin-right: 210px;
            background-color: #01549b;
        }
        .left{
            float: left;
            height: 200px;
            width: 100px;
            margin-left: -100%;
            background-color: #bd4147;
        }
        .right{
            float: left;
            height: 200px;
            width: 200px;
            margin-left: -200px;
            background-color: #419641;
        }

    1. px、em、rem、rpx 用法 与 区别
// px[像素]相对长度单位。像素px是相对于显示器屏幕分辨率而言的。
// em是相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。

// rem是CSS3新增的一个相对单位(root em,根em),
- rem 是相对于 html 根元素的字体大小的单位
// 这个单位与em有什么区别呢?区别在于使用rem为元素设定字体大小时,仍然是相对大小,但相对的只是HTML根元素。
// 除了IE8及更早版本外,所有浏览器均已支持rem.

// rpx 是微信小程序解决自适应屏幕尺寸的尺寸单位。微信小程序规定屏幕的宽度为750rpx.
// 无论是在iPhone6上面还是其他机型上面都是750rpx的屏幕宽度,拿iPhone6来讲,屏幕宽度为375px,把它分为750rpx后, 1rpx = 0.5px。

// 微信小程序同时也支持rem尺寸单位, rem 规定屏幕的宽度为20rem, 所以 1rem = (750/20)rpx = 37.5 rpx

2. javascript相关

  • 1.js的数据类型:

    • 基本数据类型:string,number,布尔值,null(空),undefined(未定义),symobol,BigInt(是指安全存储、操作大整数)

      • ES6 中新增了一种 Symbol ,独一无二的值,可以用作对象属性的标识符,避免属性名冲突的问题。
      • NaN是一个特殊的number,与其他所有值都不相等,包括它自身。
    • 引用数据类型(对象类型):object(对象是个大类:包含数组,函数,正则,日期对象等)

      • 基本数据类型由于占据的空间大小固定且较小,会被存储在中。
      • 引用数据类型存储在当中,变量访问的其实是一个指针,指向存储对象的内存地址
  • 2.箭头函数和普通函数的区别?

    • 箭头函数:箭头函数不会创建自己的this,没有自己的this,只会从自己的作用域链的上一层继承this。.

      • 会捕获自己在定义时所处的外层执行环境的this,并继承这个this值。
      • 箭头函数中this的指向在它被定义的时候就已经确定了,之后永远不会改变。箭头函数继承而来的this指向永远不变
      • 箭头函数中的this永远指向定义时所处的全局执行环境中的this,即便这个函数是作为对象obj的方法调用,它的this依旧指向Window对象。
      • 箭头函数不能作为构造函数使用否则用new调用时会报错!
      • 箭头函数没有自己的arguments
      • 箭头函数没有原型prototype
    • 普通函数:作为对象的方法调用时,this指向它所属的对象。

  • 3.this指向问题:

    • 1.在全局作用域中
    • 在普通函数中:this取决于谁调用,谁调用我,this就指向谁,跟如何定义无关。
    • 箭头函数没有自己的this,箭头函数的this就是上下文中定义的this。
    • 事件绑定函数中的this,this -> 事件源。
    • 定时器中的this,因为定时器中采用回调函数作为处理函数,而回调函数的this->window。
    • 构造函数中的this,构造函数配合new使用, 而new关键字会将构造函数中的this指向实例化对象。
  • 4.call()/.apply()/.bind()无法改变箭头函数中this的指向.

    * 这三个函数用来动态修改函数执行时`this`的指向,但由于箭头函数的`this`定义时就已经确定且永远不会改变。
    * 所以使用这些方法永远也改变不了箭头函数`this`的指向,虽然这么做代码不会报错。
    
    • 构造函数的new都做了些什么?简单来说,分为四步:
      • ① JS内部首先会先生成一个对象;

      • ② 再把函数中的this指向该对象;

      • ③ 然后执行构造函数中的语句;

      • ④ 最终返回该对象实例。

  • 4.谈谈原型和原型链:

  • 原型是 JavaScript 中的一个重要概念,是一个对象,包含了共享属性和方法,可以被该对象的实例继承。每个对象都有一个内部属性 [[Prototype]],它指向该对象的原型。

  • 当访问某个对象的属性或方法时,如果该对象本身没有该属性或方法,JS 引擎会沿着 [[Prototype]] 链向上查找,直到找到该属性或方法为止。这种机制被称为原型链。

  • 每个构造函数都有一个 prototype 属性,它是一个对象,包含了该构造函数的实例所继承的共享属性和方法。在创建对象时,可以使用 new 关键字来创建该构造函数的实例。在创建实例时,JS 引擎会将该实例的 [[Prototype]] 属性指向构造函数的 prototype 属性。

  • 如果在构造函数的 prototype 对象上添加了某个属性或方法,那么该构造函数创建的所有实例都可以访问该属性或方法。如果在某个实例上添加了某个属性或方法,那么只有该实例自身可以访问该属性或方法,其他实例和构造函数的 prototype 对象上也无法访问。

  • 原型链的终点是 Object.prototype,它是 JS 中所有对象的原型。Object.prototype 上包含了一些常用的方法和属性,例如 toString()valueOf() 等。

    通过原型链机制,可以实现 JavaScript 中的继承。例如:

    javascript
    function Animal(name) {
    this.name = name;
    }

    Animal.prototype.sayName = function() {
    console.log('My name is ' + this.name);
    };

    function Dog(name, breed) {
    Animal.call(this, name);
    this.breed = breed;
    }

    Dog.prototype = Object.create(Animal.prototype);
    Dog.prototype.constructor = Dog;

    Dog.prototype.sayBreed = function() {
    console.log('My breed is ' + this.breed);
    };

    const dog = new Dog('Buddy', 'Labrador');
    dog.sayName(); // "My name is Buddy"
    dog.sayBreed(); // "My breed is Labrador"

  • 在上面的例子中,Animal 是一个构造函数,它的 prototype 属性包含了共享的 sayName 方法。Dog 是另一个构造函数,它通过 Object.create(Animal.prototype) 继承了 Animal.prototype 对象,并添加了自己的 sayBreed 方法。通过原型链机制,Dog 的实例可以访问 Animal.prototype 中定义的共享方法。
  • 5.js数组的方法:

// 1.#### 原数组不改变的方法:

join() `数组转字符串`
    //将数组用 - 符号连接起来
    let arr = [1,2,3,4,5];
    let str = arr.join('-');
    console.log(str)//str = 1-2-3-4-5;
----------
split()`字符转数组`
    // 过指定的分隔符,将[字符串分割成数组]。
    let str = wqz-ttj
    let arr = str.split('-');
    console.log(arr);// arr=['wqz','ttj'];
    
### 数组的拼接与截取(原数组不受影响)
concat() `把两个数组里的元素拼接成一个新的数组`
    // 返回值: 返回拼接后的新数组
    let arr1 = [1,2,3];
    let arr2 = [4,5,6];
    let arr = arr1.concat(arr2);//arr = [1,2,3,4,5,6];
    arr1.push(arr2);//arr1 = [1,2,3,[4,5,6]];
---------
slice()`截取`
    // - 传两个参数.arr.slice(start,end) ;从start下标开始截取,一直到end结束,不包括end。
    let arr = [0,1,2,3,4,5,6,7];
    let newArr = arr.slice(0,3)//newArr = [0,1,2];
    
    // -传一个参数.arr.slice(start) ;从start下标开始截取,一直到最后。
    let arr = [0,1,2,3,4,5,6,7];
    let newArr = arr.slice(2)//newArr = [2,3,4,5,6,7];
    
    // -不传参数.arr.slice( ) ;全部截取
    let arr = [0,1,2,3,4,5,6,7];
    let newArr = arr.slice()//newArr = [0,1,2,3,4,5,6,7];
----------


---------

// 2.#### 原数组改变的方法:

push()`数组的最后面,添加一个或者多个元素`
    `结构`: arr.push(值)  
    // 返回值:返回的是添加元素后数组的长度.

    ## 注意:

----------

pop()`删除数组最后一个元素`
    `结构`: arr.pop()  
    // 返回值:返回的是刚才删除的元素.
----------

unshift()`在数组的最前面添加一个或者是多个元素`
    `结构`: arr.unshift(值)  
    // 返回值: 返回的是添加元素后数组的长度
----------

shift()`删除数组最前面的一个元素`
    `结构`: arr.shift()  
    // 返回值: 返回的是刚才删除的元素.
----------

splice()`两个参数是删除/三个是替换`

`结构1:` arr.splice(start,deletedCount)         `作用: 纯删除 ` 
// 从start下标开始,删除几个

`结构2:` arr.splice(start,deletedCount,item)    `作用:替换 ` 
//`从start下标开始,删除几个,并在该位置添加item

`结构3:` arr.splice(start,0,item)               `作用:纯添加 `
`从start下标开始,删除0个,并在该位置添加item,start开始全部往后移动`


// ### 3.数组的翻转和排序(改变数组)

reverse() `翻转数组`
     `结构:`arr.reserse()
----------

sort()`排序`
    let arr = [1,3,5,2,4,23,122,34];
    //没有参数:时按照首字符的先后排序
    arr.sort()//arr=[1,122,2,23,3,34,4,5];
    //有参数
    arr.sort(function(a,b){
            return a-b;//从小到大排序
            return b-a;//从大到小排序
    })
----------

// 4.常用处理数据的方法

filter()`过滤,有返回值, 过滤出符合条件的元素`
    let arr = [1, 3, 5, 2, 4, 6];
    let res3 = arr.filter(function(item, index) {
      return item % 2 === 0;
    });
    console.log(res3);

----------
 find() `查找符合条件的项,并且返回第一项`

 findIndex() `查找符合条件的下标,并且返回第一项`
 
----------

 lastIndexOf()`查找元素最后一次在数组中出现的位置`

 indexOf() `查找符合条件的元素,找到就返回该元素,找不到就返回-1.`
 includes() `判断一个数组中是否包含某一个元素,并返回true 或者false`

----------
 some()`判断数组中有没有符合条件的项,有就返回true,一个都没有惨返回false`

----------

 every()`判断数组中的所有项是否的满足条件,全部满足才返回true,否则false`

---------

 reduce()
    - 1.`求和计算`
    -2.`扁平化数组,拼接数组`
    // - 如计算数组中每个元素出现的次数。

 ----------

Object.assign(pager, { count, pageIndex, pageSize });

----------
JSON.parse() `把JSON 格式的字符串转换为js 对象`
    // 如:
    const jsonString = '{"name": "Alice", "age": 18}';
    const obj = JSON.parse(jsonString);
    console.log(obj.name); // "Alice"
    console.log(obj.age); // 18

    // 可以接受一个可选的第二个参数,用于指定解析过程中的行为
    const jsonString = '{"name": "Alice", "age": 18}';
    const obj = JSON.parse(jsonString, (key, value) => {
        if (key === 'age') {
            return value + 1;
        }
        return value;
    });
    console.log(obj.name); // "Alice"
    console.log(obj.age); // 19

    // 注意JSON.parse() 只能解析符合 JSON 格式的字符串,否则会抛出异常。
    // - 例如,以下字符串中的属性名应该使用双引号而不是单引号:
    const jsonString = "{'name': 'Alice', 'age': 18}";
    JSON.parse(jsonString); // 抛出异常


---------
  JSON.stringify()  `把一个对象转换为 JSON 字符串`
    // 如:
    const obj = {
        name: 'Alice',
        age: 18
    };
    const jsonString = JSON.stringify(obj);
    console.log(jsonString); // '{"name":"Alice","age":18}'

    // 可以接受一个可选的第二个参数,用于指定转换过程中的行为.
        // 如:入一个数组,用于指定需要转换的属性
    const obj = {
        name: 'Alice',
        age: 18,
        gender: 'female'
    };
    const jsonString = JSON.stringify(obj, ['name', 'age']);
    console.log(jsonString); // '{"name":"Alice","age":18}'

    // 还可以传入一个函数,用于对要序列化的每个属性进行进一步处理:
    const obj = {
        name: 'Alice',
        age: 18,
        gender: 'female'
    };
    const jsonString = JSON.stringify(obj, (key, value) => {
        if (key === 'age') {
            return value + 1;
        }
        return value;
    });
    console.log(jsonString); // '{"name":"Alice","age":19,"gender":"female"}'

    // 注意JSON.stringify() 只能处理符合 JSON 格式的数据,否则会抛出异常。
    // - 另外,某些 JavaScript 数据类型(如 undefined 和 function)在转换为 JSON 字符串时会被忽略。

  • 6.深浅拷贝,理解,常用的有哪些,会有什么问题?

    • 浅拷贝:
    • object.assion()合并对象
    • 扩展运算符,
    • slice(0)截取 返回值:返回截取出来的字段,放到新的数组中,不改变原数组。
    • JSON.parse(JSON.stringify()) 深拷贝 JS 对象的方法
      • 原理是先将原始对象转换为 JSON 字符串,再将 JSON 字符串解析为新的 JavaScript 对象

      • 注意:缺陷

      • 它无法深拷贝函数、正则表达式等特殊类型的对象.

      • 如果原始对象中包含循环引用,该方法也会出错.

      const obj = {
          name: 'Alice',
          age: 18,
          hobbies: ['reading', 'music']
      };
      const newObj = JSON.parse(JSON.stringify(obj));
      newObj.age = 19;
      newObj.hobbies.push('swimming');
      console.log(obj.age); // 18
      console.log(obj.hobbies); // ['reading', 'music']
      console.log(newObj.age); // 19
      console.log(newObj.hobbies); // ['reading', 'music', 'swimming']
      
      
  • 7.js字符串的方法?

  • 8.防抖和节流

  • 节流:限制执行频率,有节奏的执行

  • 防抖:限制执行次数,多次密集触发只执行一次

    • 防抖(Debounce):指在一段时间内触发的多次事件只执行最后一次,以防止事件重复执行。
      • 例如,在输入框中连续输入时,前几次的输入并不需要实时处理,而只需要等在一定时间内不再输入时再执行一次即可。防抖的实现方式是使用  setTimeout  或者  setTimeOut  和  clearTimeout,通过一定的延迟等待实现选择最后一次执行。
    • 节流:指在指定时间间隔内只执行一次事件,以防止高频率重复执行。
      • 例如,在用户频繁触发页面滚动事件时,需要等待一定时间后才执行一次函数,以减少执行次数。节流的实现方式有两种:时间戳和定时器方式。
  • 2.浏览器从输入url到页面显示发生了什么事情?

  • 重绘回流?日常中的场景?

  • webpack了解吗?怎么做优化?大概说一下

  • 模块化开发和组件开发

    • 都可以将大型复杂的系统分解成更小、更简单的可重用部件,从而提高开发效率和维护性。

    • 个模块通常是指一组相关联的功能或资源,可以独立地进行开发和测试。模块化开发的一个典型案例是Node.js,它将应用程序拆分成多个模块,每个模块都有自己的作用域和依赖关系。这使得开发者可以更加轻松地管理代码库,减少了代码耦合度,并且可以更容易地测试和维护各个模块。

    • 组件开发是指将页面或应用程序拆分成多个可重用的组件,每个组件都具有明确定义的接口和功能。组件化开发的一个典型案例是React.js,它可以将UI界面拆分成多个组件,并将它们组合在一起来构建复杂的应用程序。这使得开发人员可以更加轻松地管理UI界面,增强了代码的可重用性,并且可以更容易地实现前端功能和交互。

    • 总之,模块化和组件化开发都是现代软件开发中不可或缺的技术,它们能够帮助开发人员更高效地开发和维护软件,减少了代码的复杂性和耦合度。

  • http和https的区别?常见状态码

    • HTTP和HTTPS都是常用的协议,用于客户端(如浏览器)与服务器之间的通信。HTTP代表“超文本传输协议”,而HTTPS代表“安全的超文本传输协议”。
    • HTTP是一种无状态协议,使用明文传输数据。
    • HTTPS通常用于传输敏感信息,加密通信。例如登录凭据、信用卡号码等.
HTTP是一种无状态协议,它使用明文传输数据。
这意味着HTTP请求和响应中的所有内容都以纯文本形式进行传输,因此可能会被攻击者窃听和篡改。HTTP通常用于传输非敏感信息,例如公共网站上的静态页面。

HTTPS通常用于传输敏感信息,加密通信。例如登录凭据、信用卡号码等。
HTTPS则提供了更高的安全性,它通过使用SSL或TLS加密机制来保护传输的数据,从而实现加密通信。 HTTPS可以保护数据在传输过程中不被黑客窃取或篡改,并且还能验证服务器的身份。


以下是一些关于HTTP和HTTPS的常见面试问题:

1.  HTTP和HTTPS有什么区别? 
答:HTTP是一个无状态协议,数据以明文形式传输,而HTTPS使用SSL/TLS加密机制将数据加密并保护其完整性和机密性。
1.  HTTPS是如何保证数据的安全性的? 答:HTTPS使用SSL/TLS协议来加密数据,同时还使用公钥和私钥来验证服务器的身份,并确保数据在传输过程中不被篡改。
1.  HTTPS比HTTP更安全,但它是否完全无懈可击? 答:虽然HTTPS可以大大提高安全性,但攻击者仍可能通过某些方式攻击HTTPS连接。例如,攻击者可能会使用伪造的数字证书来欺骗用户,或使用中间人攻击窃听和篡改HTTPS通信。
1.  HTTP/2是什么?它如何改进HTTP协议? 答:HTTP/2是一种新的HTTP协议版本,旨在提供更快的加载速度,减少延迟和增加安全性。它引入了多路复用、头部压缩和服务器推送等新功能,并支持加密通信。

HTTP是一种用于在网络上传输超文本和其他资源的应用层协议。它基于客户端-服务端架构,通过请求-响应模式进行通信。

HTTP协议定义了以下常见的请求方法:

1.  GET:获取一份资源,不会对服务器上的资源产生任何影响。
2.  POST:向服务器提交数据,可能导致服务器上的资源状态发生变化。
3.  PUT:将数据存储到服务器上指定的位置。
4.  DELETE:删除服务器上指定的资源。

HTTP协议还定义了许多状态码,用于表示服务器处理请求时的结果。以下是常见的状态码及其含义:

1.  200 OK:服务器成功处理了请求,并返回了所请求的数据。
1.  201 Created:请求已经被实现,而且有一个新的资源已经依据请求的需要而建立。
1.  204 No Content:服务器成功处理了请求,但没有返回任何内容。
1.  400 Bad Request:服务器无法理解请求的格式,客户端应该检查请求是否正确。
1.  401 Unauthorized:请求未授权,客户端应该提供身份验证信息。
1.  403 Forbidden:服务器拒绝执行请求,客户端没有访问权限。
1.  404 Not Found:服务器无法找到请求的资源,路径问题。
1.  500 Internal Server Error:服务器遇到了意外的情况,无法完成请求


41.说说JS中的数据类型  
42.JS中的 ==和===有什么区别?  
43.JS中的[深拷贝和浅拷贝]()**有什么区别?  
44.如果让你实现一个深拷贝,有什么思路?  
45.简述一下对原型,构造函数以及实例的理解  
46.什么是闭包?闭包解决了什么问题?闭包会导致什么问题呢?  
47.如何理解JS中的this关键词?  
48.之前有没有解决过跨域问题?在你们项目里。当时是怎么解决的?

浏览器缓存原理

2023-04,05面试集合,搞钱要紧 // 理解: 2023-04,05面试集合,搞钱要紧 // 协商缓存 2023-04,05面试集合,搞钱要紧

2023-04,05面试集合,搞钱要紧

3. vue2相关

说说对vue的理解?

vue是一套用于构建用户界面的**渐进式框架**,与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用。Vue 的核心库只关注视图层(viewmodel),不仅易于上手,还便于与第三方库或既有项目整合。
  • 1.v2的生命周期,并且可以做什么事情?

  • 2.路由 如何监听hash变化?

    • 1.hash路由:监听 url 中 hash 的变化,然后渲染不同的内容,这种路由不向服务器发送请求,不需要服务端的支持;
    • 2.history路由:1. 监听 url 中的路径变化,需要客户端和服务端共同的支持;
    • 利用H5的 history中新增的两个API pushState() 和 replaceState() 和一个事件onpopstate监听URL变化history模式。
    • hash 就是指 url 尾巴后的 # 号以及后面的字符,history没有底带#,外观上比hash 模好看些hash回车刷新会加载到地址栏对应的页面,history一般就是404掉了。hash 能兼容到IE8, history 只能兼容到 IE10;
  • hash 模式的优缺点:

    • 优点:浏览器兼容性较好,连 IE8 都支持
    • 缺点:路径在井号 # 的后面,比较丑
  • 总结一下 history 模式的优缺点:

    • 优点:路径比较正规,没有井号 #

    • 缺点:兼容性不如 hash,且需要服务端支持,否则一刷新页面就404了

    • history API 是 H5 提供的新特性,允许开发者直接更改前端路由,即更新浏览器 URL 地址而不重新发起请求2023-04,05面试集合,搞钱要紧

    • history 路由

      • 在 history 路由中,我们一定会使用window.history中的方法,常见的操作有:
    • back():后退到上一个路由;

    • forward():前进到下一个路由,如果有的话;

    • go(number):进入到任意一个路由,正数为前进,负数为后退;

    • pushState(obj, title, url):前进到指定的 URL,不刷新页面;

    • replaceState(obj, title, url):用 url 替换当前的路由,不刷新页面;

  • 注意:调用这几种方式时,都会只是修改了当前页面的 URL,页面的内容没有任何的变化。

  • 3.路由传参数

    • query
    • params 2023-04,05面试集合,搞钱要紧
  • 4.# vue中route和router有什么区别?

    • route
      • 通过 this.$route 访问的是当前路由,获取和当前路由有关的信息。只读属性。
    • this.$ router是 router 实例
      • 通过 this.router访问路由器,相当于获取了整个路由文件,在 router 访问路由器,相当于获取了整个路由文件,在router访问路由器,相当于获取了整个路由文件,在router.option.routes中,或查看到当前项目的整个路由结构 具有实例方法。如:this.$router.query.id
  • 5.vue2组件通信:

    • 常见可以分为三类:
      • 父子通信
        • 父传子:父组件先引用子组件,并且绑定需要传的数据(如:),子组件用 props:{ list:{type:Array, default:null}}接收使用
        • 子传父:子组件自定义事件,并且调用这个事件函数,this.$emit('事件函数名称',this.要传的数据)。在父组件中(引用子组件的时候要绑定,如:<child @add=“add” />)监听这个事件函数,vlaue值就是子组件给父组件的值。
// 父组件给子组件传值用:props
    ·在父组件中定义要传给子组件,调用子组件并且把 要传的值绑定在子组件上
    <child :list="list"/>
    ·在子组件中用props:{ list:{ type:Arraydefault:null }}接收,使用

// 子组件给父组件传值用:$emit
    // 在子组件中自定义一个事件
    <div @click="add"> < /div>
    methods:{
        add(){
           this.$emit('方法名',this.要传的值)
        }
    }
    // 在父组件中监听子组件的这个方法
    ·<child @add="add"/>
    methods:{
        add(value){
            console.log(value) // 子组件给父组件的值
        }
    }
  • 兄弟组件通信
  • 跨级组件通信
3-4.vue.js中组件之间是如何通信的?  
   - 父子组件  》父传子:用props接受,子传父:子组件触发事件函数this.$emit(‘key’,要传的数据)来传递。
   - 兄弟组件 》用eventbus来传,vuex
       -  1.创建一个eventbus.js文件
       -   2.传数据的组件用eventbus.$emit()
       -   3.接受数据的组件用eventbus.$on() 
   - 祖孙组件(跨多极组件)vuex或者是依赖注入的方式
       - 祖先组件中使用:provide(‘唯一的key’,要传递的值)
       - 子孙组件中:inject(‘key’)接收。

map和foreach的区别:

foreach(){}
arr.forEach(function(item,index,arr){
//里面的function是一个回调函数,
//item: 数组中的每一项;
//index:item 对应的下标索引值
//arr: 就是调用该方法的数组本身
})

该方法等同于for循环,没有返回值.

map(){}
//里面的function是一个回调函数,  
//item: 数组中的每一项;  
//index:item 对应的下标索引值  
//arr: 就是调用该方法的数组本身
有返回值,返回一个新数组,新数组的长度和原数组长度相等.
let arr = [1,32,54,6,543];
let res = arr.map(function(item,index,arr){
	return item*2;
})


计算数组中每个元素出现的次数
var names = ['Alice', 'Bob', 'Tiff', 'Bruce', 'Alice'];
var countedNames = names.reduce(function (allNames, name) {
    // console.log(allNames, '| ' + name);
    if (name in allNames) {
      allNames[name]++;
    } else {
      allNames[name] = 1;
    }
    return allNames;
}, {});
console.log(countedNames);

6.vue怎么检测数组变化的?说说了解

Vue  提供了一种名为“响应式”的机制,能够检测到数组中某个元素的变化,当某个数组元素发生变化时,Vue  会立即通知相关的组件进行更新.这些方法在使用的时候,会通知  Vue  数组的变化,并即时更新视图。
例如:
-  push() 尾部添加 返回新数组的长度
-  pop() 尾部删除 返回的是被删除的元素
-  shift() 头部删除
-  unshift()头部添加
-  splice() -- 增加 删除 修改;本质上是删除数组(从哪里开始的下标,删除的长度,要替换的值)

-  sort() 排序,返回排序后的数组。
-  reverse() 反转数组

如果我们使用了其它不被重写的数组方法,Vue  无法自动检测到数组的变化,会导致界面不刷新。可以使用  `Vue.set()`  或者  `this.$set()`  方法手动触发更新。

// this.$forceUpdate() // 手动触发更新
// Vue.set(this.items, this.items.length, 'qux')

理解:vue2是可以监听数组数据的变化的,但基本都是只能监听到数组方法对于数组的变化,也就是有没有改变原数组。(简单理解为数组的长度发生了变化并修改了原数组),不可以监听到数组某一元素内容的数据变化。在这种情况下才需要使用vue提供的set方法,而如果是说v-for对数组的监听的话应该就是diff算法的对比了,我个人是这么理解的。

  • 7.this.$nextTick()
    • 在我们开发项目的时候,总会碰到一些场景:当我们使用vue操作更新dom后,需要对新的dom做一些操作时,但是这个时候,我们往往会获取不到跟新后的DOM.因为这个时候,dom还没有重新渲染,所以我们就要使用vm.$nextTick方法。
// nextTick接受一个回调函数作为参数,它的作用将回调延迟到下次DOM跟新周期之后执行。
this.$nextTick(function(){
   //dom现在跟新了
   //可以获取新的dom数据,执行操作
   this.doSomeThing()
  })
综合题
  • 7.为什么要选择vue.js呢,它给你们解决了什么问题?
    • Vue.js  是一个轻量级的  MVVM  框架,相比其它框架具有以下几个优点:
    • 易上手:Vue.js  使用模板和组件的方式,让代码更加易懂易读。
    • 响应式数据绑定:Vue.js  提供了依赖追踪和异步队列更新机制,能够实时追踪数据变化,并及时更新视图。这带来的好处是,数据和视图之间可以更加解耦,代码可读性更高,开发效率更高。
    •  前端路由和动画:Vue.js  自带的  Vue  Router  和  Transition  组件,可以让前端路由和动画变得更加容易,同时也提高了代码的可维护性。
    •  组件化开发:Vue.js  是一款面向组件的框架。通过组合不同的组件,可以构建出复杂的  UI  界面。组件可以很容易地进行组合、嵌套和复用,极大地提升了代码的重用性和可维护性。
    •  需要大量复杂数据操作、可重用组件、动态路由或动画的应用。生态圈完善,社区活跃,能够大幅提高我们构建  Web  应用的开发效率。  
  • 8.数据改变,视图没有改变的情况有遇到吗?是为什么?怎么处理的?

3-1.为什么要选择vue.js呢,它给你们解决了什么问题? 
3-2.谈谈对vue生命周期的理解?  
    - 
3-3.v-if 和 v-show有什么区别?  
    -
3-4.vue.js中组件之间是如何通信的?  
    - 父子组件  》父传子:用props接受,子传父:子组件触发事件函数this.$emit(‘key’,要传的数据)来传递。
    - 兄弟组件 》用eventbus来传,vuex
        -  1.创建一个eventbus.js文件
        -   2.传数据的组件用eventbus.$emit()
        -   3.接受数据的组件用eventbus.$on() 
    - 祖孙组件(跨多极组件)vuex或者是依赖注入的方式
        - 祖先组件中使用:provide(‘唯一的key’,要传递的值)
        - 子孙组件中:inject(‘key’)接收。
    
    
    
3-5.vue中数据双向绑定原理了解吗?  
3-6.如果让你实现一个基本的双向数据绑定,那你是什么思路呢?  
3-7.MVVM和MVC有什么区别?  
3-8.有没有用过其他的JS框架?  
3-9.对前端代码的自动化测试有没有了解?有没有使用过前端代码自动测试框架呢?

4. vue3相关

- 在另外一个文档里面,后面整理之后补发

5.综合能力

1.你在项目中遇到过哪些大坑,那当时是怎么解决的?  
2.在你们团队中,你有没有一些突出的亮点可以在这分享一下  
3.那你提到前端工程实践,那项目中的package.json有什么作用?它里面都有哪些内容?  
6.对webpack比较熟是吧,那你对webpack的使用有哪些优化建议呢?

2023-04,05面试集合,搞钱要紧

5.1 常见web性能优化的方式?AAAa**

性能优化基本是我们开发都要面对的问题,但是怎么做合适?收益怎么样?都是我们要考虑的?
// 在单页面应用中,一个路由对应一个页面,如果不做处理,打包的时候会把所有的页面打包成一个文件,
// 当用户打开首页的时候就会一次性加载所有的资源,造成首页加载很慢,用户体验不好。

通用的方法:
1.路由懒加载(es中的箭头函数+import的方式),组件懒加载等(需要触发的组件,如弹窗组件)
2.引入骨架屏插件(移动端),提升用户体验
3.大数据列表:使用**虚拟滚动技术,加载可视化区域的内容,或滚动加载但是要注意节流的问题(单位时间内多次点击只是触发一次)
4.无需滚动加载:要注意外层盒子加上overflow:auto,一定要限定高度。
5.更多的情况下**图片优化**会带来很大的性能提升。

#### 图片优化如下:

-   1.使用 SVG 格式。webp等格式的图片(之前打包的时候发现好几张gif图片基本都是1m以上,png500多k),

-   2.配置image-webpack-loader,处理并压缩图片,基本可以压缩到1/4或者1/5左右。

-   3.图片列表使用七牛云提供的图片动态裁剪的功能。**按文档配置即可****移动端完全没必要加载原图**压缩图片可以更快的显示。

-   4.使用 Webpack 配合`compression-webpack-plugin`插件,在前端工程的打包阶段,对静态资源进行“预压缩”,从而移除服务器端的压缩时间。

-   5.缓存图片,将图片缓存在浏览器中可以减少页面加载时间。

-   6.CDN加速主要是加速静态资源,如网站上面上传的图片、媒体,以及引入的一些Js、css等文件。我们使用的是七牛云来存储讲台资源,

 -   使用cdn加速相当于你的图片资源不是放到你自己的服务器,而是放到七牛云的服务器上了,只是把你的域名解析到七牛云服务器上而已。

1.路由懒加载:把路由用import的方式引入

a) C onst home = ()=> import @/ views/index

2.组件懒加载 比如弹窗组件 通过条件触发的组件 触发操作之后再加载该组件 ****

3.移动端可以使用骨架屏 锁定白屏时间 提升用户体验 可以引入插件 V ue - skeletion - webpack - plugin****

4.长列表虚拟滚动加载 只是渲染可视区域的列表 引入插件配置 ****

a) 计算出total数据列表总高度 并且在触发滚动事件的时候根据滚动的位置不断更新开始位置start和end的位置 然后从列表数据中截取对应的元素 ****

5.长列表使用触底加载 ****

a) 第一次传 20 条数据 或者是其他 获取当前滚动时候位置 窗口的高度 整个网页的实际高度 设置一个加载的动画 如果当前滚动的位置 + 窗口的高度 + 距离底部的高度的时候就触发动画 增加的请求的数据量 ****

6.将小图转成base 64 格式的图片 减少http请求 ****

7.尽可能的使用字体图标,而非图片

8.图片懒加载 引入插件****

9.图片优化

  • 1.技能超市列表使用七牛云提供的图片动态裁剪的功能 按文档配置即可 移动端完全没必要加载原图 压缩图片可以更快的显示
  • 2.使用 SVG 格式。webp等格式的图片(打包的时候发现好几张gif图片基本都是1m以上,png500多k),
  • 3.配置image-webpack-loader,处理并压缩图片,基本可以压缩到1/4或者1/5左右。
  • 4.使用 Webpack 配合compression-webpack-plugin插件,在前端工程的打包阶段,对静态资源进行“预压缩”,从而移除服务器端的压缩时间。
  • 5.缓存图片,将图片缓存在浏览器中可以减少页面加载时间。
  • 6.CDN加速主要是加速静态资源,如网站上面上传的图片、媒体,以及引入的一些Js、css等文件。我们使用的是七牛云来存储讲台资源,
    • 相当于你的图片资源不是放到你自己的服务器,而是放到七牛云的服务器上了,只是把你的域名解析到七牛云服务器上而已。

5.2 前端该如何优化网站性能?

[前端该如何优化网站性能?](https://youle.zhipin.com/questions/acbd21d9744b1164tnZ62t20FVQ~.html)

前端性能优化大概分为七种  
1、减少请求数量  
1.1 图片处理:  
1-1 Base64:  
将图片的内容以 Base64 格式内嵌到 HTML 中,可以减少 http 请求数量,但是编码之后的大小比图片大了

 1-2 使用字体图标来代替图片  
1.2 避免使用空的 src 和 href  
1.3 不使用 css@import

2、减少资源大小
2.1 html 压缩
html 代码压缩就是压缩在文本文件中有意义,但是在 html 中不显示的字符,包括空格,制表符

2.2 css 压缩
css 压缩包括无效代码删除与 css 语义合并

2.3 js 压缩与混乱
js 压缩与混乱包括无效字符及注释的删除、代码语义的缩减和优化、降低代码的可读性、实现代码的保护

2.4 图片压缩
3、优化网络连接  
3-1 使用 CDN

CDN 是内容分发网络,它能够实时地根据网络流量和各个节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上,其目的是使用户可以就近的取得所需内容,解决网络拥挤的状况,提高网站的响应速度

3-2 使用 DNS 预解析

4、优化资源加载  
4.1 资源加载位置  
通过优化资源加载位置,更改资源加载时机,使尽可能快地展示出页面内容,尽可能快地使用功能可用  
1、css 文件放在 head 中,先外链,后本页  
2、js 文件放在 body 底部,先外连,后本页  
3、处理页面、处理页面布局的 js 文件放在 head 中,如 babel-polyfill.js 文件、flexible.js 文件  
4、body 中尽量不写 style 标签和 script 标签

5.3 前端seo优化

// 搜索引擎优化,也就是需要被收录的网站.`meta中的,description,keywords`,以及一些简单的[语义化标签].
// 总结下来大概就是`首页,商品详情页,分类页面,店铺页面,搜索页面`保证商品被搜索引擎收录就可以在google中搜索到自己网站的产品了。

// 第一个问题:## 如何让您的网站出现在谷歌的搜索引擎中(seo)?

// # 如何做到seo优化的?
#### 1.网站`title`的描述
    -1.如果是网站首页则描述该网站的内容,  
    -2.如果是商品详情页面则是针对该商品的描述,  
    -3.如果是分类页则是对所有分类的描述。
#### 2.在seo中,其实`meta`标签是很重要的一部分。填写:content="有关网站的关键词"。
#### 3.代码层面需要优化的事项:
    1,所有的img标签要加alt属性,产品列表要加产品列表索引.
    2,所有跳转到商品详情,店铺页面,分类页面,搜索页面都要是用a标签跳转,这样爬虫才能沿着链接爬取下一个链式页面.
    3,所有a标签要写完整的路径:例如: <a href="https://buydo.com/item/a18f4cf96bc041d4979ddca4c2fd1d78.html"></a>
    4,当在网站中输入错误的链接以及产品id,网站必须有正确的404,500页面以用来引导爬虫走完整个流程,而不是弹出错误的选项卡来告诉用户没有该商品之类的.
    
#### 第四步:`Last-Modified 和 If-Modified-Since`非常重要
所有页面都必须设置Last-Modified 和 If-Modified-Since标头,这个对于爬虫搜索的索引和检索索引页面的速度非常重要。



5.4 在工作中有用到webpack吗?如何配置的?大概说一下:

  1. entry:指定入口文件,可以是单个文件或多个文件。
  2. output:指定输出文件的路径和文件名,可以使用占位符来生成动态文件名。
  3. module:配置模块的加载方式,可以使用不同的loader来处理不同类型的文件,例如使用babel-loader来处理ES6代码,使用css-loader和style-loader来处理CSS文件。
  4. plugins:配置插件,可以用于优化代码、生成HTML文件、提取公共代码等。
  5. resolve:配置模块的解析方式,可以指定模块的搜索路径、别名等。
  6. devServer:配置开发服务器,可以实现自动刷新、热替换等功能。

在配置webpack时需要注意以下几点:

  1. 版本兼容性:不同版本的webpack可能存在差异,需要根据实际情况选择合适的版本。
  2. 文件路径:需要注意文件路径的正确性,避免出现文件找不到的情况。
  3. loader和plugin的顺序:需要按照正确的顺序配置loader和plugin,避免出现错误。

5.5 说一下浏览器事件循环机制(一定会问,会现场给题目做),node事件循环机制(可能会问)

  • 理解:
    • 在js代码执行时,会将对象存在堆(heap)中,在栈(stack)中存放一些基础类型变量和对象的指针。在执行方法时,会根据当前方法的执行上下文,来进行一个执行。对于普通函数就是正常的入栈出栈即可,涉及到异步任务的时候,js执行会将对应的任务放到事件队列中(微任务队列、宏任务队列)。

我们知道js是一门单线程非阻塞的脚本语言,在执行js代码时,只有一个主线程来处理所有任务。非阻塞是指当代码需要处理异步任务时,主线程会挂起(pending),当异步任务处理完毕,主线程根据一定的规则去执行回调。事实上,当任务执行完毕,js会将这个事件加入一个队列(事件队列)。被放入队列中的事件不会立刻执行其回调,而是当前执行栈中所有任务执行完毕后,主线程会去查找事件队列中是否有任务。 异步任务有两种类型,微任务和宏任务。不同类型的任务会被分配到不同的任务队列中。 执行栈中所有任务执行完毕后,主线程会去查找事件队列中是否有任务,如果存在,依次执行所有队列中的回调,只到为空。然后再去宏任务队列中取出一个事件,把对应的回调加入当前执行栈,当前执行栈中所有任务都执行完毕,检查微任务队列是否有事件。无限循环此过程,叫做事件循环。

### 什么是浏览器事件循环机制?

我们知道js是一门单线程非阻塞的脚本语言,意思是执行js代码时,只有一个主线程来处理所有任务。非阻塞是指当代码需要处理异步任务时,主线程会挂起(pending),当异步任务处理完毕,主线程根据一定的规则去执行回调。事实上,当任务执行完毕,js会将这个事件加入一个队列(事件队列)。被放入队列中的事件不会立刻执行其回调,而是当前执行栈中所有任务执行完毕后,主线程会去查找事件队列中是否有任务。  
异步任务有两种类型,微任务和宏任务。不同类型的任务会被分配到不同的任务队列中。  
执行栈中所有任务执行完毕后,主线程会去查找事件队列中是否有任务,如果存在,依次执行所有队列中的回调,只到为空。然后再去宏任务队列中取出一个事件,把对应的回调加入当前执行栈,当前执行栈中所有任务都执行完毕,检查微任务队列是否有事件。无线循环此过程,叫做事件循环。

2023-04,05面试集合,搞钱要紧

  • 微任务:queueMicrotask、Promise、MutationObserve等
  • 常见宏任务:ajax、setTimeout、setInterval、script(js整体代码)、IO操作、UI交互、postMessage等
故事件循环可以理解为是一个桥梁,连接着应用程序的js和系统调用之间的通道。其过程为:

1.  执行一个宏任务(一般为一段script),若没有可选的宏任务,就直接处理微任务。
1.  执行中遇到微任务,就将其添加到微任务的任务队列中。
1.  执行中遇到宏任务,就将其提交到宏任务队列中。
1.  执行完当前执行的宏任务后,去查询当前有无需要执行的微任务,有就执行
1.  检查渲染,若需要渲染,浏览器执行渲染任务
1.  渲染完毕后,Js线程会去执行下一个宏任务。。。(如此循环)

console.log("script start");

const promiseA = new Promise((resolve, reject) => {
  console.log("init promiseA");
  resolve("promiseA");
});

const promiseB = new Promise((resolve, reject) => {
  console.log("init promiseB");
  resolve("promiseB");
});

setTimeout(() => {
  console.log("setTimeout run");
  promiseB.then(res => {
    console.log("promiseB res :>> ", res);
  });
  console.log("setTimeout end");
}, 500);

promiseA.then(res => {
  console.log("promiseA res :>> ", res);
});

queueMicrotask(() => {
  console.log("queue Microtask run");
});

console.log("script end");

// script start
// init promiseA
// init promiseB
// script end
// promiseA res :>>  promiseA
// queue Microtask run
// setTimeout run
// setTimeout end
// promiseB res :>>  promiseB


微任务是指由  JavaScript  引擎自身发起的任务,比如  Promise  的回调函数、MutationObserver  的回调函数。会在当前任务完成后、下一个宏任务开始前执行。比如,在一个宏任务中,Promise  状态从等待变为完成(fulfilled)或拒绝(rejected)时,会将对应的回调函数放入一个微任务队列中,等待当前宏任务执行完毕后立即执行。

简单来说,当一个宏任务执行完毕后,会检查是否有微任务需要执行,如果有,就立即执行所有微任务,执行完毕后再执行下一个宏任务。

console.log('start');
setTimeout(() => {
    console.log('timeout');
}, 0);
Promise.resolve().then(() => {
    console.log('promise');
});
console.log('end');
// 运行上述代码,会先输出  "start"、"end",然后才会输出  "promise"、"timeout",
// 因为  Promise  的回调函数是微任务,比  setTimeout  回调的执行优先级更高,
// 会在当前宏任务执行完毕后立即执行,而  setTimeout  回调则是一个新的宏任务,需要放到任务队列中等待执行。


new Promise((resolve, reject) => {}),构造器函数中的代码是同步执行的。

Promise运行机制  
async/await 你用过吗?怎么用的,有返回对象吗?  
组件传值,父子组件兄弟组件BUSvuex运行机制,如何通过 vuex 实现登录验证?  
router和route区别  
路由传参,获取参数  
延时路由  
如何提高页面的加载性能  
跨域解决方式(jsonp,cros)你配置过没有  
created 生命周期不可以干什么事情

作用域链  
vue 实例化  
computed 和 watch 的区别?什么时候使用 computed 什么时候使用 watch  
vuex 怎么模块化  
了解 vue3.0 吗?  
数据拦截是发生在哪个生命周期的?什么情况下不会对属性数据拦截,要怎么解决?  
Es6 掌握的怎么样,项目中用过 promise 吗?
1. 为什么选择前端?  
2. 讲讲浏览器从输入网址到打开网页的整个过程,越细致越好。  
3. 说一说你理解的JS 事件循环机制  
4. es6都有哪些新内容?  
5. 你提到了map,讲讲和object有什么区别?  
6. 箭头函数和普通函数的区别?  
7. 跨域,相关的几个请求头的含义。  
8. 一个盒子从中间开始,碰到最左边的边界往右移动,碰到最右边的边界往左移动,如此循环,问怎么做?  
9. 你提到了requestAnimationFrame,讲讲和setInterval的区别?  
10. 用过canvas吗,如果要实现一个一笔一画写汉字的效果,应该怎么做?  

5.6. 闭包三连,部分面试题

闭包

2023-04,05面试集合,搞钱要紧


## 5.6. 闭包三连?、为什么会出现闭包?闭包有什么作用?
    - **闭包就是一个能够访问其他函数**是将函数内部和函数外部连接起来的一座桥梁**。
    - **创建闭包最常见方式,就是在一个函数内部创建另一个函数**内部变量的函数。**
 - 1.为什么会出现闭包?
     - **函数的作用域及其所有变量都会在函数执行结束后被销毁。
     但是,在创建了一个闭包以后,这个函数的作用域就会一直保存到闭包不存在为止**
     
- 2.闭包的缺点
**闭包长期占用内存,内存消耗很大,可能导致内存泄露**。
- 3.**闭包的作用:******
    **1.访问其他函数内部变量******
    **2.保护变量不被内存回收机制回收******
    **3.避免全局变量被污染 方便调用上下文的局部变量 加强封装性** **。**
    
-4.如何避免闭包引起内存泄漏?******
    **1,在退出函数之前,将不使用的局部变量全部删除。可以使变量赋值为null;******
    **2,避免变量的循环赋值和引用。******
    **利用Jquery释放自身指定的所有事件处理程序**
    
  ------------------
2.说一下让一个盒子垂直水平居中都有啥方法
3.原型链是啥 
4.promise 用过吧,可以说一下吗 
5.Es6 有接触过吧,怎么去重呢 
6.v-if 和 v-show 的区别是啥
7.数据双向绑定你是怎么理解的, 
8.可以介绍一下自己的项目中参与的模块吗?

9.说一下深浅拷贝,
#### 基本类型(保存在栈内存中)

#### 引用类型(保存在堆内存中,引用数据类型的变量是一个指向堆内存中中实际对象的引用,存在栈中)
- 浅拷贝:
    - 将对象p1赋值给p2,改变p2里面属性的值,p1里面对应的值也会被改变。
    - 因为赋值的时候,是直接拷贝对象栈里面的地址,p1和p2的地址相同,所以修改会将两个一起改变。
    将一个对象的所有属性拷贝到另一个对象,一个对象属性改变,另外一个也会改变。
    浅拷贝: 只能拷贝一层对象,或者一层数组。
    浅拷贝的问题: 当原始对象里面的属性值是***复杂数据类型***的时候,
    -  1.扩展运算符
    - 2.`Object.assign()`合并对象。
    
    //注意:slice() concat()一维数组时候深拷贝,多维数组时候浅拷贝。都会返回新的数组。
    - 3.**slice**截取
    - 4.**concat**合并数组
    
- 深拷贝:
    - **深拷贝开辟一个新的栈,两个对象属性完成相同,但是对应两个不同的地址。
    - 修改一个对象的属性,不会改变另一个对象的属性**。
        - 1.`for-in`对象的属性进行遍历,递归实现。
        - 2.JSON.parseJSON.stringify())。会忽略undefinedsymbol和函数。
        - 3.通过嵌套扩展运算符实现深复制
        
        
-----------
10.数组去重
    - 1.**利用Array.from(new Set(arr))去重**Set中的**元素是唯一的**。
        - const res1 = Array.from(new Set(arr));
    -2.**利用includes+forEach去重**用来判断一个数组是否包含一个指定的值,如果是返回 true,否则false
    -3.**利用双层for循环去重**
    - 4.**利用Array.filter和map对象数组去重 (性能较高)
    -5.# 利用数组的[indexOf方法],思路:新建一个空数组,遍历需要去重的数组,将数组元素存入新数组中,存放前判断数组中是否已经含有当前元素,没有则存入。

6.无感登录

2023-04,05面试集合,搞钱要紧

6.1说一下前端token的理解

前端token是一种用于身份验证和授权的令牌。
通常是通过用户使用用户名和密码进行登录后返回的。一旦用户被验证,服务器会生成一个token并将其发送回前端应用程序。
该token通常是一个长字符串,包含有关用户和他们的权限的信息。

前端应用程序通常将token存储在浏览器的本地存储或cookie中,以便在用户进行其他操作时进行验证和授权。
当用户进行受保护的操作时,前端应用程序会将token发送回服务器以进行验证和授权。

使用前端token可以提高应用程序的安全性和用户体验,因为它可以减少对服务器的请求次数并允许前端应用程序在没有网络连接的情况下继续访问受保护的资源。
此外,通过使用token,服务器可以轻松地管理用户和他们的权限,而无需在每个请求中重新验证用户身份。


**token认证的流程:** **
// 用户第一次登录服务端,服务器根据用户的私有信息,时间戳,签名算法,私钥 通过算法生成token并返回给客户端,
// 之后客户端请求只需要带上这个token即可,服务端只需对这个token进行解析,即可得知那个用户进行了操作。**

6.2权限

菜单权限,按钮权限,接口权限,数据权限四种

- 所谓数据权限,就是根据不同角色的登录用户,查看不同的列表数据。
- 若依的数据权限也是基于**角色**实现的。不同角色不同权限。

-1.### 菜单权限
设置了[导航守卫],每次路由发生变化的时候就会触发router.beforeEach的回调函数。
有token的时候,判断当前用户是否已拉取完user_info信息。根据roles权限生成可访问的路由表。
没有token的时候,判断在免登录白名单,直接进入。否则全部重定向到登录页。

- 3.### 接口权限:接口权限和前端的按钮权限一一对应。为的是防止用户绕过按钮直接请求后端接口获取数据。
- 4.### 数据权限

- 2.### 按钮权限:v-hasPermi="['system:menu:edit']"
- 5.###添加页面权限: v-if="checkPermi(['taxsource:merchant_edit:taxdetail'])"

7.写在最后

 //  以上基本都是面试的时候遇到了,有的是手写,有的是问答。都是面试完会随手记一下, 知识点比较混乱,将就着看吧
    // 现在入职的这家公司事情比较多,有空再慢慢梳理一下,很多都是工作中会遇到的。
    // 个人建议:能苟着就苟着,千万不要自己主动离职,因为你不知道下一家公司怎么样。就我个人而言现在行情是真的有点差,最好等公司裁,至少还有的赔偿金。
    // 宝子们顶住