北京某公司前端线上笔试加面试复盘

360 阅读31分钟

前言:小编最近一直专心于在打怪升级中,本次笔试和面试打算也做一次总结,直接上干货...

线上笔试部分:

1. 代码分析题 :

// 第一部分
for(var i = 0; i < 3; i++) {

    setTimeout(() => {
        console.log(i)
    }, 0 )
    
}

// 第二部分
for(let i = 0; i < 3; i++) {

    setTimeout(() => {
        console.log(i)
    }, 0 )
    
}

//变式:i变为++i、let、var省略呢?

2. 代码分析题:

function getType(...args) {

    console.log(typeof args)
    
}

getType(18)

3. 问答题:px、rem、em、vw、vh 的区别?

1.  px(像素):像素是最常见的单位,表示屏幕上的一个物理像素点。它是一个绝对单位,
    具有固定的大小,不随页面缩放而改变。使用px单位可以精确地控制元素的尺寸。
    
2.  rem(根元素字体尺寸):`rem`是相对单位,它相对于根元素(通常是`<html>`元素)
    的字体尺寸。如果根元素的字体大小为16px,那么1rem等于16px。当根元素的字体大小
    发生改变时,所有使用rem单位的元素尺寸会按比例调整。rem单位适合用于响应式设计,
    可以根据根元素的字体大小来自适应调整。
    
3.  em(父元素字体尺寸):`em`也是相对单位,它相对于父元素的字体尺寸。例如,如果
    父元素的字体大小为16px,那么1em等于16px。如果一个元素的字体大小设置为2em,那
    么它的字体大小将是父元素字体大小的两倍。em单位的计算是相对于父元素的字体大小,
    因此在嵌套结构中使用时,会累计计算。
    
4.  vw(视窗宽度的百分比):`vw`表示视窗(viewport)宽度的百分比。1vw等于视窗宽度
    的1%。例如,如果视窗宽度为1000px,那么1vw等于10px。vw单位适合用于创建响应式布
    局,可以根据视窗宽度自动调整元素的尺寸。
    
5.  vh(视窗高度的百分比):`vh`表示视窗高度的百分比。1vh等于视窗高度的1%。例如,
    如果视窗高度为800px,那么1vh等于8px。vh单位也适合用于创建响应式布局,可以根
    据视窗高度自动调整元素的尺寸。
    

4. 事件分发的整个阶段?

1.  捕获阶段(Capture Phase):

    -   事件从根节点(通常是`window`对象)向下传播,经过DOM树的层级结构。
    -   在每个层级的节点上,会触发捕获阶段的事件处理程序(如果有)。

2.  目标阶段(Target Phase):

    -   事件达到目标节点,即实际触发事件的节点。
    -   在目标节点上,会触发事件的处理程序。

3.  冒泡阶段(Bubble Phase):

    -   事件从目标节点开始向上传播,经过DOM树的层级结构。
    -   在每个层级的节点上,会触发冒泡阶段的事件处理程序(如果有)。

5. get、post 的区别?

1.  数据传输方式:

    -   GET:通过URL的查询参数传输数据,将数据附加在URL的末尾,以键值对的形式进行
        传输。例如:`https://example.com/api?param1=value1&param2=value2`
        
    -   POST:通过请求的主体(Body)传输数据,将数据作为请求的一部分发送。数据
        不会直接暴露在URL中。

2.  数据长度限制:

    -   GET:由于数据通过URL传输,对URL长度有限制,不同浏览器和服务器对URL长度
        的限制可能不同,一般限制在几千个字符。
        
    -   POST:对数据长度没有特定限制,但服务器和网络设备可能有自己的限制。

3.  数据安全性:

    -   GET:数据暴露在URL中,可以被缓存、浏览器历史记录等保存下来,安全性
        较低。适合传输非敏感数据。
        
    -   POST:数据不会暴露在URL中,相对安全,适合传输敏感数据,如密码、用户信息等。

4.  请求语义:

    -   GET:用于获取数据,请求具有幂等性,即对同一个URL多次GET请求的结
        果应该是相同的,对服务器没有副作用。
        
    -   POST:用于提交数据,可能会对服务器产生副作用,如创建、修改或删除资源。

5.  缓存:

    -   GET:请求可以被浏览器缓存,下次请求相同URL时,可以直接从缓存中获取响应。
    
    -   POST:请求不会被浏览器缓存。

    总结来说,GET适合用于获取数据、幂等操作,传输非敏感数据,而POST适合用于提交数据、
    有副作用的操作,传输敏感数据。在实际应用中,根据具体需求和场景选择合适的请求方法。

6. 常见的块级元素和内联元素有哪些? 有什么区别?

常见的块级元素和内联元素如下:

块级元素:

-   `<div>`
-   `<p>`(这个是块级元素,小编总是当成行内元素了...)
-   `<h1>`-`<h6>`
-   `<ul>`
-   `<ol>`
-   `<li>`
-   `<table>`
-   `<form>`
-   `<header>`
-   `<footer>`
-   `<section>`
-   `<article>`

内联元素:

-   `<span>`
-   `<a>`
-   `<strong>`
-   `<em>`
-   `<img>`
-   `<input>`
-   `<label>`
-   `<button>`
-   `<select>`
-   `<textarea>`
-   `<i>`
-   `<code>`

区别总结如下:

1.  显示方式:

    -   块级元素:默认情况下,块级元素会独占一行,即宽度自动填满父容器。块级元素可以
        设置宽度、高度、内外边距等属性。
        
    -   内联元素:内联元素在一行内显示,宽度由内容决定,不能设置宽度、高度和上下内外
        边距,水平方向上的内外边距和边框会影响元素所占的空间。

1.  嵌套规则:

    -   块级元素:可以包含其他块级元素和内联元素。
    
    -   内联元素:不能包含块级元素,只能包含其他内联元素或文本。

1.  默认样式:

    -   块级元素:块级元素会独占一行,通常具有明显的外边距(上下空间),如`<p>``<h1>`等。
    
    -   内联元素:内联元素会在同一行内显示,没有明显的外边距,如`<span>``<a>`等。

1.  CSS布局:

    -   块级元素:块级元素可以通过CSS属性进行布局控制,可以设置宽度、高度、浮动等属性。
    
    -   内联元素:内联元素的布局受限,不能设置宽度、高度和浮动等属性。

    需要注意的是,通过CSS`display`属性可以修改元素的显示方式,使块级元素表现为内联
    元素,或将内联元素转换为块级元素。

7. 你对盒子模型的理解?

盒子模型是CSS中用于描述和布局元素的一个概念。它将每个元素看作是一个矩形的盒子,
这个盒子包含内容、内边距(padding)、边框(border)和外边距(margin)四个部分,
这些部分组成了元素的可视化框架。

盒子模型的组成部分如下:

1.  内容区(Content):盒子内部用来显示实际内容的区域,例如文本、图像等。它的
    大小由内容的宽度和高度决定。
    
2.  内边距(Padding):内容区与边框之间的空白区域,用于控制内容与边框之间的间距。
    内边距的大小由`padding-top``padding-right``padding-bottom``padding-left`
    属性来定义。
    
3.  边框(Border):包围内容和内边距的线条或规则,用于界定盒子的边界。边框的样式、
    宽度和颜色由`border-style``border-width``border-color`属性来定义。
    
4.  外边距(Margin):边框与相邻元素之间的空白区域,用于控制盒子与其他元素之间
    的间距。外边距的大小由`margin-top``margin-right``margin-bottom``margin-left`属性来定义。
    
在CSS中,`有两种常见的盒子模型``标准盒子模型(content-box)``IE盒子模型(border-box)`1.  标准盒子模型(content-box):

    -   在标准盒子模型中,元素的宽度和高度仅包括内容区域(content)的大小。
    -   内容区域的宽度和高度通过设置`width``height`属性来定义。
    -   内边距(padding)、边框(border)和外边距(margin)都会增加元素的实际尺寸。

1.  IE盒子模型(border-box):

    -   在IE盒子模型中,元素的宽度和高度包括了内容区域(content)、内边距(padding)和边框(border)的大小。
    -   内容区域的宽度和高度通过设置`width``height`属性来定义,但这些属性值包括了内边距和边框的尺寸。
    -   外边距(margin)不会增加元素的实际尺寸,仍然是从元素的边界开始计算。

可以通过CSS`box-sizing`属性来指定使用哪种盒子模型,默认值是`content-box`/* 使用标准盒子模型 */
.box {
  box-sizing: content-box;
}

/* 使用IE盒子模型 */
.box {
  box-sizing: border-box;
}

8.如何让一个元素水平竖直居中?

// 1.使用 Flexbox 布局:
    .container {
      width: 100%;
      height: 100%;
      display: flex;
      justify-content: center; /* 水平居中 */
      align-items: center; /* 垂直居中 */
    }
   
 // 2.使用绝对定位和负边距:
     .container {
      position: relative;
    }
    .element {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%); /* 平移自身的一半尺寸 */
    }
    
 // 3.使用绝对定位和自动边距(适用于已知宽高的元素):
     .container {
      position: relative;
    }
    .element {
      position: absolute;
      top: 0;
      bottom: 0;
      left: 0;
      right: 0;
      margin: auto;
    }
    
  // 4.使用表格布局:
      .container {
      display: table;
      width: 100%;
      height: 100%;
    }
    .element {
      display: table-cell;
      text-align: center; /* 水平居中 */
      vertical-align: middle; /* 垂直居中 */
    }

9. 代码题:

data:[
    {name : 'zs', age : 18},
    {name : 'ls', age : 19},
    {name : 'ww', age : 18},
    {name : 'zl', age : 19}
]
//要求: 移除数据中age为19的项(思路:过滤器)

function solutiuon(data) {

    data = data.filter( (item) => {
        return item.age !== 19
    })
    
    return data
}

10. 代码题:写一个选择排序

function selectionSort(arr) {
  const len = arr.length;
  
  for (let i = 0; i < len - 1; i++) {
    let minIndex = i;
    
    // 寻找未排序部分的最小值的索引
    for (let j = i + 1; j < len; j++) {
      if (arr[j] < arr[minIndex]) {
        minIndex = j;
      }
    }
    
    // 将最小值交换到已排序部分的末尾
    if (minIndex !== i) {
      [arr[i], arr[minIndex]] = [arr[minIndex], arr[i]];
    }
  }
  
  return arr;
}

// 示例用法
const array = [64, 25, 12, 22, 11];
console.log(selectionSort(array));  // [11, 12, 22, 25, 64]

线上面试部分(第一轮技术面试):

1. 纯CSS如何实现无线旋转?(小编当时只想到了transform:rotate();说的是结合js可以实现,但是面试官追问我能不能使用纯CSS实现,我说我不会,紧接着他下面就问我动画的实现,面试完才恍然大悟,也就是可以结合动画实现啊...)

<div class="box"></div>

.box {
  width: 100px;
  height: 100px;
  background-color: red;
  animation: spin 3s linear infinite;
}

@keyframes spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

2.请你说说CSS动画

CSS动画是一种通过CSS属性和关键帧来创建动态效果的技术。它可以用于网页中的元素,
使其在特定时间内发生平滑的变化,产生各种视觉上的动态效果。CSS动画通常使用`@keyframes`
规则和`animation`属性来定义和控制动画效果。

以下是CSS动画的基本概念和使用方法:

1.  `@keyframes`规则:`@keyframes`规则用于定义动画的关键帧。它可以指定动画在不同时间点上的样式状态。关键帧由百分比(0%到100%)或关键字(如`from``to`)表示。

    例如:
    @keyframes myAnimation {
      0% {
        /* 初始状态 */
      }
      50% {
        /* 中间状态 */
      }
      100% {
        /* 结束状态 */
      }
    }
    
2.`animation`属性:`animation`属性用于将动画应用于元素。它可以指定动画的名称、
 持续时间、动画曲线、延迟时间、重复次数等。

    例如:
    .myElement {
      animation-name: myAnimation;
      animation-duration: 2s;
      animation-timing-function: ease-in-out;
      animation-delay: 1s;
      animation-iteration-count: infinite;
    }
上述代码将应用名为`myAnimation`的动画到`.myElement`元素上,动画持续时间为2秒,
使用了缓入缓出的动画曲线,延迟1秒后开始播放,无限循环播放。    

3. 动画属性缩写:`animation`属性还有一个缩写形式,可以将多个动画属性合并到一个声明中。
    
    例如:
    .myElement {
      animation: myAnimation 2s ease-in-out 1s infinite;
    }
 上述代码与前面的示例相同,将所有的动画属性合并到了一个声明中。
 
通过使用`@keyframes`规则和`animation`属性,可以创建各种类型的动画效果,
如渐变、旋转、平移、缩放、淡入淡出等。可以通过调整关键帧的样式状态、动画
的持续时间和动画属性的设置来控制动画的效果和行为。

需要注意的是,CSS动画是在浏览器中通过GPU加速来执行的,因此通常比使用JavaScript
实现的动画效果更高效,能够提供更流畅的用户体验。

3. 如何使用CSS画一个圆?

.circle {
  width: 100px;
  height: 100px;
  border-radius: 50%;
  background-color: red;
}

4. 如何清除浮动

1. 使用空的额外元素并应用清除浮动样式:
    .clearfix::after {
      content: "";
      display: table;
      clear: both;
    }
在需要清除浮动的父元素上添加一个类名(例如`.clearfix`),然后使用伪元素 `::after` 
来创建一个空元素,并应用 `clear: both;` 样式。这将使该空元素在父元素的末尾清除浮动。

示例用法:    
    <div class="parent clearfix">
      <div class="float-left">浮动元素 1</div>
      <div class="float-left">浮动元素 2</div>
    </div>
    
    
2. 使用父元素设置`overflow: hidden;``overflow: auto;`样式:(建立BFC)
    .parent {
      overflow: hidden;
    }
在父元素上设置 `overflow: hidden;` 或 `overflow: auto;` 样式,会创建一个新的
BFC(块级格式化上下文),从而清除浮动效果。这是因为 BFC 会包含浮动元素,并阻止其溢出。

示例用法:
    <div class="parent">
      <div class="float-left">浮动元素 1</div>
      <div class="float-left">浮动元素 2</div>
    </div>
    
3. 使用父元素设置`display: flex;
    .parent {
      display: flex;
    }
将父元素的 `display` 属性设置为 `flex`,会创建一个新的弹性容器,并自动清除浮动效果。这是因为弹性容器会自动调整其内部元素的布局,不需要特别处理浮动。

示例用法:
    <div class="parent">
      <div class="float-left">浮动元素 1</div>
      <div class="float-left">浮动元素 2</div>
    </div>

5. js如何创建dom节点、追加类名、孩子节点和添加事件监听?

1. 可以使用 `document.createElement()` 方法来创建 DOM 节点。以下是创建 DOM 节点的示例:
    // 创建一个新的 <div> 元素
    const divElement = document.createElement('div');
 
2. 追加类名:可以使用 `classList.add()` 方法来向元素追加一个或多个类名。
    const element = document.getElementById('myElement');
    element.`lassList.add`('newClass');
    
3. 添加子节点:可以使用 `appendChild()` 方法将一个新的子节点添加到指定的父节点中。
    const parent = document.getElementById('parentElement');
    const newChild = document.createElement('div');
    parent.appendChild(newChild);
    
4. 添加事件监听:可以使用 `addEventListener()` 方法来为元素添加事件监听器,
    以便在特定事件发生时执行相应的操作。
    const button = document.getElementById('myButton');
    button.addEventListener('click', function() {
      // 在点击事件发生时执行的操作
      console.log('按钮被点击了');
    });

6.js 的数据类型?

    `数据类型`是指存储简单数据值的数据类型,它们在内存中占据固定的空间,
    并按值进行比较。JavaScript 中有以下基本数据类型:布尔类型(Boolean)、
    数字类型(Number)、字符串类型(String)、空值(Null)、未定义(Undefined)
    和符号类型(Symbol)。

    `用数据类型`是指存储对象的引用的数据类型,它们在内存中占据不同大小的空间,
    并按引用进行比较。JavaScript 中的引用数据类型包括对象(Object)、数组(Array)、
    函数(Function)、日期(Date)和正则表达式(RegExp)等。

基本数据类型和引用数据类型之间的区别主要体现在以下几个方面:

1.  存储方式:基本数据类型的值直接存储在变量中,而引用数据类型存储的是对象的引用(内存地址)。
2  复制行为:基本数据类型的赋值是将值复制到新变量,互不影响。而引用数据
    类型的赋值是将引用复制到新变量,它们引用同一个对象,修改其中一个会影响到另一个。
3  比较行为:基本数据类型通过值进行比较,只要值相等就视为相等。引用数据
    类型的比较是通过引用进行的,只有当两个变量引用同一个对象时才视为相等。
4  可变性:基本数据类型是不可变的,一旦创建,就无法修改其值。而引用数据
    类型是可变的,可以修改对象的属性和状态。

7. null 和undefined 的区别?

1. undefined:表示声明了一个变量,但没有给它赋值。它是一个表示"无"的原始值。当一个变量被声明但没有赋值时,默认其值为 undefined。函数没有返回值时,默认返回 undefined。对象属性没有赋值时,默认值也是 undefined。

示例:
    let a;
    console.log(a); // 输出 undefined

    function foo() {
      // 没有返回值,默认返回 undefined
    }
    console.log(foo()); // 输出 undefined

    const obj = {};
    console.log(obj.property); // 输出 undefined
    
2. null:表示一个被明确赋值为"空""无"的值。它是一个表示"空"的特殊对象值。当你想明确表示一个变量为空时,可以赋值为 null。

示例:
    let a = null;
    console.log(a); // 输出 null
    
    
虽然 nullundefined 都表示没有值,但它们的用法和含义略有不同。undefined 表示未
初始化或缺少值,而 null 表示明确赋值为空。在某些情况下,它们可以互相转换:

-   当将变量赋值为 null 时,它的值变为 null,表示空。
-   当将变量赋值为 undefined 时,它的值变为 undefined,表示未初始化或缺少值。
-   null 是一个字面量,可以直接赋值给变量。
-   undefined 是全局对象的一个属性,不是一个字面量,可以通过将变量赋值为 undefined 
    或不给变量赋值来得到 undefined。

在使用时,通常建议使用 null 来明确表示一个变量为空,而不要将变量设置为undefined,
除非特定情况需要明确表示未初始化。

8. js 作用域?

JavaScript 的作用域(Scope)是指变量、函数和对象在代码中可访问的范围。作用域控制着变量
的可见性和生命周期,决定了它们在代码中的可访问性和可用性。

在 JavaScript 中,有以下几种作用域:

1.  全局作用域(Global Scope):全局作用域是在整个 JavaScript 程序中都可访问的最外层
    作用域。在全局作用域中声明的变量和函数可以被程序中的任何部分访问。
    
2. 函数作用域(Function Scope):函数作用域是在函数内部声明的变量所拥有的作用域范围。
   这意味着在函数内部声明的变量对函数内部可见,而在函数外部无法访问。
   
3  块级作用域(Block Scope):块级作用域是在花括号({})内部声明的变量所拥有的作用
    域范围。在 ES6ECMAScript 2015)之前,JavaScript 中没有块级作用域,只有全局作
    用域和函数作用域。但通过使用 letconst 关键字,可以在 if 语句、循环和其他代码
    块中创建块级作用域。

作用域规定了变量的可见性和生命周期。变量在其作用域内可访问,超出作用域则无法访问。
当变量超出其作用域范围时,它可能会被垃圾回收机制回收内存。

JavaScript 的作用域是基于词法作用域(Lexical Scope)的,也称为静态作用域。词法作用
域是在编码阶段确定的,而不是在运行时。它使用代码中的变量和函数的声明位置来确定其作用
域,而不是根据代码执行的上下文。

9. js 闭包?

JavaScript 中的闭包(Closure)是指函数以及它所创建的作用域的组合。闭包允许函数访问其词法作用域(定义时的作用域)之外的变量。

闭包的特点如下:

1.  内部函数可以访问外部函数的变量和参数,即使外部函数已经执行完毕。
2  闭包函数可以将外部函数的变量保存在内存中,不会被垃圾回收机制回收,从而延长了变量的生命周期。

闭包的常见应用包括:

1. `封装私有变量`:通过闭包可以创建私有变量,只能通过内部函数访问,外部无法直接修改。
2  `创建函数工厂`:通过将某个通用的函数传递给一个外部函数,并在外部函数中返回该函数,
   可以创建具有不同上下文的函数。
3  `实现模块化`:通过闭包可以将一组相关的函数和数据封装在一个作用域内,防止全局命名
   空间的污染,并提供模块化的代码结构。
   
下面是一个简单的闭包示例:
    function outerFunction() {
      var outerVariable = 'Hello';

      function innerFunction() {
        console.log(outerVariable);
      }

      return innerFunction;
    }

    var closure = outerFunction(); // 调用外部函数,返回内部函数
    closure(); // 输出 "Hello"
    
在上述示例中,outerFunction 是一个外部函数,内部定义了一个变量 outerVariable
和一个内部函数 innerFunction。innerFunction 作为闭包被返回,并在外部函数执行
后仍然可以访问 outerVariable。

闭包在 JavaScript 中是一个强大且常用的概念,可以实现许多有用的模式和功能。
然而,过度使用闭包可能导致内存泄漏和性能问题,因此在使用闭包时需要注意合理
使用和释放资源。

10. 说说你对input框的理解

输入框(input)是 HTML 表单中常用的元素,用于接收用户的输入数据。它提供了各种类型
的输入控件,例如文本框、密码框、单选按钮、复选框等。

输入框的作用是通过用户输入的数据收集信息、进行交互和实现用户与应用程序的互动。在 Web
开发中,输入框是构建各种表单、搜索功能、登录页面等交互性组件的基础。

HTML 中的输入框使用 `<input>` 元素来创建,通过指定不同的 `type` 属性来定义输入框
的类型。以下是一些常见的输入框类型:

-   `text`:用于接收文本输入。
-   `password`:用于接收密码输入,显示为掩码字符。
-   `email`:用于接收电子邮件输入,浏览器会验证输入是否符合电子邮件格式。
-   `number`:用于接收数字输入。
-   `checkbox`:用于选择一个或多个选项。
-   `radio`:用于选择单个选项。
-   `file`:用于上传文件。
-   `date`:用于选择日期。
-   等等。

除了 `type` 属性,输入框还可以具有其他属性,如 `id``name``value` 、`placeholder`
等,用于标识和设置输入框的属性和值。可以使用 JavaScript 或服务器端代码来访问和操作输入框的值。

11. 追问: input 框的聚焦、失焦和改变事件分别怎么表示呢

JavaScript 中,可以使用事件监听器(Event Listeners)来处理输入框的聚焦、失焦和改变事件。以下是它们的常用事件和对应的事件监听方法:

1.  聚焦事件(Focus Event):当用户将焦点移动到输入框时触发。

    -   事件名:`focus`
    -   事件监听方法:`addEventListener('focus', callbackFunction)`

    示例:
    const inputElement = document.getElementById('myInput');

    inputElement.addEventListener('blur', function() {
      console.log('Input element blurred');
    });
    
2. 失焦事件(Blur Event):当输入框失去焦点时触发。

    -   事件名:`blur`
    -   事件监听方法:`addEventListener('blur', callbackFunction)`

    示例:
    const inputElement = document.getElementById('myInput');

    inputElement.addEventListener('blur', function() {
      console.log('Input element blurred');
    });
    
3. 改变事件(Change Event):当输入框的值发生改变时触发(通常是在输入框失去焦点后)。

    -   事件名:`change`
    -   事件监听方法:`addEventListener('change', callbackFunction)`

    示例:
    const inputElement = document.getElementById('myInput');

    inputElement.addEventListener('change', function() {
      console.log('Input value changed');
    });

12. call、apply、bind 的区别?

`call``apply` 和 `bind` 都是 JavaScript 中用于更改函数执行上下文(this)的方
法。它们的区别主要在于传递参数和函数调用的时间。

1.  `call` 方法:

    `call` 方法是在函数调用时立即改变函数的执行上下文(this)并调用函数。它可以接收
    多个参数,第一个参数指定函数执行时的上下文(this),后续参数是函数调用时的参数。

    语法:`function.call(thisArg, arg1, arg2, ...)`

    示例:
    function greet(name) {
      console.log(`Hello, ${name}! I'm ${this.title}.`);
    }

    const person = {
      title: 'Mr.'
    };

    greet.call(person, 'John');
    // 输出:Hello, John! I'm Mr.
    
2. `apply` 方法:

    `apply` 方法和 `call` 方法类似,也用于改变函数的执行上下文。但它接收一个数组作为参数,
    在函数调用时将数组的元素作为参数传递给函数。

    语法:`function.apply(thisArg, [argsArray])`

    示例:
    function greet(name) {
      console.log(`Hello, ${name}! I'm ${this.title}.`);
    }

    const person = {
      title: 'Mr.'
    };

    greet.apply(person, ['John']);
    // 输出:Hello, John! I'm Mr.
    
3. `bind` 方法:

    `bind` 方法也用于改变函数的执行上下文,但它不会立即调用函数,而是返回一个新的函数,
    该函数绑定了指定的上下文。可以稍后调用返回的函数。

    语法:`function.bind(thisArg[, arg1, arg2, ...])`

    示例:
    function greet(name) {
      console.log(`Hello, ${name}! I'm ${this.title}.`);
    }

    const person = {
      title: 'Mr.'
    };

    const boundGreet = greet.bind(person);
    boundGreet('John');
    // 输出:Hello, John! I'm Mr.

13. 数组常用方法有哪些?

推荐大家去看看小编的另一篇文章,传送门如下:

juejin.cn/post/734646…

14. 追问: push 会修改原数组吗, splice 呢? 数组如何去重?

答: `push` 方法和 `splice` 方法都可以修改原数组
1. 使用 Setconst array = [1, 2, 3, 3, 4, 4, 5];
    const uniqueArray = [...new Set(array)];
    console.log(uniqueArray); // [1, 2, 3, 4, 5]
    
2. 使用 filter 和 indexOf:
    const array = [1, 2, 3, 3, 4, 4, 5];
    const uniqueArray = array.filter((value, index, self) => {
      return self.indexOf(value) === index;
    });
    console.log(uniqueArray); // [1, 2, 3, 4, 5]
    
3. 使用 reduce 和 includes:
    const array = [1, 2, 3, 3, 4, 4, 5];
    const uniqueArray = array.reduce((accumulator, current) => {
      if (!accumulator.includes(current)) {
        accumulator.push(current);
      }
      return accumulator;
    }, []);
    console.log(uniqueArray); // [1, 2, 3, 4, 5]
    
 4. 使用 ES6Map
     const array = [1, 2, 3, 3, 4, 4, 5];
    const uniqueArray = Array.from(new Map(array.map(item => [item, item])).values());
    console.log(uniqueArray); // [1, 2, 3, 4, 5]

15. js 事件循环

JavaScript 事件循环(Event Loop)是一种用于处理异步操作的机制,它确保 JavaScript 
运行时能够处理事件和回调函数,使得异步代码能够以非阻塞的方式执行。

JavaScript 引擎使用单线程来执行代码,即一次只能执行一个操作。然而,JavaScript 
支持异步操作,例如定时器、网络请求、事件处理等,这些异步操作不会阻塞主线程的执行。
事件循环机制确保了异步操作的执行和回调函数的触发。

以下是 JavaScript 事件循环的基本流程:

1.  `执行同步任务`Synchronous Tasks):首先,JavaScript 引擎会执行当前调用栈
    中的同步任务,按照代码的顺序逐行执行。

2.  `执行微任务`Microtasks):在同步任务执行完毕后,JavaScript 引擎会检查微任
    务队列(Microtask Queue),并按照顺序执行其中的微任务。
3.  `渲染页面更新`:如果需要进行页面渲染,JavaScript 引擎会执行渲染操作,更新页面
    的显示。
4.  `执行宏任务`Macrotasks):在执行完所有的微任务后,JavaScript 引擎会检查宏
    任务队列(Macrotask Queue),并选择其中的一个任务执行。
5.  `重复上述步骤`:一次循环结束后,JavaScript 引擎会再次检查微任务队列,执行其中
    的微任务,然后检查宏任务队列并执行一个宏任务。这个过程不断重复,形成了事件循环。

需要注意的是,微任务比宏任务具有更高的优先级,每执行完一个宏任务后,会立即执行所有
的微任务,而不是等待下一个宏任务。这是因为微任务通常用于执行一些高优先级的操作,如更新界面状态、处理异步结果等。

16. 常见的宏任务与微任务有哪些?(小编上个问题回答 js 循环机制时没答出来,被追问了)

常见的宏任务(Macrotasks)包括:

1.  定时器任务(setTimeoutsetInterval):在指定的时间间隔后执行回调函数。
2.  DOM 事件(click、load、change 等):当用户与页面交互或特定的事件发生时触发回调函数。
3.  Ajax 请求的回调:在发送 Ajax 请求后,当请求返回时触发回调函数。
4.  I/O 操作:例如读取文件、写入文件等。
5.  requestAnimationFrame:用于执行动画效果的回调函数。

常见的微任务(Microtasks)包括:

1.  Promise 的回调函数:在 Promise 对象状态改变时触发的回调函数,如 `then``catch``finally`2.  MutationObserver 的回调函数:监测 DOM 变化,并在变化发生时触发的回调函数。
3.  process.nextTickNode.js 环境):在当前执行栈结束后、下一个事件循环开始之前触发的回调函数。

17. promise的构造函数是同步还是异步执行的?

Promise 的构造函数是同步执行的。

当创建一个 Promise 对象时,构造函数内的代码会立即执行。这意味着 Promise 对象的状态(pending、fulfilled、rejected)会立即确定,并且构造函数内的代码会立即执行相应的操作。

示例:
    console.log('Before creating Promise');

    const promise = new Promise((resolve, reject) => {
      console.log('Inside Promise constructor');
      // 执行一些异步操作
      // 在适当的时候调用 resolve() 或 reject()
    });

    console.log('After creating Promise');

    // 输出:
    // Before creating Promise
    // Inside Promise constructor
    // After creating Promise
    
在上述示例中,Promise 的构造函数内部的代码会立即执行,不会等待其他异步操作的完成。
因此,无论 Promise 内部是否包含异步操作,构造函数都会同步执行。

需要注意的是,虽然 Promise 的构造函数是同步执行的,但是在构造函数内部可以执行异步
的操作,例如定时器、网络请求等。在这种情况下,Promise 对象的状态会在异步操作完成
后改变,并触发相应的回调函数(`then``catch``finally`)。

总结而言,Promise 的构造函数是同步执行的,但是 Promise 对象本身可以用于处理异步
操作,以便更好地处理异步代码和异步结果。

18. vue 和 react 的区别?

1.  学习曲线和易用性:

    -   Vue.js 更易学和上手,对初学者友好。它提供了简洁的`模板语法`和直观的 API,
        使开发者可以快速入门。
    -   React 的学习曲线相对陡峭,需要对 `JSX`JavaScript XML)语法和组件生命
        周期等概念进行理解。但一旦掌握,React 提供了更大的灵活性和可扩展性。

1.  组件化开发:

    -   Vue.js 采用单文件组件(Single-File Components),将 HTML 模板、CSS 
        样式和 JavaScript 代码组合在一个文件中,使得组件化开发更加直观和维护友好。
    -   React 使用 JSX,将组件的结构和逻辑都放在 JavaScript 文件中,通过 
        JavaScript 代码编写组件。

1.  响应式和数据流管理:

    -   Vue.js 使用`双向数据绑定`,即视图和数据之间的变化能够互相影响,通过
        `v-model` 指令可以轻松实现数据的双向绑定。
    -   React 使用`单向数据流`,数据从父组件传递给子组件,子组件通过 props 
        接收数据,通过回调函数进行状态的更新。

1.  生态系统和社区支持:

    -   React 生态系统非常庞大,拥有丰富的第三方库和插件,如 React RouterReduxAxios 等。React 的社区活跃度高,有大量的学习资源和社区支持。
    -   Vue.js 生态系统也在不断壮大,拥有一些流行的第三方库和插件,如 Vue RouterVuexAxios 等。尽管规模较小,但也有一个积极的社区。

1.  性能和渲染优化:

    -   Vue.js 在性能优化方面做了很多工作,使用了`虚拟 DOM `和异步更新策略,
        能够更高效地处理组件的渲染和更新。
    -   React 通过`虚拟 DOM``高效的 Diff 算法`,能够在 UI 更新时进行最小化的 DOM 操作,
        提高性能。另外,React 还提供了钩子函数和生命周期方法,使得性能优化更加灵活。

19. v-cloak 是什么?

`v-cloak` 是 Vue.js 框架中的一个指令,用于解决在初始化渲染时由于数据加载延迟而导致
的闪烁问题。

当使用 Vue.js 渲染页面时,如果页面中包含使用 Vue.js 指令或插值表达式的元素,这些元
素在初始化渲染之前可能会显示原始的模板内容,这可能导致用户在页面加载时看到未经处理的
模板内容,然后在 Vue.js 完成初始化后才得到正确的渲染结果。这种现象通常被称为 "闪烁"。

为了解决这个问题,Vue.js 提供了 `v-cloak` 指令。该指令可以与 CSS 配合使用,确保在 Vue.js 完成初始化渲染之前,元素始终处于隐藏状态。

使用 `v-cloak` 指令的步骤如下:

1.Vue.js 组件或根元素上添加 `v-cloak` 属性。
    <div id="app" v-cloak>
      <!-- Vue.js 组件内容 -->
    </div>
2.CSS 中定义 `v-cloak` 的样式,使元素始终处于隐藏状态。
    [v-cloak] {
      display: none;
    }
    
当 Vue.js 初始化完成后,`v-cloak` 指令会被移除,元素会显示出来并正常渲染。

使用 `v-cloak` 指令可以有效解决初始化渲染时的闪烁问题,确保用户在页面加载时不会看到
未处理的模板内容。

20. v-if 与 v-show的区别

`v-if` 和 `v-show` 是 Vue.js 条件渲染的指令。

-   `v-if` 在条件为 `false` 时,元素会完全销毁,条件变为 `true` 时重新创建元素。
-   `v-show` 在条件为 `false` 时,元素仅隐藏,条件变为 `true` 时恢复显示。

主要区别:

-   `v-if` 在初始渲染时可以减少开销,但切换时开销较大。
-   `v-show` 在初始渲染时有开销,通过修改 CSS 的 `display` 属性来控制元素的显示
     和隐藏,不会涉及元素的销毁和重新创建,切换开销较小。

适用场景:

-   `v-if` 适合条件较少改变或需要根据条件动态创建和销毁元素的情况。
-   `v-show` 适合频繁切换显示和隐藏的情况。

21. 组件间通信方式有哪些

1.  Props 和事件(父子组件通信):

    -   父组件通过 props 向子组件传递数据,并在子组件中使用 props 接收数据。
    -   子组件可以通过触发事件(`$emit`)将数据发送给父组件。

2.  自定义事件(兄弟组件通信):

    -   通过一个共同的父组件,兄弟组件通过触发事件(`$emit`)和监听事件(`$on`)来进行通信。

3.  Vue 实例作为事件中心(任意组件通信):

    -   可以创建一个空的 Vue 实例作为事件中心,用于组件之间的通信。
    -   组件通过该事件中心的事件监听和触发来进行通信。

4.  Vuex(状态管理):Vue3使用 Pinia

    -   VuexVue.js 官方提供的状态管理库,用于管理应用程序的共享状态。
    -   组件通过提交 mutations 或分发 actions 来修改和获取共享状态。

5.  Provide / Inject(祖先与后代组件通信):

    -   祖先组件通过 `provide` 提供数据,后代组件通过 `inject` 注入数据。
    -   后代组件可以直接访问祖先组件提供的数据。

6.  $refs(父组件引用子组件):

    -   父组件可以通过 `ref` 属性引用子组件实例,从而直接调用子组件的方法或访问子组件的数据。

7.  EventBus(简单的事件总线):

    -   可以使用一个简单的事件总线实例来进行组件间的通信,类似于 Vue 实例作为事件中心的方式。

22. 介绍一下AJAX

AJAXAsynchronous JavaScript and XML)是一种用于在 Web 应用程序中进行异步通信
的技术。它允许在不刷新整个页面的情况下,通过在后台与服务器进行数据交换,更新部分页
面内容。使用 XMLHttpRequest 对象来实现 AJAX 请求。它提供了发送请求、接收响应和处
理数据的功能。
    示例:
    function getData() {
      var xhr = new XMLHttpRequest();
      var url = "https://api.example.com/data"; // 替换为实际的 API 地址

      xhr.onreadystatechange = function() {
        if (xhr.readyState === 4 && xhr.status === 200) {
          var responseData = JSON.parse(xhr.responseText);
          document.getElementById("result").innerHTML = responseData.message;
        }
      };

      xhr.open("GET", url, true);
      // 通过 `open()` 方法指定了请求的类型(GET)、URL和是否使用异步请求(true)。
      xhr.send();
    }

23. 你是如何封装axios的?(答案略)

24. 实习使用的技术栈

25. 你是如何做移动端适配的,有什么方案可以实现?简单展开讲一下

1.  `媒体查询`Media Queries):  
    使用 CSS3 的媒体查询可以根据屏幕尺寸应用不同的样式。通过设置不同的 CSS 规则,可以根据屏幕宽度、高度或设备类型等属性调整布局和样式。
2.  `Viewport`Viewport 是移动设备上可见区域的窗口,可以通过设置 `<meta>` 标签中的 viewport 属性来控制网页的初始缩放级别、宽度和视口大小。
3.  `弹性布局`Flexbox):  
    弹性布局是一种灵活的布局模型,可以自适应不同屏幕尺寸。通过使用 flex 容器和 flex 项目,可以轻松地实现自适应的布局和排列。
4.  `REM``EM` 单位:  
    使用相对单位 REMEM 可以根据根元素的字体大小来调整元素的尺寸。通过设置根元素的字体大小为相对于屏幕宽度的比例,可以实现基于屏幕尺寸的自适应布局。
5.  `百分比(%)`:  
    百分比单位可以相对于父元素的尺寸进行计算。通过将元素的宽度、高度、间距等属性设置为百分比值,可以实现基于父元素尺寸的自适应效果。
6.  `vw`(视窗宽度单位)和`vh`(视窗高度单位):  
    vw 和 vh 是相对于视窗宽度和视窗高度的单位,可以根据屏幕尺寸进行自适应布局。1vw 等于视窗宽度的 1%,1vh 等于视窗高度的 1%。通过设置元素的宽度、高度、字体大小等属性为 vw 或 vh 单位,可以实现基于屏幕尺寸的自适应效果。

26. git 常用命令,git fetch 和 git pull 的区别是什么

27. 反问: 公司近期的技术栈,开发方向、企业氛围

结语:以上就是这家公司前两轮的笔试和面试内容啦,面试完差不多一个小时后HR就联系说说让我准备一下复试,到时候是前端技术负责人给我面试,所以加油吧,小编还在打怪升级的路上,希望我们能够前程似锦,祝你也祝我!!!