zoukankan      html  css  js  c++  java
  • 前端框架面试题

    一、VUE的基本使用

    1. v-html:会有XSS风险,会覆盖子组件

    2. computed:有缓存,data不变则不会计算

    3. watch:默认是浅监听,可以deep:true 如果是引用类型的值 newValue和oldValue是一样的 因为是引用类型 值是指针地址 他们指向一样

    4. v-for和v-if不能一起使用 v-for的会优先v-if计算 也就是在v-for每次循环的时候 v-if都会执行一遍 官网不推荐使用

    5. $event 传参获取到的就是原生的event对象 事件被挂在到当前元素

    6. 组件通信 父子组件 props $emit 

    兄弟组件 自定义事件 event.$on event.$emit (event是vue的实例)最好在beforeDestroy 时候 emit.$off,否则可能造成内存泄漏 所以 在 event.$on('onAddTitle',this.addTitle) 给一个函数名调用this.addTitle

    beforeDestroy 可以做什么?卸载事件监听,卸载自定义事件

    7. 生命周期 挂载 - 更新 -销毁   

    beforeCreate/created(事件,周期初始化,还未开始渲染)  beforeMount/mounted (页面已经渲染完了) - beforeUpdate/updated - beforeDestroy/destroyed

    父 index 子 list 生命周期执行顺序 index created -> list created -> list mounted -> index mounted  ;update和destroy也如此

    8. vue的高级特性

    ①:自定义v-model (场景:颜色选择器)

    ②:$nextTick 

    Vue是异步渲染的框架(data改变之后,dom不会立即渲染,$nextTick会在DOM渲染之后触发,以获取最新DOM,也就是data改变后,立即去获取dom数据是获取不到的,但是可以在nextTIck中获取到

    ③:slot

    作用域插槽、具名插槽

    父组件想要往子组件插一些东西

    ④:动态、异步组件

    动态组件: :is="component-name" 需要根据数据,动态渲染的场景,即组件类型不确定

    异步组件:import()函数 在某个特定条件下这个组件才会渲染 v-if判断 然后 ()=>import('../../') ; 按需加载,异步加载大组件;

    ⑤:keep-alive

    缓存组件,频繁切换,不需要重复渲染,出现在Vue常见性能优化面试题

    第一次触发mouted 后面就不会触发生命周期函数

    分页

    ⑥:mixin

    多个组件有相同的逻辑,抽离出来

    mixin并不是完美的解决方案,会有一些问题

    Vue3 提出的composition API旨在解决这些问题

    缺点:变量来源不明确,不利于阅读;多mixin可能造成命名冲突;mixin和组件可能会出现多对多的关系,复杂度较高

     9.vuex

     10.vue-router (hash history)

    二. Vue原理篇

     1. Vue响应式

    ①:监听对象变化

    2.0核心API Object.defineProperty (监听对象)

    缺点:深度监听,需要一次性递归,一次性计算量大;无法监听新增属性/删除属性 (Vue.set,Vue.delete);无法监听原生数组,需要特殊处理

    proxy有兼容性问题:兼容性不好,无法polyfill

    function defineReactive(target,key,value){
    //注意如果是 info:{name:'123'},值是对象
      observe(target)
      Object.defineProperty(target,key, {
        get(){
            return value
        }
       set(newValue){
        if(newValue!=value){ //value一直在闭包中,再get也是可以获取到值的
    //这里有种情况 就是赋值是对象 info.name = {age:11},所以需要再次监听
            observe(target)
            value = newValue
            updateView() //更新视图
        }
        }
    })
    }    
    function observe(target){
        if(type target!=='object'&&target===null){
            return target //不是对象或数组
        }
    //监听数组时候 判断是否是数组 下面有代码
    //是对象的情况
    for(let key in target){
        defineReactive(target,key,target[key]
        }
    }        

    ②:监听数组变化

    const oldArrayProto = Array.prototype
    //创建新对象,原型指向oldArrayProto,再扩展的方法不会影响原型
    const arrProto = Object.create(oldArrayProto)
    ['push','pop','shift','unshift','splice','sort','reverse'].forEach(value=>{
        arrProto[value] = function(){
         updateView()  //更新视图
         oldArrayProto[value].call(this,...arguments) //监听7个方法 更新视图 然后执行真正意义上的数组方法
        }
    })
    // 在observe深度监听时候 如果是数组则将value的原型 赋值为arrProto
    function observe(value){
      if(Array.isArray){
        value.__proto__ = arrProto
        }
    }

     2.vdom (用JS模拟DOM)

    vdom核心概念:h、vnode、patch、diff、key等

    存在的价值:数据驱动视图,控制DOM操作

     3.diff算法总结

    patchVnode

    addVnodes

    removeVnodes 

    updateChildren(key的重要性)

    4.模板编译 (组件渲染和更新过程?)

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

     _c:createElement

    _v:createTextVNode

    _s:toString

    _l:renderList

    模板编译为render函数,执行render函数返回vnode

    基于vnode再执行patch和diff

    使用webpack vue-loader 会在开发环境下编译模板(重要) 开发环境就会编译好 就不用在浏览器运行时候去编译 性能优化

    组件 渲染/更新 过程

    初次渲染过程:

    ①:解析模板为render函数 (或在开发环境已完成,vue-loader)

    ②:触发响应式,监听data属性 getter和setter

    ③:执行render函数,生成vnode, patch(elem,vnode)

    更新过程:

    ①:修改data,触发setter(此前在getter中已被监听)

    ②:重新执行render函数,生成newVnode

    ③:patch(vnode,newVnode)

    异步渲染:

    ①:$nextTick (vue组件是异步渲染的)

    ②:汇总data的修改,一次性更新视图

    ③:减少DOM操作次数,提高性能

    总结:

    1:渲染和响应式的关系;渲染和模板编译的关系;渲染和vdom的关系

    2:初次渲染;更新过程;异步渲染

    5、前端路由原理

    ①:hash

    稍微复杂一点的SPA都需要路由 路由模式:hash、H5 history

    hash特点:hash变化会触发网页跳转,即浏览器的前进、后退

    hash变化不会刷新页面,spa必需的特点

    hash永远不会提交到server端(前端自生自灭)

     监听 onhashchange 事件

    hash变化 包括:JS修改url ;手动修改url的hash;浏览器的前进、后退

    ②:h5 history

    用url规范的路由,但跳转时不刷新页面

    history.pushState(from,'',to)  window.onpopstate(监听浏览器的前进、后退)

    服务端:无论访问什么样的路由都需要返回index.html的页面 由前端路由去判断渲染哪一块

    6.vue面试真题演练

    ①:v-show和v-if的区别 

    v-show:通过css display控制显示和隐藏

    v-if:组件真正的渲染和销毁,而不是显示和隐藏

    频繁切换显示状态用v-show,否则v-if

    ②:为何在v-for使用key

    必须用key,且不能是index和random

    diff算法中通过tag和key来判断,是否是sameNode

    减少渲染次数,提升渲染性能

    ③:描述Vue组件的生命周期(父子组件)

    ④:vue组件如何通讯

    父子组件props和$emit

    自定义事件 event.$on/$emit/$off

    vuex

    ⑤:描述组件渲染和更新过程

    ⑥:双向绑定v-model实现原理

    input元素的value = this.name

    绑定input事件this.name = $event.target.value

    data更新触发re-render

    ⑦:对MVVM的理解

     ⑧:为何组件data必须是个函数

    定义的每个vue文件都是一个类,在各个地方去使用时候 其实是实例化这个类,如果是对象的话,修改data之后其他地方都会改变,引用类型保存的是指针地址

    ⑨:ajax请求应该放在哪个生命周期

    mounted

    js是单线程,ajax异步获取数据

    放在mounted之前没有用,只会让逻辑更乱,因为在那之前如果js没有执行完成,也不会去执行异步请求

    ⑩:如何将组件所有props传给子组件

    <User v-bind="$props"> 在user组件正常接收,列出需要的组件

    11:如何实现v-model

     12.多个组件有相同的逻辑,如何抽离

    mixin 以及mixin的一些缺点

    13.何时使用异步组件

    加载大组件;路由异步加载

    14.何时需要使用keep-alive

    缓存组件,不需要重复渲染

    15.何时需要使用beforeDestory

    解绑自定义事件 event.$off

    清楚定时器

    解绑自定义的DOM事件,如window.scroll

    16.作用域插槽

     17.Vuex中action和mutation有何区别

    action中处理异步,mutation不可以

    mutation做原子操作

    action可以整合多个mutation

    18.请用vnode描述一个DOM结构

    {tag:'div',props:{},children:[]}

    19.Vue如何监听数组变化

    Object.defineProperty不能监听数组变化

    重新定义原型,重写push,pop等方法,实现监听

    19.diff算法的时间复杂度

    O(n)

    20.Vue为何是异步渲染,$nextTick有何用

    异步渲染(以及合并data修改)以提高渲染性能

    $nextTick在DOM更新完之后,触发回调

    21.Vue常见性能优化

    ①:合理使用v-show和v-if

    ②:合理使用computed(有缓存)

    ③: v-for时加key,以避免和v-if同时使用

    ④:自定义事件,DOM事件及时销毁

    ⑤:合理使用异步组件

    ⑥:合理使用keeplive

    ⑦:data层级不要太深

    ⑧:使用vue-loader在开发环境做模板编译(预编译)

    7.Vue3

    Proxy实现响应式

    基础使用

    const proxyData = new Proxy(data,{
     get(target,key,receiver){
      //只处理本身(非原型的)属性
    const ownKeys = Reflect.ownKeys(target)
    if(ownKeys.includes(key)){
    console.log('get',key)
    }
      const result = Reflect.get(target,key,receiver)
      console.log('get',key)
      return result
     },
    set(target,key,val,receiver){
    //重复的数据,不处理
    const oldVal = target[key]
    if(val===oldVal){
    return true
    }
      const result = Reflect.set(target,key,val,receiver)
      console.log('set',key,val)
      return result
     },
    deleteProperty(target,key){
      const result = Reflect.deleteProperty(target,key)
      console.log('deleteProperty',key)
      return result
     }
    })

    Reflect作用

    和proxy能力一一对应

    规划化,标准化,函数式

    替代掉Object上的工具函数

    proxy实现响应式好处

    深度递归,性能更好 (在每次获取值的时候去递归)

    可监听 新增/删除 属性 

    const ownKeys = Reflect.ownKeys(target)
    if(ownKeys.includes(key)){
       console.log('get',key) //已存在的
    }else{
     //新增的属性
    }  

    可监听数组变化

    弊端:无法兼容所有浏览器,无法polyfill

    二、React

    1. this默认是undefined

    2.event 不是原生的event事件 SyntheticEvent(组合事件) constructor是个class (原生的是MouseEvent

    可以通过event.nativeEvent获得原生事件

    vue触发的节点和绑定的节点 都是当前的节点

    react 触发是当前节点 但绑定在document上面 通过event.nativeEvent.currentTarget:绑定节点 event.nativeEvent.target:触发节点

    参数传参,最后一个参数是event

    总结:react所有的事件都被挂载在document上,和DOM事件不一样,和Vue事件也不一样

    3.受控组件和非受控组件

    受控组件:input value onChange时候去重新赋值  类似于vue的v-model 表单绑定的value受state控制 ;

    非控组件:组件的value不受state控制,内部存储其自身状态的组件 可以通过ref查看

    4.setState

    ①:不可变值

     不要修改原来state的状态

    //数组
    this.setState({
    data:this.state.data.push(100) ,//会修改原来的值
    data1:this.state.data1.concat(100) //不会修改原来的值,会返回新的值
    })

    //对象

    不能直接对this.state.obj的属性进行设置,可以返回一个新值作为替换

    this.setState({
    obj:Object.assign({},this.state.obj,{a:100})
    })

    在shouldComponentUpdate时候 会对比前后值来确定是否改变视图,以此优化性能

    ②:可能是异步更新

    渲染是异步的 ,修改值之后页面渲染时正常的,但是控制台打印是同步的,结果就会出错,

    this.setState({},()=>{
    //这里可以拿到最新的值,有点像vue的$nextTick
    })

    setTimeout 是同步的

    自定义的DOM事件是同步的(原生事件中是同步)

    直接使用时异步的

    钩子函数和合并事件是异步的

    ③:可能被合并

    传入对象可能会被合并类似 Object.assign 

    初始是 this.state = {name:'alhh'}

    后期setState的对象会和上面的合并 说明setState不会覆盖老的state而是合并操作

    this.setState({})

    传入函数 不会被合并 ,会更新完状态后再和老的合并

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

    5.组件生命周期

     父子组件生命周期和vue一样

    6.React高级特性

    ①:函数组件

    如何区别函数组件和class组件

    instanceof React.Component  为true的是class组件

    class组件如果只接收一个props去渲染页面, 不涉及state和其他逻辑 就可以使用函数组件

    函数组件:输入props,输出JSX,没有实例,没有生命周期,没有state,不能扩展其他方法

    ②:非受控组件

    ref defaultValue defaultChecked 手动操作DOM元素

    只是通过ref去获取值 没有onChange去赋值

    使用场景:

    必须手动操作DOM元素,setState实现不了

    文件上传 <input type="file">

    某些富文本编辑器,需要传入DOM元素

    受控组件 vs 非受控组件

    优先使用受控组件,复合React设计原则(数据驱动视图)

    必须操作DOM,再使用非受控组件

    ③:Portals(传送门)

    组件默认按照既定的层次嵌套渲染,如何让组件渲染到父组件外?

    ReactDom.createPortal(jsx,location)

    第一个参数是jsx,第二个参数是想要放的位置

    使用场景:

    父组件形成bfc,overflow:hidden

    父组件z-index太小

    fixed需要放在body第一层级

    ④:context

    公共信息(语言,主题)如何传递给每个组件?用props太繁琐,用redux小题大做

    最外层Provider:<Theme.Provider value={}>

    需要用到的地方 函数组件:<Sider.Consumer> {value=><p>{value}</p>}  class组件:const ThemeContext = React.createContext('light') statis contextType = ThemeContext 然后this.context就可以获取到了

    ⑤:异步组件

    import()

    React.lazy:React.lazy(()=>import('../'))

    React.Suspense:<React.Suspense fallback={<div>loading....</div>}

    ⑥:性能优化

    shouldComponentUpdate(SCU):通过返回true或者false 来控制render的渲染  默认返回的是true ;必须配合“不可变值”一起使用,否则修改两者相同则不会触发SCU;不建议使用深度比较

    React默认:父组件有更新,子组件则无条件更新(触发了render函数,render里面有子组件)

    PureComponent 适合class组件和React.memo 适合函数组件(使用了浅比较:只比较第一层)底层是SCU

    不可变值 immutable.js

    ⑦:高阶组件 HOC(接收一个组件参数,返回一个组件)

    mixin已被React弃用

    ⑧:Render Props

    render属性传入组件来控制渲染

     

     7.redux

    单向数据流

    中间件在dispatch中加逻辑 

     8.react原理

    函数式编程:纯函数,不可变值

    diff算法

    只比较同一层级,不跨级比较

    tag不相同,则直接删除重建,不再深度比较

    tag和key都相同,就认为是相同节点,不再深度比较

    ①:合成事件

    所有事件挂载到document上

    event不是原生的,是SyntheticEvent合成事件,event.nativeEvent是原生事件对象

    和Vue事件不同,和DOM事件也不同

     合成事件优点:

    更好的兼容性和跨平台 (自己实现一套事件逻辑)

    全部挂载到document,减少内存消耗,避免频繁解绑

    方便事件的统一管理(如事务机制)

    ②.setState和batchUpdate

    setState主流程

    batchUpdate机制

     1.哪些命中batchUpdate机制

        生命周期(和它调用的函数)

        React中注册的事件(和它调用的函数)

        React可以“管理”的入口  (是在入口中设置)

     2.哪些不能命中batchUpdate机制

        setTimeout setInterval等(和它调用的函数)

       自定义DOM事件(和它调用的函数)

        React "管不到“的入口

    transaction(事务)机制

     先执行一个开始的逻辑 -》函数体执行 -》执行一个结束的逻辑

    ③:更新的两个阶段

    patch会被分为两个阶段

    reconciliation阶段,执行diff算法,纯JS计算

    commit阶段 将diff结果渲染DOM

    ④:注意:可能会有的性能问题

    JS是单线程,且和DOM渲染共用一个线程

    当组件足够复杂,组件更新时计算和渲染都压力大

    同时再有DOM操作需求(动画,鼠标拖拽等)将卡顿

    解决方案:fiber(内部运行机制)

    将reconciliation阶段进行任务拆分 (commit无法拆分)

    目的是:DOM需要渲染时暂停,空闲是恢复;什么时候知道DOM需要渲染 通过window.requestIdleCallback(某些浏览器不一定支持)

    9.React面试题目

    ①:组件之间如何通信

    父子组件props

    自定义事件

    Redux和Context

    ②:JSX本质是什么

    createElement

    执行返回vnode

    ③:context是什么,如何应用

    父组件,向其下所有子组件传递信息

    如一些简单的公共信息:主题色、语言等

    复杂的公共信息 用redux

    ④:shouldComponentUpdate用途

    性能优化

    配合”不可变值“一起使用

    ⑤:redux单向数据流

  • 相关阅读:
    JDK源码阅读--AbstractStringBuilder
    JDK源码阅读--String
    JDK源码阅读--Object
    linux查看日志
    velocity 相关
    oracle Trigger
    ssm调用后台oracle存储过程统计分析数据
    oracle 优化相关
    synchronized 控制并发(活动秒杀)
    SpringBoot自动装配的原理
  • 原文地址:https://www.cnblogs.com/alhh/p/14001806.html
Copyright © 2011-2022 走看看