react//前端面试题1

1、class组件和类组件区别?

1. class组件是有状态的组件,可以定义state状态,函数组件无状态

2. class组件有生命周期的,函数组件无生命周期

3. class组件是有this对象,函数组件没有this对象

4. 组件调用:class组件实例化后调用render方法调用,函数组件直接调用的。

5. class组件内部的话,render方法return返回渲染jsx模板,函数组件直接返回即可

6. ref获取子组件的对象,class组件可以直接获取到的,函数组件无法直接获取到。

   1. forwardRef((props,ref)=>{<div ></div>})

7. 绑定bind改变this指向,只适用于class组件

2、useMemo和usecallback如何提升性能

useMemo 主要缓存复杂运算的数据的结果,第二个参数,定义监听的变量,需要返回一个结果。

当父组件的组件更新的时候会导致子组件的重新渲染,但是如果父组件的更新的数据没有传递给子组件的话,这个时候如果还让子组件重新渲染的化,就会导致组件的更新的性能消耗比较大。

所以说这个时候我们可以使用useMemo, 或者React中内置的memo方法对子组件进行缓存,这样的话只有父组件更新跟子组件相关联的数据的时候才会导致子组件的重新渲染,从而提高组件的渲染性能。

但是如果我们给子组件传递方法的时候,上面memo方法的缓存就不起作用了,原因是父组件没更新一次会导致方法的重新调用,进而导致子组件的重新更新,所以这个时候我们可以使用useCallback对传递的方法进行缓存,监听数据更新后才会重新调用方法,从而提高组件的渲染性能。

3、React-router-dom V5和V6有什么区别?

1.V5中Switch换成Routes标签,

2.V5中exact属性没有了,V6默认是精准匹配

3.V5中的component属性,V6用的element,element属性是组件标签

4.V6中重定向导航组件换成Navigate

5.V6中路由嵌套直接采用组件包裹的方式,可以不适用path绝对路径,

6.V6中的<Outlet> 相当于vue中router-view

7.获取参数和Hooks方法的变化

8.props获取V6中props值没有参数数据,必须采用Hooks的路由获取数据。

9.withRouter在V6版本中也被去掉了。

4、React中Hooks及含义

useState

函数组件中设置state数据,参数默认值,返回的结果是一个数组,数组第一个值变量值,第二个值是一个函数,修改state的数据函数,相当于setstate方法

useEffect

相当于生命周期函数,第一个参数一个回调函数,第二参数是个数组【可以不填】

第一个参数返回一个函数的时候,相当于componentWillUnmount生命周期

第二个参数为空数组的时候,componentDidMount ,第二个如果不填的话,只要页面更新就会触发,componentDidUpdate生命周期

第二个参数的值可以监听某些数据的变化,把监听的变量放入第二个参数接口

useEffect是一个副作用函数,页面渲染完成后触发

useMemo useCallback 性能提升

父组件中引入子组件,传递变量的时候,父组件有任何数据的更新的话都会导致子组件的重新渲染,改变的数据跟子组件无关的话,导致性能问题,这个这个时候我们可以使用useMemo 或者memo对组件的数据进行缓存的操作

如果绑定的属性中有方法的话,这时候会发现数据改变的时候,memo会失效,这个使用useCallback对方法进行缓存,避免子组件的重新渲染,提升性能。

useRef

相当于类组件 createRef创建ref结点对象标识符的

let ref = useRef()

ref.current 获取当前的节点对象

useContext

useContext作用用来获取context状态树对象的内容

let context = useContext(对象的内容值)

useReducer

useReducer 是对useState数据的增强,useState,无法处理比较复杂逻辑,

可以把函数组件的数据进行一个集中式的管理,并且可以处理逻辑操作

参数是reducer的纯函数,返回的值是一个state数据,dispatch方法,第二参数可以是state的初始化的值

5、React的生命周期有哪些?

挂载阶段

constructor() 类组件实例化后出发的方法,

componentWillMount 组件挂载完成之前触发的方法

render() 每次组件渲染的时候都会触发的方法

componentDidMount() 组件渲染完成触发的方法。

更新阶段

componentWillReceiveProps() 父组件传递的数据发生变化的时候触发的生命周期函数,如果父组件的数据改变频繁的话,性能消耗会比较大

shouldComponetUpdate 组件是否应该更新,返回值一个一个布尔值,true,触发render, false不会触发render方法,判断state的值和prop的值是否发生改变,return true更新

componentWillUpdate 组件更新前触发的方法

render() 渲染视图触发的方法

componentDidUpdate 组件更新完成后触发的方法。

销毁阶段

componentWillUnmount 组件销毁的阶段内容

React生命周期有哪些变化?

getDerivedStateFromProps 替换 componetWillMount , componentWillReceiveProps 生命周期

getSnapShotBeforeUpdate 替换了componentWillUpdate的生命周期函数

6什么是高阶组件?如何使用?用过哪些高阶组件

高阶函数是一个函数可以作为另外一个函数的参数,这个函数就是高阶函数,

高阶组件就是一个组件可以作为另外一个组件的参数,这个组件就可以作为一个组件,memo,  forwardRef,  withRouter  , connect

高阶组件的主要作用时是复用,条件判断也可以使用HOC

React 中的高阶组件主要有两种形式:属性代理 和 反向继承。

属性代理: 是 一个函数接受一个 WrappedComponent 组件作为参数传入,并返回一个继承了 React.Component 组件的类,且在该类的 render() 方法中返回被传入的 WrappedComponent 组件

反向继承:是 一个函数接受一个 WrappedComponent 组件作为参数传入,并返回一个继承了该传入 WrappedComponent 组件的类,且在该类的 render() 方法中返回 super.render() 方法。

7React中受控组件和非受控组件

React中,受控组件和非受控组件是指组件的状态(如input输入框的值)是由React的状态管理机制来管理还是直接由DOM元素自身的状态管理机制来管理。

受控组件指的是组件的状态(如input输入框的值)被React的状态管理机制所管理,通常需要在组件的state中存储这些状态,并通过onChange事件来更新状态。例如,以下代码中的input组件就是一个受控组件:

```

class ControlledInput extends React.Component {

  constructor(props) {

    super(props);

    this.state = { value: '' };

  }

  handleChange(event) {

    this.setState({ value: event.target.value });

  }

  render() {

    return (

      <input type="text" value={this.state.value} onChange={this.handleChange.bind(this)} />

    );

  }

}

```

在上面的例子中,input组件的值被存在组件的state属性中,当input的值发生变化时,onChage事件会被触发,从而调用handleChange方法更新组件的状态,使得input的值与组件的状态保持一致。

非受控组件则是指组件的状态由DOM元素自身的状态管理机制来管理,这意味着组件的状态不再被存储在组件的state属性中。通常需要通过ref属性来获取DOM元素的值。例如,以下代码中的input组件就是一个非受控组件:

```

class UncontrolledInput extends React.Component {

  constructor(props) {

    super(props);

    this.inputRef = React.createRef();

  }

  handleSubmit(event) {

    event.preventDefault();

    console.log('Input Value:', this.inputRef.current.value);

  }

  render() {

    return (

      <form onSubmit={this.handleSubmit.bind(this)}>

        <input type="text" ref={this.inputRef} />

        <button type="submit">Submit</button>

      </form>

    );

  }

}

```

在上面的例子中,input组件的值不再由组件的state属性来管理,因此也不需要handleChange方法来更新组件的状态。取而代之,可以通过ref属性来获取input元素的值,这里使用了React.createRef()方法创建了一个ref引用,然后在handleSubmit方法中使用了ref引用获取了input的值。

总的来说,受控组件和非受控组件各有优缺点,需要在开发过程中具体考虑使用哪种方案来满足项目需求。

8、说说你对Promise的理解?

Promise是一种异步编程的技术,用于处理一系列的异步操作。它是一个代表一个异步操作的对象,可以在异步操作完成后返回结果,也可以在异步操作失败时返回错误信息。Promise包含三种状态:pending(进行中),fulfilled(已完成)、rejected(已拒绝)。在异步操作完成或者失败后,Promise可以自动地改变状态并执行相应的回调函数。Promise的优势在于可以防止回调地狱,使异步操作更加清晰、易读、易于维护。

9Promise和async/await有什么区别?

Promise和async/await都是用来处理异步操作的方式,但是它们之间有一些区别。

1. 编码方式:使用Promise时需要手动地编写回调函数,而使用async/await则更像是同步代码的写法,更容易理解和维护。

2. 可读性:async/await代码相对于Promise的代码更加容易阅读,因为async/await在语法上可以更清楚地表达出异步调用的顺序和逻辑。

3. 错误处理:使用Promise时需要编写额外的错误处理代码,而使用async/await则可以使用try-catch语法结构直接进行错误处理。

4. Promise.all:Promise.all可以同时处理多个Promise对象,但是async/await需要使用for...of循环来达到同样的效果。

5. 适用场景:Promise适用于比较简单的异步操作,而async/await适用于复杂的异步操作,并且在处理数据流时有更好的表现。

10React性能优化的方法

提高组件渲染的效率:减少不必要的render方法:

- shouldComponentUpdate

- PureComponent

- React.memo

性能优化的方案:

- 避免使用内联函数:使用内联函数,则每次调用`render`函数时都会创建一个新的函数实例

- 使用 React Fragments 避免额外标记:用户创建新组件时,每个组件应具有单个父标签。父级不能有两个标签,所以顶部要有一个公共标签,所以我们经常在组件顶部添加额外标签`div`

这个额外标签除了充当父标签之外,并没有其他作用,这时候则可以使用`fragement`

其不会向组件引入任何额外标记,但它可以作为父级标签的作用

- 使用 Immutable

- 懒加载组件:`react`中使用到了`Suspense`和 `lazy`组件实现组件延迟加载

- 事件绑定方式:性能方面考虑,在`render`方法中使用`bind`和`render`方法中使用箭头函数这两种形式在每次组件`render`的时候都会生成新的方法实例,性能欠缺,而`constructor`中`bind`事件与定义阶段使用箭头函数绑定这两种形式只会生成一个方法实例,性能方面会有所改善

- 服务端渲染

11、虚拟DOM和真实DOM的区别

虚拟DOM和真实DOM的最大区别在于它们所代表的对象不同。

虚拟DOM是一个轻量级的JavaScript对象,它是React框架中的核心概念,用于描述页面UI的状态和结构。它将所有的元素和组件都抽象成了JavaScript对象和属性,这些对象和属性之间构成了一棵虚拟的树形结构(Virtual DOM Tree)。在每一次渲染时,React会比较前后两棵虚拟DOM树的差异,然后只对有变化的部分进行重新渲染,从而提高渲染效率。

真实DOM则是页面上实际存在的元素对象,它由浏览器根据HTML标记解析后生成,并与页面上其他元素形成复杂的关联关系。真实DOM渲染性能较低,因为每次更改都会触发浏览器的重新渲染,而且它的操作和属性都是直接作用于页面的,比较麻烦。

因此,虚拟DOM和真实DOM的区别主要体现在:

1. 虚拟DOM是JavaScript对象,真实DOM是浏览器中的页面元素。

2. 虚拟DOM渲染效率更高,真实DOM操作性更强,但渲染性能相对较低。

12React生命周期的过程

React生命周期的过程主要包括以下三个阶段:

1. Mounting(挂载阶段):组件被实例化并插入到DOM中,这个过程只会执行一次。在这个阶段,React会执行constructor(构造函数)、getDerivedStateFromProps(派生状态)、render(渲染函数)和componentDidMount(组件挂载完成钩子函数)。

2. Updating(更新阶段):当组件的props或state发生变化时,组件会被重新渲染,即更新。在这个阶段,React会执行getDerivedStateFromProps(派生状态)、shouldComponentUpdate(更新判断函数)、render(渲染函数)、getSnapshotBeforeUpdate(更新前获取快照函数)和componentDidUpdate(更新完成钩子函数)。

3. Unmounting(卸载阶段):当组件被从DOM中移除时,React会执行componentWillUnmount(组件卸载钩子函数)。

在React v17中,React官方已经宣布将废弃一些生命周期函数,包括UNSAFE_(不安全的)前缀的生命周期函数。建议开发者在使用生命周期函数时要遵循官方的最新规范。

13state和props有什么区别?

在React中,state是组件内部管理状态的一种方式,它由组件自身控制。可以使用setState()方法来更新组件的状态,组件会根据状态的改变重新渲染。

而props是从父组件传递到子组件的一种方式,它是组件之间进行通信的桥梁。props是只读的,子组件无法直接修改它的值,只能通过父组件传递新的props。

因此,state和props的区别可以总结为:

1. state是组件内部私有的,props是外部传递的。

2. state可以随时改变,而props是不可变的。

3. state由组件自身管理,props由父组件传递。

在React中,state和props都是React组件数据的重要组成部分。它们的使用取决于组件的具体需求和场景。

14React组件通信的流程

1. 父组件向子组件传递props数据

2. 子组件通过props接收父组件传递的数据进行渲染

3. 子组件通过触发事件(如点击)调用父组件传递的回调函数,以达到向父组件传递数据的目的

4. 父组件接收子组件传递的数据,更新自身的状态(state)或调用自身的方法

5. 父组件根据更新的状态重新渲染,将更新的数据通过props传递给子组件,完成组件通信的流程。

15React中Hooks的理解及使用

React中的Hooks是一种用于函数组件中的新特性。它们很容易使用,可以让你在函数组件中使用state和其他React特性。通过使用Hooks,可以使代码更加简洁、可读并且易于维护。

React中提供了多种不同的Hooks,其中一些最经常使用的是:

1. useState: 用于添加状态到函数组件中。它需要一个初始值作为参数,并返回一个数组,其中第一个参数是状态值,第二个参数是一个函数,用于更新状态。

2. useEffect: 用于在函数组件中添加副作用。它接受一个函数作为参数,该函数会在组件渲染后执行。该函数可以返回另一个函数,这个返回的函数会在组件销毁之前被执行。

3. useContext: 用于从React上下文中获取数据。它需要一个上下文对象,该对象在应用程序中定义,并返回与该上下文相关联的值。

4. useReducer: 用于创建类似Redux reducer的状态管理器。它接收一个reducer函数和一个初始状态值,并返回一个包含当前状态值和一个dispatch函数的数组。

使用Hooks的代码示例:

```

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

function MyComponent() {

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

  useEffect(() => {

    document.title = `You clicked ${count} times`;

  }, [count]);

  return (

    <div>

      <p>You clicked {count} times</p>

      <button onClick={() => setCount(count + 1)}>

        Click me

      </button>

    </div>

  );

}

```

在这个示例中,useState hook用于添加一个计数器状态值,而useEffect hook用于更新页面标题。每当计数器更新时,useEffect hook会触发并更新页面标题。

总体而言,React中的Hooks使得开发人员能够更轻松地编写复杂的功能,并可以将代码分解为更小、更易于维护的组件。

16React中setState的运行机制的理解?

在React中,组件的状态是通过state来管理的。当组件需要更新状态时,应该使用setState方法。

setState是异步的,这意味着React并不会立即更新组件状态。相反,它会把状态的更新放入一个队列中,当React空闲时再进行更新。所以,如果要在setState完成后立即访问更新后的状态,需要使用回调函数。例如:

```

this.setState({count: this.state.count + 1}, () => {

  console.log(this.state.count);

});

```

当调用setState时,React会将更新的状态与之前的状态合并,并触发组件的重新渲染。React会自动比较之前的Virtual DOM和当前的Virtual DOM,然后找出有变化的部分进行更新,这也就是React的高效之处。

需要注意的是,setState仅更新状态,但并不保证立即触发渲染。如果在组件的生命周期中多次调用setState,React会将这些更新合并成一个更新,然后再一次性渲染,以避免无效的渲染。

17说说你对React中事件机制的理解

React中的事件机制是指React组件中处理和响应用户交互的机制。React采用的是合成事件的方式处理事件。在合成事件中,React通过事件池的方式来优化事件处理,避免了每次事件触发时都创建一个新的事件对象的开销。

React中的事件处理流程与原生的DOM事件处理流程有所不同。React首先在组件中定义事件处理函数,然后通过事件绑定的方式将事件处理函数与事件绑定起来,当事件触发时,事件处理函数会被调用。

React中的事件绑定方式是通过在JSX中使用onXxx属性来绑定事件。例如,onClick、onMouseOver等事件都可以在JSX中绑定。同时,React还支持在事件处理函数中使用回调函数来处理事件的传递和状态更新等操作。

React还支持事件代理机制。在React中,事件代理可以简化大量的事件绑定操作,让代码更加精简和易读。事件代理是通过给父级元素绑定事件来处理其子元素上的事件。只需要在父级元素上绑定事件,然后在事件处理函数中根据事件目标的类型进行相应处理,就可以处理所有子元素上的事件。

18Js的数据类型和内存存储区别

JavaScript 的数据类型包括基本数据类型(primitive types)和引用数据类型(reference types)。

基本数据类型:

1. 数字(number):表示数字,包括整数和浮点数。

2. 字符串(string):表示一串字符。

3. 布尔值(boolean):表示真或假。

4. null:表示空值。

5. undefined:表示未定义的值。

6. Symbol:表示唯一和不可变的值,用于创建对象的属性名。

引用数据类型:

1. 对象(object):表示一个无序属性的集合,可以包含基本数据类型或其他对象。

2. 数组(array):是一种特殊的对象,用于存储一组有序的数据。

3. 函数(function):是一种特殊的对象,可以被调用执行。

基本数据类型的值被直接存储在变量访问的地方,而引用数据类型的值则是存储在堆内存中的对象,变量保存的只是该对象的地址。这意味着对于基本数据类型,变量的复制会创建一个新的值,而对于引用数据类型,则传递的是地址,所以任何改变都会影响到原始对象的值。当不再需要一个对象时,Javascript 的垃圾收集器会自动回收它的堆内存。

19Js中数据类型判断的方法有哪些?

1. typeof:可以判断基本数据类型(number, string, boolean, undefined)以及 function,但是不能区分 null 和 object。

2. instanceof:可以判断对象的具体类型,但是不能判断基本数据类型。

3. Object.prototype.toString:可以判断基本数据类型以及对象类型,并且可以区分 null 和 object。

4. ===:可以判断值和类型是否相等,但是不能区分 null 和 undefined。

5. isNaN:可以判断一个值是否为 NaN。

6. isInteger:可以判断一个值是否为整数。

7. isFinite:可以判断一个值是否为有限数。

8. isObject:可以判断一个值是否为对象。

9. isNull:可以判断一个值是否为 null。

10. isUndefined:可以判断一个值是否为 undefined。

20说说你对Vue中生命周期的理解?

Vue.js 中的生命周期函数是指在组件创建、更新或销毁时,Vue.js 自动调用的一些方法。这些方法可以让我们在组件不同的阶段进行一些操作和处理,方便我们进行业务逻辑开发和数据处理。

Vue.js 的生命周期函数可以分为四个阶段:

创建阶段:在组件实例化之后,开始进行 props、data 等属性的初始化工作。其中包括 beforeCreate 和 created 两个生命周期方法。

挂载阶段:将组件挂载到DOM节点上,此时可以进行一些 DOM 操作和异步请求等。其中包括 beforeMount 和 mounted 两个生命周期方法。

更新阶段:当组件数据变化时,会自动触发更新,此时可以进行一些响应式操作和对组件状态的更新。其中包括 beforeUpdate 和 updated 两个生命周期方法。

销毁阶段:当组件被销毁时,会自动触发销毁事件,可以在这里进行一些清理操作和资源释放。其中包括 beforeDestroy 和 destroyed 两个生命周期方法。

对于每个生命周期函数,在不同的阶段可以做不同的操作,并且可以访问到组件的实例和DOM节点,方便我们进行业务逻辑处理和操作。

21Vue2的响应式原理是什么?

Vue 2.x 中的响应式原理是通过 Object.defineProperty() 方法劫持对象属性的 getter 和 setter 方法,在属性值发生变化时触发 setter 方法,从而可以在内部自动更新视图。

当我们创建 Vue 实例时,Vue 会遍历 data 对象的所有属性,并使用 Object.defineProperty() 方法为每个属性设置 getter 和 setter 方法。这些 getter 和 setter 方法会将数据收集到一个叫做“依赖”的闭包中,并且在数据发生变化时通知这些依赖进行重新计算。

例如,当我们在模板中绑定了一个属性,如 {{ message }},Vue 会创建一个 Watcher 对象来监听这个属性,当属性的值改变时,Watcher 会调用对应的更新函数来更新视图。

在 Vue 的响应式系统中,数据和视图相互绑定,任何一个发生变化都会引起另外一个的变化。这也就是 Vue 的“数据驱动”的核心思想。

需要注意的是,在 Vue 2.x 中,只有 data 对象中已经存在的属性才会被劫持,并且它的子属性也需要是“可监听”的。如果需要监听动态新增的属性,需要使用 Vue.set() 或 this.$set() 方法,同时,在 Vuex 等状态管理库中,也需要使用专门的方法来进行修改状态,以保证状态改变能够被 Vue 监听到并更新视图。

22、说说你对盒子模型的理解?

CSS 盒子模型是指一种把 HTML 元素看成一个矩形盒子的思想。它包括四个部分:内容区域、内边距区域、边框区域和外边距区域。

1. 内容区域(Content):指 HTML 元素包含的全部内容,包括文本、图片、嵌入的视频等。

2. 内边距区域(Padding):指内容区域与边框之间的距离,可以通过设置 padding 属性来控制。

3. 边框区域(Border):指内边距区域与外边距区域之间的线条,可以通过设置 border 属性来控制。

4. 外边距区域(Margin):指边框区域与相邻元素之间的距离,可以通过设置 margin 属性来控制。

盒子模型的宽度和高度由内容区域、内边距区域和边框区域决定,外边距则不会影响盒子尺寸。当我们设置一个元素的宽度和高度时,实际上设置的是其内容区域的宽度和高度,而边框和内边距则会自动撑开盒子。因此在进行页面布局时,我们需要注意盒子模型各部分的尺寸和相互之间的关系,以便获得所需的布局效果。

23、说说你对BFC的理解?

BFC 是指块级格式化上下文,它是 CSS 中一个比较重要的概念。BFC 是指一个独立的渲染区域,用于管理块级盒子的布局和浮动的清除。

在一个 BFC 内部,所有的盒子按照一定的规则进行排列,而排列的过程并不会影响到外部的元素。同时,BFC 具有一些特殊的布局规则和渲染效果,例如:

1. BFC 的内部所有元素都会被垂直排列,不会发生浮动相互覆盖的情况。

2. 在 BFC 内部,每个盒子的左边距和外边距不会和 BFC 外部的元素产生重叠。

3. BFC 可以包含浮动的元素,并可以自动地将其高度计算在内,从而避免出现父元素高度塌陷的情况。

我们可以通过以下方式来创建 BFC:

1. 根元素或包含根元素的元素。

2. 浮动元素(float 不为 none)。

3. 绝对定位元素(position 为 absolute 或 fixed)。

4. display 为 inline-block、table-cell、table-caption、flex、和 inline-flex 的元素。

5. overflow 不为 visible 的元素(hidden、scroll、auto)。

BFC 的应用非常广泛,例如实现多列等高布局、避免浮动导致的父元素高度塌陷等。在进行页面布局时,我们需要对 BFC 有一个清晰的认识,并灵活地运用它来解决各种布局问题。

24、说说你对Redux以及Redux中间件的理解?

Redux 是一个 JavaScript 状态容器,它用于管理 React 应用中的状态。Redux 的核心概念包括 store、action 和 reducer。

1. store:Redux 中存放应用所有状态(state)的地方,提供了一些 API 以供读取状态、触发 action 和监听状态变化。

2. action:Redux 中通过派发 Action 来通知应用的状态更新,我们可以把 Action 理解为一个事件,它描述了发生了什么事情。

3. reducer:Redux 中负责处理 Action 的函数,它接收当前的状态和发生的 Action,并返回新的状态。

中间件是 Redux 给开发者提供的一个扩展机制,可以在 action 到达 reducer 前或后进行一些额外的处理。常用的中间件有:

1. 异步中间件:如 Redux-thunk、Redux-saga 等,可以解决 Redux 原生只能同步更新 state 的问题,支持异步更新 state。

2. 日志中间件:如 Redux-logger,可以记录 Redux 操作中产生的日志信息,便于开发调试。

使用中间件需要先将它们应用到 Redux 中,在创建 store 的时候,通过 applyMiddleware 函数将需要使用的中间件传入即可。

Redux 的使用可以帮助开发者更好地管理应用的状态,并且通过中间件的扩展机制,可以实现更多的功能,非常适用于大型的 React 应用。

25Vue中数据更新视图不更新的原理是什么?

Vue 是一款响应式的框架,它通过数据劫持和依赖追踪来实现数据更新视图的自动响应。

Vue 在初始化时通过 Object.defineProperty 或者 ES6 Proxy 劫持了组件的数据,并为每个属性项建立了一个对应的依赖追踪集合。当数据发生变化时,Vue 会自动触发依赖追踪集合中所有相关的 Watcher 对象重新计算,并通知视图进行更新。

但是在某些情况下,Vue 可能无法检测到数据的变化,从而导致视图更新不及时。造成无法检测到变化的原因可能有以下几种:

1. 对象新增属性:当使用 Object.defineProperty 定义对象属性时,只能劫持已经存在的属性,对于新增的属性 Vue 无法自动进行依赖追踪。

2. 数组改变索引或长度:Vue 对数组的响应式实现只能监听数组内部元素的变化,当直接修改数组的索引或长度时,Vue 无法检测到这种变化。

3. 非响应式数据:如果一个数据不是响应式的,那么当这个数据发生变化时,Vue 是无法进行依赖追踪的。

对于以上情况,可以使用 Vue 提供的 $set、$delete、$forceUpdate 等 API 来手动触发数据更新和视图更新。需要注意的是,在使用这些 API 时,也要特别注意避免在循环内部使用它们导致性能问题。

26Vue中data为什么是一个函数不能是对象?

在 Vue 中,data 选项用于定义组件数据(即响应式变量),可以是一个对象或者是一个函数。虽然定义为一个对象也可以正常工作,但官方推荐使用函数形式。

这是因为 Vue 在创建组件实例时,会将 data 选项与组件原型上的 data 进行合并,并在此基础上创建响应式变量。如果 data 选项是一个对象,那么所有使用该组件的实例都会共享这个对象的引用,容易造成数据混乱和不必要的副作用。

而如果将 data 定义为一个函数,则每次创建组件实例时都会调用该函数,返回一个新的数据对象,从而避免了数据的共享问题。

另外,在定义为函数形式后,我们也可以在其中访问组件实例的属性和方法,这样可以更加灵活地定义数据。例如:

```javascript

export default {

  data () {

    return {

      count: 0

    }

  },

  methods: {

    increment () {

      this.count++

    }

  }

}

```

总之,将 data 选项定义为函数形式可以强制要求每个组件实例都有自己的独立数据,避免了数据共享问题,也更加方便地管理和复用组件。

27Vue和React中key的作用是什么?

在 Vue 和 React 中,key 的作用都是为了更加高效地更新虚拟 DOM(Vue 中的 VNode,React 中的 JSX Element)。

当数据发生变化时,Vue 和 React 都会根据新的数据生成新的虚拟 DOM,并将其与旧的虚拟 DOM 进行对比,找出需要更新的节点。这个对比过程中,每个节点都需要唯一的标识来区分。

而正是因为每个节点的唯一性,才能在进行对比时判断出哪些节点需要进行更新,哪些节点需要被删除或新增。

因此,Vue 和 React 都引入了 key 属性来帮助识别节点。在 Vue 中,key 属性作用于 v-for 指令生成的列表项;而在 React 中,key 属性作用于组件内部生成的列表项(通常是使用 map 方法映射数组)。

key 属性应该是一个唯一的字符串,可以是数据的索引、数据的 ID、或者其他唯一标识符等。这个值不应该是动态生成的,否则可能会导致不必要的性能问题。

通过给节点添加 key 属性,Vue 和 React 都可以更好的识别和管理节点,提升更新的效率和性能。

28、说说什么是闭包,有哪些应用场景?

闭包(Closure)是指在一个函数内部创建另一个函数,并返回这个函数的同时,将它所在的上下文环境一起返回。换句话说,闭包可以访问定义自己的函数体外部的变量和函数,即使在外部函数已经执行结束、上下文环境已经销毁的情况下也仍然可以访问。

简单来说,闭包就是可以访问外层函数作用域中的变量和函数的函数,这种特性使得 JavaScript 可以实现很多有用的功能和设计模式。以下是一些常见的应用场景:

1. 封装私有变量和方法:在一个函数内部定义局部变量和方法,然后再返回一个新的函数,新函数通过闭包访问并返回这些属性和方法,从而实现对外不可访问的“私有”属性和方法。

2. 模块化开发:使用闭包可以实现模块化的代码组织方式,将相关的变量和函数封装在一个函数作用域内,并通过返回值暴露出需要对外公开的接口,以实现代码的解耦和复用。

3. 延迟执行:通过使用闭包可以创建一个作用域独立、拥有持久性状态的函数,该函数可以延迟执行或按需执行,例如事件处理函数、定时器等。

4. 科里化:利用闭包可以将一个多参数的函数转化为一系列单参数函数的嵌套调用,从而实现更加灵活和易于组合的调用方式。

总之,闭包是 JavaScript 中非常强大和有用的特性,掌握闭包具有重要的意义,可以提高代码的性能、可读性和可维护性。

29说说你对原型和原型链的理解?场景

在 JavaScript 中,每个对象都有一个内部属性 `[[Prototype]]` (也称为“隐式原型”),它指向该对象的原型。原型是一个对象,它包含可以被该对象实例所继承的属性和方法。而原型链就是由一连串的原型对象组成的链式结构,用于查找和继承对象的属性和方法。

具体来说,当我们使用“点”运算符访问一个对象的属性时,如果该对象本身没有定义该属性,那么 JavaScript 就会沿着原型链依次查找,直到找到包含该属性的原型对象或者找到顶层的 Object.prototype 为止。如果最终都没有找到,则返回 undefined。

以下是一些常见的原型和原型链的应用场景:

1. 原型继承:JavaScript 中的继承是基于原型链实现的。我们可以通过将一个对象的原型设置为另一个对象的实例来实现继承,并以此实现代码的复用和解耦。

2. 对象操作:由于 JavaScript 中的所有对象都具有原型,因此我们可以通过修改对象原型中的属性和方法,来扩展和增强其功能。例如,可以为数组原型添加一个新的方法,以实现数组的高级操作。

3. 访问器属性:访问器属性是指那些通过 getter 和 setter 函数来定义的属性,它们并不存储具体的值,而是在每次访问时计算并返回一个值。由于原型链的特点,我们可以将访问器属性定义在对象的原型上,从而实现访问器属性继承。

4. ES6 Class:在 ES6 中,我们可以通过 class 和 extends 关键字来实现类和继承。虽然底层实现还是基于原型和原型链,但语法更加简洁易用,也更符合面向对象编程的习惯。

总之,原型和原型链是 JavaScript 中的重要概念,掌握它们有助于提高代码的性能、灵活性和可维护性。

30说说你对同步和异步的理解?

在编程中,同步和异步是两个非常重要的概念。简单来说,同步和异步是指代码执行的顺序。

1. 同步:同步指的是代码依次执行,每段代码要等待上一个代码执行完成后才能继续执行。也就是说,在同步执行模式下,程序会一直等待某个操作完成,然后才会执行下一个操作。比如,当调用一个函数时,程序会阻塞在该函数处,直到函数返回结果才能继续往下执行。

  1. 异步:异步指的是代码不依次执行,而是同时执行多个操作,每个操作都有一个回调函数,当某个操作完成后,会回调对应的函数。换句话说,在异步执行模式下,程序不会等待某个操作完成,而是继续执行下一个操作。比如,当发起一个 Ajax 请求时,程序不会阻塞在该请求处,而是可以继续执行其他操作,当请求完成后,再执行对应的回调函数。

总之,同步和异步是针对代码执行顺序的概念,同步执行模式下代码按顺序执行,而异步执行模式下代码先执行一部分,再回调处理结果。在实际开发中,我们通常会选择使用异步模式来处理耗时操作,以避免线程阻塞和提高用户体验。

31、说说你对Promise的理解

Promise是一种异步编程的技术,用于处理一系列的异步操作。它是一个代表一个异步操作的对象,可以在异步操作完成后返回结果,也可以在异步操作失败时返回错误信息。Promise包含三种状态:pending(进行中),fulfilled(已完成)、rejected(已拒绝)。在异步操作完成或者失败后,Promise可以自动地改变状态并执行相应的回调函数。Promise的优势在于可以防止回调地狱,使异步操作更加清晰、易读、易于维护。

32、数组方法及使用场景

在 JavaScript 中,数组是一种常用的数据结构,用于存储和操作一组相关的数据。为了方便地对数组进行操作和处理,JavaScript 提供了许多内置的数组方法。下面介绍几个常见的数组方法及其使用场景:

1. push 和 pop

`push()` 方法用于在数组末尾添加一个或多个元素,`pop()` 方法用于从数组末尾删除一个元素。这两个方法一般用于实现先进先出(FIFO)的队列。示例代码如下:

```javascript

const queue = [];

queue.push(1);   // 添加元素 1 到队列末尾

queue.push(2);   // 添加元素 2 到队列末尾

queue.pop();     // 删除队列末尾的元素 2

```

2. shift 和 unshift

`shift()` 方法用于删除数组第一个元素,`unshift()` 方法用于在数组开头添加一个或多个元素。这两个方法一般用于实现后进先出(LIFO)的栈。示例代码如下:

```javascript

const stack = [];

stack.unshift(1);  // 添加元素 1 到栈底

stack.unshift(2);  // 添加元素 2 到栈底

stack.shift();     // 删除栈顶的元素 2

```

3. concat

`concat()` 方法用于将多个数组合并成一个新数组。示例代码如下:

```javascript

const arr1 = [1, 2, 3];

const arr2 = [4, 5, 6];

const newArr = arr1.concat(arr2);  // 将 arr1 和 arr2 合并成一个新数组

```

4. slice

`slice()` 方法用于从数组中选取一部分元素,并返回一个新数组,不会改变原数组。示例代码如下:

```javascript

const arr = [1, 2, 3, 4, 5];

const newArr = arr.slice(1, 4);  // 从索引为 1 的位置开始,选取三个元素,生成一个新的数组 [2, 3, 4]

```

5. splice

`splice()` 方法用于向数组中插入或删除元素,并返回被删除的元素。示例代码如下:

```javascript

const arr = [1, 2, 3, 4, 5];

arr.splice(2, 1);  // 从索引为 2 的位置开始,删除一个元素,此时 arr 为 [1, 2, 4, 5]

arr.splice(2, 0, 'a', 'b');  // 从索引为 2 的位置开始,插入两个元素 'a' 和 'b',此时 arr 为 [1, 2, 'a', 'b', 4, 5]

```

以上是常见的几个数组方法及其使用场景,除此之外,JavaScript 还提供了许多其他有用的数组方法,如 forEach、map、filter、reduce 等,需要根据实际需求来选择使用哪些方法。对于大型的数组操作,可以使用一些高效的第三方库来提高代码执行效率和开发效率。

33、字符串方法及使用场景

在 JavaScript 中,字符串是一种基本的数据类型,用于存储和操作文本字符串。为了方便地对字符串进行操作和处理,JavaScript 提供了许多内置的字符串方法。下面介绍几个常见的字符串方法及其使用场景:

1. indexOf 和 lastIndexOf

`indexOf()` 方法用于查找字符串中某个子串的位置,返回子串的开始位置,如果没有找到该子串,则返回 -1;`lastIndexOf()` 方法与 `indexOf()` 类似,但从字符串的末尾开始查找。示例代码如下:

```javascript

const str = 'Hello world!';

const index = str.indexOf('world');     // 返回 6

const lastIndex = str.lastIndexOf('o'); // 返回 7

```

2. substring 和 slice

`substring()` 方法用于从字符串中提取一部分子串,根据起始位置和结束位置来指定子串的范围,不包括结束位置的字符;`slice()` 方法也用于提取字符串的一部分,根据起始位置和结束位置来指定子串的范围,包括结束位置的字符。这两个方法的使用场景相似,但有些细节不同。示例代码如下:

```javascript

const str = 'Hello world!';

const subStr = str.substring(0, 5);  // 提取 'Hello' 子串

const sliceStr = str.slice(6, 11);   // 提取 'world' 子串

```

3. replace

`replace()` 方法用于替换字符串中的某个子串,可以替换一次或多次。示例代码如下:

```javascript

const str = 'Hello world!';

const newStr = str.replace('world', 'JavaScript');  // 将 'world' 替换为 'JavaScript',生成新的字符串 'Hello JavaScript!'

```

4. split 和 join

`split()` 方法用于将字符串分割成一个数组,`join()` 方法则是将数组转换为一个字符串,这两个方法经常成对使用。示例代码如下:

```javascript

const str = '1,2,3,4,5';

const arr = str.split(',');         // 将字符串 '1,2,3,4,5' 分割成数组 [1, 2, 3, 4, 5]

const newStr = arr.join('-');       // 将数组 [1, 2, 3, 4, 5] 转换为字符串 '1-2-3-4-5'

```

除了以上介绍的几个字符串方法,JavaScript 还提供了很多其他有用的字符串方法,例如 `charAt()`、`charCodeAt()`、`toLowerCase()`、`toUpperCase()`、`trim()` 等,需要根据实际需求来选择使用哪些方法。在处理字符串时,需要注意一些细节,如字符串的不变性、编码方式等,避免出现一些潜在的问题。

34、说说你对React中refs的理解?作用?

在 React 中,`ref` 是一个特殊的属性,可以用来获取组件或 DOM 元素的引用。使用 `ref` 可以让我们直接从 DOM 元素获取数据或对其进行操作,而不需要通过 props 或 state 来传递数据,这样可以提高程序的性能和效率。

在 React 中,有两种方式使用 `ref`:一种是使用字符串作为 `ref` 的值,另一种则是使用回调函数。使用字符串作为 `ref` 的值已经过时,建议使用回调函数。

使用回调函数的方式定义 `ref`,可以在组件挂载和卸载时获取到对应的 DOM 元素或组件实例,并将其保存到一个变量中,然后在需要使用时,可以通过访问该变量来获取或操作对应的 DOM 元素或组件实例。例如:

```javascript

class MyComponent extends React.Component {

  constructor(props) {

    super(props);

    this.myRef = React.createRef();

  }

  

  handleClick = () => {

    console.log(this.myRef.current); // 输出 <input type="text" />

    this.myRef.current.focus();      // 将 input 元素聚焦

  }

  

  render() {

    return (

      <div>

        <input type="text" ref={this.myRef} />

        <button onClick={this.handleClick}>Focus</button>

      </div>

    );

  }

}

```

在上面的代码中,我们使用 `React.createRef()` 方法创建了一个 `ref` 对象,并将其保存在组件的实例对象中。在 `render()` 方法中,将 `ref` 对象绑定到一个 `<input>` 元素上。然后,我们可以在组件的其他方法中访问该 `ref` 对象,从而获取或操作对应的 DOM 元素。

使用 `ref` 可以解决一些特殊场景下的问题,例如:

- 获取某个 DOM 元素的大小、位置、滚动等信息;

- 控制某个输入框的光标位置;

- 获取组件实例并调用其方法。

需要注意的是,使用 `ref` 应该尽量避免过度使用,因为这会使组件变得难以理解、调试和维护。在使用 `ref` 时,需要权衡其方便性和可维护性,确保代码的可读性和健壮性。

35、说说你对Redux的理解

Redux 是一个状态管理库,用于管理 JavaScript 应用的状态和数据流。Redux 通过建立一个单一的 Store 来存储整个应用的状态,并使用纯函数来处理 State 的变化,以保证应用的可预测性和可维护性。Redux 的设计思想主要包括三个方面:单一数据源、状态不可变、纯函数处理状态变化。

1. 单一数据源

Redux 应用只有一个单一的 Store 来保存整个应用的状态,而且该状态是一个不可变对象,不能被直接修改。因此,在 Redux 应用中,所有的 State 变化都是由 Action 触发的,并通过 Reducer 来处理。这种单一数据源的设计使得 Redux 应用的状态变化变得可预测、可控、易于调试和维护。

2. 状态不可变

在 Redux 应用中,State 是不可变的,不能被直接修改。当应用需要更新某个状态时,必须创建一个新的 State 对象,并在其中修改需要更新的部分数据,返回一个新的 State 对象。这种状态不可变的设计可以使得 Redux 应用的状态变化变得非常清晰和可控,避免了出现一些难以发现和调试的问题。

3. 纯函数处理状态变化

在 Redux 应用中,所有的状态变化都是通过纯函数来处理的。这些纯函数被称为 Reducer,接收当前 State 和 Action 作为参数,返回新的 State 对象。Reducer 必须是纯函数,不能有副作用,也不能修改参数。这种纯函数的设计使得 Redux 应用的状态变化变得易于理解、可测试和可维护。

Redux 的核心思想可以概括为:单一数据源、状态不可变、纯函数处理状态变化。它可以帮助我们管理整个应用的状态,并让应用的状态变化变得可预测、可控、易于调试和维护。在使用 Redux 时,需要注意一些细节,例如如何设计 Reducer、如何组织代码、如何管理异步操作等。但总体来说,Redux 是一个非常好用、灵活、可扩展的状态管理库,可以帮助我们构建高质量的 JavaScript 应用。

36、说说你对Redux中间件的理解

在 Redux 中,中间件是一种机制,用于扩展 Redux 应用的功能,比如异步操作、日志记录、错误处理等。中间件可以被看作是函数,它接收 Store 的 dispatch 和 getState 方法作为参数,并返回一个新的函数,该函数会在 Action 发出后,Reducer 处理前执行。

中间件的核心作用是对 Redux 应用的 action 进行拦截和处理,从而实现一些额外的功能。具体来说,中间件可以:

1. 实现异步操作:Redux 本身只支持同步操作,无法直接处理异步场景。使用中间件可以拦截特定的 Action,在处理前进行异步操作,并在异步操作完成后再将结果传递给 Reducer。

2. 增加附加行为:例如给 Action 添加时间戳、增加错误处理、打印日志、发送通知等。

3. 实现数据转换:例如将不同格式的数据转换为 Redux 所需的格式。

一些常见的中间件包括 redux-thunk、redux-saga、redux-logger 等。它们都提供了丰富的功能,以帮助开发者更方便地使用 Redux。

对于中间件的实现,基本思想是在 Store.dispatch 上拦截所有的 Action,然后对其进行处理。中间件接收两个参数:dispatch 和 getState。其中,getState 用于获取当前的 State,dispatch 用于将处理后的 Action 发送给 Reducer。中间件可以根据自己的需求对 Action 进行处理,然后调用 dispatch 方法将处理后的 Action 传递给下一个中间件或者 Reducer。

总之,中间件是一种强大而且灵活的机制,可以用来增强 Redux 应用的功能和灵活性。使用中间件可以让我们更加方便地处理异步、增加附加行为、实现数据转换等,从而提升应用的性能和用户体验。

37说说你对弹性盒子布局的理解

弹性盒子布局(flexbox)是一种 CSS 布局方式,用于实现灵活、可响应的网页设计。它能够让容器内部的元素具有自适应和弹性的特性,可以根据不同的布局需求进行自动调整和排列。

在弹性盒子布局中,有两个重要的概念:弹性容器(flex container)和弹性项目(flex item)。弹性容器是指应用了 flexbox 布局的容器元素,用于定义一组弹性项目的布局方式;弹性项目则是指这些子元素,它们通过弹性容器来进行排列和布局。

常用的属性

Flex 容器的属性

- display: flex; 将元素设置为弹性盒子容器。

- flex-direction: row | row-reverse | column | column-reverse; 定义主轴方向。

- justify-content: flex-start | flex-end | center | space-between | space-around | space-evenly; 定义主轴位置对齐方式。

- align-items: stretch | flex-start | flex-end | center | baseline; 定义交叉轴位置对齐方式。

- align-content: stretch | flex-start | flex-end | center | space-between | space-around; 定义行列放置位置对齐方式。

Flex 项目的属性

- flex-grow: <number>; 定义弹性项目的放大比例,默认为0,即不会放大。

- flex-shrink: <number>; 定义弹性项目的缩小比例,默认为1,即会自动缩小。

- flex-basis: <length> | auto; 定义弹性项目在分配多余空间之前的在主轴方向上的大小。

- flex: none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]; 组合属性,定义弹性项目的放大比例、缩小比例和在主轴方向上的初始大小。

- order: <integer>; 定义弹性项目的排列顺序,默认是0。

弹性盒子布局的优点

1. 自适应性强:弹性盒子布局能够自动适应不同大小、不同分辨率、不同设备的屏幕。

2. 灵活性强:弹性盒子布局可以灵活地调整元素的宽度、高度、间距和位置。

3. 可读性好:弹性盒子布局代码简洁,易于阅读和理解,不需要过多的 CSS 嵌套。

总之,弹性盒子布局是一种非常实用、灵活、自适应和可扩展的布局方式,可以让我们更容易地定制和管理网页的布局。

38、防抖和节流有什么区别,使用场景?

防抖(debounce)和节流(throttle)都是为了解决 JavaScript 中频繁触发事件而导致的性能问题。

区别:

防抖(debounce)的原理是在事件被触发 n 秒后才会执行回调函数,如果在这 n 秒内又被触发,则重新计时。也就是说,只有在触发事件后 n 秒内没有再次触发事件,函数才会执行一次。常见的场景有:输入框输入完成后进行搜索、窗口大小改变后重新渲染等。

举例来说,当我们在输入框里输入文字时,每次输入都会触发输入事件,如果我们希望在用户输入完成之后再进行搜索,那么可以通过 debounce 将输入事件延迟 n 秒执行,避免了每次输入都触发一次搜索请求,从而提高性能并减少服务器的负担。

节流(throttle)的原理是在一定时间内只允许函数执行一次,也就是说,如果在这段时间内连续多次触发事件,函数也只会执行一次,直到这段时间结束。常见的场景有:鼠标拖拽、页面滚动等。

举例来说,当我们在网页中进行无限滚动操作时,如果每次滚动都触发一次加载更多数据的操作,可能会导致页面卡顿,从而影响用户体验。这个时候可以通过 throttle 将加载数据的操作暂停一段时间,待用户停止滚动后再进行加载。

使用场景:

1. 防抖通常应用于输入框等可能频繁触发事件的场景,以减少事件触发次数并提高性能。例如:搜索框搜索、调整窗口大小等。

2. 节流通常应用于连续触发事件后需要执行某些操作的场景,以限制函数的触发次数。例如:鼠标滚动、拖拽操作等。

总之,防抖和节流都是常用的 JavaScript 性能优化方法,通过合适地选择使用场景,可以有效地提高代码性能和用户体验。

39、深拷贝和浅拷贝的区别,如何实现深拷贝

深拷贝和浅拷贝是 JavaScript 中两种不同的对象复制方式。

区别:

1. 浅拷贝只复制了对象的引用,而不是对象本身,因此原始对象和拷贝对象会共享相同的属性和方法,改变一个对象的属性或者方法会影响到另一个对象。而深拷贝是将原始对象和拷贝对象完全独立,两者之间不会相互影响。

2. 浅拷贝是逐层复制,如果对象中嵌套了其他对象,那么拷贝对象中的嵌套对象仍然是原来的引用,因此仍然是共享的。而深拷贝则会递归地复制所有的对象和数组,使得拷贝后的对象和原始对象完全分离。

实现深拷贝的方法:

1. 使用 JSON.parse()/JSON.stringify() 方法:这是最简单也最常用的实现深拷贝的方法,通过使用 JSON.stringify() 方法将对象转换为字符串,再使用 JSON.parse() 方法将字符串转换为新的对象。这种方法虽然简单易用,但是有一些限制,例如无法复制函数、正则表达式等特殊类型数据。

2. 递归拷贝:递归拷贝是使用递归函数遍历对象的所有属性和方法,并将其复制到新的对象中。对于嵌套的对象和数组,需要递归调用拷贝函数。

3. Object.assign()方法:这种方式是浅拷贝,如果只需要拷贝对象的第一层属性,可以使用 Object.assign() 方法,它将源对象的属性复制到目标对象中,返回目标对象。但是如果源对象中有嵌套对象或者数组,那么拷贝后的对象仍然会共享嵌套对象和数组的引用。

总之,了解深拷贝和浅拷贝的区别以及实现方法,能够帮助我们更好地理解 JavaScript 中的对象和数据类型,并且让我们在开发中更加灵活地进行对象的复制和管理。

40React和Vue的区别,相同点和不同点?

React 和 Vue 是目前最流行的前端框架之一,它们都具有很多优点和适用场景,但是也存在一些明显的区别和不同之处。

相同点:

1. 都是基于组件化开发的思想,将 UI 界面抽象成一个个可复用的组件,方便代码的重用和维护。

2. 都支持虚拟 DOM 技术,能够高效地渲染页面,并且通过数据的双向绑定,实现了数据和 UI 界面的自动同步。

3. 都具有丰富的生命周期函数,可以方便地控制组件的加载、更新、卸载等过程,同时也能够进行一些逻辑处理和异步请求操作。

4. 都有非常丰富的社区和生态系统,提供了大量的插件、组件和工具,方便开发者进行项目开发和维护。

不同点:

1. React 更加注重灵活性和可扩展性,提供了 JSX 语法和函数式编程模式,通过高阶函数和组合等方式来实现复杂功能。而 Vue 更加注重易用性和开发效率,提供了模板语法和单文件组件的写法,使得开发者可以更快速地创建界面。

2. React 采用的是单向数据流的架构模式,父子组件之间通过 props 和回调函数来进行数据的传递和事件的处理。而 Vue 采用的是双向数据绑定的架构模式,通过 v-model 来实现数据的双向绑定,同时也提供了自定义事件和 $emit 方法来进行事件处理。

3. React 更加注重配合使用其他库和框架,例如 Redux、React Router、Webpack 等,通过组合方式来实现复杂应用的架构。而 Vue 更加注重集成性和全家桶,例如 Vuex、Vue Router、Vue CLI 等,提供了完整的开发工具链。

总之,React 和 Vue 都是非常优秀的前端框架,具有各自的优点和适用场景。在项目开发中,需要根据具体需求和团队的技术水平选择合适的框架,并且充分利用其提供的特性和生态系统,提高开发效率和项目质量。

41、说说React中虚拟DOM和真实DOM的区别?

在 React 中,虚拟 DOM 和真实 DOM 都是用来表示页面上的元素和组件的两种不同形式。

真实 DOM 是指浏览器中的 DOM 节点,它是由 HTML 解析器解析 HTML 文档生成的文档树,通过 JavaScript 操作可以改变页面的结构和内容。每次更新页面时都需要重新计算布局和重绘,非常消耗性能。

而虚拟 DOM 则是对真实 DOM 的一种抽象表示,在内存中维护了一个以 JavaScript 对象为基础的虚拟节点树。每次组件状态发生改变时,React 会先比较新旧两棵虚拟节点树的差异,然后再将差异部分渲染到真实 DOM 上,最大程度地减少了页面的重排和重绘,提高了性能。

虚拟 DOM 和真实 DOM 的区别主要体现在以下几个方面:

1. 性能方面:虚拟 DOM 可以极大地提升页面性能,因为它不需要直接操作浏览器的 DOM,而是通过比较虚拟 DOM 树的差异,只对有变化的部分进行重新渲染,可以避免不必要的重排和重绘,大大提高了页面的渲染速度和性能。

2. 使用方式:虚拟 DOM 可以直接通过 JavaScript 对象来表示页面上的元素和组件,可以方便地进行操作和维护。而真实 DOM 则需要通过 HTML 解析器解析 HTML 文档生成,需要通过浏览器 API 进行操作,使用比较麻烦。

3. 更新方式:虚拟 DOM 是基于状态变化来更新的,只有当组件的状态发生改变时才会重新渲染 DOM,这样可以避免多余的渲染操作。而真实 DOM 则是基于 DOM 的变化来更新的,每次变化都会重新渲染整个 DOM,效率比虚拟 DOM 低。

4. 扩展性:虚拟 DOM 比真实 DOM 更容易扩展,因为它只是一个 JavaScript 对象,可以随意添加属性和方法。而真实 DOM 则受到浏览器支持的限制,不能随意添加属性和方法。

总之,虚拟 DOM 和真实 DOM 在 React 中都具有重要的作用,但它们的实现方式和优点不同,需要根据具体情况选择合适的方式来进行开发。

42、说说你对Redux的理解?项目中Redux目录是怎么划分的?应用场景有哪些?

Redux 是一种状态管理工具,可以将应用程序的状态(state)保存在一个全局存储(store)中,并提供一些 API 来操作这个状态。Redux 的核心思想是将组件和状态分离,让组件只负责展示数据,而将数据逻辑部分交给 Redux 来处理。

在 Redux 中,状态是不可变的,所有的更新都是通过派发(dispatch)一个动作(action)来触发的,动作会被 Redux 中间件(middleware)拦截并进行处理,最终更新全局存储中的状态。Redux 的数据流是单向的,从组件到动作、到中间件、到状态。

在项目中,Redux 目录一般会被划分为以下几个子目录:

1. actions:用于存放所有的动作(action),每个动作都是一个普通对象,包含一个 type 属性和其他常量属性。

2. reducers:用于存放所有的 reducer 函数,每个 reducer 都是一个纯函数,接受当前状态和动作对象,返回一个新的状态。

3. store:用于创建和管理全局存储(store)对象,可以将多个 reducer 组合成一个根 reducer。

4. middleware:用于实现中间件功能,比如异步操作、日志记录、错误处理等。

5. components:用于存放所有的组件文件,每个组件都可以通过 connect 方法连接到全局存储中的状态和动作。

Redux 的应用场景很多,特别是在大型项目中,它可以帮助我们更好地管理和组织应用程序的状态,避免状态分散在各个组件中导致难以维护。Redux 可以用于实现复杂的业务逻辑、数据缓存、状态同步等功能,在多人协作或者需要长期维护的项目中特别有用。

43、说说你对React-router的理解?V5和V6的区别?

React Router 是一个基于 React 的前端路由库,它可以帮助我们在单页应用中实现页面的切换和状态的管理。React Router 提供了一些组件和 API,例如 Route、Link、Switch,可以帮助我们实现路由匹配、页面跳转、参数传递、代码分割、权限控制等功能。

React Router V5 和 V6 最明显的区别是 V6 引入了一种新的路由模式,称为“位置感知路由(location-aware routing)”,这种模式下,路由和组件之间的关系更紧密,可以更灵活地定义路由规则和页面结构。V6 还引入了一些新的 API 和改进了一些原有的特性,例如:

1. 改进了动态路由的处理方式,可以更好地支持异步组件和代码分割。

2. 引入了新的组件 Outlet 和 RouteIndex,可以更方便地组织嵌套的路由结构。

3. 提供了新的 API useRoutes 和 useMatch,可以更方便地使用 Hooks 实现路由逻辑。

4. 改进了错误处理机制,可以更好地处理未匹配路由和重复渲染等问题。

5. 改进了导航和过渡效果,可以更好地实现页面切换和动画效果。

总之,React Router 是一个非常优秀的路由库,可以帮助我们更好地管理前端应用程序的状态和页面结构。V6 引入的新特性和改进可以帮助我们更方便地编写路由代码和组织页面结构,提高开发效率和用户体验。

44React性能优化的方法有哪些?

React 是一个非常优秀的前端框架,但是在处理大规模数据和复杂逻辑的场景下,性能问题可能会成为开发人员头疼的问题。为了提高 React 应用程序的性能,我们可以采用以下几种方法:

1. 使用 Key 属性:在渲染列表或者动态组件时,使用 Key 属性来帮助 React 更好地识别不同的元素,避免不必要的重绘。Key 属性可以唯一标识每个元素,如果 Key 值发生变化,React 会重新渲染该元素;如果 Key 值不变,React 比较前后两次的 Virtual DOM,只更新发生变化的部分。

2. 避免不必要的 State 更新:在组件中,State 的变化可能会导致整个组件重新渲染,因此我们应该尽量避免不必要的 State 更新。例如,在 shouldComponentUpdate 生命周期中进行比较,如果前后两次 State 没有变化,则返回 false,否则返回 true。

3. PureComponent 和 memo:PureComponent 和 memo 是 React 提供的两种性能优化方式,它们都可以避免不必要的重新渲染。PureComponent 会自动比较前后两个 props 和 State,如果没有变化则不重新渲染;memo 则可以包裹函数组件,只有当 props 发生变化时才重新渲染。

4. 使用 shouldComponentUpdate 声明周期:shouldComponentUpdate 声明周期可以用来手动比较前后两次 props 和 State,如果没有变化则返回 false,避免不必要的重新渲染。

5. 懒加载和代码分割:懒加载和代码分割是一种非常有效的性能优化方式,可以将页面按需加载和分割成多个小块,在需要时才进行加载和渲染,避免不必要的资源浪费。

6. 使用 Webpack 或者 Rollup 进行打包和压缩:Webpack 和 Rollup 是两种常见的打包和压缩工具,可以将 React 应用程序中的代码进行打包和压缩,减小文件大小,提高加载速度。

总之,React 的性能优化涉及很多方面,其中最重要的就是避免不必要的重新渲染和资源浪费,合理使用 key 属性、PureComponent 和 memo、shouldComponentUpdate 等特性,可以有效提高应用程序的性能。

45、元素水平垂直居中的方法有哪些?

在前端开发中,元素水平/垂直居中是一个非常常见的需求。以下是几种实现元素水平/垂直居中的方法:

1. 使用 Flexbox:Flexbox 是一种非常强大的布局方式,可以很方便地实现元素的水平和垂直居中。只需要将容器的 display 属性设置为 flex,然后使用 justify-content 和 align-items 分别设置水平和垂直方向的对齐方式即可。

2. 使用 Position 和 transform:可以通过将元素的定位方式设置为 absolute 或者 fixed,然后使用 top/bottom 和 left/right 属性配合 transform 来实现垂直和水平方向的居中。例如,可以将元素的 left/top 和 transform 属性分别设置为 50%,然后使用负值来修正位置。

3. 使用 Table 和 table-cell:可以使用 table 和 table-cell 布局模型来实现元素的水平和垂直居中。首先,将容器的 display 属性设置为 table,然后将子元素的 display 设置为 table-cell,最后使用 vertical-align 和 text-align 属性分别设置垂直和水平方向的对齐方式即可。

4. 使用 Grid 布局:Grid 布局是一种相对比较新的布局方式,也可以很方便地实现元素的水平和垂直居中。只需要将容器的 display 属性设置为 grid,然后使用 justify-items 和 align-items 分别设置水平和垂直方向的对齐方式即可。

总之,以上几种方法都可以有效实现元素的水平和垂直居中,具体使用哪种方法可以根据实际需求进行选择。

46React中router的V5和V6版本的差异

React Router 是一个流行的用于在 React 应用程序中实现路由功能的第三方库。目前,React Router 的最新版本是 V6,与 V5 相比,V6 有以下几点差异:

1. 路由定义方式:V6 引入了一种新的路由定义方式,即使用 Routes 和 Route 组件来代替以前的 Router 和 Route 组件。使用 Routes 组件定义应用程序的路由规则,而 Route 组件则用于匹配对应的路由。

2. 使用路径参数优化匹配:在 V6 中,可以通过使用路径参数来优化路由匹配。例如,可以使用 :id 的方式定义路径参数,并利用 useParams 钩子函数来获取参数值。

3. 路由状态管理:在 V6 中,Route 组件引入了一个新的属性 element,用于返回要呈现的组件或标记路由渲染器。此外,还可以使用 useRoutes 钩子函数来自定义路由状态管理。

4. 生命周期钩子名称变更:在 V6 中,生命周期钩子名称发生了变化,componentDidMount 变成了 useLayoutEffect,componentWillUnmount 变成了 useEffect,componentDidUpdate 变成了 useUpdatedLayoutEffect。

5. 路由导航钩子名称变更:在 V6 中,路由导航钩子名称也发生了变化,例如原来的 withRouter 变成了 withRoutes,原来的 useHistory 变成了 useNavigate。

6. 删除一些过时的 API:在 V6 中,删除了一些过时的 API,例如 withRouter、matchPath 和 useHistoryWithQuery 等。

需要注意的是,虽然 V6 与 V5 存在上述差异,但是在很多方面,它们的使用方式仍然非常类似。因此,如果你已经熟悉了 React Router V5,那么学习和使用 V6 应该不会有太大的难度。

47React性能优化的方法都有哪些?

React 是一个非常强大的 JavaScript 库,但是在处理大型应用程序时,性能问题可能会成为一个瓶颈。为了解决这个问题,可以采用以下一些 React 性能优化的方法:

1. 使用 React.memo:React.memo 是一个高阶组件,它可以在组件需要更新时进行比较操作,以确定是否需要重新渲染。一般来说,只有在组件的 props 或者状态发生了变化时,才需要重新渲染组件。

2. 减少不必要的渲染:在 React 中,每次组件更新时,都会重新渲染整个组件树。为了减少不必要的渲染,可以使用 shouldComponentUpdate 或者 PureComponent 来只更新当前组件及其子组件的内容。

3. 利用 Key 属性优化列表渲染:当在 React 中渲染一个列表时,为每个列表项添加唯一的 Key 属性。这样,当列表项的顺序改变时,React 可以快速地确定修改部分而不需要对整个列表进行重新渲染。

4. 优化图片加载:将页面中的大型图片压缩和延迟加载可以大大提高首次加载时间,以及整个应用程序的性能。

5. 延迟加载组件:当应用程序初始化时,不需要立即加载所有组件。可以将非关键组件进行按需加载,以便提高应用程序的响应速度。

6. 使用 Webpack 进行代码拆分:Webpack 可以将应用程序的代码拆分成多个小块,以实现按需加载并提高应用程序性能。

7. 使用 memoized 函数:Memoized 函数可以缓存函数的调用结果,避免函数被重复执行,从而提高整个应用程序的性能。

需要注意的是,以上优化方法并不能适用于所有情况,具体需要根据应用程序的实际情况进行选择和调整。

48css3动画都做过哪些?

作为前端开发工程师,我已经使用 CSS3 动画实现过很多不同的效果,包括:

1. 过渡动画:CSS3 过渡动画可以用于创建平滑的动画效果,例如在元素状态之间添加过渡效果(如悬停、聚焦或单击)时。

2. 旋转动画:CSS3 的 transform 属性可以用于实现旋转效果,例如使一个元素绕一个中心点旋转或自转。

3. 缩放动画:可以使用 CSS3 的 transform 属性来调整元素的大小,以实现缩放动画效果。

4. 移动动画:CSS3 的 transform 属性也可以用于元素的移动,例如在屏幕上滑动一个元素或元素组。

5. 渐变动画:可以使用 CSS3 的渐变属性来创建惊艳的渐变动画效果,例如背景渐变或文字颜色渐变。

6. 透明度动画:可以使用 CSS3 的 opacity 属性来实现元素的淡入淡出效果。

7. 动态阴影:CSS3 的 box-shadow 属性是用于创建阴影效果,可以实现动态阴影效果,例如光线投影、蒙版或悬浮效果。

8. 多重阴影效果:CSS3 的 box-shadow 属性还可以用于创建多重阴影效果,例如多重光源或浮动立方体。

9. 文字效果:CSS3 的 text-shadow 属性可以用于为文本添加阴影效果,可以创建漂亮的艺术字体和 3D 文本效果。

这只是 CSS3 动画的一小部分,还有很多不同的效果可以使用 CSS3 实现。在实际工作中,我会根据具体需求选择最合适的 CSS3 动画效果。

49call,apply,bind有什么区别?如何实现一个bind?

`call`, `apply` 和 `bind` 都是 JavaScript 中用于改变函数执行上下文的方法。

`call` 和 `apply` 的作用类似,都是立即调用一个函数并指定其中的 `this` 关键字。其区别仅在于传递参数的方式不同:`call` 方法接受多个单独的参数,而 `apply` 方法则接受一个数组作为参数,数组中的每个元素对应函数的一个参数。

`bind` 方法与 `call` 和 `apply` 方法的区别在于,它返回一个新的函数,而不是立即调用该函数。新的函数具有与原始函数相同的代码和作用域,但是其执行上下文中的 `this` 关键字被永久地绑定到指定的对象。

以下是一个简单的实现 `bind` 方法的示例:

```javascript

Function.prototype.myBind = function(obj) {

  // 存储原始函数和绑定对象

  var originalFunc = this;

  var boundObj = obj;

  

  // 返回一个新的函数

  return function() {

    // 在新函数中使用 apply 方法调用原始函数

    return originalFunc.apply(boundObj, arguments);

  };

};

```

以上示例通过添加 `myBind` 方法到 `Function.prototype` 中来扩展 `Function` 对象,并返回一个新的函数。新函数中调用原始函数时使用 `apply` 方法,并将绑定对象作为第一个参数传递。由于 `arguments` 是当前函数中可用的特殊变量,它将包含新函数的所有参数。使用 `arguments` 参数的优点是,可以将 `bind` 方法与任意数量的参数一起使用,而不必显式指定每个参数。

50、说说你对BOM对象的理解?常见的BOM对象有哪些?

BOM(浏览器对象模型)是指浏览器提供的一组 JavaScript 对象和方法,用于操作浏览器窗口和其他功能。 BOM对象通常都指window对象的属性或方法,也就是全局变量。

常见的BOM对象有:

1. window 对象:代表了整个浏览器窗口,是所有 BOM 对象的容器对象,它包含了很多属性和方法,例如定时器、地址栏等。

2. navigator 对象:提供了与浏览器有关的信息,例如浏览器的名称和版本号,还可以检测用户浏览器类型、插件信息等。

3. location 对象:提供了当前文档的 URL 信息,可以用于读取和修改当前页面的 URL 路径、参数、锚点等。

4. screen 对象:提供了用户屏幕的信息,例如屏幕的分辨率、可用宽度和高度等。

5. history 对象:提供了浏览器历史记录的信息,可以用于向前和向后遍历历史记录。

6. document 对象:虽然不是严格意义上的 BOM 对象,但它也是浏览器提供的重要对象,用于操作文档的内容、结构和样式等。

BOM 对象对于前端开发非常重要,它们提供了许多有用的功能和方法,能够使我们更有效地操作浏览器窗口、检测用户环境、管理浏览器历史记录等。

51、说说你对盒子模型的理解?

盒子模型是网页布局中一种用于描述元素尺寸和定位的概念。

每个 HTML 元素都被看作一个矩形的盒子,由内容区域、内边距(padding)、边框(border)和外边距(margin)组成。这四个部分决定了盒子在文档流中的位置和其大小。

具体来说:

1. 内容区域(content):位于盒子的内部,用于包含元素的实际内容,例如文本、图像等。

2. 内边距(padding):位于内容区域和边框之间,用于控制内容与边框之间的空白区域。

3. 边框(border):位于内边距之外,用于围绕内容和内边距的可见线条。

4. 外边距(margin):位于边框之外,用于控制元素与其他元素之间的空白区域。

盒子模型中的这些部分共同决定了元素的总宽度和高度。元素的实际宽度由内容区域的宽度、左右内边距以及左右边框宽度的总和决定。元素的实际高度由内容区域的高度、上下内边距以及上下边框宽度的总和决定。

在 CSS 中,我们可以使用 `width` 和 `height` 属性来指定元素的内容区域的尺寸,使用 `padding`、`border` 和 `margin` 属性来控制内边距、边框和外边距的大小。此外,还可以使用 `box-sizing` 属性来改变盒子模型的行为方式,包括是否计算边框和内边距在内部。

了解盒子模型对于正确布局和样式设计非常重要,它允许我们精确控制元素的大小、间距和位置,以实现预期的页面效果。

52css如果要画一个三角形? 有哪些方法?

要使用 CSS 来绘制一个三角形,可以尝试以下几种方法:

1. 使用 border 属性:可以通过设置元素的宽度、高度为0,然后通过设置边框的宽度和颜色来实现绘制三角形的效果。通过调整不同方向边框的宽度来绘制不同方向的三角形。

```css

.triangle {

  width: 0;

  height: 0;

  border-left: 50px solid transparent;

  border-right: 50px solid transparent;

  border-bottom: 100px solid #000;

}

```

2. 使用伪元素 before 和 after:可以通过给元素的伪元素 before 和 after 设置宽度和高度为0,然后通过设置边框和相对定位来实现绘制三角形的效果。同样通过调整边框的宽度和位置来绘制不同方向的三角形。

```css

.triangle {

  position: relative;

}

.triangle:before,

.triangle:after {

  content: "";

  position: absolute;

  width: 0;

  height: 0;

  border-style: solid;

}

.triangle:before {

  border-width: 0 50px 100px 50px;

  border-color: transparent transparent #000 transparent;

  left: 0;

  top: 0;

}

.triangle:after {

  border-width: 0 50px 100px 50px;

  border-color: transparent transparent #000 transparent;

  right: 0;

  top: 0;

}

```

3. 使用 transform 属性:可以通过将元素的宽度和高度设为0,然后使用 transform 属性中的 `rotate()`、`scale()` 和 `skew()` 方法来实现绘制三角形的效果。通过调整旋转角度和缩放比例来绘制不同方向的三角形。

```css

.triangle {

  width: 0;

  height: 0;

  border-left: 50px solid transparent;

  border-right: 50px solid transparent;

  border-bottom: 100px solid #000;

  transform: rotate(45deg);

}

```

这些方法中,使用 border 属性和伪元素 before 和 after 的方式较为常见且灵活,可以满足大部分绘制三角形的需求。根据具体情况选择最适合的方法来绘制所需的三角形。

53ES6中数组的方法有哪些?

ES6(ECMAScript 2015)引入了一些新的数组方法,以下是其中一些常用且重要的数组方法:

1. map():对数组中的每个元素进行操作,并返回一个新的数组。

2. filter():根据指定条件筛选数组中的元素,并返回一个新的数组。

3. forEach():对数组中的每个元素执行一次指定的函数。

4. find():根据指定条件查找数组中第一个符合条件的元素,并返回该元素。

5. findIndex():根据指定条件查找数组中第一个符合条件的元素的索引,并返回该索引。

6. some():检测数组中是否存在满足指定条件的元素,只要有一个满足条件即返回 true。

7. every():检测数组中的所有元素是否都满足指定条件,只有所有元素都满足条件才返回 true。

8. reduce():将数组中的元素通过指定的函数进行归纳(从左到右),返回一个值。

9. includes():判断数组中是否包含指定的元素,返回布尔值。

10. Array.from():将类似数组或可迭代对象转换为真正的数组。

11. Array.of():根据传入的参数创建一个新的数组。

12. flat():将多维数组扁平化为一维数组。

13. flatMap():首先映射每个元素,然后将结果扁平化为一维数组。

除了上述方法,ES6 还引入了许多其他的数组方法,如:sort()、reverse()、join()、concat()、slice()、splice() 等,以及使用扩展运算符等更多便捷的处理方式。

这些新的数组方法在日常开发中非常实用,可以帮助我们更加方便、高效地操作和处理数组数据。

54、说说DOM常见的操作有哪些?

在 JavaScript 中,DOM(文档对象模型)是表示 HTML 文档的标准编程接口。通过使用 DOM,我们可以使用一组常见的操作来操纵 HTML 元素和处理页面中的内容。以下是 DOM 常见的操作:

1. 获取元素:

   - getElementById():根据元素的 ID 获取元素。

   - getElementsByClassName():根据类名获取一组元素。

   - getElementsByTagName():根据标签名获取一组元素。

   - querySelector():根据选择器获取第一个匹配的元素。

   - querySelectorAll():根据选择器获取所有匹配的元素。

2. 操作元素属性和内容:

   - innerHTML:获取或设置元素的 HTML 内容。

   - value:获取或设置表单元素的值。

   - className:获取或设置元素的类名。

   - attribute:获取或设置元素的属性值。

3. 创建、添加和删除元素:

   - createElement():创建新的元素节点。

   - createTextNode():创建包含文本的文本节点。

   - appendChild():将一个元素节点添加为另一个元素节点的子节点。

   - removeChild():从父节点中移除子节点。

4. 添加和移除事件监听器:

   - addEventListener():为元素添加事件监听器。

   - removeEventListener():移除元素的事件监听器。

5. 修改 CSS 样式:

   - style.property:修改元素的具体 CSS 属性。

   - classList.add():为元素添加一个或多个类名。

   - classList.remove():从元素中移除一个或多个类名。

6. 遍历和操作节点树:

   - parentNode:获取父节点。

   - childNodes:获取子节点列表。

   - nextSibling:获取下一个兄弟节点。

   - previousSibling:获取前一个兄弟节点。

   - cloneNode():复制节点。

以上仅是一些常见的 DOM 操作,还有许多其他的方法和属性可以用于处理和操纵 HTML 元素。DOM 操作在前端开发中非常重要,通过它可以实现动态更新页面内容、响应用户交互和操作HTML 元素等功能。

55、js本地存储的方式有哪些? 有什么区别?

JavaScript 提供了几种本地存储方式,用于在客户端浏览器中保存数据。以下是常见的本地存储方式以及它们之间的区别:

1. Cookie:

   - 存储容量:大多数浏览器支持每个域名最多存储 4KB 的数据。

   - 存储位置:数据存储在客户端浏览器中,每次请求都会发送到服务器。

   - 过期时间:可以设置过期时间,可以是会话级别(关闭浏览器后过期)或具体的日期时间。

   - 使用场景:适合存储小型数据,如用户标识、会话数据等。

2. LocalStorage:

   - 存储容量:大多数浏览器支持至少 5MB 的数据存储。

   - 存储位置:数据永久存储在客户端浏览器中。

   - 过期时间:没有过期时间,除非手动清除或使用代码删除。

   - 使用场景:适合存储较大的数据,如用户首选项、本地缓存等。

3. SessionStorage:

   - 存储容量:与 LocalStorage 相同,大多数浏览器支持至少 5MB 的数据存储。

   - 存储位置:数据存储在客户端浏览器中,每个浏览器窗口或标签页都有自己的 SessionStorage。

   - 过期时间:在会话结束后(关闭浏览器窗口或标签页)自动清除。

   - 使用场景:适合存储临时数据,如表单数据、页面间通信等。

4. IndexedDB:

   - 存储容量:较大,一般支持数百 MB 的数据存储。

   - 存储位置:数据存储在客户端浏览器中,以数据库形式进行组织。

   - 过期时间:没有过期时间,需要手动删除。

   - 使用场景:适合存储大量结构化数据,如离线应用、高级查询等。

5. Web SQL Database(已废弃):

   - 存储容量:与 IndexedDB 相同,较大。

   - 存储位置:数据存储在客户端浏览器中,以关系数据库形式进行组织。

   - 过期时间:没有过期时间,需要手动删除。

   - 使用场景:适合存储结构化数据,但已经被废弃,不建议使用。

区别总结:

- Cookie 是最古老的本地存储方式,容量小且每次请求都会发送到服务器。

- LocalStorage 和 SessionStorage 容量较大,但 SessionStorage 在会话结束后会自动清除。

- IndexedDB 是一种功能强大的数据库存储方式,适合存储大量结构化数据。

- Web SQL Database 已废弃,不建议使用。

选择合适的本地存储方式取决于数据大小、需要持久性还是临时性、是否涉及结构化数据等因素。

56、说说虚拟DOM和真实DOM的区别?优缺点

虚拟DOM(Virtual DOM)和真实DOM(Real DOM)是用于描述和操作网页上的元素的两种不同的概念和技术。

区别:

1. 结构:虚拟DOM是在内存中构建的一个虚拟副本,它是通过JavaScript对象表示的树状结构,而真实DOM是浏览器中实际存在的文档对象模型。

2. 操作速度:虚拟DOM操作速度相对较快,因为它在内存中进行处理,只在必要的时候将更改更新到真实DOM上,而真实DOM的操作速度相对较慢,因为每次更改都会引起页面的重新渲染和重绘。

3. 渲染频率:虚拟DOM可以进行批量更新,只在需要时对真实DOM进行最小化的更新,从而减少了页面重新渲染的次数,而真实DOM会立即更新,可能导致频繁的页面渲染。

4. 内存占用:虚拟DOM在内存中维护了一份副本,需要消耗额外的内存空间,而真实DOM直接操作浏览器的DOM树,不需要额外的内存占用。

优点:

- 虚拟DOM提供了一种方便的方式来描述和操作页面上的元素,使得前端开发更加灵活、高效。

- 虚拟DOM可以进行批量操作和最小化的更新,减少了页面的重新渲染次数,提高了性能。

- 虚拟DOM可以实现跨平台开发,例如使用React Native框架可以将虚拟DOM渲染到移动端设备上。

缺点:

- 使用虚拟DOM需要引入额外的库或框架,并且需要一定的学习成本。

- 虚拟DOM在处理大型应用或复杂页面时可能会消耗较多的内存。

- 虚拟DOM需要在内存中维护一份副本,可能带来一定的性能损耗。

总结而言,虚拟DOM具有便于操作、高效的特点,可以提升开发效率和性能,但也存在一些额外的开销。真实DOM则是浏览器的原生API,直接操作实际的DOM树,速度较慢,但没有额外的学习和库依赖。选择使用哪种方法取决于具体的应用场景和需求。

57、说说React不同阶段的生命周期?方法是?

在React中,组件的生命周期可以分为三个阶段:挂载阶段(Mounting)、更新阶段(Updating)和卸载阶段(Unmounting)。下面是每个阶段的生命周期方法:

1. 挂载阶段(Mounting):

   - `constructor()`:组件的构造函数,在组件实例化时调用,用于初始化状态和绑定方法。

   - `static getDerivedStateFromProps(props, state)`:该方法在组件实例化和重新渲染之前调用,用于根据新的属性来更新组件状态。

   - `render()`:此方法负责渲染组件的内容,返回JSX元素。

   - `componentDidMount()`:在组件被挂载到DOM后立即调用,适合进行异步数据获取、订阅事件等操作。

2. 更新阶段(Updating):

   - `static getDerivedStateFromProps(props, state)`:同挂载阶段。

   - `shouldComponentUpdate(nextProps, nextState)`:根据新的属性和状态判断是否需要重新渲染组件,默认返回true,可以通过优化控制是否进行重新渲染。

   - `render()`:同挂载阶段。

   - `getSnapshotBeforeUpdate(prevProps, prevState)`:在更新DOM之前获取更新前的快照,比如滚动位置等相关信息。

   - `componentDidUpdate(prevProps, prevState, snapshot)`:在组件更新后调用,适合进行DOM操作或网络请求等副作用操作。

3. 卸载阶段(Unmounting):

   - `componentWillUnmount()`:在组件即将被卸载和销毁之前调用,适合进行清理工作,如取消订阅、清除定时器等。

此外,还有一些其他的生命周期方法,如错误处理相关的方法:

- `static getDerivedStateFromError(error)`:在组件内部的子组件发生错误时调用,用于更新组件状态。

- `componentDidCatch(error, info)`:在组件内部的子组件发生错误后立即调用,用于记录错误信息。

需要注意的是,在React 16.3版本之后,一些生命周期方法被标记为已过时,建议使用新的生命周期方法或React钩子函数来替代。

58说说React的事件机制理解?

React的事件机制是建立在浏览器原生事件机制基础之上的,但使用了一些差异化的处理方式,以提供更好的可控性和性能。

1. 事件绑定:

   - React使用类似于HTML的事件绑定语法,在JSX中通过将事件作为属性传递给组件来进行事件绑定。例如,`<button onClick={handleClick}>Click me</button>`。

   - 在事件绑定时,需要将事件处理函数传递给事件属性,而不是直接在标签中使用字符串。

2. 事件处理函数:

   - React的事件处理函数是普通的JavaScript函数,定义在组件类中,可以使用箭头函数或普通函数的方式。

   - 事件处理函数接收一个事件对象作为参数,可以通过该对象获取事件的相关信息。

   - 在事件处理函数中,可以使用`this`关键字来引用组件实例。

3. 合成事件(SyntheticEvent):

   - React封装了一个合成事件对象(SyntheticEvent),它是一个跨浏览器兼容的事件对象,使开发者无需关心浏览器的差异性。

   - 合成事件对象提供了与原生事件对象类似的属性和方法,如`preventDefault()`、`stopPropagation()`等。

4. 事件委托:

   - React使用了事件委托的机制,将事件绑定到父组件上,然后通过事件冒泡机制处理子组件的事件。

   - 这样可以减少事件绑定的数量,提升性能,并且方便动态生成组件。

5. 性能优化:

   - React利用了事件委托机制和虚拟DOM的特性,通过事件的统一管理和高效的DOM更新算法,实现了更高效的事件处理和渲染性能。

   - React会对事件进行批量处理,通过合并多个事件更新,减少了不必要的DOM操作。

总结而言,React的事件机制在使用方式上与浏览器原生事件类似,但它提供了一些额外的功能和优化,如合成事件、事件委托和性能优化等,使得事件处理更加可控和高效。这样的设计使得开发者能够更好地处理和管理组件中的事件,并提升应用的性能和用户体验。

59、说说React中性能优化的方案有哪些?

React提供了许多性能优化的方案,以下是其中一些常用的方案:

1. 使用更高效的组件更新策略:

   - 使用合适的`shouldComponentUpdate`方法或`React.memo`来避免不必要的组件渲染。

   - React会自动比较前后两次渲染的虚拟DOM树的差异,并只更新变化的部分,但手动优化可以进一步减少渲染次数和开销。

2. 列表渲染的优化:

   - 使用`key`属性为列表项提供稳定的唯一标识,避免出现不必要的重新渲染和移动节点。

   - 对大型列表使用虚拟滚动技术,只渲染可见区域的列表项,减少DOM操作和内存消耗。

   - 使用列表组件如`React Virtualized`或`react-window`来实现虚拟滚动和优化。

3. 避免在渲染函数中创建新的对象和函数:

   - 避免在每次渲染时创建新的对象和函数,可以将它们移到组件外部或使用`useMemo`、`useCallback`进行缓存。

4. 异步渲染和分割任务:

   - 使用`React.lazy`和`Suspense`实现按需加载和代码分割,减少首次加载的资源大小。

   - 使用`React.Portal`将耗时的渲染任务移动到单独的线程或延迟处理,使主线程保持响应性。

5. 使用Immutable数据结构:

   - 使用Immutable数据结构(如`immutable.js`、`immer.js`)来避免不必要的对象复制和比较,提高性能和减少内存消耗。

6. 使用优化的第三方库和工具:

   - 使用经过优化的第三方库和工具,如`React.memo`、`React-router`的`<Link>`组件、`react-helmet`等。

7. 监控和分析性能:

   - 使用性能监控工具(如`React Profiler`、`react-devtools`、`Lighthouse`等)来分析应用的性能瓶颈并进行优化。

需要注意的是,性能优化的方案因项目需求和场景而有所不同,开发者需要根据具体情况选择合适的优化策略。同时,性能优化也需要权衡代码复杂性和可读性,避免过度优化影响开发效率和代码可维护性。

60、说说你对同步异步的理解?

同步(Synchronous)和异步(Asynchronous)是两种不同的执行方式,用于描述操作的执行顺序和控制流程。

1. 同步:

   - 在同步操作中,代码按照顺序依次执行,每个操作都会等待前一个操作完成后再进行。

   - 同步操作是阻塞的,即当前操作未完成时,后续操作会一直等待。

   - 同步操作适用于需要按照特定顺序执行的场景,但可能会导致程序在等待耗时操作完成期间出现阻塞,降低程序的响应性能。

2. 异步:

   - 在异步操作中,代码不会等待操作完成,而是继续执行下面的代码,并通过回调函数、Promise、async/await等方式来处理操作完成后的结果。

   - 异步操作是非阻塞的,即后续代码可以继续执行而无需等待当前操作完成。

   - 异步操作适用于需要处理耗时操作或依赖外部资源的场景,可以提高程序的并发性能和响应性能,但也增加了代码的复杂性和处理异步结果的难度。

总结而言,同步和异步是描述代码执行方式的概念。同步操作按顺序执行且阻塞,适用于顺序执行的场景。异步操作不等待操作完成且非阻塞,适用于需要处理耗时操作或并发执行的场景。开发者需要根据具体需求选择合适的操作方式,并注意异步操作带来的回调处理、错误处理和代码复杂性等方面的考虑。

61、说说你对event Loop的理解?

事件循环(Event Loop)是一种用于处理异步操作和事件响应的机制,广泛应用于Javascript等单线程的编程语言中。

事件循环的主要任务是监听事件队列,并按顺序执行队列中的事件。它由以下几个组件组成:

1. 调用栈(Call Stack):用于存储函数调用的记录,即当前执行的代码。当函数被调用时,会将其添加到调用栈中,执行完毕后从栈中移除。

2. 事件队列(Event Queue):用于存储待处理的事件和回调函数。当异步操作完成、定时器到期或用户触发事件时,相应的事件和回调函数会被添加到事件队列中。

3. 事件循环(Event Loop):负责不断地检查调用栈和事件队列,将事件队列中的事件逐个取出并推入调用栈中执行。事件循环会在调用栈为空时,将下一个事件添加到调用栈中执行。

事件循环的执行过程如下:

1. 执行全局同步代码,将其中的函数调用和声明添加到调用栈中执行。

2. 当遇到异步操作(如定时器、网络请求等),将其交由相应的Web API处理,并放置在事件队列中。

3. 当调用栈为空时,事件循环开始工作,从事件队列中取出一个事件,将其添加到调用栈中执行。

4. 如果事件是一个异步操作的回调函数,则执行该回调函数,并可能触发新的异步操作。

5. 重复步骤3和步骤4,直到事件队列为空。

事件循环的机制使得异步操作可以在单线程中以非阻塞的方式执行,提高了程序的并发性能和响应性能。同时,开发者需要理解事件循环的工作方式,避免出现长时间的同步操作或过多的嵌套回调,导致调用栈无法清空,造成程序的阻塞或卡死。

62Vue2的响应式的原理是什么?

Vue2的响应式原理是利用了 ES5 的Object.defineProperty() 方法,为对象的属性设置 getter 和 setter 方法,在数据变化时可以监听到变化并触发相应的更新。当一个对象被响应化后,对该对象的设置、删除和添加属性的操作都会被监听到,从而触发重新渲染视图。Vue2的响应式系统是基于依赖收集的概念,当数据被使用时会建立依赖关系,如果数据发生改变,那么依赖于该数据的所有组件都会收到通知并触发重新渲染。这种基于依赖管理的响应式原理是 Vue2 的核心特性之一。

63Vue中数据更新视图不更新的原因是什么?

Vue中数据更新视图不更新的原因可能有以下几点:

1. 数据未设置响应式:如果数据没有被设置为响应式,当此数据变化时,视图不会跟着变化。

2. 数据的更新不在Vue的监控之下:如果是数据变化影响了视图,但是这个变化不是由Vue所监控的,比如直接在浏览器控制台中修改了数据,那么视图是不会更新的。

3. 异步更新:有些特殊的情况下,比如在Vue的watcher更新DOM时,会使用异步更新,如果我们在异步更新前修改了数据,那么数据的变化可能就不会触发更新DOM的逻辑。

4. 代码书写问题:可能是我们在代码书写上存在一些问题,比如没有在正确的位置绑定数据,或者没有正确的更新相关数据等等。

64Vue中nextTick的作用是什么?

Vue中的nextTick方法的作用是将回调函数延迟到下次 DOM 更新循环之后执行。这个方法通常用于在更新页面后需要对新的DOM结构进行操作或者进行一些复杂或计算性的操作,以确保这些操作在DOM更新完毕后执行。

这是因为在 Vue 中,当我们更新的数据被引起了DOM结构的改变时,并不会立即更新 DOM,而是在下一个tick中进行更新。这样做的目的是为了优化性能,避免在数据变化时,频繁的去操作 DOM,以此提高用户体验和页面性能。

使用nextTick()方法可以确保在下一次更新DOM时执行回调函数,因此可以在操作DOM之前确定DOM已经被更新。它还可以用作Vue更新生命周期钩子(例如updated)之后执行的回调函数的替代方法。

总之,Vue中的nextTick方法非常有用,它可以确保我们的操作(例如访问DOM元素)在页面渲染后进行,从而避免了许多潜在的问题。

65Vue中组件缓存如何实现? A页面到B页面。A页面缓存,A页面到C页面,A页面缓存取消?如何实现?

Vue中可以使用<keep-alive>标签来实现组件缓存。在需要缓存的组件外层套上<keep-alive>标签,即可实现组件缓存。同时,可以通过include和exclude属性来控制哪些组件需要被缓存,哪些组件不需要被缓存。

根据题目描述,可以在A页面外层套上<keep-alive>标签实现A页面的缓存。在A页面跳转到B页面时,如果需要保持A页面的缓存,则不做任何处理;如果需要取消A页面的缓存,则可以使用$destroy方法销毁A页面的状态。

在A页面跳转到C页面时,再次根据需要来决定是否需要保持A页面的缓存。如果需要保持缓存,则不做任何处理;如果需要取消缓存,则调用$destroy方法销毁A页面的状态。

具体代码实现如下:

<template>

  <div>

    <keep-alive :include="[A]">

      <router-view></router-view>

    </keep-alive>

  </div>

</template>

<script>

export default {

  data() {

    return {

      A: 'A'

    }

  },

  methods: {

    destroyCache() {

      this.$refs.A.$destroy()

    }

  }

}

</script>

// 在A页面中跳转到B页面

this.$router.push('/B')

// 取消A页面缓存

this.$refs.cache.destroyCache()

// 在A页面中跳转到C页面

this.$router.push('/C')

// 保持A页面缓存,不做任何处理

66、说说你对Vue中虚拟DOM和diff算法的理解?

Vue中的虚拟DOM是一种内存中的表现形式,通过与真实的DOM进行比对来实现高效的渲染更新。当Vue的数据发生变化时,Vue会进行一次虚拟DOM的重渲染,并与先前的虚拟DOM进行比对,找出需要更新的部分,并只更新这些部分到真实的DOM中,从而减少DOM操作的次数,提升了页面的性能。

而diff算法就是用来比对前后虚拟DOM树的算法。其核心思想是根据前后虚拟DOM树之间的差异,将需要更新的部分针对性地更新到真实的DOM中,而不是把整个DOM重新渲染一遍。Vue中的diff算法采用了较为高效的双指针算法,同时也使用了一些优化措施,如设置key值来判定节点是否是相同节点,避免不必要的更新等,从而进一步提升了页面的性能。

总之,虚拟DOM和diff算法是Vue中非常重要的概念,其应用使得Vue可以在不影响页面性能的情况下实现高效的数据渲染和更新。

67、什么是防抖和节流?使用场景?

防抖和节流是前端开发中常用的优化性能的技术。

防抖:指在事件被触发n秒后再执行回调函数,如果在这n秒内又被触发,则重新计时。简单来说就是限制一个函数在一段时间内只能执行一次。

常见场景:

- 搜索框输入联想,用户在输入完毕后可以等待一段时间再发送请求搜索,避免用户频繁触发请求。

- 窗口大小改变时需要重新计算布局,但是用户连续快速地调整窗口大小会导致代码过于频繁地重新计算布局,影响性能。

节流:指间隔一段时间执行一次回调函数,如果在这段时间内又被触发,则不会再执行回调函数。简单来说就是减少一个函数的执行次数。

常见场景:

- 页面滚动时需要动态加载数据,用户滚动非常快的时候会频繁地触发加载数据,导致浏览器负载过高,影响性能。

- 按钮点击事件,防止用户连续点击触发多次请求,导致服务器负载过高。

综上,防抖和节流都是为了避免频繁触发函数从而影响性能,防抖是限制一个函数在一段时间内只能执行一次,而节流是间隔一定时间执行一次函数。

68说说你对弹性盒子的理解?使用场景有哪些?常用属性?

弹性盒子(Flexbox)是一种用于网页布局的模块化CSS布局工具。它通过定义容器和容器内的子元素之间的关系,实现了灵活的自适应布局。

弹性盒子的使用场景包括但不限于以下几种:

1. 垂直居中:弹性盒子可以轻松实现垂直居中,无论是将内容垂直居中还是完整的盒子垂直居中。

2. 等高列布局:当需要多列布局时,弹性盒子可以确保多个盒子的高度相等,使布局更加整齐美观。

3. 自适应布局:弹性盒子可以根据容器的大小自动调整子元素的宽度和高度,从而适应不同尺寸的屏幕或设备。

4. 排序和重新排序:弹性盒子允许轻松地改变子元素在容器中的顺序,从而实现灵活的排列方式。

常用的弹性盒子属性有:

1. display:指定容器为弹性盒子,可以设置为"flex"或"inline-flex"。

2. flex-direction:指定弹性盒子的主轴方向,可以是"row"(水平方向)、"column"(垂直方向)、"row-reverse"(水平反向)或"column-reverse"(垂直反向)。

3. flex-wrap:指定子元素是否换行,可以是"nowrap"(不换行)或"wrap"(换行)。

4. justify-content:指定子元素在主轴上的对齐方式,可以是"flex-start"(起点对齐)、"flex-end"(终点对齐)、"center"(居中对齐)、"space-between"(两端对齐,中间间隔相等)或"space-around"(子元素之间间隔相等)。

5. align-items:指定子元素在交叉轴上的对齐方式,可以是"flex-start"(起点对齐)、"flex-end"(终点对齐)、"center"(居中对齐)、"baseline"(基线对齐)或"stretch"(拉伸填充对齐)。

6. align-content:指定多行子元素在交叉轴上的对齐方式,只有在有多行时才有效果,可以是"flex-start"(起点对齐)、"flex-end"(终点对齐)、"center"(居中对齐)、"space-between"(两端对齐,中间间隔相等)或"space-around"(子元素之间间隔相等)。

这些属性可以通过组合使用,灵活地控制弹性盒子的布局和对齐方式。

69、说说你对css预编译语言的理解?使用场景有哪些?

CSS预处理器是一种将类似于编程语言的特性引入CSS的工具。它们允许开发者使用变量、函数、嵌套规则、混合等高级概念来编写CSS样式表,并通过预处理器将其转换为标准的CSS代码。

使用CSS预处理器的主要场景包括但不限于以下几个方面:

1. 提高开发效率:通过使用变量和嵌套规则,可以减少代码的重复书写,使样式表更加易于维护。预处理器还提供了一些实用的函数和混合(Mixin)功能,可以进一步简化样式的编写。

2. 提供可复用的样式组件:通过使用预处理器的函数和混合功能,可以创建可复用的样式组件。这些组件可以在多个项目中共享和重用,减少了代码冗余并提高了代码的可维护性。

3. 支持条件逻辑和算术运算:预处理器引入了条件语句和数学运算的功能,使得可以根据特定条件应用不同的样式,或者对数值进行计算。这使得样式更加灵活和动态。

4. 自动添加浏览器前缀:许多CSS属性在不同的浏览器中需要添加前缀以实现兼容性。预处理器可以根据配置自动添加这些前缀,省去手动添加的繁琐过程。

5. 代码模块化和组织:通过将样式表分割成多个模块,可以更好地组织和管理代码。预处理器提供了导入和注释功能,使得可以轻松地引用其他模块并进行代码注释。

不同的CSS预处理器有不同的语法和特性,常见的CSS预处理器包括Sass、Less和Stylus等。它们都提供了类似的功能,但具体的语法和用法可能有所不同。选择适合自己项目需求的预处理器,并根据文档学习其语法和使用方法,可以在开发中获得更高效且可维护的CSS样式表。

70、说说原生Ajax的实现原理是什么,实现步骤?

原生Ajax(Asynchronous JavaScript and XML)是一种通过JavaScript使用XMLHttpRequest对象与服务器进行异步通信的技术。它可以在不重新加载整个页面的情况下,通过后台发送HTTP请求并接收响应数据,实现动态更新页面内容。

原生Ajax的实现原理如下:

1. 创建XMLHttpRequest对象:通过JavaScript代码创建一个名为XMLHttpRequest的对象,用于向服务器发送HTTP请求和接收响应。

2. 初始化请求:使用XMLHttpRequest对象的open()方法,指定请求的类型(GET、POST等)、URL和是否采用异步方式(通常为true,即异步)。

3. 设置回调函数:使用XMLHttpRequest对象的onreadystatechange事件,指定当状态改变时要执行的处理函数。

4. 发送请求:使用XMLHttpRequest对象的send()方法,发送HTTP请求到服务器。

5. 接收响应:浏览器会异步地接收来自服务器的响应,并将响应数据存储在XMLHttpRequest对象的responseText或responseXML属性中,可以通过这些属性获取到服务器返回的数据。

6. 处理响应:在回调函数中,检查XMLHttpRequest对象的readyState属性,它表示请求的当前状态。当readyState值为4时,表示请求已完成,可以从responseText或responseXML属性中获取到完整的响应数据。

7. 更新页面内容:根据请求的响应数据,使用JavaScript代码更新页面的内容,可以是更新特定的元素、执行其他操作或进行错误处理。

原生Ajax的实现步骤可以简单概括为创建对象、初始化请求、发送请求、接收响应和处理响应。通过这些步骤,可以实现与服务器的异步通信,并在不刷新整个页面的情况下更新页面内容。

71、为什么要有跨域?JS跨域怎么解决?

跨域是指在浏览器中,当前网页所在的域(协议、域名或端口)与请求的资源所在的域不一致,浏览器会限制跨域请求。这是为了保护用户隐私和安全,防止恶意网站访问其他域上的资源。跨域问题是前端开发中常遇到的一种限制。

JS跨域问题可以通过以下几种方式解决:

1. JSONP (JSON with Padding):JSONP是一种利用<script>标签进行跨域请求的技术。通过在页面中动态创建<script>标签,将跨域请求的URL作为<script>的src属性值,服务器返回的响应需要包裹在一个函数调用中,并在响应中传递回调函数名作为参数。这样可以绕过浏览器的同源策略。但JSONP只支持GET请求,且存在安全风险。

2. CORS (Cross-Origin Resource Sharing):CORS是一种现代浏览器提供的跨域解决方案。服务器通过在响应头中添加特定的HTTP头部字段,如Access-Control-Allow-Origin,来告知浏览器哪些域允许访问资源。前端发送请求时,浏览器先发起一个预检请求(OPTIONS),以确定是否允许实际请求,然后根据服务器返回的响应决定是否发送实际请求。

3. 代理服务器:通过在同源域名下设置一个代理服务器,将跨域请求转发到目标服务器,并将响应返回给前端。前端通过访问代理服务器解决跨域问题。这种方式需要后端配合设置代理服务器。

4. WebSocket:由于WebSocket是一种基于TCP协议的双向通信协议,它允许浏览器与服务器之间建立持久连接,因此不会受到同源策略的限制。前端可以通过WebSocket与服务器进行跨域通信。

以上是常见的几种解决JS跨域问题的方式。选择适合自己项目需求和环境的方式来解决跨域问题是很重要的。

72new 一个对象具体做了什么?

使用`new`关键字来创建一个对象时,会进行以下几个步骤:

1. 创建一个新的空对象:在内存中分配一块空间,用于存储新创建的对象。

2. 将对象的原型指向构造函数的原型:新对象会继承它的构造函数的原型对象上的属性和方法。通过设置新对象的[[Prototype]]属性指向构造函数的prototype属性,建立了对象与构造函数之间的原型链。

3. 执行构造函数的代码块:将构造函数作为一个普通的函数调用,此时的`this`指向新创建的对象。在构造函数内部,可以通过`this`关键字来引用新对象,并给新对象添加属性和方法。

4. 返回新的对象:如果构造函数没有显式返回其他对象,则`new`表达式返回新创建的对象;否则,返回构造函数显式返回的对象。

总结起来,`new`关键字的作用是创建一个新的对象,并将该对象的原型指向构造函数的原型,同时执行构造函数内的代码,并返回新的对象。这样,通过`new`操作符调用构造函数可以方便地创建具有相同属性和方法的多个对象。

73js中数据类型判断的方法有哪些?

在JavaScript中,我们可以使用多种方法来进行数据类型的判断。以下是一些常用的方法:

1. typeof操作符:可以用于判断一个值的基本数据类型,返回一个表示数据类型的字符串。例如,`typeof 42`会返回"number",`typeof "hello"`会返回"string",`typeof true`会返回"boolean",等等。需要注意的是,`typeof null`会返回"object",这是一个历史遗留问题。

2. instanceof操作符:可以用于判断一个对象是否属于某个类或构造函数的实例。例如,`obj instanceof Array`可以判断`obj`是否是数组的实例。

3. Object.prototype.toString方法:可以通过调用`Object.prototype.toString`方法,传入要判断的值作为方法的上下文,可以返回一个表示值的具体类型的字符串。例如,`Object.prototype.toString.call([])`会返回"[object Array]",`Object.prototype.toString.call({})`会返回"[object Object]"。

4. Array.isArray方法:用于判断一个值是否为数组类型。例如,`Array.isArray([])`会返回true,而`Array.isArray({})`会返回false。

5. isNaN函数:用于判断一个值是否为NaN(非数字)。例如,`isNaN(NaN)`会返回true,而`isNaN(42)`会返回false。需要注意的是,`isNaN`函数会先尝试将参数转换为数值类型,如果无法转换,则返回true。

6. 自定义类型检测函数:根据不同的需求,也可以自定义一些类型检测函数来进行判断。例如,检测一个值是否为函数类型可以使用`typeof value === 'function'`,检测一个值是否为字符串类型可以使用`typeof value === 'string'`等。

这些方法可以根据具体的需求和场景来选择使用,通常结合多个方法来做更加准确的类型判断。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值