一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第2天,点击查看活动详情。
前言
金三银四是拿offer的好时候,对于面试官各种层出不穷的面试题,我们总结了一些高频的考点,分享给大家,预祝大家在这个春天,收获满满
1.什么是数据突变
在javascript中,对象属于引用数据类型,将一个对象赋值给另一个对象时,实际上是将对象的引用地址赋值给了另一个对象,此时两个对象同时指向了内存中的同一个对象,通过两个变量对对象进行的任何操作,都会影响另一方,这就是数据突变。
由于数据突变带来的不可预测,javascript中的这项特性非常容易导致改A坏B的问题
2.什么是数据的不可变
对应用类型的数据进行更改,更改并不会作用于原数据,而是返回一个更改后的全新的数据。
const before = ['a','b','c','d'];
const after = before.slice(0,2);
console.log(after);// ["a","b"]
console.log(before);// ["a","b","c","d"]
可以把数据突变想象为"保存",它会在原有数据上进行修改。
可以把数据的不可变想象为"另存为",他返回全新的更改后的数据。
由于数据的不可变,使数据的操作更加安全,更加可预测。
尽量通过扩展运算符实现数组的增删改
3.什么是不完整的数据不可变
js不具备完整的数据不可变性,因为它提供的哪些具有数据不可变的方法都属于浅拷贝,对于引用数据类型嵌套的情况,内层数据仍然是引用地址的拷贝
const state = [{name:'super me'}];
const newState = state.slice(0);
newState[0].name = "李四";
console.log("state",state); // state:[{name:"李四"}]
console.log("state",state);// newState:[{name:"李四"}]
以上问题可以通过深拷贝解决,但是深拷贝是有性能问题的,其一是每次深拷贝都要把整个对象递归复制一份(耗性能),其二是在内存中多出了很多重复的相同的数据(占内存)
4.谈谈你对react的理解
React 是一个网页 UI 框架,通过组件化的方式解决视图层开发复用的问题,本质是一个组件化框架。
-
它的核心设计思路有三点,分别是
声明式、组件化与通用性。 -
声明式的优势在于直观与组合。
-
组件化的优势在于视图的拆分与模块复用,可以更容易做到高内聚低耦合。
-
通用性在于一次学习,随处编写。比如 React Native,React 360 等, 这里主要靠虚拟 DOM 来保证实现。
-
这使得 React 的适用范围变得足够广,无论是 Web、Native、VR,甚至 Shell 应用都可以进行开发。这也是 React 的优势。
-
但作为一个视图层的框架,React 的劣势也十分明显。它并没有提供完整的一揽子解决方 案,在开发大型前端应用时,需要向社区 寻找并整合解决方案。虽然一定程度上促进了社区的繁荣,但也为开发者在技术选型和学习适用上造成了一定的成本。
-
承接在优势后,可以再谈一下自己对于 React 优化的看法、对虚拟 DOM 的看法
5.什么是声明式编程
声明式编程是一种编程范式,它关注的是你要做什么,而不是如何做。它表达逻辑而不显式地定义步骤。这意味着我们需要根据逻辑的计算来声明要显示的组件。它没有描述控制流步骤。声明式编程的例子有HTML、SQL等
HTML file
// HTML
<div>
<p>Declarative Programming</p>
</div>
SOL file
select * from studens where firstName = 'declarative';
6.什么是函数式编程
函数式编程是声明式编程的一部分。javascript中的函数是第一类公民,这意味着函数是数据,你可以像保存变量一样在应用程序中保存、检索和传递这些函数。
函数式编程有些核心的概念,如下:
-
不可变性(Immutability)
-
纯函数(Pure Functions)
-
数据转换(Data Transformations)
-
高阶函数 (Higher-Order Functions)
-
递归
-
组合
不可变性
不可变性意味着不可改变。 在函数式编程中,你无法更改数据,也不能更改。 如果要改变或更改数据,则必须复制数据副本来更改。
例如,这是一个student对象和changeName函数,如果要更改学生的名称,则需要先复制 student 对象,然后返回新对象。
在javascript中,函数参数是对实际数据的引用,你不应该使用 student.firstName =“testing11”,这会改变实际的student 对象,应该使用Object.assign复制对象并返回新对象。
let student = {
firstName: "testing",
lastName: "testing",
marks: 500
}
function changeName(student) {
// student.firstName = "testing11" //should not do it
let copiedStudent = Object.assign({}, student);
copiedStudent.firstName = "testing11";
return copiedStudent;
}
console.log(changeName(student));
console.log(student);
7.生命周期
16.3版本之前的生命周期
挂载阶段:
constructor---->componentWillMount---->render---->componentDidMount
更新阶段: componentWillReceiveProps---->shouldComponentUpdate---->componentWillUpdate---->render---->componentDidUpdate
卸载阶段:componentWillUnmount
16.3版本之后的生命周期
挂载阶段: constructor---->getDerivedStatedFromProps---->render---->componentDidMount
更新阶段: getDerivedStateFromProps---->shouldComponentUpdate---->render---->getSnapshotBeforeUpdate---->componentDidUpdate
卸载阶段:componentWillUnmount
-
getDerivedStateFromProps触发时间:此生命周期并非props变化的时候才会调用(不单单更新时才会调用),他在挂载阶段也会执行替代的方法: componentWillReceiveProps
class Example extends React.Component { static getDerivedStateFromProps(nextProps, prevState) { // 没错,这是一个static } } -
getSnapshotBeforeUpdate触发时间:update发生的时候,在render之后,在组件dom渲染之前。替代的方法:componentWillUpdate
class Example extends React.Component { getSnapshotBeforeUpdate(prevProps, prevState) { // ... } }8. react16+版本中为什么要更新生命周期?(为什么要废弃一些生命周期)
1.首先我们要理解Fiber架构
react16+版本以后,是将reconciler(diff+render+创建dom)+commit(patch),这两个操作是分开的,在15版本的时候,这两个操作是交替进行的,不能被打断
因为fiber架构下允许被打断,所以reconciler阶段会调用多次,等一切结束了才会调用commit,所以will也会被执行多次,被执行多次以后可能出现意料之外的bug
2.由于三个
will钩子使用率不高,而且容易误解和滥用