zoukankan      html  css  js  c++  java
  • Vue全家桶+React全家桶面试题及部分原理整理

    Vue全家桶+React全家桶面试题及部分原理整理



    Vue
    v-if和v-show的区别?
    v-if表达式为true显示该元素,为false隐藏该元素(直接删除)
    v-show根据表达式的真假来显示与隐藏元素,会在标签加入display属性
    为何v-for中要用key
    vue中列表循环需加:key=“唯一标识” 唯一标识可以是item里面id index等,因为vue组件高度复用增加Key可以标识组件的唯一性,为了更好的区别各个组件,key的作用主要是为了高效的更新虚拟DOM
    注意:v-for和v-if不能同时使用
    父子组件之间的通讯
    父传子组件标签中,子组件通过props接收
    子组件通过$emit()传送事件,父组件需要通过v-on去监听自定义事件
    vue生命周期
    ------------------beforeCreate初始化之前状态(el,data,msg还没有初始化)
    el:undefined
    data:undefined
    msg:undefined
    ------------------created初始化之后状态(el还没有挂载,data中已经初始化有了数据)
    el:undefined
    data:[object Object]
    msg:hello vue
    ------------------beforeMount挂载之前状态(el已经挂载,但还没有渲染)
    el:

    {{msg}}


    data:[object Object]
    msg:hello vue
    ------------------mounted挂载之后状态(el挂载并渲染)
    el:

    hello vue


    data:[object Object]
    msg:hello vue
    ------------------beforeUpdate更新前
    ------------------updated更新后
    ------------------beforeDestroy销毁前的状态
    ------------------destroyed销毁后的状态
    父子组件生命周期调用顺序
    先父组件created,然后子组件created,之后子组件mounted,再父组件mounted
    (创建是从外到内,渲染是从内到外,子组件渲染完再父组件)
    更新阶段,先父组件update,然后子组件update,然后子组件updated,再父组件updated
    何时需要使用beforeDestory
    解绑自定义事件event.$off
    清除自定义的DOM事件,如window scroll等
    Vuex中action和mutation有何区别
    action中处理异步,mutation不可以
    mutation做原子操作
    action可以整合多个mutation
    Vue3升级内容
    全部用ts重写(响应式、dom、模板编译等)
    性能提升,代码量减少,会调整部分API
    Proxy实现响应式(基本使用)
    Proxy能规避Object.defineProperty的问题,但Proxy无法兼容所有浏览器,无法polyfill


    Vue高级特性
    自定义v-model

    //---------------子组件传值
    //绑定 input 事件,$emit 触发父组件的 input 事件
    <input type="text" @input="$emit('input', $event.target.value)">
    //父组件监听 input 事件,然后将事件携带的 input 输入的值传入到 data 状态中
    <my-children @input="value = $event"></my-children>
    export default {
    data () {
    return {
    value: ''
    }
    }
    }
    //-------------父组件传值
    //将value值传递给子组件,子组件再绑定 value值到 input的value属性上
    <my-children :value="value" @input="value = $event"></my-children>
    //子组件中绑定 input 的 value 属性
    <input type="text" @input="$emit('input', $event.target.value)" :value="value">
    //props设定value值
    export default {
    name: 'myChildren',
    props: ['value']
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    $nextTick

    Vue是异步渲染,data改变之后,DOM不会立即渲染,$nextTick会在DOM渲染之后被触发,以获取最新DOM节点
    页面渲染时会将data的修改做整合,多次data修改只会渲染一次

    <ul ref="uls">
    <li>***</li>
    </ul>

    this.$nextTick(()=>{
    //获取DOM元素
    const ulElem =this.$refs.uls
    console.log(ulElem.childNodes.length)
    })
    1
    2
    3
    4
    5
    6
    7
    8
    9
    slot

    <div id="app">
    <my_cpn>
    <button>按钮</button>
    <span slot="btn">具名插槽使用</span>
    <my_cpn>
    <template v-slot="get">
    <span v-for="item in get.set_data">{{item}}</span>
    </template>
    </my_cpn>
    </my_cpn>
    </div>
    <template id="p">
    <div>
    <slot><p>匿名slot插件默认内容</p></slot>
    <slot name="btn"><button>按钮</button></slot>//具名插槽
    <slot :set_data="str">//作用域插槽使用
    <ul>
    <li v-for="item in str">{{item}}</li>
    </ul>
    </slot>
    </div>
    </template>
    const vm = new Vue({
    el:"#app",
    data:{},
    components:{
    my_cpn:{
    template:"#p",
    data(){
    return {
    str:["一","二","三","四"]
    }
    }
    }
    }
    })
    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
    动态异步组件
    :is="component-name"用法,需要根据数据,动态渲染的场景。即组件类型不确定

    <component :is="NextTickName"/>//使用动态组件

    <FormDemo v-if="showFormDemo"/>//异步组件
    <button @click="showFormDemo = true">show form demo </button>
    import NextTick from "./NextTick"//导入外部组件
    export default{
    components:{
    NextTick,
    FormDemo:() => import("../BaseUse/FormDemo")//异步加载组件
    },
    data(){
    return {
    name:"home",
    NextTickName:"NextTickName"
    }
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    keep-alive
    缓存组件,频繁切换,不需要重复渲染(被包裹的组件不会被销毁)
    mixin
    多个组件有相同的逻辑,抽离出来
    mixin并不是完美的解决方案,会有一些问题(
    变量来源不明确,不利于阅读,多mixin可能造成命名冲突,mixin和组件可能出现多对多的关系,复杂度较高
    ),vue3提出的composition API旨在解决这些问题

    <div>
    <p>{{name}}{{age}}{{sex}}</p>
    </div>
    import myMixin from "./mixin"
    export default {
    mixins:[myMixin],//可以添加多个,会自动合并起来
    data(){
    return {
    name:"张三",
    age:18
    }
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    Vue部分原理(≠源码)
    组件化(MVVM,数据驱动视图)

    MVVM 即模型-视图-视图模型。【模型(M)】指的是后端传递的数据。【视图(V)】指的是所看到的页面。【视图模型(VM)】mvvm模式的核心,它是连接view和model的桥梁。它有两个方向:一是将【模型】转化成【视图】,即将后端传递的数据转化成所看到的页面。实现的方式是:数据绑定。二是将【视图】转化成【模型】,即将所看到的页面转化成后端的数据。实现的方式是:DOM 事件监听。这两个方向都实现的,我们称之为数据的双向绑定
    响应式(数据驱动视图第一步)
    核心API:Object.defineProperty(Vue3.0之前)

    //基本使用
    const data ={}
    const name="zhangsan"
    Object.defineProperty(data,"name",{
    get:function(){//get返回内容
    console.log("get")
    return name
    },
    set:function(newVal){//set赋值内容
    console.log("set")
    name=newVal
    }
    })
    //如果监听的类型是对象,需要判断进行深度监听
    //如果监听的类型是数组,不污染全局的数组原型情况下,重新定义数组原型
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    Object.defineProperty的缺点:深度监听,需要递归到底,一次性计算量大
    无法监听新增属性/删除属性(需要Vue.set Vue.delete两个API来使用)
    Vue3.0使用Proxy取代,但Proxy有兼容性问题,且无法polyfill,所以Vue2.x还会存在一段时间

    vdom(Virtual DOM)和diff(虚拟DOM和diff算法,面试中的热门问题)
    vdom----用js模拟DOM结构,计算出最小的变更,操作DOM

    vue是参考snabbdom实现的vdom和diff
    ----------diff算法
    diff即对比,是一个广泛的概念,如linux diff命令,git diff等
    diff算法过程:patch(elem,vnode)和patch(vnode,newVnode)
    patchVnode和addVnodes和removeVnodes
    updateChidren(key的重要性)
    两课树做diff

    模板编译
    前置知识点:with语法

    改变{}内自由变量的查找规则,当做obj属性来查找,如果找不到匹配的obj属性,就会报错
    with要慎用,它打破了作用域规则,易读性变差

    模板它不是html,有指令,插值,js表达式,能实现判断,循环
    模板编译为render函数,执行render函数返回vnode
    基于vnode再执行patch和diff
    vue组件中使用render代替template
    渲染过程
    ①初次渲染过程
    解析模板为render函数
    触发响应式,监听data属性 getter setter
    执行render函数,生成vnode,patch(elem,vnode)

    ②更新过程
    修改data,触发setter(此前在getter中已被监听)
    重新执行render函数,生成newVnode
    path(vnode,newVnode)

    ③异步渲染
    通过$nextTick方法
    汇总data的修改,一次性更新视图,减少DOM操作次数,提高性能

    前端路由
    ①hash

    hash的特点:hash变化不会触发网页跳转,即浏览器的前进、后退
    hash变化不会刷新页面,SPA必需的特点
    hash永远不会提交到server端
    ②H5 history
    用url规范的路由,但跳转时不刷新页面
    H5 history需要后端支持
    to B的系统推荐用hash,简单易用,对url规范不敏感
    to C的系统,可以考虑选择H5 history,但需要服务端支持

    React
    React vs Vue
    React和Vue一样重要(特别是大厂面试),力求两者都学会
    React和Vue有很多相通之处,而且正在趋于一致
    React比Vue学习成本高,尤其对于初学者
    React的event
    ①event是SyntheticEvent,模拟出来DOM事件所有能力
    ②event.nativeEvent是原生事件对象
    ③所有的事件,都被挂载到document上
    ④和DOM事件不一样,和Vue事件也不一样
    受控组件和非受控组件
    例如等元素都要绑定一个change事件,当表单的状态发生变化,就会触发onChange事件,更新组件的state。这种组件在React中被称为受控组件,在受控组件中,组件渲染出的状态与他的value或checked属性相对应,react通过这种方式消除了组件的局部状态,使整个状态可控。react官方同样推荐使用受控表单组件
    如果一个表单组件没有value props(单选和复选按钮对应的是checked props)时,就可以称为非受控组件.
    在非受控组件中,我们可以使用一个ref来从DOM获得表单值。而不是为每个状态更新编写一个事件处理程序。
    setState(同步还是异步)
    setState之前不可变值,可能是异步更新,可能会被合并(传入对象的情况下,多个setState只执行一次,传入函数,不会被合并)
    同步还是异步?
    setState直接使用是异步的,想获取state中最新的值,在setState加入回调
    setTimeout中setState是同步的,自定义的DOM事件中也是同步的
    React组件生命周期
    1.第一次初始化渲染显示:ReactDOM.render()
    construction() 创建对象初始化state
    componentWillMount() 组件渲染之前
    render() 渲染组件
    componentDidMount() 组件渲染之后
    2.每次更新this.setState()
    componentWillUpdata() 将要更新之前
    render() 更新(重新渲染)
    componentDidUpdata()已经更新之后
    3.移除组件ReactDOM.unmountComponentAtNode(containerDom dom容器)
    componentWillUnmount()组件要被移除回调

    React高级特性
    函数组件


    非受控组件
    使用场景
    必须手动操作DOM元素,setState实现不了
    文件上传

    showInput = () => {
    const input = this.refs.content//之前版本获取ref的标签
    console.log(input.value);
    console.log(this.input.value);//新方法
    }
    render(){
    <input type="text" ref={input => this.input = input}//ref标识组件内的元素
    <button onClick={this.showInput}>获取input值</button>
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    Portals
    组件默认会按照既定层次嵌套渲染。如何让组件渲染到父组件以外?
    Portals使用场景
    overflow:hidden 父组件z-index值太小 fixed需要放在body第一层级
    基本使用:

    render(){
    //使用Portals渲染到body上
    return ReactDOM.createPortal(
    <div className="modal">{this.props.children}</div>,
    document.body
    )
    }
    1
    2
    3
    4
    5
    6
    7
    context
    公共信息(语言、主题)如何传递给每个组件?用props太繁琐,用redux小题大做
    React.createContext:创建一个上下文的容器(组件), defaultValue可以设置共享的默认数据

    const {Provider, Consumer} = React.createContext(defaultValue)
    1
    Provider(生产者): 和他的名字一样。用于生产共享数据的地方。生产什么呢? 那就看value定义的是什么了。value:放置共享的数据。

    <Provider value={/*共享的数据*/}>
    /*里面可以渲染对应的内容*/
    </Provider>
    1
    2
    3
    Consumer(消费者):这个可以理解为消费者。 他是专门消费供应商(Provider 上面提到的)产生数据。Consumer需要嵌套在生产者下面。才能通过回调的方式拿到共享的数据源。当然也可以单独使用,那就只能消费到上文提到的defaultValue

    <Consumer>
    {value => /*根据上下文 进行渲染相应内容*/}
    </Consumer>
    1
    2
    3
    异步组件
    Vue中使用import() React中使用React.lazy React.Suspense

    从 React 中引入 lazy 方法和 Suspense 组件,然后用 lazy 方法处理我们的组件,lazy 会返回一个新的React 组件,我们可以直接在 Suspense 标签内使用,这样组件就会在匹配的时候才加载。
    lazy 接受一个函数作为参数,函数内部使用 import() 方法异步加载组件,加载的结果返回。
    Suspense 组件的 fallback 属性是必填属性,它接受一个组件,在内部的异步组件还未加载完成时显示,所以我们通常传递一个 Loading 组件给它,如果没有传递的话,就会报错。
    基本使用:

    import React, { lazy, Suspense } from 'react';

    const Index = lazy(() => import('components/Index'));
    const List = lazy(() => import('components/List'));

    class App extends React.Component {
    render() {
    return <div>
    <Suspense fallback={Loading}>//fallback 属性是必填属性,它接受一个组件
    <Index></Index>
    <List></List>
    </Suspense>
    </div>
    }
    }
    function Loading() {
    return <div>
    Loading...
    </div>
    }
    export default App;
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    性能优化
    shouldComponentUpdate(简称SCU)

    _.isEqual方法做对象或者数组的深度比较
    SCU默认返回true,即React默认重新渲染所有子组件,必须配合“不可变值”一起使用,可先不用SCU,有性能问题时再考虑使用

    PureComponent和React.memo
    PureComponent,SCU中实现了浅比较
    memo,函数组件中的PuceComponent,浅比较已使用大部分情况(尽量不要做深度比较)

    不可变值immutable.js
    彻底拥抱“不可变值”,基于共享数据(不是深拷贝),速度好,按需使用

    高阶组件HOC
    基本用法


    Render Props


    Redux使用
    和Vuex作用相同,但比Vuex学习成本高,不可变值,纯函数
    基本概念
    store state
    action
    reducer

    import { createStore } from 'redux';
    /**
    * 这是一个 reducer,形式为 (state, action) => state 的纯函数。
    * 描述了 action 如何把 state 转变成下一个 state。
    *
    * state 的形式取决于你,可以是基本类型、数组、对象、
    * 甚至是 Immutable.js 生成的数据结构。惟一的要点是
    * 当 state 变化时需要返回全新的对象,而不是修改传入的参数。
    *
    * 下面例子使用 `switch` 语句和字符串来做判断,但你可以写帮助类(helper)
    * 根据不同的约定(如方法映射)来判断,只要适用你的项目即可。
    */
    function counter(state = 0, action) {
    switch (action.type) {
    case 'INCREMENT':
    return state + 1;
    case 'DECREMENT':
    return state - 1;
    default:
    return state;
    }
    }
    // 创建 Redux store 来存放应用的状态。
    // API 是 { subscribe, dispatch, getState }。
    let store = createStore(counter);
    // 可以手动订阅更新,也可以事件绑定到视图层。
    store.subscribe(() =>
    console.log(store.getState())
    );
    // 改变内部 state 惟一方法是 dispatch 一个 action。
    // action 可以被序列化,用日记记录和储存下来,后期还可以以回放的方式执行
    store.dispatch({ type: 'INCREMENT' });
    // 1
    store.dispatch({ type: 'INCREMENT' });
    // 2
    store.dispatch({ type: 'DECREMENT' });
    // 1
    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
    单项数据流

    react-redux

    异步action

    redux中间件

    React-router使用
    路由模式(hash、H5 history),同vue-router,路由配置(动态路由、懒加载),同vue-router

    React部分原理(≠源码)
    函数式编程
    一种编程范式,概念比较多,纯函数,不可变值
    函数式编程:是一种设计思想,尽量用函数组合来进行编程,先声明函数,然后调用函数的每一步都有返回值,将具体的每一步逻辑运算抽象,封装在函数中。再将函数组合来编写程序。
    vdom和diff

    JSX本质

    合并事件

    batchUpdate机制

    setState

    batchUpdate机制

    transaction事务机制

    组件渲染过程

    内容来源bilibili,链接视频

  • 相关阅读:
    cors
    js 离开页面
    移动端 touch
    eclipse
    java获取classpath以外的路径
    Javascript类型转换的规则
    myeclipse开发安装C++
    MyEclipse10中配置开发Python所需要的PyDev 绝对靠谱 不忽悠!
    POI生成EXCEL,公式不自动执行的有关问题
    POI中设置Excel单元格格式样式(居中,字体,边框等)
  • 原文地址:https://www.cnblogs.com/onesea/p/13091470.html
Copyright © 2011-2022 走看看