前端总结

289 阅读12分钟

JS篇

h5新特性

  • 语义化标签,比如header、footer、nav、aside、article、section、main;作用:有利于SEO优化,代码可读性更强
  • 音视频标签,audio、video
  • 画布canvas、矢量图svg
  • 本地存储localStorage、sessionStorage
  • web worker,作用:开启一个子线程,且子线程的操作不受线程的影响 应用场景: 1.大数据处理; 2.耗费时间较长的操作;

localStorage与sessionStorage的区别?

  • 生命周期不同:localStorage会一直存在浏览器,sessionStorage在页面关闭时清除

cookie

  • 页面关闭清除,存在于http请求头中

rem与em的区别是什么呢?

  • rem:相对于html标签的font-size去决定大小,例如:html标签font-size为14px,则2rem === 28px
  • em:相对于自身的font-size去决定大小,自身没有font-size则继承祖先级元素的font-size

promise的作用?

  • promise的then方法返回一个新的promise对象,保证了then方法可以进行链式调用
  • 解决链式调用的回调地域,让代码更加优雅
  • 它有padding(等待)、resolved(成功)、reject(失败)三种状态,有状态不可逆的效果

async和await的作用

  • 用同步的方式执行异步操作,实现排队效果
  • async:async函数指向返回一个promise
  • await:await后接promise则会等待promise返回结果,接普通函数执行则会接收返回结果
  • await只能在async中使用,但在浏览器调试中可单独使用

什么是跨域?解决跨域有几种方式?

  • 同源策略,域名、协议、端口其中一个不相同会造成跨域问题 解决:
  • 1.CORS(跨域资源共享)
  • 2.proxy本地代理
  • 3.jsonp(通过script标签,只能get请求)
  • 4.后端加上请求头进行跨域

数据类型有哪些?

基本数据类型:

  • number、array、string、null、undefined、symbol、bigInt 复杂数据类型:
  • array、object、function

ES6新特性有哪些?

  • 模板字符串
  • 箭头函数
  • 数据结构
  • 扩展运算符
  • set和map
  • class声明类
  • find和findIndex
  • promise
  • let和const
  • 函数参数默认值
  • import和export ES7
  • includes ES8
  • async和await
  • object.values

数组的方法有哪些?

  • find和findIndex
  • map、filter、every(遍历数组中所有元素是否满足条件,返回true和false)、foreach、some(跟findIndex用法一样,但返回的是布尔值)
  • join(数组拼接字符串)
  • push(返回数组长度)、pop(返回删除元素的下标)
  • shift(删除元素)和unshift(在数据开头加入多个元素并返回数组长度)
  • reverse(数组反转)和sort(数组排序)
  • slice(不改变原数组)和splice(改变原数组)
  • concat
  • includes和indexOf

字符串的方法有哪些?

  • length、indexOf、split(字符串分割为数组)
  • 字符串截取:substr(开始,结束)、substring、slice
  • 符串转换:toLowerCase(小写)、toUpperCase(大写)
  • 字符串匹配:replace、match和search
  • trim、toString、parseInt、parseFloat

判断数据类型有几种方法?

  • typeOf(不能精确判断null、array、object、因为都返回object)
  • instanceOf
  • Object.prototype.toString.call()

call、apply、bind的区别?

  • call与apply的区别在于传参,前者直接传参,后者传一个数组
  • bind传参后不立即执行,而是返回一个函数,这个函数可以继续传参,且执行(bind函数可以分两次传参)

什么是闭包?它有什么优缺点?应用场景有哪些?

  • 一个函数中返回一个函数就是闭包
    • 优点:有独立的作用域,防止外部污染
    • 缺点:占内存,容易造成内存泄漏
    • 应用场景:防抖与节流

什么是数据长列表?原理是什么?

  • 概念:长列表其实是按需显示的一种实现,即只对可见区域进行渲染,对非可见区域中的数据不渲染或部分渲染的技术,从而达到极高的渲染性能。文章

什么是原型?什么是原型链?原型继承有哪些?

  • 先从原型说起,在定义函数的时候,函数就会生成一个原型prototype,每个原型会生成一个实例,实例里面有个属性叫__proto__和构造函数,根据__proto__属性可以追述到它的原型,从而形成一种三角关系,这样组成一个原型一个实例下去就是原型链,直到最上层object最终会指向null
  • 原型继承有6种继承方式:
    • 1.原型链继承:通过prototype继承,将原型的prototype指向person达到继承效果,优点:继承了父级原型方法,缺点:实例化多个相同函数都必须共用相同的属性名
    • 2.构造函数继承:在子类构造函数中调用父类构造函数,可以在子类构造函数中使用call()apply()方法
    • 3.组合继承:将原型链继承和借调构造函数的技术组合到一块,从而发挥两者的优点的一种继承方式,优点:只继承属性,值不同,可以继承父原型中的方法
    • 4.原型式继承:借助原型可以基于已有的对象创建对象,类似复制了一个对象
    • 5.寄生式继承:就是给原型式继承外面套个壳子,没用到原型
    • 6.寄生组合式继承:通过借调函数来继承属性,通过原型链的混成形式来继承方法(常用)

什么是bfc机制?

  • 块级格式化上下文,它是指一个独立的块级渲染区域,一般用来解决margin塌陷 形成方法:
    1. float:left
    1. position: absolute或fixed
    1. display: inline-block
    1. flex: inline-flex
    1. overflow: hidden(最佳方法)

什么是重绘和回流?

  • 概念:浏览器采用的是流式布局,浏览器会将html解析为Dom节点,把css解析为cssom,最后把dom和cssom结合产生render树,再把render树绘制到页面上,回流一定引起重绘,但重绘不一定引起回流
  • 引起回流:当rebder树的结构或者尺寸发生改变的时候,浏览器重新渲染就会引起回流,比如说页面窗口大小发生变化,内容的变更,添加或删除DOM节点这些都会发生回流
  • 引起重绘:当页面中元素样式的改变不影响它在文档流中的位置,这个过程就是重绘 优化:少用table,避免频繁操作dom

赋值、深拷贝和浅拷贝?

  • 赋值:赋值指针指向,还是用的同一个内存空间
  • 浅拷贝:只拷贝第一层
  • 深拷贝:所有层都会进行拷贝

有哪几种作用域?

  • 全局作用域
    • 1.全局作用域:全局作用域为程序的最外层作用域,一直存在
    • 2.函数作用域:函数作用域只有函数被定义时才会创建,包含在父级函数作用域 / 全局作用域内。
  • 块级作用域
    • 花括号内{...}的就是块级作用域,比如:if判断也是一个块级作用域
  • 作用域链
    • 函数内部打印一个不存在的变量,如果内部没有就会去外部寻找,直到全局作用域停止

箭头函数的作用?

  • 1.语法更加简洁清晰
  • 2.箭头函数没有prototype,所以箭头函数本身没有this
  • 3.call | apply | bind 无法改变箭头函数中this的指向
  • 4.箭头函数不能作为构造函数使用
  • 5.箭头函数没有arguments

谈谈EventLoop?

  • 概念:EventLoop即事件循环,是浏览器解决js单线程运行时不会阻塞的一种机制,在js执行过程中会将异步分为宏任务于微任务,因为宏任务执行较久会将微任务排在前面执行完毕再执行宏任务,会形成一个先进先出的效果

浏览器的垃圾回收机制?

  • 概念:在代码执行过程中使用的内存,垃圾收集器会定期找出那些不再继续使用的变量,然后释放内存,现在各大浏览器所采用的垃圾回收机制有两种:一种是标记清除,一种是引用计数;
  • 标记清除:
    • 当声明一个变量时,会将变量标记为‘进入环境’,从逻辑上讲,永远不能释放标记为‘进入环境’变量所占的内存,因为只要执行流进入相应的环境,就可能会用到它们,而当变量离开环境时,则将变量标记为‘离开环境’,从而垃圾回收机制就会释放这些离开环境变量的内存,回收它们所占用的空间
  • 引用计数:
    • 跟踪记录每个值被引用的次数,当声明变量并赋值的时候,这个值的引入次数就是1,如果这个值赋值给另一个变量,则引用次数加1,相反,如果变量脱离了该值的引用,则该值引入次数就减1,当次数为0时,就会等待垃圾收集器回收,这个方式存在一个比较大的问题就是循环引用,就是说A对象包含一个指向B的指针,对象B也包含一个指向A的引用,这就会造成大量内存得不到回收,造成内存泄漏,因为它们得引用次数永远不等于0,早期ie9采用的就是这种计数回收机制,闭包导致内存泄漏的一个原因就是这个算法的一个缺陷,解决办法就是把循环引用中的变量设置为null即可

HTTP状态码有哪些?

  • 200(请求成功)
  • 201(请求成功,并创建了新的资源)
  • 204(请求成功,但没有资源可返回)
  • 206(范围请求)
  • 301(永久重定向)
  • 302(临时重定向)
  • 303(请求资源存在另一个url,应用get请求定向获取请求的资源)
  • 304(资源已找到,但没符合条件请求)
  • 307(临时重定向)
  • 400(客户端错误)
  • 401(http认证失败)
  • 403(没权限访问)
  • 404(服务器没有找到资源)
  • 405(服务器禁止使用该方法)
  • 500(服务器错误)
  • 502(服务器关闭,无响应)
  • 503(服务器繁忙)

防抖和节流的区别?

  • 防抖:
    • 概念:多次执行,只以最后一次为准
    • 原理:将若干个函数调用合成为一次,并在设定时间过去之后仅被调用一次
    • 应用场景:商品搜索
      function debounce(fn, delay) {
        let timer = null;
        return function () {
          let arg = arguments;
          clearTimeout(timer);
          timer = setTimeout(() => {
            fn.apply(this, arg); // 若不改变this指向,则会指向fn定义环境
          }, delay)
        }
      }
      
  • 节流:
    • 概念:多次执行,执行完一次才能再次执行
    • 原理:节流函数不管事件触发有多频繁,都会保证在规定时间内一定会执行一次真正的事件处理函数
    • 应用场景:滚动加载更多
      //时间戳+定时器版: 实现第一次触发可以立即响应,结束触发后也能有响应 (该版才是最符合实际工作需求)
      //该版主体思路还是时间戳版,定时器的作用仅仅是执行最后一次回调
      function throttle(fun, delay = 500) {
           let timer = null;
           let previous = 0;
           return function(args) {
               let now = Date.now();
               let remaining = delay - (now - previous); //距离规定时间,还剩多少时间
               let that = this;
               let _args = args;
               clearTimeout(timer);  //清除之前设置的定时器
                if (remaining <= 0) {
                      fun.apply(that, _args);
                      previous = Date.now();
                } else {
                      timer = setTimeout(function(){
                      fun.apply(that, _args)
              }, remaining); //因为上面添加的clearTimeout.实际这个定时器只有最后一次才会执行
            }
        }
      }
      

web有哪些安全问题?

  • 防止sql注入,xss攻击

web如何做性能优化?

  • 使用雪碧图
  • 使用webp代替其他格式,图片一定要压缩
  • 图片懒加载、路由懒加载
  • button加loading效果
  • 注意避免页面回流操作
  • 第三方库按需引入
  • 打包使用CDN加载
  • css放在头部,js放在底部
    • CSS 执行会阻塞渲染,阻止 JS 执行
    • JS 加载和执行会阻塞 HTML 解析,阻止 CSSOM 构建
    • 如果这些 CSS、JS 标签放在 HEAD 标签里,并且需要加载和解析很久的话,那么页面就空白了。所以 JS 文件要放在底部(不阻止 DOM 解析,但会阻塞渲染),等 HTML 解析完了再加载 JS 文件,尽早向用户呈现页面的内容。
    • 那为什么 CSS 文件还要放在头部呢?
    • 因为先加载 HTML 再加载 CSS,会让用户第一时间看到的页面是没有样式的、“丑陋”的,为了避免这种情况发生,就要将 CSS 文件放在头部了。
    • 另外,JS 文件也不是不可以放在头部,只要给 script 标签加上 defer 属性就可以了,异步下载,延迟执行。
  • 使用字体图标 iconfont 代替图片图标
  • 减少http请求
  • 使用webpack打包压缩文件
  • 借助性能优化辅助工具,比如:Lighthouse

VUE篇

vue的生命周期

  • 更新
    • beforeCreate()
      • 概念:初始化事件和生命周期,初始化数据,不能获取data数据
    • created()
      • 概念:created向vue添加了data和methods配置项,可以获取data数据,但不能获取到真实DOM
      • 应用场景:通常可以在这个阶段发起ajax请求,初始化数据
  • 挂载
    • beforeMount()
      • 概念:虚拟DOM和数据挂载到真实DOM的过程,DOM挂载之前触发,获取不到真实DOM
    • mounted()
      • 概念:挂载结束,可以拿到真实DOM
      • 应用场景:一般可以在这个钩子函数中进行DOM操作,也可以进行ajax操作
  • 更新
    • beforeUpdate()
      • 概念:DOM更新前触发
    • updated()
      • 概念:DOM更新后触发,能够获取最新的DOM元素
      • 应用场景:当数据更新并更新DOM的时候才会触发更新钩子函数
  • 销毁
    • beforeDestroy()
      • 概念:销毁前触发
    • destroyed()
      • 概念:销毁后触发
      • 应用场景:一般用于移除全局事件的操作,比如;定时器和window事件

vue的组件传值有哪些?

  • 父传子,在组件中绑定变量,子组件通过props接收变量
  • 子传父,通过$emit进行传值,父组件通过事件接收值
  • 兄弟组件通过EventBus作为中间件,用emitemit和on进行通信
  • $ref获取实例
  • parent,children获取当前组件的父组件和当前组件的子组件

什么是MVVM?说一下和MVC的区别?

  • 映射关系简化,隐藏controller MVVM在MVC的基础上,把控制层隐藏掉了。
  • Vue不是一个MVVM框架,它是一个视图层框架。
  • ViewModal是一个桥梁,将数据和视图进行关联。

v-model的底层原理?

  • vue是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发响应的监听回调。
  • 单项绑定过程:变量变了,由Object.defineProperty()的set发通知给watcher,watcher告知虚拟DOM树,叫它该比较了,我这有值变了,于是生成新的dom树进行一个比较,比较出哪个元素发生变化就把这个元素更新到页面,这就是单项数据绑定原理 16ede3f4bc83638a_tplv-t2oaga2asx-zoom-in-crop-mark_1304_0_0_0.awebp
  • v-model原理其实就是给input事件绑定oninput事件 就会立刻调用底层对象对应的setter方法 改变data里的属性的值 从而实现双向数据绑定

vue的虚拟DOM和diff算法

  • vue中虚拟dom是template生成的js对象文件,作用,减少dom生成次数,将多次生成dom改为一次
  • Vue的diff算法是平级比较,不考虑跨级比较的情况。节点层层比对,递归比较子节点,不同替换,相同则复用旧节点,优点:减少dom的生成次数,缺点,需要每层去比对,如果数据量极大的情况下,真实dom加载比较快

v-for为什么比v-if优先级高?

  • v-for比v-if优先级高,不能在同一个标签中使用,影响性能,应该先处理v-for,再处理v-if。

nixtTick的原理?

nextTick是一个微任务。

  • nextTick中的回调是在下次Dom更新循环结束之后执行的延迟回调
  • 可以用于获取更新后的Dom
  • Vue中的数据更新是异步的,使用nextTick可以保证用户定义的逻辑在更新之后执行

vuex的理解?

  • vuex做数据共享管理的,vuex中只能通过mutation修改state
  • 如果修改vuex中的state,通过display去调用store文件中的action(异步)中的方法,再通过commit操作mutation(同步)的方法修改state,

keep-alive组件的理解?

  • 因为组件切换会导致组件被频繁销毁和重新创建, 性能不高,keep-alive可以将组件进行缓存,被缓存的组件不再创建和销毁, 而是会生成激活和非激活两个钩子函数

computed和watch?

  • 前者一对一,后者一对多
  • computed计算属性:
    • 作用:它的依赖结果会被缓存,当computed中所依赖的值没有发生改变的时候,那么调用当前函数的结果就会从缓存中读取,computed中的函数必须用return返回结果,computed比watch更高效,优先使用
    • 应用场景:当一个变量需要依赖另一个值的时候使用,比如:购物车商品结算功能
  • watch监听属性:
    • 作用:watch是用来监听一个值的变化,可以拿到旧值和最新值,deep开启深度监听,可以监听到对象里的值的变化,需要在数据变化时执行异步或开销较大的操作时使用
    • 应用场景:当一条数据影响多条数据的时候使用,比如:搜索数据

v-for中key的作用?

  • 唯一标识的作用

路由中hash模式和history模式原理是什么?它们的区别是什么?

  • hash模式:监听url中hash的变化来实现不同页面的展示,链接带#
  • history模式:url中不带#,利用html5的history.pushState方法进行无刷新页面跳转,但需要后端配合404时的重定向

Vue的组件data为什么必须是一个函数

  • vue中data采用的是闭包的模式,作用就是每个组件的数据都有自己独立的作用域,防止组件之间的污染

导航守卫

  • 全局守卫
    • 1.前置守卫:beforeEach,全局配置路由
    • 2.全局解析守卫:beforeResolve,这个钩子和beforeEach类似,也是路由跳转前触发,区别:它是在 beforeEach 和 组件内beforeRouteEnter 之后,afterEach之前调用
    • 3.全局后置钩子:afterEach,和beforeEach相反,他是在路由跳转完成后触发,参数包括to,from没有了next,他发生在beforeEach和beforeResolve之后,beforeRouteEnter(组件内守卫)之前。
  • 路由独享守卫
    • 1.路由独享守卫:beforeEnter,在路由里面配置
  • 组件守卫
    • 1.进入路由:beforeRouteEnter,进入路由的钩子
    • 2.更新路由:beforeRouteUpdate,更新路由的钩子
    • 3.离开路由:beforeRouteLeave,离开路由的钩子
  • 它们的参数有:
    • to:即将进入的目标路由对象
    • from:当前导航正要离开的路由
    • next:一定要用这个函数才能到达下一个路由,如果不用就会遭到拦截

Vue2与React的区别在哪?

相同点:

  • 1.都使用了虚拟dom
  • 2.组件化开发
  • 3.都是单向数据流(父子组件之间,不建议子修改父传下来的数据)
  • 4.都支持服务端渲染 不同点:
  • 1.React的JSX,Vue的template
  • 2.数据变化,React手动(setState),Vue自动(初始化已响应式处理,Object.defineProperty,Proxy)
  • 3.React单向绑定,Vue双向绑定
  • 4.React的Redux,Vue的Vuex

React篇

React.memo

React.memo为高阶组件 作用:提高性能,如果props,state和context没有变化React将跳过渲染组件的操作直接复用最近一次渲染的结果,默认情况下只会对复杂对象做浅层对比,防止重复渲染。

使用示例:

const MyComponent = React.memo(function MyComponent(props) {
  /* 使用 props 渲染 */
});

React.useMemo

作用:提高性能,当依赖的值不变则不会重复渲染,如果依赖值变则再次渲染。

使用场景:

1 缓存一些值,避免重新执行上下文

const number = useMemo(()=>{
    /** ....大量的逻辑运算 **/
    return number
},[ props.number ]) // 只有 props.number 改变的时候,重新计算number的值。

2.减少不必要的dom循环

/* 用 useMemo包裹的list可以限定当且仅当list改变的时候才更新此list,这样就可以避免selectList重新循环 */
{useMemo(() => (
    <div>{
            selectList.map((i, v) => (
                <span
                    className={style.listSpan}
                    key={v} >
                    {i.patentName} 
                </span>
            ))}
    </div>
), [selectList])}

3 减少子组件渲染

/* 只有当props中,list列表改变的时候,子组件才渲染 */
const  goodListChild = useMemo(()=> <GoodList list={ props.list } /> ,[ props.list ])

React.useReducer

作用:合并多个state

使用示例:

const DemoUseReducer = ()=>{
    /* number为更新后的state值,  dispatchNumbner 为当前的派发函数 */
    const [ number , dispatchNumbner ] = useReducer((state,action)=>{
        const { payload , name  } = action
        /* return的值为新的state */
        switch(name){
            case 'add':
                return state + 1
            case 'sub':
                return state - 1 
            case 'reset':
                return payload       
        }
        return state
    },0)
    return <div>
        当前值:{ number }
        { /* 派发更新 */ }
        <button onClick={()=>dispatchNumbner({ name:'add' })} >增加</button>
        <button onClick={()=>dispatchNumbner({ name:'sub' })} >减少</button>
        <button onClick={()=>dispatchNumbner({ name:'reset' ,payload:666 })} >赋值</button>
        { /* 把dispatch 和 state 传递给子组件  */ }
        <MyChildren  dispatch={ dispatchNumbner } State={{ number }} />
    </div>
}

React.useContext

作用:跨组件传值。

使用示例:

/* 用useContext方式 */
const DemoContext = ()=> {
    const value:any = useContext(Context)
    /* my name is alien */
    return <div> my name is { value.name }</div>
}
/* 用Context.Consumer 方式 */
const DemoContext1 = ()=>{
    return <Context.Consumer>
        {/*  my name is alien  */}
        { (value)=> <div> my name is { value.name }</div> }
    </Context.Consumer>
}
​
export default ()=>{
    return <div>
        <Context.Provider value={{ name:'alien' , age:18 }} >
            <DemoContext />
            <DemoContext1 />
        </Context.Provider>
    </div>
}

React.createRef

作用:React.createRef 创建一个能够通过 ref 属性附加到 React 元素的ref。

使用示例:

class MyComponent extends React.Component {
    constructor(props) {
        super(props);
​
        this.inputRef = React.createRef();
    }
​
    render() {
        return <input type="text" ref={this.inputRef} />;
    }
​
    componentDidMount() {
        this.inputRef.current.focus();
    }
}

React.forwardRef

作用:React.forwardRef会创建一个React组件,这个组件能够将其接受的 ref 属性转发到其组件树下的另一个组件中,通常配合useImperativeHandle使用

使用示例:

详细案例:juejin.cn/post/696866…

const FancyButton = React.forwardRef((props, ref) => (
    <button ref={ref} className="FancyButton">              {props.children}
    </button>
));
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;

React.useImperativeHandle

配合forwardRef使用,共用ref的值

  • 第一个参数:接受 forWardRef 传递过来的 ref
  • 第二个参数:处理函数,返回值作为暴露给父组件的ref对象。
  • 第三个参数:依赖项 deps,依赖项更改形成新的ref对象。

使用示例:

function Son (props,ref) {
    const inputRef = useRef(null)
    const [ inputValue , setInputValue ] = useState('')
    useImperativeHandle(ref,()=>{
        const handleRefs = {
            /* 声明方法用于聚焦input框 */
            onFocus(){
                inputRef.current.focus()
            },
            /* 声明方法用于改变input的值 */
            onChangeValue(value){
                setInputValue(value)
            }
        }
        return handleRefs
    },[])
    return <div>
        <input
            placeholder="请输入内容"
            ref={inputRef}
            value={inputValue}
            />
    </div>
}
const ForwarSon = forwardRef(Son)

React.useCallBack

作用:提高性能,用于函数,防止函数重复渲染,用法跟useMemo一样,区别在于 useMemo 返回的是函数运行的结果, useCallback 返回的是函数

React.useLayoutEffect

原理:useLayoutEffect的监听函数和clear的清除函数都是同步执行的,是在真实DOM发生改变之后,浏览器绘制前执行

注意:尽量用useLayoutEffect去操作Dom

React.useEffect

原理:useEffect的监听函数和clear的清除函数都是异步执行的,是在真实DOM发生改变并且浏览器绘制完成后异步执行

注意:在useEffect中操作Dom会引起重绘和回流

React.useTransition

作用:在useTransition的回调函数中的内容执行完毕,ispedding会为true,没执行完毕为false

const [isPedding, useTransition] = useTransition()
const [count,setCount] = useState();
// isPedding = false //默认为false 
// setCount 设值完毕 isPedding = true 
useTransition(()=>{
    setCount(1)
})