【前端面试】 React

前端 专栏收录该内容
10 篇文章 0 订阅

1. Vue与React的区别

每个人的见解不同,按自己的理解回答。

2. 类组件和函数组件的区别

  • 函数组件/无状态组件

            <script type="text/babel">
                // 函数名使用大驼峰命名规范
                function MyCom(){
                    return (
                        <div>
                            <h1>我是一个react无状态组件</h1>  
                        </div>
                    )
                }
                ReactDOM.render(<MyCom/>,document.getElementById("demodiv"))
            </script>
    
  • class类组件

    • 一个组件类必须要实现一个render方法。这个方法必须要返回一个jsx元素。必须要用一个外层的jsx元素把所有的内容包裹起来,返回并列的多个元素需要有个父元素包裹

          <script type="text/babel">
              class MyCom extends React.Component{
                  render(){
                      return (
                          <div>
                              <h1>我是一个react类组件</h1>  
                          </div>
                      )
                  }
              }
              class Fu extends React.Component{
                  render(){
                      return (
                          <div>
                              <MyCom/>
                              <MyCom/>
                              <MyCom/>  
                          </div>
                      )
                  }
              }
              ReactDOM.render(<Fu/>,document.getElementById("demodiv"))
          </script>
      

3. 函数组件实现生命周期

  • Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
  • Hook中的useEffect,通过使用这个 Hook,可以告诉 React 组件需要在渲染后执行某些操作。useEffect需要有一组依赖的state,如果依赖的state发生变化,那么回调就会执行

4. React中refs的作用

  • 需要抓取dom元素与第三方 DOM 库集成,触发命令式动画,管理焦点,文本选择或媒体播放
  • 表示对组件真正实例(也就是html标签,也就是DOM对象)的引用,其实就是ReactDOM.render()返回的组件实例;ref可以写在html标签里,也可以写在组件(自定义标签里),和vue的ref是同样的意思。
  • 官方建议: 勿过度使用 Refs(尽量不要操作DOM),在对逻辑进行处理的时候尽量优先考虑state(数据驱动)。

5. React中refs的转发

6. Context状态树

  • 在平时使用react的过程中,数据都是自顶而下的传递方式,例如,如果在顶层组件的state存储了theme主题相关的数据作为整个App的主题管理。那么在不借助任何第三方的状态管理框架的情况下,想要在子组件里获取theme数据,就必须的一层层传递下去,即使两者之间的组件根本不需要该数据。

  • Context 旨在共享一个组件树,可被视为 “全局” 的数据,达到越级传递,场景:当前经过身份验证的用户,主题或首选语言,包括管理当前的 locale,theme,或者一些缓存数据。

  • createContext(): 用于创建context,需要一个defaultValue的参数,并返回一个包含Provider(提供者),以及Consumer(消费者)的对象

  • Provider:提供者,提供数据。接收一个将要被往下层层传递的props,该值需在组件树最顶层设置。一个Provider可以关联到多个Consumers。这是一个顶层用于提供context的组件,包含一个value的props,value是实际的context数据。

  • Consumer: 消费者,使用者,接收一个函数作为子节点,函数接收当前 context 的值。这是一个底层用于获取context的组件,需要一个函数作为其子元素,该函数包含一个value的参数,该函数的参数就是上层所传递context value

创建一个context组件,并设定默认值。语法如下:

 const  {Provider, Consumer} = React.createContext(defaultValue);

示例代码:

context组件: ./src/utils/myContext;

import {createContext} from "react";

export const {Provider, Consumer} = createContext({
  name:"张三疯"
});

//顶层组件:./src/App.js

import {Provider} from "./utils/myContext"

function App() {
  let val={
    name:"hi"
  };
  return (
    <div className="App">
      <Provider value={val}>
        <Home  />
      </Provider>
    </div>
  );
}

//孙子组件: App->Home->Goodslist
import {Consumer} from "../utils/myContext";

export default class GoodsList extends React.Component {
   
    render = () => (
        <div className="goodsList-box">
            <h1>商品列表:</h1>            
            <Consumer>
                    {
 					  (val)  => <div> { val.name } </div>
					}
            </Consumer>
        </div>
    )
}

注意:

export const {Provider, Consumer} = createContext({

​ name:“张三疯”
});

​ 这个默认值是在顶层组件没有使用Provider组件时的值,而不是,没有给value属性赋值时的值。

即:顶层组件的代码如下:

function App() {
  let val={
      name:"hi"
  };
  return (
    <div className="App">  
         <Home />
    </div>
  );
}

7. 原型、原型链、继承

  • 原型:每一个构造函数都有一个prototype属性,这个属性会在生成实例的时候,成为实例对象的原型对象。javascript的每个对象都继承另一个对象,后者称为“原型”(prototype)对象。
  • 原型链:每一个对象都有一个__proto__属性,对象的属性和方法,有可能定义在自身,也有可能定义在它的原型对象。由于原型本身也是对象,又有自己的原型,所以形成了一条原型链(prototype chain)。 (“原型链”的作用是:读取对象的某个属性时,JavaScript 引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined。举例来说,如果让某个函数的prototype属性指向一个数组,就意味着该函数可以当作数组的构造函数,因为它生成的实例对象都可以通过prototype属性调用数组方法。)
  • 继承:继承就是在子类构造函数中继承父类构造函数的私有属性和原型属性。我们在子类构造函数中使用call或apply方法调用父类构造函数并改变其this指向为子类构造函数的this,此时子类的构造函数就继承了父类的私有属性和私有方法。将父类的实例化对象赋值给子类的原型对象,此时子类就继承了父类的原型属性和原型方法。

8. JS中new的作用

  • 创建一个空对象,并使该空对象继承Func.prototype;

  • 执行构造函数,并将this指向刚刚创建的新对象;

  • 返回新对象;

9. 闭包

  • 官方解释:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。(函数就是一个表达式)

  • 通俗的来说:JavaScript中所有的function都是一个闭包。不过一般来说,嵌套的function所产生的闭包更为强大,也是大部分时候我们所谓的“闭包”。

  • 什么是闭包:闭包是指在函数外部访问函数作用域中变量(局部变量)的函数;或者说闭包就是能够读取其他函数内部变量的函数;或者说闭包是指有权访问另一个函数作用域中的变量的函数;由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”。

应用场景: 防抖与节流函数柯里化

10. 数组去重

  1. 利用ES6 Set去重(ES6中最常用)
function unique (arr) {
  return Array.from(new Set(arr))
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
console.log(unique(arr))
  1. 利用for嵌套for,然后splice去重(ES5中最常用)
function unique(arr){            
        for(var i=0; i<arr.length; i++){
            for(var j=i+1; j<arr.length; j++){
                if(arr[i]==arr[j]){         //第一个等同于第二个,splice方法删除第二个
                    arr.splice(j,1);
                    j--;
                }
            }
        }
return arr;
}
var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
    console.log(unique(arr))
  1. 利用对象的属性
function unique(arr) {
    if (!Array.isArray(arr)) {
        console.log('type error!')
        return
    }
    var arrry= [];
     var  obj = {};
    for (var i = 0; i < arr.length; i++) {
        if (!obj[arr[i]]) {
            arrry.push(arr[i])
            obj[arr[i]] = 1
        } else {
            obj[arr[i]]++
        }
    }
    return arrry;
}
    var arr = [1,1,'true','true',true,true,15,15,false,false, undefined,undefined, null,null, NaN, NaN,'NaN', 0, 0, 'a', 'a',{},{}];
        console.log(unique(arr))

11. set与map的区别

Set 和 Map 主要的应用场景在于数据重组和数据储存。
Set 是一种叫做集合的数据结构,Map 是一种叫做字典的数据结构。

  • 共同点:集合、字典 可以储存不重复的值
  • 不同点:集合 是以 [value, value]的形式储存元素,字典 是以 [key, value] 的形式储存
    (集合)set: ES6 新增的一种新的数据结构,类似于数组,但成员是唯一且无序的,没有重复的值。
    Set 本身是一种构造函数,用来生成 Set 数据结构。
    Set 对象允许你储存任何类型的唯一值,无论是原始值或者是对象引用。
    (字典)map: 是一组键值对的结构,具有极快的查找速度。

12. Promise、async和await

  • Promise是一种异步操作的解决方案,将写法复杂的传统的回调函数和监听事件的异步操作,用同步代码的形式表达出来。避免了多级异步操作的回调函数嵌套。
    • 1、主要用于异步计算
    • 2、可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
    • 3、可以在对象之间传递和操作promise,帮助我们处理队列
  • Promise是一个对象,它的内部其实有三种状态。
    • 初始状态( pending )。
    • 已完成( resolve): resolve 方法可以使 Promise 对象的状态改变成成功
    • 已拒绝( reject ): reject 方法则是将 Promise 对象的状态改变为失败
  • Promise常用的三种方法
    • 第一种:then 表示异步成功执行后的数据状态变为resolve
    • 第二种:catch表示异步失败后执行的数据状态变为reject
    • 第三种:all表示把多个没有关系的Promise封装成一个Promise对象使用then返回一个数组数据。
  • Promise 构造函数有两个变量 resolve 用于返回异步执行成功的函数 reject 用于返回异步执行失败的函数,配合then与catch一起使用

Promise使用场景

  1. Ajax异步请求的时候
  2. 函数嵌套层级多的时候使用promise,优点在于,回调函数变成了链式写法,程序的流程可以看得很清楚,而且有一整套的配套方法,可以实现许多强大的功能。

async和await

13. ES6 Symbol

14. 深浅拷贝

15. width:auto 和 width:100%的区别

  1. width:100% 并不包含margin-left margin-right的属性值,直接取其父容器的宽度加上含margin-left /margin-right的值。如果设置了margin那新的width值是容器的宽度加上margin的值。(细心观察)就会发现加了 margin相对应的边就会多出设置的空白。而且会多出横向滚动条因为宽度已经超出了屏幕的范围。(这条相对于父容器是body)。

  2. width:auto包含margin-left/margin-right的属性值。其值包含margin-left /margin-right的值。width:auto总是占据整行!!!这其中margin的值已经包含其中了(也就是一整行)如果要设置margin的值那就用一整行然后减去margin的值就得到了现在的宽度了。减去的这个值就是相应边得空白。显著的特征是这个没有横向滚动条出现也就是宽度没有增加。

16. 伪元素和伪类的区别

  • 伪类:用于向某些选择器添加特殊的效果
  • 伪元素:用于将特殊的效果添加到某些选择器

17. react hooks

Hooks 介绍

​ react hooks是v16.8新增的特性, 他允许你在不写class(即:函数式组件)的情况下操作state 和react的其他特性(如:生命周期的钩子函数)。
​ hooks 只是多了一种写组件的方法,使编写一个组件更简单更方便,同时可以自定义hook把公共的逻辑提取出来,让逻辑在多个组件之间共享。

Hook 是什么? Hook 是一个特殊的函数,它可以让你“钩入” React 的特性。例如,useState 是允许你在 React 函数组件中添加 state 的 Hook。

​ 函数式组件里面没有state,所以,无状态组件我们用函数写,或者说函数式组件是无状态组件。而现在有了Hook后,函数式组件里,也可以使用state了。当然还有其它Hook。

使用规则

  • Hook可让您在不编写类(组件)的情况下使用状态(state)和其他React功能
  • 只能在顶层调用Hooks 。不要在循环,条件或嵌套函数中调用Hook
  • 只能在functional component或者自定义钩子中使用Hooks
  • 钩子在类内部不起作用,没有计划从React中删除类

useState (使用状态):

格式:

1、定义:
const [状态名,更新状态的函数] = React.useState(初始值|函数);

如:

声明一个新的叫做 “count” 的 state 变量,初始值为0 。

const [count, setCount] = useState(0);

相当于类组件中的
this.state={
    count :0
}

const [person, setPerson] = React.useState({name: '张三疯', age: 18,sex:"女"})
const [person, setPerson] = React.useState(() => ({name: '张三疯', age: 18,sex:"女"}))

2、读取值:
{count}
{person.name}   {person.age}

3、修改值:
  不能局部更新,所以,需要使用扩展运算符先拷贝以前所有的属性
  setCount(5);

  setPerson({
     ...person, //拷贝之前的所有属性
     age:person.age+1,
     name: '张四疯' //这里的name覆盖之前的name
 })

示例代码:

import React,{useState} from 'react';

function App() {
// 声明一个叫 "count" 的 state 变量
  const [count,setCount] = useState(0);

  return (
    <div className="App">
      <p>{count}</p>
      <input type="button" value="测试" onClick={()=>{setCount(count+1)}} />
    </div>
  );
}

对应的函数class组件:

class App extends React.Component {
  state = {
      count:0
  }
  render = () => (
    <div>
       <p>{this.state.count}</p>
       <input type="button" value="测试" 
			onClick={()=>this.setState({count:this.state.count+1})} />
    </div>
  )
}

我们之前把函数式的组件叫做“无状态组件”。但现在我们为它们引入了使用 React state 的能力

再如:

function App() {
  const [person, setPerson] = React.useState({name: '张三疯', age: 18})
 
  const onClick = () =>{
    //setPerson不可以局部更新,如果只改变其中一个,那么整个数据都会被覆盖,所以,需要使用扩展运算符先拷贝以前所有的属性
    setPerson({
        ...person, //拷贝之前的所有属性
        age:person.age+1,
        name: '张四疯' //这里的name覆盖之前的name
    })
  }

  return (
    <div className="App">
        <p>name:{person.name}</p>
        <p>age:{person.age}</p>
        <input type="button"  value="测试" onClick={onClick} />
    </div>
  );
}

useEffect 处理副作用

​ 可以使得你在函数组件中执行一些带有副作用的方法,天哪,“副作用”(大脑中无数个????)。

​ 每当 React组件更新之后,就会触发 useEffect,在第一次 render 和每次 update 后触发,不用再去考虑“挂载”还是“更新”。React 保证了每次运行 effect 的同时,DOM 都已经更新完毕。

​ 你可以把 useEffect Hook 看做 componentDidMountcomponentDidUpdatecomponentWillUnmount 这三个函数的组合。

​ 我们在函数式组件里,没有 componentDidMountcomponentDidUpdatecomponentWillUnmount,用useEffect。即:当数据发生变化后,渲染到组件上,组件渲染完毕后,就会调用useEffect。

import React,{useState,useEffect} from 'react';

function App() {
  const [count,setCount] = useState(0);
  
  useEffect(()=>{
      console.log("userEffect");
      document.title = count;
  });

  return (
    <div className="App">
      <p>{count}</p>
      <input type="button" value="测试" onClick={()=>{setCount(count+1)}} />
    </div>
  );
}

useRef 保存引用值

useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。

import {useRef} from "react";

let refContainer = useRef(initialValue)  

<JSX ref={refContainer} ...

refContainer.current.dom操作

一个常见的用例便是命令式地访问子组件:

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  
  const onButtonClick = () => {
    // `current` 指向已挂载到 DOM 上的文本输入元素
    inputEl.current.focus();
  };
    
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}
  • 6
    点赞
  • 6
    评论
  • 6
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

评论6
请先登录 后发表评论~
©️2021 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页

打赏作者

逗芽菜₁₅₁₉₁₈₁₀₇₅₅

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值