前端面经(字节)------持续更新

1. JS数据类型有哪些?

JS数据类型分为两类

  • 基本数据类型(也叫简单数据类型),包含7种类型,分别是:
    Number,String,Boolean,Null,Undefined,Symbol,BigInt。
  • 另一类是引用数据类型也叫复杂数据类型,通常用Object代表(普通对象,数组,正则,日期,Math数学函数都属于Object)。

数据分成两大类的本质区别:

基本数据类型和引用数据类型它们在内存中的存储方式不同

  • 基本数据类型是直接存储在栈中的简单数据段,占据空间小,属于被频繁使用的数据。
  • 引用数据类型是存储在堆内存中,占据空间大。引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址,当解释器寻找引用值时,会检索其在栈中的地址,取得地址后从堆中获得实体。

扩展:
(1) Symbol是ES6新出的一种数据类型,这种数据类型的特点就是没有重复的数据,可以作为object的key。
数据的创建方法:

 const symbol1 = Symbol('foo')

因为它的构造不完整,所以不能使用new Symbol()创建数据。
由于Symbol()创建的数据具有唯一性,所以Symbol()!==Symbol()。
同时使用Symbol数据作为key不能使用for获取到这个key值,需要使用Object.getOwnPropertySymbols(obj)获得这个obj对象中key类型是Symbol的key值。

let key = Symbol('key');
let obj = { [key]: 'symbol'};
let keyArray = Object.getOwnPropertySymbols(obj); // 返回一个数组[Symbol('key')]
obj[keyArray[0]] // 'symbol'

MDN上对于Symbol的介绍(比较官方化):
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol
阮一峰ES6教程中对Symbol介绍的比较详细:
https://es6.ruanyifeng.com/#docs/symbol
一篇通俗易懂的symbol简单介绍:
https://www.zhangxinxu.com/wordpress/2018/04/known-es6-symbol-function/
(2)BigInt也是ES6新出的一种数据类型,这种数据类型的特点就是数据涵盖的范围大,能够解决超出普通数据类型范围报错的问题。
Number的范围:
JavaScript中Number范围为正负2的53次方,
也即从最小值-9007199254740992到最大值+9007199254740992之间的范围,
BigInt可以处理超出Number范围的数。
使用:
可以用在一个整数字面量后面加 n 的方式定义一个 BigInt ,如:10n,或者调用函数 BigInt()(但不包含 new 运算符)并传递一个整数值或字符串值。

const theBiggestInt = 9007199254740991n;

const alsoHuge = BigInt(9007199254740991);
// ↪ 9007199254740991n

const hugeString = BigInt("9007199254740991");
// ↪ 9007199254740991n

const hugeHex = BigInt("0x1fffffffffffff");
// ↪ 9007199254740991n

const hugeBin = BigInt("0b11111111111111111111111111111111111111111111111111111");
// ↪ 9007199254740991n
  • 注意:BigInt和Number之间不能进行混合操作。
    可以看到咱们控制台的运算结果报的错误。
    在这里插入图片描述

一篇比较好的BigInt基本介绍:
https://segmentfault.com/a/1190000019912017
来自MDN官方介绍:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/BigInt

2. 如何判断是Null

使用Object.prototype.toString.call()
在这里插入图片描述

如何判断数组

  1. arr instanceof Array
    在这里插入图片描述
  2. Object.prototype.toString.call()

JavaScript判断变量类型的方法

JavaScript有4种方法判断变量的类型,分别是:
typeof
instanceof
Object.prototype.toString.call()(对象原型链判断方法)
constructor (用于引用数据类型)

1. typeof

常用于判断基本数据类型,对于引用数据类型除了function返回’function‘,其余全部返回’object’。
这里值得注意的是typeof null 返回的也是object
null作为一个基本数据类型为什么会被typeof运算符识别为object类型呢? 这是因为javascript中不同对象在底层都表示为二进制,而javascript 中会把二进制前三位都为0的判断为object类型,而null的二进制表示全都是0,自然前三位也是0,所以执行typeof时会返回’object。

具体案例(用法):

const num1 = 1;
const str1 = "icyakuya";
const comicList = ["凡人修仙传", "斗破苍穹", "吞噬星空"];
const big = BigInt(999999999999999999999999999999999);
const symbol = Symbol("icy");
const happyDay = {
 play: "出去玩",
 game: "打电动",
 eatting: "吃好吃的",
 sleepping: "睡到自然醒",
};
const myFunc = () => {
 return "icygodlike";
};
/* 基本数据类型 */
console.log(typeof num1); // number
console.log(typeof str1); //string
console.log(typeof undefinded); //undefinded
console.log(typeof null); //object
console.log(typeof true); //boolean
console.log(typeof big); //bigInt
console.log(typeof symbol); //symbol
/* 函数 */
console.log(typeof myFunc); //function
/* 引用数据类型 */
console.log(typeof comicList); //object
console.log(typeof happyDay); //object

输出的结果按顺序依次如下:
在这里插入图片描述

2. instanceof

主要用于区分引用数据类型,检测方法是检测的类型在当前实例的原型链上,用其检测出来的结果都是true,不太适合用于简单数据类型的检测,检测过程繁琐且对于简单数据类型中的undefined, null, symbol检测不出来。

具体案例(用法):

/*无法用来检测基本数据类型*/
console.log(num1 instanceof Number); //false
console.log(str1 instanceof String); //false
//boolean, null ,undefinded ,bigInt ,symbol 数据类型均无法检测

/* 引用数据类型 */
console.log(myFunc instanceof Function); //true
console.log(myFunc instanceof Object); //true
console.log(comicList instanceof Array); //true
console.log(comicList instanceof Object); //true
console.log(happyDay instanceof Object); //true

注意点:可以看到,函数myFunc既是函数又是对象,comicList既是数组又是对象,这里涉及到原型链的问题,不了解的可以去学习js原型链相关概念。

instanceof的实现原理
验证当前类的原型prototype是否会出现在实例的原型链__proto__上,只要在它的原型链上,则结果都为true。因此,instanceof 在查找的过程中会遍历左边变量的原型链,直到找到右边变量的 prototype,找到返回true,未找到返回false。
想深入了解可以参考MDN官方介绍:
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/instanceof

4. constructor

用于检测引用数据类型,检测方法是获取实例的构造函数判断和某个类型是否相同,如果相同就说明该数据是符合那个数据类型的,这种方法不会把原型链上的其他类也加入进来,避免了原型链的干扰。
用法案例

/* 引用数据类型 */
console.log(myFunc.constructor); // [Function:Function]
console.log(comicList.constructor); // [Function:Array]
console.log(happyDay.constructor); //[Function:Obejct]

console.log(myFunc.constructor === Function); // true
console.log(comicList.constructor === Array); // true
console.log(happyDay.constructor === Object); //true

注意点,constructor可能会被继承影响,而instanceof不会,具体如下:

function A() {}
function B() {}
const a = new A();
B.prototype = new A(); //让B继承自A
const b = new B(); //创建B是实例

console.log(a.constructor); //[Function:A]
console.log(b.constructor); // [Function:A]   可见,继承会影响constructor的判断,让它的类型指向父类

console.log(b instanceof A); //true
console.log(b instanceof B); //true  可见instanceof 并没有被继承影响

//解决方案,让b的constructor手动指向B
b.constructor = B;
console.log(b.constructor); //[function: B]
5. Object.prototype.toString.call()

适用于所有类型的判断检测,检测方法是Object.prototype.toString.call(数据) 返回的是该数据类型的字符串。

Object.prototype.toString.call()原理
Object.prototype.toString 返回一个对象类型的字符串,call()方法可以改变this的指向,那么把Object.prototype.toString()方法指向不同的数据类型上面,返回不同的结果

用法示例:

const num1 = 1;
const str1 = "icyakuya";
let unknown; //undefinded
const comicList = ["凡人修仙传", "斗破苍穹", "吞噬星空"];
const big = BigInt(999999999999999999999999999999999);
const symbol = Symbol("icy");
const happyDay = {
  play: "出去玩",
  game: "打电动",
  eatting: "吃好吃的",
  sleepping: "睡到自然醒",
};
const myFunc = () => {
  return "icygodlike";
};
const date = new Date(); //日期
function A() {} //构造函数
const a = new A(); //构造函数实例

console.log(Object.prototype.toString.call(num1)); //[object Number]
console.log(Object.prototype.toString.call(num1) === "[object Number]"); //true
console.log(Object.prototype.toString.call(str1)); // [objec String]
console.log(Object.prototype.toString.call(str1) === "[object String]"); //true
console.log(Object.prototype.toString.call(unknown)); //[objec Undefinded]
console.log(Object.prototype.toString.call(null)); //[objec Null]
console.log(Object.prototype.toString.call(comicList)); //[objec Array]
console.log(Object.prototype.toString.call(big)); //[objec BigInt]
console.log(Object.prototype.toString.call(symbol)); //[objec Symbol]
console.log(Object.prototype.toString.call(happyDay)); //[objec Object]
console.log(Object.prototype.toString.call(myFunc)); //[objec Function]
console.log(Object.prototype.toString.call(date)); //[objec Date]
console.log(Object.prototype.toString.call(A)); //[objec Function]
console.log(Object.prototype.toString.call(a)); //[objec Object]

输出结果:

在这里插入图片描述
总结: 这四种判断数据类型的方法中,各种数据类型都能检测且检测精准的就是Object.prototype.toString.call() 这种方法。

3. 浏览器是单线程还是多线程

浏览器通常是多线程的。浏览器需要处理多个任务,比如渲染网页、处理用户输入、下载资源等,因此通常会使用多线程来提高效率和响应速度。例如,浏览器可能会有一个线程负责渲染页面,一个线程负责处理用户输入,一个线程负责网络请求等。这样可以让浏览器在处理多个任务时更加高效。

详细版本:
浏览器通常是多进程的,每个标签页通常都在单独的进程中运行,这样可以提高稳定性和安全性。在每个进程内部,浏览器通常会使用多线程来处理不同的任务。
其中,主要的线程包括:
渲染线程:负责将 HTML、CSS 和 JavaScript 转换为用户可以交互的页面。通常情况下,浏览器会使用多个渲染线程来加快页面的渲染速度。
JavaScript 引擎线程:负责处理 JavaScript 代码,例如执行 JavaScript 代码、处理事件等。现代浏览器通常会使用多线程来加速 JavaScript 的执行。
定时器线程:负责处理定时器,例如 setTimeout 和 setInterval。
事件触发线程:负责处理用户输入、网络请求等事件。
网络请求线程:负责处理网络请求,例如下载资源、发送请求等。
这些线程之间会通过线程同步和通信来协调工作,以确保浏览器能够高效地处理各种任务,并提供良好的用户体验。

4. web worker

解释:
Web Worker 是 HTML5 提供的一种技术,它允许在浏览器中运行后台脚本,从而在主线程之外执行代码。
作用:
Web Worker 的主要作用是在不阻塞用户界面的情况下执行耗时的 JavaScript 代码,从而提高页面的响应速度和性能。
应用场景:
Web Worker 的使用场景包括但不限于:
计算密集型任务:例如大量数据的排序、搜索算法等,这些任务可能会占用大量的 CPU 资源,如果在主线程中执行,会导致页面卡顿,使用 Web Worker 可以将这些任务转移到后台线程中执行,不影响用户界面的响应。
大规模数据处理:例如图像处理、音视频处理等,这些任务可能需要大量的时间来处理,使用 Web Worker 可以在后台线程中进行处理,不影响用户的交互体验。
网络请求和数据处理:例如在后台线程中进行数据的预处理、解析等,可以加快页面加载速度。
Web Worker 的工作原理是通过创建一个新的线程来执行 JavaScript 代码,这个线程与主线程相互独立,可以进行计算和处理任务,但不能直接操作 DOM。主线程和 Web Worker 之间通过消息传递进行通信,这样可以确保在不阻塞用户界面的情况下进行后台任务的处理。需要注意的是,由于 Web Worker 不能直接操作 DOM,因此在使用时需要注意如何与主线程进行通信和数据交换。

5. 前端布局有哪些

前端布局有很多种方式,其中一些常见的包括:

  1. 盒模型布局:基于盒模型的布局是前端开发中最基本的布局方式,通过设置元素的宽度、高度、内边距和外边距来实现页面布局。
  2. Flexbox 布局:Flexbox 是一种弹性盒子布局模型,通过设置容器和子元素的属性,可以实现灵活的布局,特别适合于排列一维的元素,如导航菜单、工具栏等。
  3. Grid 布局:CSS Grid Layout 是一种二维的布局系统,可以将页面划分为行和列,通过设置网格容器和网格项的属性,实现复杂的页面布局。
  4. 响应式布局:响应式布局是指根据设备的不同尺寸和屏幕分辨率,为网站提供不同的布局和样式,以适应不同的设备和屏幕大小,提高用户体验。
  5. 浮动布局:通过设置元素的浮动属性,使得元素可以脱离文档流,实现多栏布局等效果。
  6. 定位布局:使用相对定位、绝对定位和固定定位来实现元素的精确定位,常用于实现特定位置的布局效果。
  7. 网格布局:通过使用网格系统,将页面划分为等宽的列,可以方便地实现栅格化布局,适用于响应式设计。
    这些布局方式可以单独应用,也可以结合使用,根据具体的页面需求和设计要求选择合适的布局方式。

6. diff算法

Diff算法是一种用于比较两个数据结构之间差异的算法。在前端开发中,Diff算法通常用于比较虚拟DOM树的变化,以便在更新页面时尽可能高效地更新真实DOM。
最经典的Diff算法是由Paul Heckel在1978年提出的,被称为"Edit Distance"算法。这个算法的时间复杂度是O(n^2),其中n是数据集的大小。Diff算法的核心思想是尽可能地找出两个数据集之间的最小差异。

Diff算法的过程可以分为以下几个步骤:

  1. 生成虚拟DOM树:在前端框架中,当状态发生变化时,会重新生成虚拟DOM树。
  2. 比较新旧虚拟DOM树:Diff算法会递归地比较新旧虚拟DOM树的节点,找出它们之间的差异。
  3. 标记差异:在比较过程中,Diff算法会标记出新增、删除和更新的节点,以及节点内部的文本内容或属性的变化。
  4. 应用差异:最终,Diff算法会根据标记的差异,只更新真实DOM中发生变化的部分,从而提高页面更新的效率。

在实际应用中,Diff算法通常会结合一些启发式的优化策略,例如只比较同级元素、使用唯一标识符进行快速查找等,以提高算法的效率。这些优化策略可以帮助Diff算法在实际应用中更快地找出数据集之间的差异,从而减少页面更新时的开销。

总的来说,Diff算法在前端开发中扮演着非常重要的角色,它通过高效地比较数据集之间的差异,帮助前端框架实现了虚拟DOM的高效更新,从而提高了页面的性能和用户体验。

7. react生命周期 ,每个生命周期都做了什么?

在这里插入图片描述

React 组件的生命周期可以分为三个阶段:挂载阶段、更新阶段和卸载阶段。每个生命周期方法都有特定的目的和功能。

  1. 挂载阶段:

    • constructor:组件的构造函数,在组件被创建时调用,用于初始化状态和绑定方法。
    • static getDerivedStateFromProps:在组件实例化和每次接收新的 props 时被调用,用于根据新的 props 更新状态。
    • render:根据组件的状态和属性返回 JSX 元素。
    • componentDidMount:在组件被挂载到 DOM 后立即调用,可以进行异步数据获取、订阅事件等操作。
  2. 更新阶段:

    • static getDerivedStateFromProps:在接收到新的 props 或 state 时被调用,用于根据新的 props 或 state 更新状态。
    • shouldComponentUpdate:在组件更新前被调用,用于控制组件是否需要重新渲染,默认返回 true。
    • render:根据组件的状态和属性返回 JSX 元素。
    • getSnapshotBeforeUpdate:在 render 方法之后、更新 DOM 之前被调用,用于获取更新前的 DOM 快照。
    • componentDidUpdate:在组件更新后被调用,可以进行 DOM 操作或发送网络请求等操作。
  3. 卸载阶段:

    • componentWillUnmount:在组件被卸载前调用,可以进行清理操作,如取消订阅、清除定时器等。

除了上述生命周期方法,还有一些其他的生命周期方法,如错误边界相关的 componentDidCatch 方法,用于捕获子组件中的错误。

需要注意的是,由于 React Hooks 的引入,部分生命周期方法已经不再推荐使用。可以使用 useEffect Hook 来代替 componentDidMount、componentDidUpdate 和 componentWillUnmount。

具体介绍

render()

render() 方法是 class 组件中唯一必须实现的方法。当 render 被调用时,它会检查 this.props 和 this.state 的变化并返回以下类型之一:

  • React 元素。
    通常通过 JSX 创建。例如,<div /> 会被 React 渲染为 DOM 节点,<MyComponent />会被 React 渲染为自定义组件,无论是 <div /> 还是 <MyComponent /> 均为 React 元素。
  • 数组或 fragments。 使得 render 方法可以返回多个元素。欲了解更多详细信息,请参阅 fragments 文档。
  • Portals。可以渲染子节点到不同的 DOM 子树中。欲了解更多详细信息,请参阅有关 portals 的文档
  • 字符串或数值类型。它们在 DOM 中会被渲染为文本节点
  • 布尔类型或 null。什么都不渲染。(主要用于支持返回 test && 的模式,其中 test 为布尔类型。)
    render() 函数应该为纯函数,这意味着在不修改组件 state 的情况下,每次调用时都返回相同的结果,并且它不会直接与浏览器交互。

如需与浏览器进行交互,请在 componentDidMount() 或其他生命周期方法中执行你的操作。保持 render() 为纯函数,可以使组件更容易思考。
React中,Portal是一种机制,用于将组件的渲染结果插入到DOM树的不同位置,而不是直接插入到其父组件的DOM节点中。这在某些情况下非常有用,例如当你需要在React组件的层次结构之外渲染内容时。

使用Portal的步骤如下:

  1. 导入React和ReactDOM,因为Portal需要ReactDOM来渲染到不同的DOM位置。
import React from 'react';
import ReactDOM from 'react-dom';
  1. 在组件中创建一个容器元素,用于渲染Portal内容。这个容器元素可以是任何有效的DOM元素,但通常会在组件的顶层进行创建。
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.portalContainer = document.createElement('div');
  }

  componentDidMount() {
    document.body.appendChild(this.portalContainer);
  }

  componentWillUnmount() {
    document.body.removeChild(this.portalContainer);
  }

  render() {
    return null; // Portal不会渲染任何内容,它只是提供一个容器
  }
}
  1. 在组件需要的地方使用Portal进行渲染。使用ReactDOM.createPortal方法将组件的渲染结果渲染到创建的容器元素中。
class MyComponent extends React.Component {
  // ...

  render() {
    return ReactDOM.createPortal(
      <div>Portal内容</div>,
      this.portalContainer
    );
  }
}

在上面的例子中,我们在MyComponent组件的顶层创建了一个容器元素this.portalContainer。在组件的render方法中,使用ReactDOM.createPortal方法将一个包含内容的div元素渲染到这个容器元素中。

请注意,当组件被卸载时,需要手动从DOM中移除容器元素,以防止内存泄漏。在上面的例子中,我们在componentWillUnmount生命周期方法中移除了容器元素。

通过使用Portal,我们可以在React组件的层次结构之外渲染内容,这为处理一些特殊情况提供了更大的灵活性。

constructor()

如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数。

在 React 组件挂载之前,会调用它的构造函数。在为 React.Component 子类实现构造函数时,应在其他语句之前前调用 super(props)。否则,this.props 在构造函数中可能会出现未定义的 bug。
通常,在 React 中,构造函数仅用于以下两种情况:
通过给 this.state 赋值对象来初始化内部 state。

  • 为事件处理函数绑定实例
  • 在 constructor() 函数中不要调用 setState() 方法。如果你的组件需要使用内部 state,请直接在构造函数中为 this.state 赋值初始 state。

只能在构造函数中直接为 this.state 赋值。如需在其他方法中赋值,你应使用 this.setState() 替代。

要避免在构造函数中引入任何副作用或订阅。如遇到此场景,请将对应的操作放置在 componentDidMount 中。

componentDidMount()

componentDidMount() 会在组件挂载后(插入 DOM 树中)立即调用。依赖于 DOM 节点的初始化应该放在这里。如需通过网络请求获取数据,此处是实例化请求的好地方。

这个方法是比较适合添加订阅的地方。如果添加了订阅,请不要忘记在 componentWillUnmount() 里取消订阅

你可以在 componentDidMount() 里直接调用 setState()。它将触发额外渲染,但此渲染会发生在浏览器更新屏幕之前。如此保证了即使在 render() 两次调用的情况下,用户也不会看到中间状态。请谨慎使用该模式,因为它会导致性能问题。通常,你应该在 constructor() 中初始化 state。如果你的渲染依赖于 DOM 节点的大小或位置,比如实现 modals 和 tooltips 等情况下,你可以使用此方式处理。

componentDidUpdate()

componentDidUpdate() 会在更新后会被立即调用。首次渲染不会执行此方法。

当组件更新后,可以在此处对 DOM 进行操作。如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求。(例如,当 props 未发生变化时,则不会执行网络请求)。

componentDidUpdate(prevProps) {
  // 典型用法(不要忘记比较 props):
  if (this.props.userID !== prevProps.userID) {
    this.fetchData(this.props.userID);
  }
}

你也可以在 componentDidUpdate() 中直接调用 setState(),但请注意它必须被包裹在一个条件语句里,正如上述的例子那样进行处理,否则会导致死循环。它还会导致额外的重新渲染,虽然用户不可见,但会影响组件性能。不要将 props “镜像”给 state,请考虑直接使用 props。 欲了解更多有关内容,请参阅为什么 props 复制给 state 会产生 bug。

如果组件实现了 getSnapshotBeforeUpdate() 生命周期(不常用),则它的返回值将作为 componentDidUpdate() 的第三个参数 “snapshot” 参数传递。否则此参数将为 undefined。

componentWillUnmount()

componentWillUnmount() 会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等。

componentWillUnmount() 中不应调用 setState(),因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。

shouldComponentUpdate()

根据 shouldComponentUpdate() 的返回值,判断 React 组件的输出是否受当前 state 或 props 更改的影响。默认行为是 state 每次发生变化组件都会重新渲染。大部分情况下,你应该遵循默认行为。

当 props 或 state 发生变化时,shouldComponentUpdate() 会在渲染执行之前被调用。返回值默认为 true。首次渲染或使用 forceUpdate() 时不会调用该方法。

此方法仅作为性能优化的方式而存在。不要企图依靠此方法来“阻止”渲染,因为这可能会产生 bug。你应该考虑使用内置的 PureComponent 组件,而不是手动编写 shouldComponentUpdate()。PureComponent 会对 props 和 state 进行浅层比较,并减少了跳过必要更新的可能性。

如果你一定要手动编写此函数,可以将 this.props 与 nextProps 以及 this.state 与nextState 进行比较,并返回 false 以告知 React 可以跳过更新。请注意,返回 false 并不会阻止子组件在 state 更改时重新渲染。

我们不建议在 shouldComponentUpdate() 中进行深层比较或使用 JSON.stringify()。这样非常影响效率,且会损害性能。

目前,如果 shouldComponentUpdate() 返回 false,则不会调用 UNSAFE_componentWillUpdate(),render() 和 componentDidUpdate()。后续版本,React 可能会将 shouldComponentUpdate 视为提示而不是严格的指令,并且,当返回 false 时,仍可能导致组件重新渲染。

static getDerivedStateFromProps()

getDerivedStateFromProps 会在调用 render 方法之前调用,并且在初始挂载及后续更新时都会被调用。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。

此方法适用于罕见的用例,即 state 的值在任何时候都取决于 props。例如,实现 组件可能很方便,该组件会比较当前组件与下一组件,以决定针对哪些组件进行转场动画。

派生状态会导致代码冗余,并使组件难以维护。 确保你已熟悉这些简单的替代方案:

如果你需要执行副作用(例如,数据提取或动画)以响应 props 中的更改,请改用 componentDidUpdate。
如果只想在 prop 更改时重新计算某些数据,请使用 memoization helper 代替。
如果你想在 prop 更改时“重置”某些 state,请考虑使组件完全受控或使用 key 使组件完全不受控代替。
此方法无权访问组件实例。如果你需要,可以通过提取组件 props 的纯函数及 class 之外的状态,在getDerivedStateFromProps()和其他 class 方法之间重用代码。

请注意,不管原因是什么,都会在每次渲染前触发此方法。这与 UNSAFE_componentWillReceiveProps 形成对比,后者仅在父组件重新渲染时触发,而不是在内部调用 setState 时。

getSnapshotBeforeUpdate()

getSnapshotBeforeUpdate() 在最近一次渲染输出(提交到 DOM 节点)之前调用。它使得组件能在发生更改之前从 DOM 中捕获一些信息(例如,滚动位置)。此生命周期方法的任何返回值将作为参数传递给 componentDidUpdate()。

此用法并不常见,但它可能出现在 UI 处理中,如需要以特殊方式处理滚动位置的聊天线程等。

应返回 snapshot 的值(或 null)。

Error boundaries

Error boundaries 是 React 组件,它会在其子组件树中的任何位置捕获 JavaScript 错误,并记录这些错误,展示降级 UI 而不是崩溃的组件树。Error boundaries 组件会捕获在渲染期间,在生命周期方法以及其整个树的构造函数中发生的错误。

如果 class 组件定义了生命周期方法 static getDerivedStateFromError() 或 componentDidCatch() 中的任何一个(或两者),它就成为了 Error boundaries。通过生命周期更新 state 可让组件捕获树中未处理的 JavaScript 错误并展示降级 UI。

仅使用 Error boundaries 组件来从意外异常中恢复的情况;不要将它们用于流程控制。

static getDerivedStateFromError()

此生命周期会在后代组件抛出错误后被调用。 它将抛出的错误作为参数,并返回一个值以更新 state。

componentDidCatch()

此生命周期在后代组件抛出错误后被调用。 它接收两个参数:

error —— 抛出的错误。
info —— 带有 componentStack key 的对象,其中包含有关组件引发错误的栈信息。
componentDidCatch() 会在“提交”阶段被调用,因此允许执行副作用。 它应该用于记录错误之类的情况。

React 的开发和生产构建版本在 componentDidCatch() 的方式上有轻微差别。

在开发模式下,错误会冒泡至 window,这意味着任何 window.onerror 或 window.addEventListener(‘error’, callback) 会中断这些已经被 componentDidCatch() 捕获的错误。

相反,在生产模式下,错误不会冒泡,这意味着任何根错误处理器只会接受那些没有显式地被 componentDidCatch() 捕获的错误。

8. 浏览器关闭后,react生命周期

当浏览器关闭后,React 中的组件生命周期会经历以下阶段:

  1. componentWillUnmount:在组件即将被卸载和销毁时调用。你可以在这个方法中进行一些清理工作,比如清除定时器、取消网络请求、销毁一些非 React 的实例等。
  2. componentDidUnmount:在组件被卸载和销毁后调用。这是进行一些清理工作的最后机会,可以进行一些必要的清理操作,但是在这个阶段已经不能再执行 setState 了。
    这两个生命周期方法会在组件即将被销毁和被销毁后被调用,可以用来做一些清理工作,确保组件在被销毁时不会留下一些不必要的副作用。

9. 解决跨域

跨域是什么?如何解决?

跨域:当前页面中某个接口请求的地址和当前页面的地址,如果协议,域名,端口其中有一项不同,就说名该接口跨域了。
跨域限制的原因:浏览器为了保证网页的安全,出的同源协议策略。
跨域解决方案

  1. cors 通过服务端设置允许跨域实现
    如设置:res.setHeader(‘Acess-Control-Allow-Origin’,‘*’);
    res.setHeader(“Access-Control-Allow-Methods”, “GET, PUT, OPTIONS, POST”);
  2. JSONP (比较老了,据说是当年的程序猿想出的临时解决方法)
    原理:script标签可以跨域请求资源,将回调函数作为参数拼接在url中。后端收到该请求,拼接成回调函数并且调用,将数据作为参数返回出去,前端运行script就能拿到后端返回的资源。
  3. 代理
    如node中间件,niginx反向代理,当然还有我们常用的proxyLight。
    原理:虽然跨域限制的时候浏览器不能跨域访问服务器,但是node中间件和其他代理方式都是让请求发给代理服务器,静态页面和代理服务器是同源的,然后代理服务器再向后端服务器发起请求,服务器和服务器之间没有同源策略。
  4. postMessage: H5新增的API,通过发送和接受API实现跨域通信。
    mdn上的解释是:
    window.postMessage() 方法可以安全地实现跨源通信。通常,对于两个不同页面的脚本,只有当执行它们的页面位于具有相同的协议(通常为 https),端口号(443 为 https 的默认值),以及主机 (两个页面的模数 Document.domain设置为相同的值) 时,这两个脚本才能相互通信。window.postMessage() 方法提供了一种受控机制来规避此限制,只要正确的使用,这种方法就很安全。
    使用方法:
    发送数据用postMessage,接收数据是监听message事件:element.addEventListener(‘message’, callback)
    如:otherWindow.postMessage(message, targetOrigin, [transfer]);
    window.addEventListener(‘message’, function (e) {})
    message 的属性有:
    data
    从其他 window 中传递过来的对象。
    origin
    调用 postMessage 时消息发送方窗口的 origin . 这个字符串由 协议、“😕/“、域名、“ : 端口号”拼接而成。例如 “https://example.org (隐含端口 443)”、“http://example.net (隐含端口 80)”、“http://example.com:8080”。请注意,这个 origin 不能保证是该窗口的当前或未来 origin,因为 postMessage 被调用后可能被导航到不同的位置。
    source
    对发送消息的窗口对象的引用;
    这里引用mdn官方原话,很好解释了使用postMessage时候的安全问题。
    安全问题:
    如果不希望从其他网站接收 message,请不要为 message 事件添加任何事件侦听器。 这是一个完全万无一失的方式来避免安全问题。

如果希望从其他网站接收 message,请始终使用 origin 和 source 属性验证发件人的身份。 任何窗口(包括例如 http://evil.example.com)都可以向任何其他窗口发送消息,并且您不能保证未知发件人不会发送恶意消息。 但是,验证身份后,您仍然应该始终验证接收到的消息的语法。 否则,您信任只发送受信任邮件的网站中的安全漏洞可能会在您的网站中打开跨网站脚本漏洞。

当使用 postMessage 将数据发送到其他窗口时,始终指定精确的目标 origin,而不是*。 恶意网站可以在您不知情的情况下更改窗口的位置,因此它可以拦截使用 postMessage 发送的数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/233979.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

perl处理base64、md5、SHA-1、SHA-256的计算

使用perl可以进行base64、md5、SHA-1、SHA-256的计算&#xff0c;使用也非常方便&#xff0c;下面是示例代码&#xff1a; #! /usr/bin/perl use v5.14; use MIME::Base64; use Digest;my $test_str hello world;# 测试base64 say encode_base64($test_str);# 测试md5 my $md…

Rsync+Sersync

服务器相关参数 源服务器 192.168.17.101 目标服务器&#xff08;同步到的服务器&#xff09; 192.168.17.103 ##目标服务器配置 ###1、配置rsync服务 1、安装rsync yum -y install rsync 2、配置rsync vim /etc/rsyncd.conf 配置文件内容 uid root gid root use c…

Jenkins+Ant+Jmeter接口自动化集成测试

一、Jenkins安装配置 1、安装配置JDK1.6环境变量&#xff1b; 2、下载jenkins.war&#xff0c;放入C:\jenkins目录下&#xff0c;目录位置随意&#xff1b; Jenkins启动方法&#xff1a; cmd进入Jenkins目录下&#xff0c;执行java -jar jenkins.war 浏览器输入&#xff1a;l…

网络协议疑点记录

1.RIP, OSPF,BGP 首先什么是自治系统:治系统就是几个路由器组成了一个小团体 ?,小团体内部使用专用的协议进行通信,而小团体和小团体之间也使用专用的协议进行通信。 IGP RIP 距离矢量路由算法,bellman-ford算法,每个路由节点知道全局的路由信息,通过和邻居交换信息得…

【MySQL进阶】索引使用

一、索引使用 1.验证索引效率 tb_sku 这张表中准备了 1000w 的记录。 我用夸克网盘分享了「1000w的模拟数据」链接&#xff1a;https://pan.quark.cn/s/15cf665202b2 这张表中id为主键&#xff0c;有主键索引&#xff0c;而其他字段是没有建立索引的。 我们先来查询其中的…

「Verilog学习笔记」多bit MUX同步器

专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点&#xff0c;刷题网站用的是牛客网 输入数据暂存在data_reg中&#xff0c;使能信号data_en用打两拍的方式跨时钟域传输到时钟域B&#xff0c;最后data_out根据使能信号更新数据。data_en信号在A时钟域用一个D…

Spring Boot的配置文件

配置文件的作用 整个项目中所有重要的数据都是在配置文件中配置&#xff0c;如数据库的连接信息&#xff0c;项目的启动端口&#xff0c;用于发现和定位问题的普通日志和异常日志等等。配置文件可以分为两类 系统使用的配置文件&#xff08;系统配置文件&#xff09;&#xf…

309. 买卖股票的最佳时机含冷冻期(leetcode) 动态规划思想

文章目录 前言一、题目分析二、算法原理1.状态表示2.状态转移方程3.初始化边界条件4.填表顺序5.返回值是什么 三、代码实现总结 前言 在本文章中&#xff0c;我们将要详细介绍一下Leetcode中买卖股票的最佳时机含冷冻期相关的内容&#xff0c;本题采用动态规划的思想解决 一、…

Oracle高可用一家老小全在这里

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

打工人副业变现秘籍,某多/某手变现底层引擎-Stable Diffusion写好提示词

Stable Diffusion 是一种文生图 AI 模型,由互联网上数百万图像和文本描述对训练而来,通过理解文本描述与图像信息的内在关联,不断利用扩散过程进而得到满意的生成图片。 比如,通过一串提示词,midjourney 会输出这样的情侣合照: A pair of young Chinese lovers, wearing…

【机器学习】040_理解偏差与方差

一、定义 偏差&#xff1a;衡量预测值与真实值之间的关系——指预测值和真实值之间差值 方差&#xff1a;衡量预测值之间的关系&#xff0c;与真实值无关——指各个预测值之间的离散程度 误差 偏差 方差 高偏差——模型欠拟合&#xff1b; 高方差——模型过拟合&#…

【已解决】解决UbuntuKali无法进行SSH远程连接

目录 Ubuntu20.04配置SSH远程连接Kali Linux配置SSH远程连接 Ubuntu20.04配置SSH远程连接 首先更新安装包 sudo apt-get update 下载SSH服务 sudo apt install openssh-server 查看SSH服务 service ssh status 打开 /etc/ssh/sshd_config文件修改配置文件 将PermitRootLog…

万户协同办公平台ezoffice wpsservlet接口任意文件上传漏洞

声明 本文仅用于技术交流&#xff0c;请勿用于非法用途 由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;文章作者不为此承担任何责任。 一、漏洞描述 万户ezOFFICE协同管理平台是一个综合信息基础应用平台&am…

JUC包(面试常问)

1. Callable接口 类似于Runnable接口&#xff0c;Runnable描述的任务&#xff0c;不带返回值&#xff1b;Callable描述的任务带返回值。 public class Test {//创建线程&#xff0c;计算12...1000public static void main(String[] args) throws ExecutionException, Interru…

论文阅读《Domain Generalized Stereo Matching via Hierarchical Visual Transformation》

论文地址&#xff1a;https://openaccess.thecvf.com/content/CVPR2023/html/Chang_Domain_Generalized_Stereo_Matching_via_Hierarchical_Visual_Transformation_CVPR_2023_paper.html 概述 立体匹配模型是近年来的研究热点。但是&#xff0c;现有的方法过分依赖特定数据集上…

输入一组数据,以-1结束输入[c]

我们新手写题时总能看到题目中类似这样的输入 没有给固定多少个数据&#xff0c;我们没有办法直接设置数组的元素个数&#xff0c;很纠结&#xff0c;下面我来提供一下本人的方法&#xff08;新手&#xff0c;看到有错误或者不好的地方欢迎大佬指出&#xff0c;纠正&#xff0…

20231210原始编译NanoPC-T4(RK3399)开发板的Android10的SDK

20231210原始编译NanoPC-T4(RK3399)开发板的Android10的SDK 2023/12/10 17:27 rootrootrootroot-X99-Turbo:~$ rootrootrootroot-X99-Turbo:~$ mkdir nanopc-t4 rootrootrootroot-X99-Turbo:~$ rootrootrootroot-X99-Turbo:~$ rootrootrootroot-X99-Turbo:~$ cd nanopc-t4/ …

如何理解java中的context对象?

背景 java中&#xff0c;常见的 Context 有很多, 例如: ServletContext, ActionContext, ServletActionContext, ApplicationContext, PageContext, SessionContext… 常见Context 熟悉spring是怎样在web容器中启动起来的。spring的启动过程其实就是其IoC容器的启动过程&…

盲盒小程序搭建:实现盲盒消费新体验

近几年来&#xff0c;潮玩市场中的盲盒逐渐席卷了年轻一代人的生活&#xff0c;吸引了不少消费者。盲盒的不确定性给消费者带来了惊喜和快乐&#xff0c;盲盒的商业价值也是逐渐增加&#xff0c;预计2024年盲盒市场规模将突破300亿元。 但在当下互联网快速发展的时代下&#x…

stu05-前端的几种常用开发工具

前端的开发工具有很多&#xff0c;可以说有几十种&#xff0c;包括记事本都可以作为前端的开发工具。下面推荐的是常用的几种前端开发工具。 1.DCloud HBuilder&#xff08;轻量级&#xff09; HBuilder是DCloud&#xff08;数字天堂&#xff09;推出的一款支持HTML5的web开发…
最新文章