前端面试2022

9 篇文章 0 订阅
2 篇文章 0 订阅

一.路由传参
       params: 传参
       1.this.$router.push({name:’ patch路由’,params:{aaa:1111,bbb:222}});

       可用 this.$route.params.aaa 获取数据

       这个时候如果没有在路由配置 需要传的参数,页面的url不会显示参数,

页面刷新参数丢失。

       我们需要在路由配置  aaa,bbb如下(这样就)

       {

              Patch: ‘/patch/:aaa/:bbb’,

              Name:’details’,

              Components: Details

}

这么配置后 页面url 上就会显示参数。刷新参数也不会消失

显示的url: http://localhost:8080/#/ruleCenter/1111/222

如果我们想在组件里面不通过this.$route.params 获取我们可以直接在路由

上配置 props: true;

{

              Patch: ‘/patch/:aaa/:bbb’,

              Name:’details’,

              Components: Details

}

然后再组件的props 上写上

props:{

       aaa:{

              type: String,

},

bbb:{

              type: String,

}

}

2.This.$router.push({name:’xxx’,query:{

       aaa : 1111,bbb :222

}})

这样传就不需要在路由进行配置:

浏览器上url 会以? 号拼接的形式显示。

http://localhost:8080/#/ruleCenter/ruleManage/edit?aaa=1111&bbb=222

优点: 不需要路由上进行配置,刷新参数也不会消失

              使用this.$route.query.aaa 直接获取

缺点: 不能解耦到props

=, provide/inject

  1. Provide

在父组件使用可传参给子或者孙或者更孙的组件。

如:

Provide:{

        Res:’你’,

}

如果想要使用data 里面的变量。Provide 需要写成 函数形式

Provide(){

        Return {

               Res:this.data  //我们也可以把整个 this 都传过去

}

}

  1. inject

我们在子组件或者孙组件我们可以使用 inject  接收。

如:

Inject:[‘res’],

//注释: 当vue 版本低于 2.2.1 版本inject 注入的值只能在data,props

初始化后得到。高于这个版本就可以在data 中使用inject 赋值给变量

在vue 2.5.+ 版本也可以写成

Inject:{

        Res:{

               From:’component1’, //值来至于哪个组件,比如这个组件

                                                  有父组件和祖父组件,这个from 可以规定

                                                  我们取的这个值是哪个组件的。

               Default:’nb ’

}

       

}

三、Vue 无状态组件。

 1. 声明函数组件

        使用functional 字段

        如:

               <template  functional> <div>1111</div></template>

        或者:

               {

                      functional: true,

                      props:{

}

                      render(cteateElement,context){

}

}

              2.注意事项

                Props 在2.3.+ 以上的版本变成隐式注入,也就是可以不写props 需要

                参数 默认全部注入

               不能使用 this // 因为组件不是实例化组件

               不触发任何生命周期

  1. 组件render 函数只有两个值  一个是createElement另外一个是context

第一个参数是创建节点的

第二个参数是 传递所有的参数的。它包括了

props, 注入的全部props 对象

slots, 提供的全部插槽的对象

children, 子节点的数组

scopedSolts(2.6.+)暴露的一个暴露传入的做用域插槽的对象。也以函数形

式暴露普通插槽

              data:传递给组件的整个data 数据

              parent: 父组件的引用

              listeners: 父组件实例为当前组件注入的事件 @形式注入的

              injections: 就相当于普通组件inject,用来接收父组件的注入

             

四、vue 自定义指令(directive)

       1.注册自定义指令(可全局定义也可以局部定义)

        全局定义:vue.directive(‘name’,{}) 局部定义:directtive:{name:{} }

       2.自定义指令的周期钩子

       bind: 第一次绑定到元素调用,只执行一次

       unbind: 指定元素解除绑定时调用,只执行一次

       inserted:被绑定的元素插入到父节点的dom 时候调用

update:组件更新时候调用

componentUpdated:组件和子组件更新时候调用。

       3.除了update和componentUpdated钩子外其他的钩子都含有 3个参数

        el: 指绑定的dom 元素

        binding: 是一个对象包含  name,value,oldvalue,expression,arg,modifiers,

        vnode

        除了el 参数其他的参数都是只读属性

     oldVnode 只在update 和 componentUpdated 钩子中生效。

     注释:自定义指令也可以写修饰符和传参  如 stop 修饰符。

五:过滤器(filter)

  1. 可全局注册也可以局部注册

全局 Vue.filter(‘moeny’,function(nam,arg){ });局部注册 filter:{functionName:(name,rage)={}}

2.使用方法 {msg | moeny} 也可以传另外的值   { msg| money(2)};

3.在methods方法中调用filter 方法

       全局注册的  vue.filter[‘moeny’](value)

       局部注册  this.$options.filter[‘moeny](value)。

六,vue 对数组方法的重写

  1. 复制数组原型Array.prototype
  2. 用 object.defineproperty 对方法进行监听
  3. 使用 notify 调用 修改队列里面watcher的方法 update 方法更新界面。

  1. 浏览器渲染和HTML 的过程
    (1)用户输入网址
    (2)查找网址对应的ip 地址
    (3)三次握手(和服务器建立链接)
    (4)接收HTML 代码
    (5)开始解析HTML(解析成dom树,从上到下解析)
    (6)遇到link 标签会像服务器再次请求css 数据然后再往下渲染
    (7)遇到图片会向服务器请求图片,然后继续往下渲染,当图片返回后,因为图片占了一定的宽度,需要返回继续渲染这部分代码
    (8)遇到script 标签会请求js 代码然后执行js 代码
  2. Css 如何避免样式污染
    (1) 采用约定的命名方式
    (2)css scoped
    (3)css module
  3. 盒子模型
    盒子模型是由外边距 + 边框 + 内边距 + 内容组成
    变异和模型 是外边距 + 内容组成
  4. Css BFC
  5. 元素的几种隐藏方法
    (1)visibility:hidden, (隐藏元素元素位置还在)
    (2)display:none(元素位置被隐藏)
    (3)opcity: 0  (隐藏元素元素位置还在)
    (5)position (把元素定位到浏览器之外)
  6. align-itemsalign-content的区别
    1align-items 是单行上下居中
    2align-content 是多行上下居中
  7. 什么是原型,什么是原型链
    1)所有的对象都有显示原型和隐式原型
    2)对象的隐式原型指向构造函数的显示原型(直到object的原型形成原型链,object 的隐式原型是空的)隐式写法_proto_ 显示原型 prototypePrototype 具有constructor指针。指向了构造函数或者说指向对象
    3)示例:当调用对象的函数,先在对象里面找,没找到,到显示原型里面找,显示原型没找到再到隐式原型指向的原型里面找。以此向上找到object
    4)手写原型链示例:
         function Foo(name){
            this.name = name
          }
          Foo.prototype.showName = function(){
             console.log(this.name)
          }
          const f1 = new Foo(‘sh’);
          f1.showName(); //
    输出sh
  8. New 实例化做了一些什么;

1)创建一个对象
2)对象的隐式原型指向构造函数的显示原型
3)适用apply 或者call 改变构造函数的this指向,指向新的对象执行函数返回结果

(4)判断结果是不是空的是空的就返回上面新建的空对象。不是空的就return 执行结果

dom树构建。

  1. 浏览器构建dom 树需要DOM树构建器和标签解析器
  2. Dom构建器接收到了标签解析器发送的起始标签名后,会加入到栈中。
  3. 标签解析器每解析一个标签名会把它压入到栈中,当遇到标签的结束标签时,判断结束标签跟栈顶是不是同元素标签如果是就会把栈内容弹窗放到dom树种。以此类推下去直到HTML标签的结束标签也加入到DOM 中。构建结束。
  4. 如果其中有标签缺少结束标签时候会到解析到body 的结束标签才会弹出栈内容放入dom 树中。

http2.0

http2.0主要基于SPDY协议

优点

  1. 新的二进制格式
  2. 可设置请求优先级
  3. 请求头部信息压缩
  4. 多路复用(多个请求可同时在一个连接上并行执行。某个请求任务耗时严重,不会影响到其它连接的正常执行;
  5. 服务端推送。即网页中有其他的资源请求如网页请求一个style.css 样式资源,网页中还有一个 style.js 资源。服务端会把style.js 的资源推送给客户端。(服务端推送能把客户端所需要的资源伴随着index.html一起发送到客户端

    1. diff 算法

1.调用patch方法

function patch(oldvnode,vnode){
  if(sameVnode(oldvnode,vnode)){

        patchVnode(oldvnode,vnode)

} else {

       Const oEl = oldvnode.el

       Let ParentEle = api.parentNode(oEl);

       createEle(vnode);

       if(parentEle !== null) {

              api.insertBefore(parentEle,vnode.el,api.nextSibling(oEl))

              api.removeChild(parentEle,oldvnode.el)

              oldvnode = null

}

}

return vnode;
}

2. vnode 和 oldvnode 两个对象简单的属性不是全部属性

{

       el: div,真实节点的引用

       tagName: ‘DIV’ 标签名称

       sel:’div#v.classB’,  节点的选择器

       data: null  节点的属性即(prop 如 onclick style)

       children:[], 存子节点的数组

       text: null ,如果是文本对应文本内容

}

3. 进行patch 先判断两个节点是否有对比意义。就是调用sameVnode进行对比

       Function sameVnode(oldvnode,vnode){

       Return vnode.tagName== oldvnode.tagName&&vnode.key  === oldVnode.key && vnode.sel = oldvnode.sel

} //判断两个节点的key 和sel (选择器)和标签名称相同才去比较他们,如果不同就直接替换掉。

4.值得比较就会调用patchVnode 方法

patchVnode (oldVnode, vnode) {

    const el = vnode.el = oldVnode.el //把旧的真实dom 赋给新的vnode 对象的el 属性

    let i, oldCh = oldVnode.children, ch = vnode.children

    if (oldVnode === vnode) return //两个对象引用一致, 就直接结束对比。

if (oldVnode.text !== null && vnode.text !== null && oldVnode.text !== vnode.text) {

       //如果是文本节点就对比文本,如果文本需要进行修改 进行文本修改

        api.setTextContent(el, vnode.text)

    }else {

        updateEle(el, vnode, oldVnode)

        if (oldCh && ch && oldCh !== ch) { //对比两个节点如果有子节点就调用 updateChildren方法进行子节点对比。

            updateChildren(el, oldCh, ch)

        }else if (ch){ //如果只有新节点就直接添加子节点

            createEle(vnode) //create el's children dom

        }else if (oldCh){ //如果新节点没有子节点,老节点有,那么直接删除老节点的

            api.removeChildren(el)

        }

    }

}

5.比较子节点  调用  updateChildren 方法:

代码比较多略网上百度都有(直接讲原理)

  1. 看上图应该知道了新老节点的左右两边都有一个变量标记,在遍历的过程中这几个标记值会像中间靠拢
  2. 当oldStartIdx >= oldEndIdx 或者newStartIdx >= newEndIdx时候结束循环
  3. 序号标记和对应的节点关系 刚刚开始   
    oldStartIdx == oldStartVnode
    oldEndIdx == oldEndVnode
    newStartIdx == newStartVnode
    newEndIdx == newEndVnode
    先判断节点是否为空 如果 oldStartVnode == null 就把 oldStartVnode  == oldch[++oldStartIdx ],如果oldEndVnode  == null  就把oldStartVnode  == oldch[--oldStartIdx ]赋值。new的也一样这样处理。
  4. 进行对比  刚刚开始老节点第一个跟新节第一个调用sameVnode方法进行对比判断是否有对比意义,然后 老节点最后一个跟新节点最后一个进行对比。这个时候两两对比如果有对比意义直接调用patchVnode 方法进行对比。
  5. 然后老节点第一个跟新节点最后一个对比
    如果这两个有对比意义,这时候说明老节点第一个已经跑到了oldEndVnode节点后面去,进行patchVnode 对比时候需要把真实的dom移动到 oldEndVnode节点后一个子节点后面
  6. 然后老节点最后一个跟新节点第一个对比。
    如果这两个有对比意义,这时候说明老节点最后一个已经跑到了oldStartVnode节点的前面去了,进行patchVnode 对比时候需要把真实的dom移动到 oldStartVnode节点前面
  7. 如果以上都不满足就进行key 对应的节点对比,如果在旧的子节点没有找到新的子节点对应的key。那么就会新建一个dom节点。如果找到了旧进行对比。到此结束。接下来就是处理多余的节点等问题。

       传统算法通过循环递归对节点进行一次对比效率低下。算法复杂度达到o(N^3),主要原因是在于其追求完全对比和最小修改。而react 和vue 放弃了完全对比及最小修改。才实现了算法复杂度o(N).

  1. 全量对比
  2. 运行时对所有节点生成一个虚拟节点树,当页面数据发生变更,会遍历判断虚拟dom所有的节点;。如果时复制的大型项目,必然存在狠复杂的父子关系的节点。这个时候diff vue0 算法会不断的递归调用patchVNode.]

Vue3.0

1.采用动静结合的方式
       在编译模板时候编译器会在动态标签末尾打上Patchflg.(即在生成节点(VNode)时候,同时打上标记)

Patchflg 值有 13种

当patchFlg < 0  时表示元素为静态元素,对于静态元素,在渲染时候会直接复用。

优点:

事件缓存(事件会先读取缓存如果缓存没有会把传入的事件存到缓存)

Vue2 里每当触发更新的时候,不管元素是否参与更新,每次都会全部重新创建

而在 Vue3 中会把这个不参与更新的元素保存起来,只创建一次,之后在每次渲染的时候不停地复用

Vue2 updateChildren 会进行

  • 头和头比
  • 尾和尾比
  • 头和尾比
  • 尾和头比
  • 都没有命中的对比

Vue3 patchKeyedChildren

  • 头和头比
  • 尾和尾比
  • 基于最长递增子序列进行移动/添加/删除

Vue3.0 做的优化讲的比较好的  博客  

https://blog.csdn.net/weixin_43294560/article/details/121928356

        1. 和UDP 的区别
    1. Tcp  是面向链接的,UDP 是面向无链接的。
    2. TCP 是单播的,UDP 是单播,多播,和广播。
    3. UDP 头部开销比TCP 小,效率更快。
    4. TCP是基于三次握手建立链接,UDP 是无链接的,是不可靠的传输协议。

1. 实现对象劫持。vue2.x 用它实现数据双向绑定

缺点:

1.不能监听数组变化

   注释:并不是object.definedporperty不监听数组改变。而且vue 源码里面对数组监听做了限制。当去掉源码里面的限制后,当我们输入 arry[0]=hjdask  页面是会有响应式的只是数组被遍历了两次。那为啥vue 限制了呢。这个尤大大给的回答是 性能问题。并没有多做解释

2.必须遍历对象的每一个属性3.必须深层遍历嵌套的对象

无法监听数组变化,vue2.x 无法对数组的变异方法(push,pop,shift,unshift,sort,reserve)进行监听,只是对这些方法进行重载hack,达到监听变化的效果。

必须遍历对象属性:vue2.x 对对象进行监听变化需要使用 Object.keys()搭配Object.definedProperty 对每个对象属性进行绑定,开销大

必须生成遍历对象:针对多层嵌套的对象,则需要递归遍历进行绑定

兼容 ie9 及以上

proxy

  实现数据劫持,vue3.x 用它实现数据双向绑定

      

proxy 监听的是整个对象而不是对象的某个属性。

可以监听数组变化

有多达13种拦截方式,比 Object.definedProperty 功能更强大

proxy 结果返回新对象而不是 像object.property 直接修改对象

proxy 可维护性更好。

深层监听需要跟 Reflect 结合使用。

proxy 不兼容ie 

无法转译成 es5 或者用 polyfill 提供兼容

重绘和回流

  1. 当浏览器获取的资源后进行了dom 解析生成dom树 和css 解析生成 css树,
  2. Dom 树和css树结合生成渲染树
  3. 回流:浏览器计算元素节点几何信息
  4. 浏览器渲染渲染树。

触发重绘: 修改元素的背景颜色,文字颜色等会触发重绘不会触发重排

触发重排: 1.修改元素的大小,使用display: none 隐藏元素,删除增加元素

                 2.浏览器视口改变

                 3.获取dom 的布局信息,如offsetHeight  clientWidth getComputedStyle()等

避免重排的方法:

  1. 合并多次的样式修改
  2. 对于会频繁导致重排的元素设置 position: absolute 或者fixed。使其脱离文档流。就不会让浏览器发生重排,也不是完全不重排,个人理解是会重排改变元素得那一图层。然后合并图层。合并图层依然会吃gpu.
  3. 对于dom 比如添加很多列数据的不要一列一列添加。现在js 构建好html 结构一次性添加。

硬件加速

概念: 告诉浏览器开启gpu 加速,切换到gpu模式发挥gpu 功能。

1.Css 3 不会主动开启硬件加速  如 animation,transform,transtions 不会主动开启gpu 速

2.需要被动触发

       方法:

  1. 开启3d 如  translate3d,rotate3d 等属性
  2. 可以使用 translateZ0)来欺骗浏览器,让它以为我们开启了3d

注释: translateZ(0)可能会触发闪烁,有两个办法可以修改一个是隐藏旋转背面和改变透明度。第二个就是直接设置 translate3d(0,0,0)

强缓存 (优先级   Pragma -> Cache-Control -> Expires)

  1. 强缓存有两种方式 expires 和 cache-control (注释:还有一个pragma值只能是no-cache 是为了做http1 之前的兼容);
  2. Expires : 第一次请求接口后,后端会在响应头返回字段expires这个字段是一个时间绝对时间。浏览器第二次请求会拿客户端时间跟这个时间对比查看缓存是否可用。如果可用就直接使用缓存不去请求
  3. Cache-control: 第一次请求接口后,接口返回Cache-control字段这个字段有6个值: 如下
    max-age: 相对时间,相对于第一次请求间隔多少时间。如果第二次请求间隔时间在这个时间内,就可以直接拿缓存,不发请求。
    s-maxage:中间服务器缓存相对于第一次请求的时间的过期时间。
    privte: 允许被客户端浏览器缓存,不允许被中间服务器缓存。
    public: 允许浏览器和中间服务器缓存
    no-store: 不允许缓存
    no-cache: 允许协商缓存;

弱缓存

         弱缓存的方式有两种,我总结一种是时间缓存,一种是标记缓存。

网络攻击

       Xss攻击

  1. 用户输入脚本攻击(持续性攻击)
  2. 修改url 参数成js 脚本攻击,诱导用户点击(非持续)

防御:

  1. 对用户输入内容进行校验
  2. 把用户输入中的敏感字符进行转化,如 <>

CSRF攻击

原理:

       用户登录网站A,获取cookie 信息并存到浏览器,在没有关掉网站A 的情况下进行登录钓鱼网站B。网站B拿着cookie和用户信息去请求网站A。比如转账等请求。

防范:

  1. 判断post 请求的报文头部查referer 判断请求来源
  2. 利用token: 生成token。后端利用token 判断token 是否正确是否过期解决。

SQL 注入攻击

  1. 用户通过登录,或者评价等功能输入SQL 代码,达到欺骗服务器执行恶意SQL 的目的。

防范:

  1. 对输入的数据进行校验。

文件上传漏洞:

  1. 通过上传可执行脚本的文件进行攻击

防范:

  1. 文件上传的目录设置为不可执行的
  2. 对文件类型进行校验
  3. 使用随机数改写文件和文件路劲

原型

  1. 只有函数有原型,函数的原型(prototype)属性是一个对象。
  2. 因为函数还是一个对象所以函数还有隐式原型(__proto__)。
  3. 函数的隐式原型指向 Function 的 显示原型。
    即 function a (x,y){}; a.__proto__ -> function.prototype;
    why: 因为function a   a 函数相当于 是 var a  = new Function(x,y)
  4. Function 也是一个构造函数也是一个函数对象。所以它的隐式原型指向它自己;
    即: Function.__proto__ -> Function.prototype;
    why: 因为函数是 Function  构造函数的实例。Function 也是  Function 的实例
    即function 是它本身的实例所以  它的隐式原型指向它的显示原型
  5. 对象只有隐式原型没有显示原型,
  6. 对象的显示原型为undefined  如: var a = {}; a.prototype == undefined;
  7. 对象的隐式原型指向构造函数的显示原型;
    即: 上面a.__proto__ -> Object.prototype;
    why: 因为var a ={}; 即 var a = new Object();
  8. 这个时候就会有人问Object.有没有__proto__。答案肯有啊。因为它也是函数,函数的隐式原型都是指向 Function.prototype的 即:object.__proto__ == Function.prototype;
  9. 原型因为是一个对象,它也具有隐式原型。它的隐式原型指向object.prototype。
  10. 顺便提示一下class 定义的类实际就是一个构造函数。Class 相当于是 es5 构造函数的语法糖。所以class.__proto__ 也是指向Function.prototype。它的原型的prototype.__proto 也是指向Object.prototype;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值