前端面试题详解整理89|状态码,水平垂直居中,原型flex,单行文本溢出,回流重绘,数据类型,数组判断,数组方法,新增元素,并集,交集,转换,浅拷贝闭包,防抖,

94 阅读27分钟

蔚来前端实习一面

56min
1.自我介绍

2.水平垂直居中

要在网页中实现水平垂直居中,可以使用以下方法之一:

方法一:使用 Flexbox 布局

<div class="container">
  <div class="content">
    <!-- 内容 -->
  </div>
</div>
.container {
  display: flex;
  justify-content: center; /* 水平居中 */
  align-items: center; /* 垂直居中 */
  height: 100vh; /* 设置容器高度为视口高度 */
}

方法二:使用绝对定位和 transform 属性

<div class="container">
  <div class="content">
    <!-- 内容 -->
  </div>
</div>
.container {
  position: relative; /* 相对定位 */
  width: 100%;
  height: 100vh; /* 设置容器高度为视口高度 */
}

.content {
  position: absolute; /* 绝对定位 */
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%); /* 平移使其水平垂直居中 */
}

方法三:使用 Grid 布局

<div class="container">
  <div class="content">
    <!-- 内容 -->
  </div>
</div>
.container {
  display: grid;
  place-items: center; /* 将子元素水平垂直居中 */
  height: 100vh; /* 设置容器高度为视口高度 */
}

以上方法都可以实现将内容水平垂直居中显示在容器中。具体选择哪种方法取决于项目需求和个人偏好。

3.flex是哪几个属性的简写

Flex 是 Flexbox 布局模型的简写,它涉及到了一系列属性来控制弹性容器(Flex Container)和其内部的弹性项目(Flex Items)的布局。Flex 属性的简写形式是 flex,而它的完整写法包括了以下几个属性:

  1. flex-grow:定义项目的放大比例,默认为 0,即项目不放大。
  2. flex-shrink:定义项目的缩小比例,默认为 1,即项目根据空间大小自动缩小。
  3. flex-basis:定义项目的基础大小,默认为 auto,即项目的原始大小。
  4. flex:以上三个属性的缩写,按顺序依次代表 flex-growflex-shrinkflex-basis,例如 flex: 1 1 auto

使用 flex 属性时,可以只设置一个值,也可以设置三个值,分别对应上述三个属性。如果只设置一个值,则表示 flex-grow 属性的值;如果设置两个值,则第一个值表示 flex-grow,第二个值表示 flex-shrink;如果设置三个值,则分别表示 flex-growflex-shrinkflex-basis

4.如何处理单行文本溢出,用省略号显示

要处理单行文本溢出并使用省略号显示,可以使用 CSS 的 text-overflow 属性结合 overflowwhite-space 属性来实现。具体步骤如下:

  1. 设置元素的 white-space 属性为 nowrap,使文本不换行。
  2. 设置元素的 overflow 属性为 hidden,使超出部分隐藏。
  3. 设置元素的 text-overflow 属性为 ellipsis,当文本溢出时显示省略号。

以下是一个示例:

.ellipsis-text {
    white-space: nowrap;    /* 文本不换行 */
    overflow: hidden;       /* 超出部分隐藏 */
    text-overflow: ellipsis;  /* 显示省略号 */
}

然后,将该类应用于需要处理的元素上:

<div class="ellipsis-text">这是一段很长的单行文本,当它超出容器时将显示省略号。</div>

这样,当文本超出容器宽度时,就会显示省略号,而不会影响布局。

5.回流和重绘

回流(Reflow)和重绘(Repaint)是浏览器渲染页面时的两个重要概念,它们的区别如下:

  1. 回流(Reflow)

    • 当 DOM 的结构发生变化,或者页面的布局发生改变时,浏览器需要重新计算元素的几何属性(比如位置、大小等),然后重新布局页面,这个过程就是回流。
    • 回流会导致页面的重新布局和重新渲染,消耗较大的性能。
    • 触发回流的操作包括:添加或删除 DOM 元素、修改元素的尺寸、内容或样式等。
  2. 重绘(Repaint)

    • 当元素的样式发生变化,但是不影响其几何属性(比如颜色、背景、边框等),浏览器只需要重新绘制这个元素的样式,而不需要重新计算其几何属性和重新布局页面,这个过程就是重绘。
    • 重绘的性能开销比回流要小很多。
    • 触发重绘的操作包括:修改元素的颜色、背景、边框等。

总的来说,回流比重绘开销更大,因为回流不仅要重新绘制元素样式,还需要重新计算元素的几何属性和页面的布局。因此,优化页面性能时应该尽量减少回流的触发,例如通过批量修改样式、使用 CSS3 动画代替 JavaScript 动画等方式。

6.js数据类型

在 JavaScript 中,数据类型可以分为以下几种:

  1. 基本数据类型(Primitive Types)

    • Undefined:表示未定义的值。
    • Null:表示空值。
    • Boolean:表示逻辑上的真或假。
    • Number:表示数值,包括整数和浮点数。
    • String:表示字符串。
  2. 引用数据类型(Reference Types)

    • Object:表示对象,是 JavaScript 中所有对象的基类。
    • Array:表示数组,是一种特殊的对象,用于存储一组有序的数据。
    • Function:表示函数,是一种特殊的对象,可以被调用。
    • Date:表示日期和时间。
    • RegExp:表示正则表达式。
  3. 特殊数据类型

    • Symbol:表示独一无二的值,用于创建对象的唯一属性名。
  4. 其他

    • BigInt:表示任意精度的整数,在 JavaScript 中是一种较新的数据类型。

在 JavaScript 中,基本数据类型存储在栈内存中,而引用数据类型存储在堆内存中,变量存储的是其在堆内存中的地址。JavaScript 是一种弱类型语言,变量的数据类型可以动态变化,即使在运行时也可以改变。

7.如何判断是一个数组。

在 JavaScript 中,判断一个变量是否为数组有几种常见的方法:

  1. Array.isArray() 方法

    • Array.isArray() 是 JavaScript 提供的原生方法,用来检测一个值是否为数组。
    • 示例:
      const arr = [1, 2, 3];
      console.log(Array.isArray(arr)); // 输出: true
      
  2. instanceof 操作符

    • instanceof 操作符用于检测构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。
    • 示例:
      const arr = [1, 2, 3];
      console.log(arr instanceof Array); // 输出: true
      
  3. Array.prototype.isPrototypeOf() 方法

    • Array.prototype.isPrototypeOf() 方法用于检测数组对象是否为给定对象的原型。
    • 示例:
      const arr = [1, 2, 3];
      console.log(Array.prototype.isPrototypeOf(arr)); // 输出: true
      
  4. toString() 方法

    • 可以使用 toString() 方法检查对象的类型信息,如果是数组,则其类型信息中会包含字符串 "[object Array]"
    • 示例:
      const arr = [1, 2, 3];
      console.log(Object.prototype.toString.call(arr) === '[object Array]'); // 输出: true
      

以上方法都可以用来判断一个变量是否为数组,其中 Array.isArray() 是最推荐的方法,因为它简单直观且具有更好的兼容性。

Object.prototype.toString.call()判断使用是什么原理

Object.prototype.toString.call() 方法是用来获取一个对象的类型信息的常用方法。它的原理是利用了 JavaScript 中的原型链和内置对象的特性。

当调用 Object.prototype.toString.call() 方法时,它会返回一个字符串,表示传入对象的类型。例如,对于数组、函数、日期对象等,它们的类型信息都可以通过 Object.prototype.toString.call() 方法来获取。

这个方法的工作原理是:

  1. 首先,通过原型链的特性,获取 Object.prototype 对象上的 toString 方法。
  2. 然后,调用这个方法,并将要检测的对象作为参数传入。
  3. 最后,返回结果是一个字符串,表示传入对象的内部属性 [[Class]] 的值,这个值就代表了对象的类型信息。

举个例子,对于数组,它的 [[Class]] 属性值是 "[object Array]",所以调用 Object.prototype.toString.call([]) 就会返回 "[object Array]",表示这是一个数组对象。

这种方法的优势在于它可以准确地判断对象的类型,不受对象所在环境的影响,是一种比较可靠的类型检测方式。

8.说说常用的数组方法,map和foreach的区别,是否都会改变原数组

常用的数组方法包括 forEach()map()filter()reduce() 等等,它们都可以在处理数组时提供便利和功能。

常用的数组方法:

  1. forEach() 方法

    • forEach() 方法对数组中的每个元素执行指定操作,并没有返回值。
    • 示例:
      const arr = [1, 2, 3];
      arr.forEach(item => console.log(item * 2)); // 输出: 2, 4, 6
      
  2. map() 方法

    • map() 方法对数组中的每个元素执行指定操作,并返回一个新数组,新数组的元素是对原数组元素执行操作后的结果。
    • 示例:
      const arr = [1, 2, 3];
      const doubled = arr.map(item => item * 2);
      console.log(doubled); // 输出: [2, 4, 6]
      
  3. filter() 方法

    • filter() 方法根据指定条件过滤数组中的元素,并返回一个包含满足条件的元素的新数组。
    • 示例:
      const arr = [1, 2, 3, 4, 5];
      const evenNumbers = arr.filter(item => item % 2 === 0);
      console.log(evenNumbers); // 输出: [2, 4]
      
  4. reduce() 方法

    • reduce() 方法对数组中的所有元素执行指定操作,并将结果累积为单个值。
    • 示例:
      const arr = [1, 2, 3, 4, 5];
      const sum = arr.reduce((acc, cur) => acc + cur, 0);
      console.log(sum); // 输出: 15
      

map() 和 forEach() 方法的区别:

  • map() 方法返回一个新数组,其中每个元素是对原数组中相应元素应用处理函数的结果。
  • forEach() 方法执行指定操作,但并不返回任何值,仅用于遍历数组中的元素。

是否都会改变原数组:

  • map() 方法不会改变原数组,而是返回一个新数组。
  • forEach() 方法也不会改变原数组,仅用于遍历数组,执行指定操作。

9.数组中新增元素的方法,splice方法有几个参数,返回值是什么,push方法的返回值是什么
在 JavaScript 中,常用的数组中新增元素的方法包括 push()unshift()splice() 等。

数组中新增元素的方法:

  1. push() 方法

    • push() 方法用于向数组的末尾添加一个或多个元素,并返回新的数组长度。
    • 示例:
      const arr = [1, 2, 3];
      const length = arr.push(4, 5); // 向数组末尾添加元素 4 和 5
      console.log(arr); // 输出: [1, 2, 3, 4, 5]
      console.log(length); // 输出: 5
      
  2. unshift() 方法

    • unshift() 方法用于向数组的开头添加一个或多个元素,并返回新的数组长度。
    • 示例:
      const arr = [3, 4, 5];
      const length = arr.unshift(1, 2); // 向数组开头添加元素 1 和 2
      console.log(arr); // 输出: [1, 2, 3, 4, 5]
      console.log(length); // 输出: 5
      
  3. splice() 方法

    • splice() 方法用于在指定位置插入、删除或替换元素,并返回被删除的元素组成的数组。
    • 它的参数包括起始位置、要删除的元素个数(可选)、要插入的元素(可选)。
    • 示例:
      const arr = [1, 2, 3, 4, 5];
      const removed = arr.splice(2, 0, 6); // 在索引为 2 的位置插入元素 6
      console.log(arr); // 输出: [1, 2, 6, 3, 4, 5]
      console.log(removed); // 输出: [],因为没有删除任何元素
      

splice() 方法的参数和返回值:

splice() 方法的参数包括:

  • start:要操作的起始位置索引。
  • deleteCount:要删除的元素个数。
  • item1, item2, ...:要插入的元素(可选)。

splice() 方法的返回值是一个包含被删除元素的数组,如果没有删除任何元素,则返回一个空数组。

10.常用的字符串方法。字符串转数组和数组转字符串的方法。

常用的字符串方法包括以下几种:

  1. 字符串查找和匹配方法

    • indexOf():返回指定字符在字符串中第一次出现的位置。
    • lastIndexOf():返回指定字符在字符串中最后一次出现的位置。
    • startsWith():检查字符串是否以指定的字符开头。
    • endsWith():检查字符串是否以指定的字符结尾。
    • includes():检查字符串是否包含指定的字符。
  2. 字符串截取和提取方法

    • substring():返回字符串的指定部分。
    • slice():提取字符串的一部分,并返回一个新字符串。
    • substr():从字符串中提取指定长度的字符。
  3. 字符串替换和修改方法

    • replace():替换字符串中的指定字符。
    • toUpperCase():将字符串转换为大写。
    • toLowerCase():将字符串转换为小写。
    • trim():去除字符串两端的空格。
  4. 字符串分割和连接方法

    • split():将字符串分割成数组。
    • concat():连接两个或多个字符串。
  5. 字符串长度和访问方法

    • length 属性:获取字符串的长度。
    • 字符串索引:可以通过索引来访问字符串中的特定字符。

字符串转数组和数组转字符串的方法:

字符串转数组:

使用 split() 方法将字符串转换为数组,可以指定分隔符来进行分割。

const str = "apple,banana,orange";
const arr = str.split(","); // 将字符串按逗号分割成数组
console.log(arr); // 输出: ["apple", "banana", "orange"]

数组转字符串:

使用 join() 方法将数组转换为字符串,可以指定连接符将数组中的元素连接起来。

const arr = ["apple", "banana", "orange"];
const str = arr.join(","); // 将数组中的元素用逗号连接成字符串
console.log(str); // 输出: "apple,banana,orange"

以上方法是常用的字符串和数组之间相互转换的方式。

11.求两个数组并集交集的方法

要求两个数组的并集和交集,可以使用 JavaScript 中的一些数组方法来实现。

求并集(Union)

并集是指两个集合中所有的元素的集合。在 JavaScript 中,可以通过 concat() 方法和 Set 对象来实现两个数组的并集。

function union(arr1, arr2) {
  // 将两个数组合并成一个新数组
  const combinedArray = arr1.concat(arr2);
  // 使用 Set 对象去除重复元素
  return [...new Set(combinedArray)];
}

// 示例用法
const arr1 = [1, 2, 3];
const arr2 = [3, 4, 5];
const unionResult = union(arr1, arr2);
console.log(unionResult); // 输出: [1, 2, 3, 4, 5]

求交集(Intersection)

交集是指两个集合中共同存在的元素的集合。在 JavaScript 中,可以通过 filter() 方法和 includes() 方法来实现两个数组的交集。

function intersection(arr1, arr2) {
  // 使用 filter() 方法筛选出 arr1 中与 arr2 共有的元素
  return arr1.filter(item => arr2.includes(item));
}

// 示例用法
const arr1 = [1, 2, 3];
const arr2 = [3, 4, 5];
const intersectionResult = intersection(arr1, arr2);
console.log(intersectionResult); // 输出: [3]

这些方法可以很方便地求得两个数组的并集和交集。

12.数据类型隐式转换规则和显示转换的做法

JavaScript 中的数据类型转换主要涉及到两种:隐式转换和显示转换。

隐式转换(Implicit Conversion)

隐式转换是指在某些运算或比较操作中,JavaScript 引擎会自动将一个数据类型转换为另一个数据类型,以满足操作的要求。这种转换是自动发生的,不需要程序员明确指定。常见的隐式转换规则包括:

  1. 字符串和数字之间的隐式转换

    • 在字符串和数字之间的加法操作中,数字会被隐式转换为字符串:
      const num = 10;
      const str = 'The number is ' + num; // 隐式转换,num 被转换为字符串
      
  2. 布尔值之间的隐式转换

    • 在布尔值的逻辑运算中,非布尔值会被隐式转换为布尔值:
      const result = 'Hello'; // 隐式转换,非空字符串转换为 true
      if (result) {
        console.log('Expression is true');
      }
      

显示转换(Explicit Conversion)

显示转换是指程序员明确地将一个数据类型转换为另一个数据类型。在 JavaScript 中,可以使用一些内置函数或操作符进行显示转换。常见的显示转换方法包括:

  1. parseInt() 和 parseFloat()

    • 用于将字符串转换为整数或浮点数:
      const str = '10';
      const num = parseInt(str); // 显示转换,字符串转换为整数
      
  2. Number()、String() 和 Boolean() 构造函数

    • 用于将值显式转换为数字、字符串或布尔值:
      const num = Number('10'); // 显示转换,字符串转换为数字
      const str = String(10); // 显示转换,数字转换为字符串
      const bool = Boolean(0); // 显示转换,数字转换为布尔值
      
  3. 操作符 +、-、*:

    • 一元加操作符 (+) 可以将字符串转换为数字:
      const str = '10';
      const num = +str; // 显示转换,字符串转换为数字
      

显示转换可以让程序员更加明确地控制数据类型之间的转换过程,使代码更加易读和可维护。

13.js中有哪些是实现浅拷贝的方法。json转换实现深拷贝方法的局限性。写实现深拷贝的方法。

在 JavaScript 中,实现浅拷贝的常见方法包括:

  1. Object.assign() 方法

    const shallowCopy = Object.assign({}, originalObject);
    
  2. 扩展运算符 (...)

    const shallowCopy = { ...originalObject };
    
  3. Array.slice() 方法(仅适用于数组):

    const shallowCopy = originalArray.slice();
    
  4. Array.concat() 方法(仅适用于数组):

    const shallowCopy = originalArray.concat();
    
  5. Object.create() 方法

    const shallowCopy = Object.create(originalObject);
    

这些方法都是对对象或数组的浅拷贝,即只会拷贝对象或数组的第一层属性,而不会拷贝嵌套对象或数组的内部元素。这就引出了深拷贝的需求。

然而,使用 JSON.stringify() 和 JSON.parse() 来实现深拷贝具有一定的局限性,因为它们无法处理函数、RegExp、Date 等特殊类型的数据,并且会忽略对象原型链上的属性。

以下是一个简单的实现深拷贝的方法:

function deepCopy(obj) {
  // 如果是基本类型,则直接返回
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }

  // 创建一个空对象或数组
  const newObj = Array.isArray(obj) ? [] : {};

  // 遍历原始对象或数组的所有属性,递归进行深拷贝
  for (let key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      newObj[key] = deepCopy(obj[key]);
    }
  }

  return newObj;
}

// 使用示例
const originalObject = { a: 1, b: { c: 2 } };
const deepCopiedObject = deepCopy(originalObject);

这个方法递归地遍历原始对象或数组的所有属性,并进行深拷贝。对于每一个属性,如果是基本类型则直接赋值,如果是对象或数组则递归调用深拷贝函数。这样可以确保所有的嵌套对象和数组都被正确地拷贝。

14.闭包
15.防抖,说实现思路

闭包(Closure)

闭包是指函数与其相关的引用环境(词法环境)的组合,它使函数可以访问其外部作用域中的变量,即使在函数执行完毕后,这些变量的引用仍然存在。闭包允许函数保存状态,可以在函数内部访问外部变量,并且这些变量不会被垃圾回收机制回收,直到闭包不再被使用。

function outerFunction() {
  let outerVar = 'I am from outer function';
  
  function innerFunction() {
    console.log(outerVar); // 使用外部变量 outerVar
  }

  return innerFunction; // 返回内部函数
}

const inner = outerFunction(); // 调用外部函数,得到内部函数
inner(); // 调用内部函数,打印 "I am from outer function"

在上面的示例中,innerFunction 是一个闭包,它可以访问外部函数 outerFunction 中的变量 outerVar,即使 outerFunction 已经执行完毕。

防抖(Debouncing)

防抖是一种用于控制函数执行频率的技术,它可以确保在连续触发某个事件时,函数只在指定的时间间隔内执行一次。防抖的实现思路如下:

  1. 在事件被触发时,设置一个定时器。
  2. 如果在定时器到期之前再次触发了相同事件,则清除之前的定时器,重新设置定时器。
  3. 直到指定的时间间隔内没有新的触发事件,定时器到期,执行相应的函数。

下面是一个简单的 JavaScript 实现:

function debounce(func, delay) {
  let timerId;

  return function() {
    const context = this;
    const args = arguments;

    clearTimeout(timerId); // 清除之前的定时器

    timerId = setTimeout(function() {
      func.apply(context, args); // 执行函数
    }, delay);
  };
}

// 使用示例
const debouncedFunction = debounce(function() {
  console.log('Function debounced');
}, 200);

// 触发事件
debouncedFunction();
debouncedFunction(); // 会清除之前的定时器重新设置

在上述示例中,debounce 函数接受一个函数和一个延迟时间作为参数,返回一个新的函数。该新函数在触发时会清除之前的定时器并设置一个新的定时器,在延迟时间到达后执行原始函数。这样可以确保函数只会在最后一次触发后经过指定的延迟时间后执行一次。

16.说说原型

在 JavaScript 中,每个对象都有一个原型(prototype)。原型是对象的一个属性,它指向另一个对象,被称为原型对象。JavaScript 中的对象通过原型链连接到其他对象,形成一个原型链的结构。

以下是关于原型的一些重要概念和特点:

  1. 原型链(Prototype Chain):圆形

    • JavaScript 中的对象通过原型链连接到其他对象。当访问一个对象的属性或方法时,如果当前对象没有定义该属性或方法,JavaScript 引擎会沿着原型链向上查找,直到找到对应的属性或方法,或者查找到原型链的尽头(即 Object.prototype)。
  2. 原型对象(Prototype Object)

    • 每个对象都有一个原型对象,它用于存储对象共享的属性和方法。当访问对象的属性或方法时,如果当前对象没有定义,则会去原型对象中查找。
  3. 构造函数(Constructor Function)

    • 构造函数是用来创建对象的函数。在 JavaScript 中,构造函数可以定义对象的属性和方法,通过 new 关键字调用构造函数时,会创建一个新的对象,并将该对象的原型指向构造函数的 prototype 属性。
  4. 原型属性和方法

    • 对象的原型中可以存储属性和方法,这些属性和方法会被该对象的所有实例共享。通过原型,可以实现对象之间的数据共享和代码复用。
  5. 原型继承

    • JavaScript 中的继承是通过原型链实现的。子对象通过原型链继承父对象的属性和方法。当子对象无法在自身找到对应的属性或方法时,会沿着原型链向上查找,直到找到为止。

总的来说,原型是 JavaScript 中实现对象继承和共享的机制,它通过原型链连接对象,实现了对属性和方法的共享和继承。

17.说说promise,一个输出题

18.http状态码

HTTP 状态码是在客户端与服务器之间传递的一个三位数字代码,用于表示 HTTP 请求的处理结果。这些状态码被分为五类,每一类由一个数字开头,分别代表不同的意义。以下是常见的 HTTP 状态码及其含义:

  1. 1xx 信息性状态码

    • 100 Continue:服务器已接收到请求的一部分,客户端应该继续发送剩余的请求。
    • 101 Switching Protocols:服务器已经理解了客户端的请求,同意切换协议。
  2. 2xx 成功状态码

    • 200 OK:请求成功,服务器已成功处理了请求。
    • 201 Created:请求已经被实现,并且创建了新的资源。
    • 204 No Content:服务器成功处理了请求,但不需要返回任何实体内容。
  3. 3xx 重定向状态码

    • 301 Moved Permanently:永久重定向,请求的资源已被分配了新的 URI。
    • 302 Found:临时重定向,请求的资源已被临时移动到新的 URI。
    • 304 Not Modified:客户端发起条件 GET 请求时,服务器端指出资源未被修改。
  4. 4xx 客户端错误状态码

    • 400 Bad Request:客户端发送的请求有错误,服务器无法处理此请求。
    • 401 Unauthorized:请求要求身份验证,客户端需要提供有效的身份验证信息。
    • 404 Not Found:服务器无法找到请求的资源。
  5. 5xx 服务器错误状态码

    • 500 Internal Server Error:服务器遇到了意料不到的情况,导致无法完成请求。
    • 503 Service Unavailable:服务器暂时无法处理请求,通常是因为服务器过载或维护。

这些状态码能够帮助客户端和服务器更好地理解和处理 HTTP 请求,有效地进行通信和故障排查。

19.get请求和post请求的区别

GET 请求和 POST 请求是 HTTP 协议中两种常用的请求方法,它们在以下几个方面有所不同:

  1. 参数传递方式

    • GET 请求将参数以查询字符串的形式附加在 URL 后面,例如:http://example.com/api?param1=value1&param2=value2
    • POST 请求将参数放在请求体中传输,而不是放在 URL 中,因此在请求体中传输的数据对用户是不可见的。
  2. 数据大小限制

    • GET 请求的参数长度有限制,因为参数是以 URL 的方式传输,受到浏览器和服务器的限制,通常在 2KB - 8KB 之间。
    • POST 请求的参数长度理论上没有限制,因为参数是放在请求体中传输的,但实际上服务器和客户端都可能会对请求体大小进行限制。
  3. 安全性

    • GET 请求的参数以明文形式出现在 URL 中,因此不适合传输敏感信息,如密码等。
    • POST 请求的参数放在请求体中,相对于 GET 请求来说更安全,可以传输敏感信息。
  4. 幂等性

    • GET 请求是幂等的,即对同一资源的多次请求产生的效果是一致的,不会对服务器资源产生影响。
    • POST 请求通常用于提交表单或上传数据等操作,不是幂等的,对同一资源的多次请求可能会产生不同的效果。
  5. 缓存

    • GET 请求可以被浏览器缓存,因为它的请求参数直接暴露在 URL 中。
    • POST 请求默认情况下不会被浏览器缓存。

总的来说,GET 请求适合用于获取数据,且请求参数较少、不敏感、幂等的场景;而 POST 请求适合用于提交数据,且请求参数较多、敏感、非幂等的场景。

20.输入url到页面加载的过程

从输入 URL 到页面加载的过程大致可以分为以下几个步骤:

  1. DNS 解析

    • 浏览器首先会进行 DNS 解析,将域名解析成对应的 IP 地址,以确定要访问的服务器地址。
  2. 建立 TCP 连接

    • 浏览器通过 DNS 解析得到服务器的 IP 地址后,会与服务器建立 TCP 连接。这个过程经历了三次握手,确保客户端和服务器之间建立可靠的连接。
  3. 发送 HTTP 请求

    • 客户端向服务器发送 HTTP 请求,请求的内容包括要访问的资源、请求头信息等。
  4. 服务器处理请求

    • 服务器收到客户端发送的 HTTP 请求后,会根据请求的内容进行相应的处理,可能涉及到查询数据库、生成动态内容等操作。
  5. 服务器响应

    • 服务器处理完请求后,会将响应的内容以 HTTP 响应的形式返回给客户端,响应的内容包括状态码、响应头信息以及实际的资源内容。
  6. 浏览器接收响应

    • 浏览器接收到服务器返回的 HTTP 响应后,会根据响应的内容进行相应的处理。如果响应的内容是 HTML 页面,则开始解析页面内容。
  7. 页面渲染

    • 浏览器解析 HTML 页面,并根据其中的 CSS 样式、JavaScript 脚本等内容进行页面布局和渲染。
  8. 下载其他资源

    • 页面渲染过程中,如果遇到外部 CSS、JavaScript、图片等资源,浏览器会根据需要向服务器发起相应的请求,并下载这些资源。
  9. 页面加载完成

    • 当所有资源都被下载并且页面的 DOM 树构建完成后,页面加载完成,此时可以执行 DOMContentLoaded 事件,表示页面已经就绪可以交互。
  10. DOMContentLoaded

    • 当页面的 HTML 文档被完全加载和解析完成后,DOMContentLoaded 事件被触发,此时页面的 DOM 树已经构建完成,但可能还有一些外部资源(如图片)没有加载完成。
  11. onload

    • 当所有资源都加载完成(包括图片、样式表、脚本等),并且页面的所有元素都已经呈现到浏览器中时,会触发 onload 事件,表示页面完全加载完成,此时页面可以进行交互操作。

21.常用的git命令。在自己主分支上修改一些内容后怎样再提交到主分支
常用的 Git 命令包括:

  1. git init:初始化一个新的 Git 仓库。
  2. git clone [url]:克隆远程仓库到本地。
  3. git add [file]:将文件添加到暂存区。
  4. git commit -m "[message]":提交暂存区中的文件到本地仓库。
  5. git push:将本地仓库的提交推送到远程仓库。
  6. git pull:从远程仓库拉取最新的提交。
  7. git branch:查看当前分支。
  8. git checkout [branch]:切换到指定分支。
  9. git merge [branch]:将指定分支合并到当前分支。
  10. git status:查看当前工作区的状态。
  11. git log:查看提交日志。

若要在自己的主分支上修改内容并提交到主分支,可以按以下步骤进行:

  1. 确保当前分支是主分支:使用 git checkout main 切换到主分支。
  2. 在主分支上进行修改:对文件进行修改或添加新文件。
  3. 将修改添加到暂存区:使用 git add [file] 将修改的文件添加到暂存区。
  4. 提交修改到本地主分支:使用 git commit -m "[message]" 提交暂存区的内容到本地主分支。
  5. 如果其他人已经在远程主分支上进行了提交,先拉取最新提交:使用 git pull 拉取远程主分支的最新提交。
  6. 解决可能出现的冲突:如果拉取操作引发了冲突,需要手动解决冲突。
  7. 将本地主分支的提交推送到远程主分支:使用 git push 将本地主分支的提交推送到远程仓库的主分支。

这样就完成了在自己的主分支上进行修改并提交到主分支的操作。

22.常用的hook,usememo和memo,usecallback怎么用的,useeffect想只在销毁时执行应该怎么写依赖项

常用的 React Hooks 包括:

  1. useState:用于在函数组件中添加状态管理。
  2. useEffect:用于在函数组件中执行副作用操作,如数据获取、订阅事件等。
  3. useContext:用于在函数组件中访问 React 上下文。
  4. useReducer:类似于 Redux 中的 reducer,用于复杂状态的管理。
  5. useMemo:用于在函数组件中缓存计算结果,优化性能。
  6. useCallback:用于在函数组件中缓存函数引用,避免不必要的重新创建。
  7. useRef:用于在函数组件中创建可变的 ref 对象。
  8. useLayoutEffect:类似于 useEffect,但在 DOM 变更后同步触发,用于处理 DOM 相关操作。

关于 useMemomemouseCallback 的使用方法:

  • useMemo:接收一个函数和一个依赖项数组,在依赖项发生变化时重新计算函数的返回值,并缓存返回值,避免不必要的重复计算。

    const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
    
  • memo:接收一个组件函数,并返回一个新的高阶组件,用于优化组件的渲染性能,只在组件的 props 发生变化时重新渲染。

    const MemoizedComponent = memo(MyComponent);
    
  • useCallback:接收一个函数和一个依赖项数组,在依赖项发生变化时返回一个记忆化的函数引用,避免不必要的函数重新创建。

    const memoizedCallback = useCallback(() => {
      doSomething(a, b);
    }, [a, b]);
    

关于 useEffect 只在销毁时执行的情况,可以通过在 useEffect 的回调函数中返回一个清理函数,在清理函数中执行销毁时的操作。这样可以确保在组件卸载时执行清理工作。

useEffect(() => {
  // 在组件挂载时执行初始化操作

  return () => {
    // 在组件卸载时执行清理操作
  };
}, []); // 注意传入空依赖项数组,确保只在挂载和卸载时执行

作者://鲨鱼辣椒
链接:www.nowcoder.com/feed/main/d…
来源:牛客网