前端面试题总结04

前端面试总结04

一、介绍mvvm模式以及它的优势

MVVM模式主要包含一下三个组件:

  1. Model(模型):模型代表应用程序的数据和业务逻辑。它负责处理数据的存储,检索和修改,以及应用程序的业务逻辑。
  2. View(视图):视图是用户界面的呈现层。负责展示数据给用户并与用户交互。视图通常是由数据绑定到视图元素上的模板组成。
  3. ViewModel(视图模型):视图模型是连接模型和视图的桥梁,负责处理视图的展示逻辑和用户交互,并与模型进行交互。视图模型包含视图所有的数据和方法,它通过双向数据绑定将视图和模型连接起来。

MVVM模式的优势:

  1. 分离关注点。MVVM模式将用户界面的展示逻辑从业务逻辑和数据处理逻辑中分离出来,使得代码更加模块化和易于维护。
  2. 双向数据绑定:MVVM模式通过双向数据绑定机制实现视图和模型之间的自动同步,当模型数据发生变化时,视图自动更新;反之,用户在视图上的操作也会直接影响模型数据。
  3. 可测试性:由于MVVM模式将视图和业务逻辑分离得很清晰,因此可以更容易地编写单元测试来测试视图模型的逻辑,而不需要依赖于用户界面。
  4. 代码复用:MVVM模式鼓励将视图模型和数据逻辑分开,这样可以更好地复用视图模型,使得在不同的视图中共享相同的逻辑变得更加容易。
  5. 增强开发效益:MVVM模式使得前端开发更叫高效,开发人员可以专注于不同层面的工作,提高团队协作效率。

二、双向数据绑定是如何实现的

双向绑定是MVVM模式的一个重要的特性,它实现了视图和视图模型之间的数据同步。当一个地方的数据发生改变时,另一个地方的数据也会随之更新。

实现方式:

  1. 数据劫持:Vue中使用数据劫持方法实现双向数据绑定。当创建Vue实例时,Vue会遍历data选项中的属性,使用Object.defineProperty()方法将这些属性转为getter和setter,从而在数据发生变化时能够通知到订阅者。
  2. 脏检查(Angular):在Angular中使用脏检查机制来实现双向数据绑定。在Angular中,会创建一个脏检查机制,定期检查数据模型和视图之间的变化。如果数据模式发生变化,Angular会更新视图,反之亦然。
  3. 事件监听(原生):在JavaScript中通过事件监听来实现简单的数据双向绑定。例如,可以通过监听输入框的input事件来实时更新数据模型,同时也可以在数据模型发生变化时更新视图。
  4. Angular的双向数据绑定指令:Angular中提供了一些指令来实现双向数据绑定,这些指令会自动处理数据模型和视图之间的同步,简化开发过程。

三、动态路由如何实现

动态路由是根据特定的参数或条件来动态地加载不同的页面或组件。

在React中,可以通过React Router来实现动态路由。

示例:

  1. 下载依赖 npm install react-router-dom

  2. 在主组件中设置路由:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import User from './User';

function App() {
return (
<Router>
<Switch>
<Route path="/user/:id" component={User} />
</Switch>
</Router>
);
}

export default App;
  1. 创建一个对应的User.jsx组件,展示自定义信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React from 'react';
import { useParams } from 'react-router-dom';

function User() {
let { id } = useParams();

return (
<div>
<h2>User ID: {id}</h2>
{/* 在这里根据用户ID加载对应的用户信息 */}
</div>
);
}

export default User;
  1. 在其他组件中,也可以通过动态链接来访问User组件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from 'react;
import { Link } from 'react-router-dom';

function otherComponent() {
return (
<div>
<Link to="/user/123">User 123</Link>
<Link to="/user/456">User 456</Link>
</div>
);
}

export default otherComponent;

在Vue中,可以使用Vue Router来实现动态路由。

示例:

  1. 下载依赖 npm install vue-router

  2. 在router/index.js中设置路由

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import Vue from 'vue';
import Router from 'vue-router';
import User from '@/components/User.vue';

Vue.use(Router);

export default new Router({
routes: [
{
path: '/user/:id',
name: 'User',
component: User
}
]
});

  1. 创建User.vue来显示自定义内容。
1
2
3
4
5
6
7
8
9
10
11
12
<template>
<div>
<h2>User ID: {{ $route.params.id }}</h2>
<!-- 在这里根据用户ID加载对应的用户信息 -->
</div>
</template>

<script>
export default {
name: 'User',
};
</script>
  1. 在其他组件中,也可以使用来生成动态链接,同理于React。
1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<div>
<router-link :to="{ name: 'User', params: { id: 123 }}">User 123</router-link>
<router-link :to="{ name: 'User', params: { id: 456 }}">User 456</router-link>
</div>
</template>

<script>
export default {
name: 'otherComponent',
};
</script>

四、vue中如何深度监听数组

以下方法可以监听数组的变化并触发重新渲染:

  1. 使用Vue.set方法
1
2
//假设目标数组为myArr
this.$set(this.myArr,indexOfItem,newValue);
  1. 使用Object.assign方法
1
2
// 假设你有一个名为 myArr 的对象数组
this.items = Object.assign([], this.myArr, { [indexOfItem]: newValue });
  1. 使用splice方法
1
this.myArr.splice(indexOf,1,newValue);

五、路由传参方式以及如何获取参数

在Vue中有三种路由传参的方法,分别为params传参和query传参,其中params传参又分为显示参数和不显示参数两种。

  1. params传参(显示参数)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//子路由需要提前配置
{
path:'/child/:id',//定义一个带参数的路由
component:Child
}

//父路由组件
//声明式router-link
<router-link :to='/child/123'>进入到child组件中<router-link/>
//编程式---一般通过事件触发
this.$router.push({
path:'/child/123'
})

//组件获取参数
this.$route.params.id
  1. params传参(不显示参数)

params传参不显示参数与显示参数不同的是,此时需要路由的别名name进行传值。(不显示参数的方式会导致在刷新页面的时候,传递的值会丢失)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//路由配置
{
path:'/child',
name:'child',
component:Child
}
//声明式
<router-link :to="{name:'child',params:{id:123}}">进入child路由中<router-link/>

//编程式
this.$route.push({
name:'Child',
params:{
id:123
}
})

//获取参数
this.$route.params.id
  1. query传参
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//路由配置
{
path:'/child',
name:'child',
component:Child
}

//声明式
<router-link :to="{name:'child',query:{id:123}}">进入child路由中<router-link/>

//编程式
this.$router.push({
name:"child",
query:{
id:123
}
})

//获取参数
this.$route.query.id

React中路由传参的方式有:

  1. params传参:useParams()
1
2
3
4
5
6
7
8
9
10
11
//首选进行路由配置
{
path:"/child/:id",
element:<Child/>,
}

//声明式
<Link to={`/child/${id}`}>路由跳转</Link>

//接收参数
const {id}=useParams();
  1. search传参:useSearchParams()
1
2
3
4
5
6
7
8
9
10
11
12
////首选进行路由配置
{
path:"/child",
element:<Child/>,
}

//声明式
<Link to={`/child?id=${id}`}>路由跳转</Link>

//接收参数
const [search,setSearch]=useSearchParams();
const id=search.get('id');
  1. state传参:useLocation()
1
2
3
4
5
6
7
8
9
10
11
12
////首选进行路由配置
{
path:"/child",
element:<Child/>,
}

//声明式导航传参
<Link to='/child' state={{id:123}}>路由跳转</Link>

//接收参数
const {state} =useLocation();
const {id}=state;

六、介绍Vuex

Vuex是Vue的状态管理模式。

主要概念:

  1. State状态

    Vuex中的State类似于组件中的data,所有组件都共享这些数据,并且可以通过this.$store.state进行访问。

  2. Getter获取器

    类似于组件中的计算属性,组件可以通过this.$store.getters来访问这些状态。

  3. Mutations突变

    Mutations是用来修改state的唯一方式,且它必须是同步函数,通过提交一个mutation来改变状态,可以通过this.$store.commit来调用。

  4. Actions动作

    actions用于处理异步操作,通过提交mutation来改变状态。通过this.$store.dispatch来调用。

  5. Modules模块

    modules可以将store分隔成模块,一般在store状态过多时使用。每个模块都有自己的state,getters,mutations,actions。

一个简单的store写法为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import Vue from 'vue';
import Vuex from 'vuex';//需要下载Vuex依赖

Vue.use(Vuex);
const store=new Vuex.Store({
state:{
count:0
},
getters:{},
mutations:{
changeCount(state){
state.count++;
}
},
actions:{
changeCount01(context){
context.commit('changeCount')
}
}
});
export default store;

七、vuex中actions可以直接修改state中的数据吗?

严格来说,actions不应该直接修改state中的数据。actions主要用于处理异步操作,触发mutations来改变state的值。

这样做的好处是:

  1. 可追踪性质:通过提交mutations来修改state,可以更加清晰地追踪数据的变化,了解数据是如何被修改的。
  2. 数据流的明确性:严格遵守数据流的规则:actions复杂处理异步操作和业务逻辑,而mutations复杂修改state,各司其职。
  3. 易于调试:将修改state的逻辑集中在mutations中,可以使得代码逻辑更加清晰,易于调试和理解代码。

八、组件之间的通信方式

Vue中组件的通信方式有:

  1. Props和Events

    父组件可以通过props属性向子组件传递数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    <!--父组件-->
    <template>
    <ChildComponent :message='parentMessage'></ChildComponent>
    </template>

    <script>
    import ChildComponent from './ChildComponent.vue';
    export default{
    data(){
    return {
    parentMessage:'这是父组件传给子组件的数据'
    }
    },
    components:{
    ChildComponent
    }
    }
    </script>

    <!--子组件-->
    <template>
    <div>
    {{messgae}}
    </div>
    </template>
    <script>
    export default {
    props:['message']
    }
    </script>

    子组件可以通过event事件触发来通知父组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    <!--子组件-->
    <template>
    <div>
    <button @click='sendMessageToParent'>
    向父组件发送事件
    </button>
    </div>
    </template>
    <script>
    export default {
    methods:{
    sendMessageToParent(){
    this.$emit('message-to-parent','这是子组件向父组件传递的数据');
    }
    }
    }
    </script>

    <!--父组件-->
    <!--接收数据-->
    <template>
    <ChildComponent @message-to-parent='handleMessageFromChild'></ChildComponent>
    </template>

    <script>
    import ChildComponent from './ChildComponent.vue';
    export default{
    components:{
    ChildComponent
    },
    methods:{
    handleMessageFromChild(message){
    console.log("获取到子组件传递来的数据",message);
    }
    }
    }
    </script>
  2. Vuex:

    使用Vuex进行全局的状态管理,实现组件之间的通信。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
       // store/index.js
    import Vue from 'vue';
    import Vuex from 'vuex';
    Vue.use(Vuex);
    export default new Vuex.Store({
    state:{
    message:"一个全局数据",
    },
    mutations:{
    changeMessage(state,newMessage){
    state.message=newMessage;
    }
    }
    });
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <!--在组件中使用store中的数据-->
    <template>
    <div>
    {{message}}
    </div>
    </template>
    <script>
    export default {
    computed:{
    message(){
    //获取Vuex中的数据
    return this.$store.state.message;
    }
    }
    }
    </script>
  3. Event Bus

    事件总线实现组件之间的通信,相当于在组件之间架起了一个桥梁。

    1
    2
    3
    // EventBus.js
    import Vue from 'vue';
    export const EventBus=new Vue();
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    <!--在组件中使用事件总线发送数据-->
    <template>
    <button @click='sendMessage'>
    发送数据
    </button>
    </template>
    <script>
    import {EventBus} from './EventBus.js';
    export default {
    methods:{
    sendMessage(){
    EventBus.$emit('message-to-other','发送一条数据');
    }
    }
    }
    </script>

    <!--在组件中使用事件总线接收数据-->
    <template>
    <div>
    {{message}}
    </div>
    </template>
    <script>
    import {EventBus} from './EventBus.js';
    export default {
    data(){
    return {
    massage:""
    }
    }
    created(){
    EventBus.$on('message-to-other',message=>{
    this.message=message;
    })
    }
    }
    </script>

前端面试题总结04
https://chen77.top/2024/03/01/interview/前端面试题总结04/
作者
小陈
发布于
2024年3月1日
许可协议