前端面试题总结(react版)6

简介: 前端面试题总结(react版)6

19、 说说javascript内存泄漏的几种情况?

一、是什么

内存泄漏(Memory leak)是在计算机科学中,由于疏忽或错误造成程序未能释放已经不再使用的内存


并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费


程序的运行需要内存。只要程序提出要求,操作系统或者运行时就必须供给内存


对于持续运行的服务进程,必须及时释放不再用到的内存。否则,内存占用越来越高,轻则影响系统性能,重则导致进程崩溃

在C语言中,因为是手动管理内存,内存泄露是经常出现的事情。


char * buffer; buffer = (char*) malloc(42); // Do something with buffer free(buffer);


上面是 C 语言代码,malloc方法用来申请内存,使用完毕之后,必须自己用free方法释放内存。


这很麻烦,所以大多数语言提供自动内存管理,减轻程序员的负担,这被称为"垃圾回收机制"

二、垃圾回收机制

Javascript 具有自动垃圾回收机制(GC:Garbage Collecation),也就是说,执行环境会负责管理代码执行过程中使用的内存

原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存

通常情况下有两种实现方式:

  • 标记清除
  • 引用计数

标记清除

JavaScript最常用的垃圾收回机制

当变量进入执行环境是,就标记这个变量为“进入环境“。进入环境的变量所占用的内存就不能释放,当变量离开环境时,则将其标记为“离开环境“


垃圾回收程序运行的时候,会标记内存中存储的所有变量。然后,它会将所有在上下文中的变量,以及被在上下文中的变量引用的变量的标记去掉


在此之后再被加上标记的变量就是待删除的了,原因是任何在上下文中的变量都访问不到它们了


随后垃圾回收程序做一次内存清理,销毁带标记的所有值并收回它们的内存


举个例子:

var m = 0,n = 19 // 把 m,n,add() 标记为进入环境。
add(m, n) // 把 a, b, c标记为进入环境。
console.log(n) // a,b,c标记为离开环境,等待垃圾回收。
function add(a, b) {
  a++
  var c = a + b
  return c
}

引用计数

语言引擎有一张"引用表",保存了内存里面所有的资源(通常是各种值)的引用次数。如果一个值的引用次数是0,就表示这个值不再用到了,因此可以将这块内存释放

如果一个值不再需要了,引用数却不为 0 ,垃圾回收机制无法释放这块内存,从而导致内存泄漏

const arr = [1, 2, 3, 4];
console.log('hello world');

面代码中,数组[1, 2, 3, 4]是一个值,会占用内存。变量arr是仅有的对这个值的引用,因此引用次数为1。尽管后面的代码没有用到arr,它还是会持续占用内存

如果需要这块内存被垃圾回收机制释放,只需要设置如下:

arr = null

通过设置 arr null ,就解除了对数组 [1,2,3,4] 的引用,引用次数变为 0,就被垃圾回收了

小结

有了垃圾回收机制,不代表不用关注内存泄露。那些很占空间的值,一旦不再用到,需要检查是否还存在对它们的引用。如果是的话,就必须手动解除引用

三、常见内存泄露情况

意外的全局变量

function foo(arg) {
    bar = "this is a hidden global variable";
}

另一种意外的全局变量可能由 this 创建:

function foo() {
    this.variable = "potential accidental global";
}
// foo 调用自己,this 指向了全局对象(window)
foo();

上述使用严格模式,可以避免意外的全局变量

定时器也常会造成内存泄露

var someResource = getData();
setInterval(function() {
    var node = document.getElementById('Node');
    if(node) {
        // 处理 node 和 someResource
        node.innerHTML = JSON.stringify(someResource));
    }
}, 1000);

如果id为Node的元素从DOM中移除,该定时器仍会存在,同时,因为回调函数中包含对someResource的引用,定时器外面的someResource也不会被释放

包括我们之前所说的闭包,维持函数内局部变量,使其得不到释放

function bindEvent() {
  var obj = document.createElement('XXX');
  var unused = function () {
    console.log(obj, '闭包内引用obj obj不会被释放');
  };
  obj = null; // 解决方法
}

没有清理对 DOM 元素的引用同样造成内存泄露

const refA = document.getElementById('refA');
document.body.removeChild(refA); // dom删除了
console.log(refA, 'refA'); // 但是还存在引用能console出整个div 没有被回收
refA = null;
console.log(refA, 'refA'); // 解除引用

包括使用事件监听addEventListener监听的时候,在不监听的情况下使用removeEventListener取消对事件监听

20、 说说React生命周期中有哪些坑?如何避免?

避免生命周期中的坑需要做好两件事:1、不在恰当的时候调用了不该调用的代码;2、在需要调用时,不要忘了调用。

那么下面7种情况最容易造成生命周期的坑:

getDerivedStateFromProps 容易编写反模式代码,使受控组件和非受控组件区分模糊

componentWillMount 在 React 中已被标记弃用,不推荐使用,主要的原因是因为新的异步架构会导致它被多次调用,所以网络请求以及事件绑定应该放到 componentDidMount 中

componentWillReceiveProps 同样也被标记弃用,被 getDerivedStateFromProps 所取代,主要原因是性能问题。

shouldComponentUpdate 通过返回 true 或者 false 来确定是否需要触发新的渲染。主要用于性能优化。

componentWillUpdate 同样是由于新的异步渲染机制,而被标记废弃,不推荐使用,原先的逻辑可结合 getSnapshotBeforeUpdate 与 componentDidUpdate 改造使用。

如果在 componentWillUnmount 函数中忘记解除事件绑定,取消定时器等清理操作,容易引发 bug。

如果没有添加错误边界处理,当渲染发生异常时,用户将会看到一个无法操作的白屏,所以一定要添加。

追问:React 的请求应该放到哪里?为什么?

对于异步请求,应该放到componentDidMount 中去操作,从生命周期函数执行顺序来看,除了componentDidMount 之外还有下面两种选择:

constructor 中可以放,但是不推荐,因为 constructor 主要用于初始化 state 和函数绑定,并不承载业务逻辑,而且随着类属性的流行,constructor 很少用啦

componentWillMount 已被标记废弃,因为在新的异步渲染下该方法会触发多次渲染,容易引发bug,不利于 React 的后期维护和更新

所以React 的请求放在 componentDidMount 里是最好的选择。

21、 说说redux的实现原理是什么,写出核心代码?

前言

相信很多人都在使用redux作为前端状态管理库进去项目开发,但仍然停留在“知道怎么用,但仍然不知道其核心原理”的阶段,接下来带大家分析一下redux和react-redux两个库的核心思想和API

redux

1.为什么要使用redux?

随着互联网的高速发展,我们的应用变得越来越复杂,进行导致我们的组件之间的关系也变得日趋复杂,往往需要将状态父组件 -> 子组件 -> 子子组件 -> 又或者只是简单的 父组件与子组件之间的props传递也会导致我们的数据流变得难以维护,因为二次开发者不在熟悉项目的情况下无法第一时间确定数据来源是由谁发起的。使用redux之后,所有的状态都来自于store中的state,并且store通过react-redux中的Provider组件可以传递到Provider组件下的所有组件,也就是说store中的state对于Provider下的组件来说就是全局的。

2.redux的核心原理是什么?


1.将应用的状态统一放到state中,由store来管理state。

2.reducer的作用是返回一个新的state去更新store中对用的state。

3.按redux的原则,UI层每一次状态的改变都应通过action去触发,action传入对应的reducer 中,reducer返回一个新的state更新store中存放的state,这样就完成了一次状态的更新

4.subscribe是为store订阅监听函数,这些订阅后的监听函数是在每一次dipatch发起后依次执行

5.可以添加中间件对提交的dispatch进行重写

3.redux的api有哪些?

**1.**createStore 创建仓库,接受reducer作为参数

2.bindActionCreator 绑定store.dispatch和action 的关系

3.combineReducers 合并多个reducers

4.applyMiddleware 洋葱模型的中间件,介于dispatch和action之间,重写dispatch

5.compose 整合多个中间件

22、谈谈你对BFC的理解?


是什么?


我们在页面布局的时候,经常会出现下面几种情况


这个元素的高度怎么没了?


这两栏布局怎么没法自适应?


这两种元素的间距怎么有点奇怪的样子?


。。。


归根揭底是元素之间相互影响,导致了意料之外的情况,这里就涉及到了BFC概念。


BFC(Block Formatting Context),即块级格式化上下文,他是页面中的一块渲染区域,并且有属于自己一套的渲染规则。


1.内部的盒子会在垂直方向上一个接一个的放置。


2.对于同一个BFC的两个相邻盒子的margin会发生重叠,与方向无关。


3.每一个元素的左外边距与包含块的左边界相接触(从左到右),即使是浮动元素也是如此。


4.BFC区域不会与float的元素区域重叠。


5.计算BFC的高度时,浮动元素也参与计算。


6.BFC就是页面上的一个隔离的独立容器,容器里面的子元素不会影响外面的元素,反之亦然。


触发条件


触发BFC条件包含但是不限于


根元素,即HTML元素。


浮动元素。float值为left、right


overflow的值不为visible,为auto、scroll、hidden


display的值为inline-block、inltable-cell、table-caption、table、inline-table、flex、inline-flex、grid、inline-grid


position的值为absolute或fixed


运用场景


利用BFC的特性,我们将BFC运用在以下的场景
1.防止margin重叠(塌陷)

<style>
p {
color: #f55;
background: #fcc;
width: 200px;
line-height: 100px;
text-align:center;
margin: 100px;
    }
</style>
<body>
<p>Haha</p>
<p>Hehe</p>
</body>


两个p元素之间的距离为100px,发生了margin重叠(塌陷),以最大的为准,如果第一个margin为80的话,两个p元素之间的距离也是100,以最大的为准。


前面讲到,同一个BFC的两个相邻盒子的margin会发生重叠。


可以在p外面包裹一层容器,并触发这个容器生成一个BFC,那么两个p不属于同一个BFC,则不会出现margin重叠。

<style>
    .wrap {
        overflow: hidden;// 新的BFC
    }
    p {
        color: #f55;
        background: #fcc;
        width: 200px;
        line-height: 100px;
        text-align:center;
        margin: 100px;
    }
</style>
<body>
<p>Haha</p>
<divclass="wrap">
<p>Hehe</p>
</div>
</body>

这时候,则不会发生重叠


清楚内部浮动

<style>
    .par {
        border: 5px solid #fcc;
        width: 300px;
    }
    .child {
        border: 5px solid #f66;
        width:100px;
        height: 100px;
        float: left;
    }
</style>
<body>
    <div class="par">
        <div class="child"></div>
        <div class="child"></div>
    </div>
</body>

页面显示如下


而BFC在计算高度的时候,浮动元素也会参与,所以我们可以触发.par元素才能触发BFC,则内部浮动元素计算高度也会计算。

.par {
overflow: hidden;
}

实现出来的效果如下


适应多栏布局

这里举例一个两栏布局

<style>
body {
width: 300px;
position: relative;
    }
.aside {
width: 100px;
height: 150px;
float: left;
background: #f66;
    }
.main {
height: 200px;
background: #fcc;
    }
</style>
<body>
<divclass="aside"></div>
<divclass="main"></div>
</body>

效果图如下


前面讲到,每一个元素的左外边距与包含块的左边界相接触。

因此,虽然.aslide为浮动元素,但是main的左边依然会与包含块的左边相接触而BFC区域不会与浮动盒子重叠

所以我们可以通过触发main生成BFC,以此适应两栏布局

.main {
overflow: hidden;
}

这时候,新的BFC不会与浮动的.aside元素重叠。因此会根据包含块的宽度,和.aside的宽度,自动变窄

效果如下


小结

可以看到上面几个案例,都体现了BFC实际上就是一个页面的独立容器,里面的子元素不影响外面的元素

相关文章
|
7天前
|
前端开发
深入解析React Hooks:构建高效且可维护的前端应用
本文将带你走进React Hooks的世界,探索这一革新特性如何改变我们构建React组件的方式。通过分析Hooks的核心概念、使用方法和最佳实践,文章旨在帮助你充分利用Hooks来提高开发效率,编写更简洁、更可维护的前端代码。我们将通过实际代码示例,深入了解useState、useEffect等常用Hooks的内部工作原理,并探讨如何自定义Hooks以复用逻辑。
|
6天前
|
前端开发 数据管理 编译器
引领前端未来:React 19的重大更新与实战指南🚀
React 19 即将发布,带来一系列革命性的新功能,旨在简化开发过程并显著提升性能。本文介绍了 React 19 的核心功能,如自动优化重新渲染的 React 编译器、加速初始加载的服务器组件、简化表单处理的 Actions、无缝集成的 Web 组件,以及文档元数据的直接管理。这些新功能通过自动化、优化和增强用户体验,帮助开发者构建更高效的 Web 应用程序。
24 1
引领前端未来:React 19的重大更新与实战指南🚀
|
8天前
|
XML 前端开发 JavaScript
前端开发进阶:从HTML到React.js
【10月更文挑战第9天】前端开发进阶:从HTML到React.js
|
8天前
|
前端开发 JavaScript 开发者
探索现代Web前端技术:React框架入门
【10月更文挑战第9天】 探索现代Web前端技术:React框架入门
|
5天前
|
Web App开发 JavaScript 前端开发
前端Node.js面试题
前端Node.js面试题
|
10天前
|
前端开发 JavaScript API
深入理解前端框架:React 和 Vue 的比较
【10月更文挑战第7天】深入理解前端框架:React 和 Vue 的比较
|
5天前
|
存储 人工智能 前端开发
前端大模型应用笔记(三):Vue3+Antdv+transformers+本地模型实现浏览器端侧增强搜索
本文介绍了一个纯前端实现的增强列表搜索应用,通过使用Transformer模型,实现了更智能的搜索功能,如使用“番茄”可以搜索到“西红柿”。项目基于Vue3和Ant Design Vue,使用了Xenova的bge-base-zh-v1.5模型。文章详细介绍了从环境搭建、数据准备到具体实现的全过程,并展示了实际效果和待改进点。
|
5天前
|
JavaScript 前端开发 程序员
前端学习笔记——node.js
前端学习笔记——node.js
17 0
|
5天前
|
人工智能 自然语言处理 运维
前端大模型应用笔记(一):两个指令反过来说大模型就理解不了啦?或许该让第三者插足啦 -通过引入中间LLM预处理用户输入以提高多任务处理能力
本文探讨了在多任务处理场景下,自然语言指令解析的困境及解决方案。通过增加一个LLM解析层,将复杂的指令拆解为多个明确的步骤,明确操作类型与对象识别,处理任务依赖关系,并将自然语言转化为具体的工具命令,从而提高指令解析的准确性和执行效率。
|
5天前
|
存储 弹性计算 算法
前端大模型应用笔记(四):如何在资源受限例如1核和1G内存的端侧或ECS上运行一个合适的向量存储库及如何优化
本文探讨了在资源受限的嵌入式设备(如1核处理器和1GB内存)上实现高效向量存储和检索的方法,旨在支持端侧大模型应用。文章分析了Annoy、HNSWLib、NMSLib、FLANN、VP-Trees和Lshbox等向量存储库的特点与适用场景,推荐Annoy作为多数情况下的首选方案,并提出了数据预处理、索引优化、查询优化等策略以提升性能。通过这些方法,即使在资源受限的环境中也能实现高效的向量检索。