IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> 前端常见面试题(详解)——持续更新中 -> 正文阅读

[JavaScript知识库]前端常见面试题(详解)——持续更新中

目录

vue

1.vue生命周期

2.vue.use()

3.自定义指令

4.computed和watch有何区别?

5.过滤器的使用filters

6.vuex 的理解

7.父子组件的生命周期钩子

8.v-mode和.sync的对比

9.对nextTick的理解

10.哈希路由和history路由的区别

11. 组件之间的传参方式

12.mutation和action的使用区别

13.vue2中v-model是一个语法糖,那具体是怎么实现的?

14.v-if和v-show的区别

15.循环的时候,为什么一定要绑定key

16.vue2 常用的指令有哪些

17.vue2和vue3的区别

18.vue2中响应式的原理

JS

1.js的数据类型 8种

2.如何判断数据类型 5种

3.原型链

4.闭包

5.如何判断this的指向

6.call和apply 和bind的使用

7.数组常用的api

8.什么是回调地狱,如何解决

9.promise的使用

10.new的背后做哪些事情

11.防抖和节流

12.高阶函数

13.函数柯里化

14.for in和for of的区别

15.递归及应用场景

16.eventloop事件循环

17.深拷贝与浅拷贝

网络

1.https和http的区别

2.常见http的状态码

3.如何减少重绘和回流

4.描述输入url地址到网页展示的过程

5.跨域问题及解决方案

6.get请求和post请求的区别

7.http的协议的三个内容

8.请求头中的contentType有什么用处

?dom

1.事件冒泡和事件捕获

2.?事件委托

3.如何添加和删除事件


vue

1.vue生命周期

Vue 实例从创建到销毁的过程,就是生命周期。也就是从开始创建、初始化数据、编译模板、挂载Dom→渲染、更新→渲染、卸载等一系列过程

初始化??

在beforeCreate生命周期函数执行的时候,data和method 还没有初始化

在created 生命周期函数执行的时候,data和method已经初始化完成

挂载

在beforeMount 生命周期函数执行的时候,已经编译好了模版字符串、但还没有真正渲染页面中

在mounted 生命周期函数执行的时候,已经渲染完,在视图中可以看到页面

更新

在beforeUpdate生命周期函数执行的时候,已经可以拿到最新的数据,但还没渲染到视图中去。

在updated生命周期函数执行的时候,已经把更新后的数据渲染到视图中去了。

销毁

在beforeDestroy 生命周期函数执行的时候,实例进入准备销毁的阶段、此时data 、methods 、指令等还是可用状态?

在destroyed生命周期函数执行的时候,实例已经完成销毁、此时data 、methods 、指令等都不可用?

三个不常用

keep-alive 主要用于保留组件状态或避免重新渲染。

activated只有在keep-alive 组件激活时调用。

deactivated只有在keep-alive 组件停用时调用。

errorCapured 当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此钩子可以返回 false 以阻止该错误继续向上传播


2.vue.use()

在 install 里我们可以拿到 Vue 那么和 Vue 相关的周边工作都可以考虑放在 Vue.use() 方法里,比如:

  • directive注册
  • mixin注册
  • filters注册
  • components注册
  • prototype挂载
  • ...

通过全局方法?Vue.use()?使用插件;也可以将使用理解成注册

Vue.use(js对象/function,参数)
js对象:{
    install(Vue,options){
      // 在Vue.use后,该方法会执行  
    }
}
function:function(Vue,options){
  // 在Vue.use后,该方法会执行    
}

常见的注册场景

import Router from 'vue-router'
Vue.use(Router)

import Vuex from 'vuex'
Vue.use(Vuex)

import Echarts from 'echarts'
Vue.prototype.$echarts = Echarts

echarts 用 Vue.use() 来注册

main.js

import Vue from 'vue'
import echarts from './echarts.js'
Vue.use(echarts)

new Vue({
  ...
})

echarts.js

import Echarts from 'echarts'
export default {
  install(Vue){
    Vue.prototype.$echarts = Echarts
  }
}

3.自定义指令

可以看这个??8个非常实用的vue自定义指令

除了默认的内置指令 (v-model?和?v-show)等之外,Vue 也允许注册自定义指令。当我们需要对普通 DOM 元素进行底层操作时,这时候就会用到自定义指令。

指令定义函数提供了几个钩子函数(可选):

  • bind: 只调用一次,指令第一次绑定到元素时调用,用这个钩子函数可以定义一个在绑定时执行一次的初始化动作。

  • inserted: 被绑定元素插入父节点时调用(父节点存在即可调用,不必存在于 document 中)。

  • update: 被绑定元素所在的模板更新时调用,而不论绑定值是否变化。通过比较更新前后的绑定值,可以忽略不必要的模板更新(详细的钩子函数参数见下)。

  • componentUpdated: 被绑定元素所在模板完成一次更新周期时调用。

  • unbind: 只调用一次, 指令与元素解绑时调用。

接下来我们来看一下钩子函数的参数 (包括 elbindingvnodeoldVnode) 。

  • el: 指令所绑定的元素,可以用来直接操作 DOM 。

  • binding? ?一个对象,包含以下属性 (具体的vue.js文档查看)

  • vnode: Vue 编译生成的虚拟节点,查阅 VNode API 了解更多详情。

  • oldVnode: 上一个虚拟节点,仅在 updatecomponentUpdated 钩子中可用。

除了 el 之外,其它参数都应该是只读的,尽量不要修改他们。如果需要在钩子之间共享数据,建议通过元素的 dataset 来进行

添加一个自定义指令,有两种方式:

  • 通过 Vue.directive() 函数注册一个全局的指令。

  • 通过组件的 directives 属性,对该组件添加一个局部的指令。

创建全局指令:

需要传入指令名称以及一个包含指令钩子函数的对象,该对象的键即钩子函数的函数名,值即函数体,钩子函数可以有多个。

Vue.directive('指令名',{
    自定义指令的生命周期
    bind:绑定时,自定义指令绑定于相应dom时执行(类似于vue生命周期的beforeMount)
    bind(dom,obj,vnode){
        dom:指令所在dom
        obj:{
            属性名
            修饰符
            值
        }
        vnode:虚拟dom节点信息
           context:能获取指令所在组件的实例对象        
    }
    inserted:指令所在dom添加到父节点时执行,渲染时(类似于以前的mounted)
    inserted(dom,obj,vnode){
        
    },
    update:更新时,不保证更新完成(指令所在组件有更新时执行),不保证该更新和当前指令所在dom有关 
    update(dom,obj,vnode){
        dom:当前指令所在dom
        obj:{
            属性名
            修饰符
            值   
        }
        vnode:context:获取指令所在组件的实例对象
    }
    
    componentUpdated:更新完成时,指令所在组件更新完成(类似于以前vue生命周期的updated)
    unbind:解除绑定,类似于beforeDestroy
})

?局部自定义指令

directieves:{
    指令名:{
        bind,
        inserted,
        update,
        componentUpdated,
        unbind
    }
}

应用场景

在做过的一个项目中,有一个上传头像的部分,上传了一张图片后,它的地址有错误,就需要自己给定一个默认的图片,就用到了自定义指令,v-images 当地址是错误的时候,就需要用到自己自定义的一个默认的图片

批量注册指令,新建?directives/index.js?文件

import copy from './copy'
import longpress from './longpress'
// 自定义指令
const directives = {
  copy,
  longpress,
}
 
export default {
  install(Vue) {
    Object.keys(directives).forEach((key) => {
      Vue.directive(key, directives[key])
    })
  },
}

?在?main.js?引入并调用

import Vue from 'vue'
import Directives from './JS/directives'
Vue.use(Directives)

4.computed和watch有何区别?

计算属性computed :

1.computed是依赖已有的变量来计算一个目标变量,大多数情况都是多个变量凑在一起计算出一个变量

2.并且computed具有缓存机制,依赖值不变的情况下其会直接读取缓存进行复用

3.computed不能进行异步操作,当computed内有异步操作时无效,无法监听数据的变化

4.如果computed属性属性值是函数,那么默认会走get方法;函数的返回值就是属性的属性值;在computed中的属性都有一个get和一个set方法,当数据变化时,调用set方法。

5.使用? 给计算属性的变量赋值时使用全写? ? ? 需要进行计算求和的时候使用到

computed: {
    属性名: {
       set(值) {   // set()接收要赋予的值
 
   },
       get() {
         return "值"   // get()里要返回给这个计算属性具体值
   }

  }
}

侦听属性watch:

1.watch是监听某一个变量的变化,并执行相应的回调函数,通常是一个变量的变化决定多个变量的变化

2.不支持缓存,数据变,直接会触发相应的操作

3.watch可以进行异步操作

4.监听数据必须是data中声明过或者父组件传递过来的props中的数据,当数据变化时,触发其他操作,监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值;  immediate:组件加载立即触发回调函数执行

deep: 深度监听,为了发现对象内部值的变化,复杂类型的数据时使用

5.使用: 当进行全选与饭选的时候用到

监听一个基本数据时:

watch: {
    value () {
        // do something
    }
}

?监听一个引用数据类型时:

watch: {

    需要监听的属性名 obj: {
       handler (newVal,oldVal) { // 执行回调
           // do something
       },
       deep: true, // 是否进行深度监听 复杂数据类型
       immediate: true // 是否初始执行handler函数, 立即执行
    }
}

总结

当目的是进?数值计算,且依赖于其他数据,那么推荐使用 computed

当需要在某个数据发生变化的, 同时做?些稍复杂的逻辑操作,那么推荐使? watch


5.过滤器的使用filters

过滤器就是一个函数, 传入值返回处理后的值,被用于转换格式,常见的文本格式化,将值转换为另一种形式

Vue3中舍弃了filters 过滤器,用函数替代了过滤器

过滤器可以用在两个地方:双花括号插值和v-bind表达式

全局的用Vue.filter():Vue.filter("过滤器名", (值) => {return "返回处理后的值"})

局部的用filters属性:?filters: {过滤器名字: (值) => {return "返回处理后的值"}

过滤器传参: vue 变量 | 过滤器传参

多个过滤器: vue变量 | 过滤器1 | 过滤器2

应用场景: 时间格式化用到过滤器,有一个禁用和启用的状态改变用到了过滤器,人员员工的聘用形式用到了过滤器:过滤器的名字:function() {return}? 导入,全局过滤器注册, 使用{vue变量:过滤器名字}


6.vuex 的理解

vuex的本质是一个对象,是响应式的,管理公共数据的工具,用于多个组件之间的数据共享。vuex的出现是为了解决web组件化开发的过程中,各组件之间传值的复杂和混乱的问题。

?整个虚线部分就是Vuex,我们可以把它看成一个公共仓库store。store中有Actions(行为)、Mutations(变动)和State(状态)。整个的逻辑是组件通过Dispatch调用Actions中的方法,Actions通过Commit调用Mutations中的方法,Mutatisons改变State中的值。

vuex是全局状态管理库,可以通过它来进行全局数据流的管理。

state: 存放多个组件都用得到的公共数据,定义了应用状态的数据结构,可以在这里设置默认的初始状态(相当于data)

mutations: 存放操作数据的方法,修改state (相当于methods)

actions: 存放一些异步操作 (也可以进行一些同步处理) 注意: actions是不能直接修改state数据的, 需要提交mutation

getters: 存放基于state计算出来的一些值 (相当于计算属性)

modules: 分模块, 项目大了, 推荐分模块管理,用到映射,先从vuex中导入mapState,然后使用

注意点: 分模块了, 默认muations, actions, getters 注册到全局的, 一般会开启命名空间,语法: namespaced: true??可以解决不同模块命名冲突的问题,将不同模块的namespaced:true,之后在不同页面中引入getter、actions、mutations时,需要加上所属的模块名。

简述vuex的数据传递流程

当组件进行数据修改的时候,我们需要调用dispatch来触发actions里面的方法。actions里面的每个方法中都会有一个 commit 方法,当方法执行的时候,会通过commit 来触发 mutations 里面的方法来进行数据的修改,?mutations 里面的每个函数都会有一个 state 参数, 这样就可以在 mutations 里面进行state 的数据修改, 当数据修改完成后, 会传导给页面,页面的数据也会发生改变。


7.父子组件的生命周期钩子

0. 加载渲染过程

父 beforeCreate 父 created 父 beforeMount

子 beforeCreate 子 created 子 beforeMount 子 mounted 父 mounted

1. 子组件更新过程

子 beforeUpdate 子 updated

2. 父组件更新过程? 父组件更新的数据子组件有使用!

父 beforeUpdate 子 beforeUpdate 子 updated 父 updated

3. 销毁过程

父 beforeDestroy 子 beforeDestroy 子 destroyed 父 destroyed


8.v-mode和.sync的对比

v-model 只能使用一次,一个页面中只能使用一次

.async可以使用多次

vue3中没有async 用函数来替代

v-model = " 父组件属性"? ? ?就相当于?? :value= “父组件的属性” @ input = "父组件的属性" = $event

v-model
   父组件中的子组件标签上   :value="父组件属性"  @input="父组件属性=$event"
   父组件中的子组件标签上  v-model="父组件属性"  (与上面的写法意思相同)
   子组件内:
      props:['value']
      model:{
          prop:'value',
          event:'input'
      }
      触发:this.$emit('input',实参值)

.sync修饰符
   子组件标签  :属性名="父组件属性"   @update:属性名="父组件属性=$event"
   子组件标签  :属性名.sync="父组件属性"
   子组件内
     props:['属性名']
     触发:this.$emit('@update:属性名',实参值)

9.对nextTick的理解

vue是响应式的框架:状态的变化能自动更新视图。不过,这个过程是异步的。nextTick就是用来实现这个异步过程的核心函数。

在updated生命周期钩子函数里面可以访问到更新后的DOM,或者在this.$nextTick里的函数体中访问到

有两种情况会调用nextTick:

  1. 情况1是当状态被修改,vue会自动调用nextTick,并传入这个状态的观察者-watcher。简化记为:nextTick(watcher函数)。
  2. 情况2是我们手动调用nextTick(用Vue.nextTick,或者是this.$nextTick),并传入自己的回调函数。简化记为:nextTick(callback函数)

那么nextTick内部做了什么呢? 主要是两件事:

  1. 将实参push到其内部维护的callbacks数组中
  2. 用Promise.resolve().then 注册微任务(这里简化场景:以支持Promise的浏览器环境为例,就不考虑其他),执行callbacks中的所有回调。

应用场景1: 父组件的状态通过props传递给子组件使用时,当父组件的状态改动后,想通过子组件的实例获取内部的props, 伪代码如下:

this.data1 = 新值
this.$nextTick(()=>{
    this.$refs.子组件.prop1 // 子组件的prop的新值
})

?应用场景2:? ?静默刷新 ,无感知的刷新

对象的新增属性vue无法响应式的更新,原有属性可正常更新

数组的能修改源数组的方法能实现数组的响应式更新,但是如果直接修改数组的值无法响应式更新

vue 不能检测对象属性的添加与删除? ? 通过这个方法 this.$set(对象,属性名,修改后的值) 可以解决?

但是有时候项目中的属性多了,不知道改哪一个,就可以使用 静默刷新 解决

静默刷新
        适用场景:数据修改了,页面没更新
                 组件的还原  将一个做了很多处理的组件,就可以用静默刷新将组件还原
          需要刷新的数据  v-if="bol"  bol默认为true
          this.bol=false
          this.$nextTick(()=>{
              this.bol=true
          })

应用场景3

关于vue 引入 echarts获取不到DOM节点的问题

vue3中需要这样引入并把echarts挂载到vue原型上

遇到的问题
即使放在mounted中也无法取到dom节点返回为null
使用vue3中的ref获取依旧为null
一个奇怪的问题获取dom节点时可以取到组件最外层的元素,但是内层无法获取
最后放在了this.$nextTick中解决了问题

created(){
this.$nextTick(()=>{
	console.log(document.getElementById('echartsbox'))、
	//这里成功取到了DOM元素
})
}

10.哈希路由和history路由的区别

单页面(SPA)应用是在移动互联时代诞生的,它的目标是不刷新浏览器,而通过感知地址栏中的变化来决定内容区域显示什么内容。要达成这个目标,我们要用到前端路由技术,具体来说有两种方式来实现:hash模式和history模式。

一是原理不同。hash模式的实现原理是通过监听hashChange事件来实现的。history模式是通过调用 history.pushState方法(或者replaceState) 并且 监听popstate事件来实现的。history.pushState会追加历史记录,并更换地址栏地址信息,但是页面不会刷新,需要手动调用地址变化之后的处理函数,并在处理函数内部决定跳转逻辑;监听popstate事件是为了响应浏览器的前进后退功能。

二是表现不同。hash模式会在地址栏中有#号,而history模式没有;同时由于history模式的实现原理用到H5的新特性,所以它对浏览器的兼容性有要求(IE >= 10)。

三是history模式开发的SPA项目,需要服务器端做额外的配置,否则会出现刷新白屏(链接分享失效)。原因是页面刷新时,浏览器会向服务器真的发出对这个地址的请求,而这个文件资源又不存在,所以就报404。处理方式就由后端做一个保底映射:所有的请求全部拦截到index.html上。


11. 组件之间的传参方式

props $emit eventBus ref parents children vuex v-model .sync provide inject

    父传子
       传   子组件标签   属性名=值
       // 可以通过数组或者对象的形式来接收传过来的参数,如果使用的是对象来接收,说明要对传过来的参数进行校验
       // props: ['属性名']  
       收   props:{
           属性名:{
               type:类型,多个类型  [Object,Array,String],
               default:基本数据类型,直接写
                       复杂数据类型:()=>{return 复杂数据类型}
               required:true, // 必填
               validator:(value)=>{
                   return boolean值
                      true:验证通过
                      false:验证失败
               }
           }
           单向数据流:栈不可修改,堆随便改
                   基本数据类型不可修改,复杂 数据类型,只要不修改它的引用地址(栈),它的值随便修改

       }
子传父(子触发父方法)
     绑定:  子组件标签  @子组件方法名="父组件方法"
     触发:
        子组件内触发:this.$emit('子组件方法名',参数值)
 ref传值
   获取组件的实例对象
   1. 父获取子组件实例对象
      1. 子组件标签  ref="xxx"
      2. 子组件的this(实例对象)====this.$refs.xxx
   2. 子获取父组件实例对象
      1. this.$parent===父组件的实例对象,它找到的父组件是最近的父组件
         1. 子组件标签如果是其它组件包着的就是其它组件是它的父级
         2. 如果子组件标签是原生标签包着的,它的父组件就是它所在的组件
父子组件双向绑定  v-model

  子组件标签   :value="父组件属性"  @input="父组件属性=$event"      
  子组件标签   v-model="父组件属性"   
  子组件内:
     props:['value'],
     model:{
         prop:'传入的属性名,默认是value',
         event:'绑定的事件名,默认是input'
     },
     单向数据流:栈不可修改,堆可以修改
               基本数据类型不可修改,复杂数据类型,只要不改变它的引用地址(栈),它的值随便修改
      this.$emit('input',实参值) 
      
      
1:子组件标签上  :value="父组件属性"   @input="父组件属性=$event"
   子组件标签上  v-model="父组件属性"  
2:子组件内
   props:['value'],
   修改value
    this.$emit('input',修改后的值)
  不使用value和input
  model:{
      prop:'value',
      event:'input'
  }
.sync修饰符
   子组件标签  :属性名="父组件属性"   @update:属性名="父组件属性=$event"
   子组件标签  :属性名.sync="父组件属性"
   子组件内
     props:['属性名']
     触发:this.$emit('@update:属性名',实参值)
兄弟组件传值 
     1:Vue.prototype.$bus=new Vue()
     2: 监听 在mounted 中 this.$bus.$on('方法名',(参数值)=>{...})
     3:触发  在methods中 this.$bus.$emit('方法名',实参值)
     4:销毁 在beforeDestroy中 this.$bus.$off('方法名')
     监听与销毁写在一个组件中,触发写在一个组件中
     特点:bus的监听会累加,bus的监听不使用时要销毁,beforeDestroy销毁处理

12.mutation和action的使用区别

action 和 mutations 也很类似,主要的区别在于mutations 只能是同步操作,action 可以包含异步操作,而且可以通过 action 来提交 mutations

mutations 有一个固有参数 state,接收的是 Vuex 中的 state 对象

action 也有一个固有参数 context,但是 context 是 state 的父级,包含 state、getters

Vuex 的仓库是 store.js,将 axios 引入,并在 action 添加新的方法

分发调用action:

this.$store.dispatch('action中的函数名',发送到action中的数据)

在组件中提交 Mutation: this.$store.commit(“mutation函数名”,发送到mutation中的数据)

在action中提交mutation :

const store = new Vuex.Store({
  state: {
    count: 0
  },
  mutations: {
    increment (state) {
      state.count++
    }
  },
  actions: {
    increment (context) {    //官方给出的指定对象, 此处context可以理解为store对象
      context.commit('increment');
    }
  }
})
// 第一种写法简写形式
  const actions = {
    action的函数名({commit}) { 
      commit(“mutation函数名”, value);   //调用mutation中的函数
      //此处value可以是对象,可以是固定值等
    }
  }
  // 第二种形式
  const actions = {
    action中的函数名(context) {
      //context 官方给出的指定对象, 此处context可以理解为store对象
      context.commit(“mutation函数名”, value);     //调用mutation中的函数
    }
  }

13.vue2中v-model是一个语法糖,那具体是怎么实现的?

v-model 原理:

  从接触Vue我们就知道 v-model是实现数据双向绑定的 那他怎么实现绑定的原理的呢?

  其实v-model本质上就是语法糖 在使用 v-model 后既绑定了数据 又添加了一个@input事件监听 

 <input v-model='search' />

  等价于

 <input :bind='search' @input='search = $event.target.value'>

当在input元素中使用v-model实现双数据绑定,其实就是在输入的时候触发元素的input事件,通过这个语法糖,也能够实现父子组件数据的双向绑定

<input v-model="str" />

// 等同于 

<input :value="str" @input="str = $event.target.value" />

$event 指代当前触发的事件对象。

$event.target 指代当前触发的事件对象的dom

$event.target.value 就是当前dom的value值

在@input方法中,value => str? ? ? ? ? 在:value中:str => value

如此,形成了一个闭环,也就是所说的数据的双向绑定。

当我们在一个自定义组件上使用v-model并不能实现双向绑定,因为自定的组件并没有默认的value和input事件,在使用时,我们需要按照上面那样显式的去声明定义这些东西。这时,model选项就派上用场了,在定义组件的时候,指定prop的值和监听的事件。

<template>
  <div>
    <input type="text" :value="xxxx" @input="$emit('xxxx', $event.target.value)">
  </div>
</template>

<script>
export default {
    model:{
        prop:'xxxx',
        event:'xxxx' // 代表自定义的事件名称
    }

    props: {
        xxxx: String // 代表自定义的变量名称
     }
}
</script>

14.v-if和v-show的区别

v-show 和v-if都是true的时候显示,false的时候隐藏

但是:false的情况下

v-show是采用css样式的display:none 来控制显示与隐藏的

v-if是采用 DOM 元素的 创建与销毁 来 控制显示与隐藏的

如果需要频繁切换显示隐藏需要使用v-show

应用场景

自己做的项目中,有一个编辑的弹框的组件,在标签页点击修改弹框上的内容有所属学科与目录名称,但是从学科页面点击就只有目录名称,他们公用一个弹框组件,显示的内容不一样,用v-show 来解决的。


15.循环的时候,为什么一定要绑定key

:key是给v-for循环生成标签颁发唯一标识的,key的作用主要是为了高效的更新虚拟DOM 用于性能的优化

如果没有唯一key , 页面上删除一条标签, 由于并不知道删除的是那一条! 所以要把全部虚拟dom重新渲染

如果知道key为x标签被删除掉, 只需要把渲染的dom为x的标签去掉即可!

虚拟DOM? ?本质就是一个对象,保存DOM的关键信息

虚拟DOM的好处,提高DOM更新的性能,不频繁操作真实DOM

(在内存中找到变化的部分,再更新真实DOM? ——打补丁)


16.vue2 常用的指令有哪些

v-for 根据数组的个数, 循环数组元素的同时还生成所在的标签

v-show 显示内容

v-if 显示与隐藏

v-else 必须和v-if连用 不能单独使用 否则报错

v-bind 动态绑定 作用: 及时对页面的数据进行更改, 可以简写成:分号

v-on 给标签绑定函数,可以缩写为@,例如绑定一个点击函数 函数必须写在methods里面

v-text 解析文本

v-html 解析html标签

v-slot? ?简写 #


17.vue2和vue3的区别

vue3中没有$on, filter过滤器 .sync? ? ?生命周期? ? 选项api 与 组合api

1.为什么要有vue3

我们使用vue2常常会遇到一些体验不太好的地方,比如:

  1. 随着功能的增长,需求的增加,复杂组件的代码越来越难以维护,逻辑混乱,虽然vue2也有一些复用的方法,但是都存在一定的弊端,比如我们常常用的Mixin,特别容易发生命名冲突,暴露出来的变量意图不是很明显,重用到其他组件容易冲突。

  2. vue2对于typeScript的支持非常有限,没有考虑到ts的集成。

vue3的出现就是为了解决vue2的弊端,其composition API很好的解决了逻辑复用的问题,而且vue3源码就是用ts写的,对ts的支持非常好。我们在开发项目过程中可以使用ts的加持,使代码更加健壮。

2.vue3的优点

  1. vue3支持vue2的大多数特性,实现对vue2的兼容

  2. vue3对比vue2具有明显的性能提升

    • 打包大小减少41%

    • 初次渲染快55%,更新快133%

    • 内存使用减少54%

  3. vue3具有的composition API实现逻辑模块化和重用

  4. 增加了新特性,如Teleport组件,全局API的修改和优化等

3.响应式原理的不同

Vue2.x实现双向数据绑定原理,是通过es5的 Object.defineProperty,根据具体的key去读取和修改。其中的setter方法来实现数据劫持的,getter实现数据的修改。但是必须先知道想要拦截和修改的key是什么,所以vue2对于新增的属性无能为力,比如无法监听属性的添加和删除、数组索引和长度的变更,vue2的解决方法是使用Vue.set(object, propertyName, value) 等方法向嵌套对象添加响应式。

Vue3.x使用了ES2015的更快的原生proxy 替代 Object.defineProperty。Proxy可以理解成,在对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy可以直接监听对象而非属性,并返回一个新对象,具有更好的响应式支持

4.生命周期的不同

beforeCreate -> 请使用 setup()

created -> 请使用 setup()

beforeMount -> onBeforeMount

mounted -> onMounted

beforeUpdate -> onBeforeUpdate

updated -> onUpdated

beforeDestroy -> onBeforeUnmount

destroyed -> onUnmounted

errorCaptured -> onErrorCaptured

如果要想在页面中使用生命周期函数,以往vue2的操作是直接在页面中写入生命周期,而vue3是需要去引用的,这就是为什么3能够将代码压缩到更低的原因

5.默认项目目录结构的不同

vue3移除了配置文件目录,config 和 build 文件夹,移除了 static 文件夹,新增 public 文件夹,并且 index.html 移动到 public 中,在 src 文件夹中新增了 views 文件夹,用于分类视图组件和公共组件


18.vue2中响应式的原理

vue.js 是 采 用 数 据 劫 持 结 合 发 布 者 - 订 阅 者 模 式 的 方 式 , 通 过Object.defineProperty()来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

MVVM 作为数据绑定的入口,整合 Observer、Compile 和 Watcher 三者,通过 Observer 来监听自 己的 model 数据变化,通过Compile 来解析编译模板指令,最终利用 Watcher 搭起 Observer 和Compile 之间的 通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input)数据 model 变更的双向绑定效果


JS

1.js的数据类型 8种

1、【数据类型分类】

-js中数据类型分为两大类:基本数据类型和引用数据类型

-基本数据类型分为:数值类型number、字符串string、布尔类型boolean、null、undefined

-引用数据类型分为:对象类型object、函数function,

对象类型又分为:Object对象、Array数组、RegExp正则、Date时间对象、Math数学对象

ES6 中新增了一种 Symbol 。这种类型的对象永不相等,即始创建的时候传入相同的值,可以解决属性名冲突的问题,做为标记

2、【基本数据类型和引用数据类型的区别】

- 基本数据类型存储在栈内存中,引用数据类型存储在堆内存中

- 数据存储时,基本数据类型在变量中存的是值,引用数据类型在变量中存储的是空间地址

- 基本数据操作的是值,引用数据类型操作的是空间地址


2.如何判断数据类型 5种

1.typeof(除了null 其他的都可以判断,判断原始数据)

  • 可以判断数据类型,它返回表示数据类型的字符串(返回结果只能包括number,boolean,string,function,object,undefined);

  • 可以使用typeof判断变量是否存在(如if(typeof a!="undefined"){...});

  • Typeof 运算符的问题是无论引用的对象是什么类型 它都返回object

typeof {} // object
typeof  [1,2] // object
typeof /\s/ //object

2.instanceof (通过原型链可以正确判断对象数据类型)

instanceof 可以判断一个对象是否是某个构造函数的实例

原理 因为A instanceof B 可以判断A是不是B的实例,返回一个布尔值,由构造类型判断出数据类型

console.log(arr instanceof Array ); // true
console.log(date instanceof Date ); // true
console.log(fn instanceof Function ); // true
//注意: instanceof 后面一定要是对象类型,大小写不能写错,该方法试用一些条件选择或分支

3.通过Object下的toString.call()方法来判断 (最准确)

Object.prototype.toString.call();
console.log(toString.call(123)); //[object Number]
console.log(toString.call('123')); //[object String]
console.log(toString.call(undefined)); //[object Undefined]
console.log(toString.call(true)); //[object Boolean]
console.log(toString.call({})); //[object Object]
console.log(toString.call([])); //[object Array]
console.log(toString.call(function(){})); //[object Function]

4.根据对象的contructor判断

console.log('数据类型判断' -  constructor);
console.log(arr.constructor === Array); //true
console.log(date.constructor === Date); //true
console.log(fn.constructor === Function); //true

5.jq中判断数据类型的方法

jQuery提供了一系列工具方法,用来判断数据类型,以弥补JavaScript原生的typeof运算符的不足。以下方法对参数进行判断,返回一个布尔值。
jQuery.isArray();是否为数组
jQuery.isEmptyObject();是否为空对象 (不含可枚举属性)。
jQuery.isFunction():是否为函数
jQuery.isNumberic():是否为数字
jQuery.isPlainObject():是否为使用“{}”或“new Object”生成对象,而不是浏览器原生提供的对象。
jQuery.isWindow(): 是否为window对象;
jQuery.isXMLDoc(): 判断一个DOM节点是否处于XML文档中

3.原型链

每个对象都会在其内部初始化一个属性,就是 prototype(原型)对象,当我们访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,这个对象内部不存在这个属性,那么他就会去它的proto隐式原型即它的构造函数的prototype里查找这个属性,如果还没有找到就会再在构造函数的prototype的proto中查找,直到查到Object.prototype.proto为nul,,这样一层一层向上查找就会形成一个链式结构,我们称为原型链 应用:原型链是实现继承的主要方法


4.闭包

闭包(closure)指有权访问另一个函数作用域中变量的函数。简单理解就是 ,一个作用域可以访问另外一个函数内部的局部变量。(闭包是一个受保护的变量空间)

在一个函数里面嵌套函数,里面的函数需要用到外面函数定义的变量,return出来为了延迟局部变量的生命周期

作用:延伸变量的作用范围,闭包函数 中的局部变量不会等着闭包函数执行完就销毁, 因为还有别的函数要调用它,只有等着所有的函都调用完了,它才会销毁,...

?应用场景 setTimeout 回调, 函数防抖 ..........很多


5.如何判断this的指向

普通函数, 定时器函数, 立即执行函数中:this指向全局对象window

以函数形式调用时,this 永远都是window

以方法的形式调用时,this是调用方法的对象

事件处理函数中:this指向事件触发对象

以构造函数的形式调用时,this 是新创建的那个对象,构造函数的实例

使用call和apply调用时,this 是指定的那个对象

箭头函数:箭头函数的this 看外层是否有函数 如果有,外层函数的this 就是内部箭头函数的this 如果没有,就是window

特殊情况:通常意义上 this 指针指向为最后调用它的对象。这里需要注意的一点就是 如果返回值是一个对象,那么this 指向的就是那个返回的对象,如果返回值不是一个对象那么 this 还是指向函数的实例

this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,一般情况下this的最终指向的是那个调用它的对象。谁调用这个 this 就指向谁


6.call和apply 和bind的使用

共同点:

1、都是用来改变函数的this对象的指向的。

2、第一个参数都是 this要指向的对象。

3、都可以利用后续参数传参。

不同点:

call方法调用一个函数, 其具有一个指定的this 值和分别地提供的参数(参数的列表)。 注意:该方法的作用和 apply() 方法类似,只有一个区别,就是 call()方法接受的是若干个 参数的列表,而apply()方法接受的是一个包含多个参数的数组 方法调用一个具有给定this 值的函数,以及作为一个数组(或类似数组对象)提供的参 数。 注意:call()方法的作用和 apply() 方法类似,区别就是call()方法接受的是参数列表,而 apply()方法接受的是一个参数数组 bind()方法创建一个新的函数,当这个新的函数被调用时,其this 值为提供的值,其参 数列表前几项,置为创建时指定的参数序列

call: 方法.call(对象,参数1,参数2,参数3…) call参数是一个一个挨着写的

apply:方法.apply(对象,[参数1,参数2,参数…]) apply是2个参数,第二个参数是一个大数组?

bind()方法主要就是将函数绑定到某个对象,bind()会创建一个函数,函数体内的this对象的值会被绑定到传入bind()第一个参数的值,例如,f.bind(obj),实际上可以理解为obj.f(),这时,f函数体内的this自然指向的是obj


7.数组常用的api

1.向数组添加元素的方法

Array.push() 在数组的末尾处添加;会改变原有数组,返回值是添加数据后数组的新长度

Array.unshift() 在数组的开头处添加,会改变原有数组返回值是添加数组后数组的新长度

splice(index,0,value1,value2,...) 向数组的指定index处插入;返回的是被添加的元素;会改变原有数组

2.向数组删除元素的方法

pop() 从尾部删除一个元素;返回被删除的元素;会改变原有数组

shift() 从头部删除一个元素;返回被删除的元素;会改变原有数组

splice(index,howmany) 在index处删除howmany个元素,返回的是被删除掉的元素的集合;会改变原有数组

splice(从哪个位置开始删除, 删除几个元素)

3.数组排序

reverse() 数组的翻转 颠倒数组中元素的排序 无参数 会改变原来的数组 返回新的数组 sort() 数组的排序 冒泡排序

var arr = [23,45,2,5,56]
arr.sort(function(a, b) {
 ?  return a -b; 升序的顺序排序
 ?  return b -a; 降序的顺序排序
})
console.log(arr)
按照指定规则排序,改变原有数组
数组的sort()方法里面的参数就是一个回调函数,有俩个值,返回值如果是第一个值减去第二个值,那么就是从小到大排序,如果是第二个数减去第一个值就是从大到小排序。

4.数组链接

concat() 数组连接,返回的是新数组

join() 将数组的每个元素以指定分隔符(默认为‘,’)连接成字符, 返回该连接完成后的字符串

5.数组截取

slice(start,end) 从start起始索引处,截取到end结束索引处,返回截取到的元素集合

6.数组转换

toString() 转换为字符串,和不传参数的join()一致

7.数组查找

indexOf(val[,fromIndex=0]) 数组的indexOf方法用来查找数组中某个val值第一次出现的索引,找不到就返回-1

lastIndexOf(val[,fromIndex=arr.length=-1]) 数组的lastIndexOf()方法用来查找数组中的某个val值第一次出现的索引,找不到返回 -1,lastIndexOf是从数组的最后往前找

8.数组累加

reduce()方法接收一个函数作为累加器,reduce为数组中的每一个元素依次执行回调函数,接收四个参数:初始值(上一次回调返回的值),当前元素,当前索引,原数组。

语法:reduce(callback, [initialValue]

arr.reduce(function(previousvalue,currentValue,index,array){
...
}, initialValue);

其中,
previousvalue表示上一次调用回调时的返回值,或者初始值 init;
currentValue表示当前正在处理的数组元素;
index 表示当前正在处理的数组元素的索引,若提供 init 值,则索引为0,否则索引为1;
array表示原数组;
initialValue表示初始值。

reduce()被一个非空数组调用(如果被非空数组调用返回undefined),接收两个参数,一个callback和一个设置的累加初始值,需要注意的是如果给reduce()传入了初始值,则在该值的基础是做累加操作,如果初始值不存在,则total为数组的第一项,currentValue为下一项,在第一项的基础上累加,相当于设置初始值为0,然后逐步累加。

9.?includes():搜索指定元素是否在数组中,若在,则返回true,否则返回false。第二个参数指定开始搜索的位置。

10.对数组做迭代遍历操作,并且返回相应的值,迭代的入参是回调函数

map():操作数组每个元素,最终返回一个新的数组

forEach():操作数组的每个参数,没有返回值

filter():操作数组的每个元素,每次操作的结果为true的元素插入最终返回的数组(过滤)

some():判断当前数组中是否有符合条件的元素,没有返回false,,否则返回true

every():判断当前数组中是否含有所有元素都符合条件,都符合则返回true,否则返回false


8.什么是回调地狱,如何解决

层层嵌套的回调函数

由于回调函数是异步的,每一层的回调函数都需要依赖上一层的回调执行完,所以形成了 层层嵌套的关系最终形成了回调地狱。例如:定时器中再写定时器再写定时器,这种就形成了 通常所说的回调地狱

解决:

1、避免函数的嵌套 2、模块化开发 3、使用 Promise 解决

如果上一个 .then() 方法中返回了一个新的 Promise 实例对象,则可以通过下一个 .then() 继续进行处理。通 过 .then() 方法的链式调用,就解决了回调地狱的问题。


9.promise的使用

promise 是用来解决回调地狱的问题的

Promise的构造函数接收一个参数,是函数,并且传入两个参数:resolve,reject,分别表示异步操作执行成功后的回调函数和异步操作执行失败后的回调函数

三个状态: 等待, 执行resolve, 拒绝 reject? ? ? ? ?默认情况下是等待状态pending,

1、自己身上有 all、reject、resolve 这几个方法

2、原型上有 then、catch 等方法

3、一旦建立,就无法取消,这是它的缺点


10.new的背后做哪些事情

创建一个对象。让this指向这个对象。设置原型链 空对象指向构造函数的原型对象。返回这个对象

1、创建一个空对象: 并且 this变量引入该对象,同时还继承了函数的原型

2、设置原型链 空对象指向构造函数的原型对象

3、执行函数体 修改构造函数this 指针指向空对象,并执行函数体

4、判断返回值 返回对象就用该对象,没有的话就创建一个对象


11.防抖和节流

  • 防抖:如果事件被频繁触发,防抖能保证只有最有一次触发生效!前面 N 多次的触发都会被忽略!

  • 节流:如果事件被频繁触发,节流能够减少事件触发的频率,因此,节流是有选择性地执行一部分事件!

防抖(debounce):

input 输入框 一直打字,直到停止打字后,才会发请求调用防抖的函数

search搜索联想,用户在不断输入值时,用防抖来节约请求资源。

window 触发resize 的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖 来让其只触发一次

实现输入框的防抖

  • 防抖动的 timer

  • 定义防抖的函数,函数里面定义一个延时器,在演示器里面调用发起JSONP的请求

  • 在触发 keyup 事件时,立即清空 timer,然后调用防抖的函数

节流(throttle)

鼠标不断点击触发,mousedown(单位时间内只触发一次) 监听滚动事件,比如是否滑到底部自动加载更多,用throttle 来判断

使用节流优化鼠标跟随效果

  • 预定义一个 timer 节流阀

  • 当设置了鼠标跟随效果后,清空 timer 节流阀,方便下次开启延时器

  • 执行事件的时候判断节流阀是否为空,如果不为空,则证明距离上次执行间隔不足16毫秒

function debounce(fn, wait) {
 var timeout = null;
 return function() {
 if(timeout !== null)
 clearTimeout(timeout);
 timeout = setTimeout(fn, wait);
 }
 }
 // 处理函数 function handle() {
 console.log(Math.random());
 }
 // 滚动事件 window.addEventListener('scroll', debounce(handle, 1000));

12.高阶函数

将函数作为参数, 返回函数

高阶函数是对其他函数进行操作的函数,操作可以是将它们作为参数或者是返回它们。 简单来说,高阶函数是一个接收函数作为参数或将函数作为输出返回的函数。(回调函数)(闭包)

例如,Array.prototype.map,Array.prototype.filter 和 Array.prototype.reduce 是语言中内置的一些高阶函数。


13.函数柯里化

是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术

// 普通的add函数
function add(x, y) {
    return x + y
}

// Currying后
function curryingAdd(x) {
    return function (y) {
        return x + y
    }
}

add(1, 2)           // 3
curryingAdd(1)(2)   // 3

?实际上就是把add函数的x,y两个参数变成了先用一个函数接收x然后返回一个函数去处理y参数。现在思路应该就比较清晰了,就是只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数

const _ = require('lodash')
/* function sum(a, b, c, d) {
  return a + b + c + d
} */
// sum(1, 2, 3, 4)
// 需求:sum(1)(2)(3)(4) 也能拿到 10,怎么做?

/* function sum(a) {
  return (b) => (c) => (d) => a + b + c + d
}
console.log(sum(1)(2)(3)(4)) */

function sum(a, b, c, d) {
  return a + b + c + d
}
// curry: 能把普通函数变成柯里化的形式进行调用
// const sumTemp = _.curry(sum)

function curry(fn) {
  // 函数参数的长度
  const len = fn.length // 4
  return function temp(...args) {
    if (args.length >= len) {
      return fn(...args)
    } else {
      return function (...args2) {
        return temp(...args, ...args2)
      }
    }
  }
}

const sumTemp = curry(sum)

// 真正的需求是这样的!
console.log(sumTemp(1, 2, 3, 4))
console.log(sumTemp(1)(2, 3, 4))
console.log(sumTemp(1)(2)(3)(4))
console.log(sumTemp(1, 2)(3, 4))

// 柯里化很重要的一个作用:参数复用

function acdution(school, classs, xingming) {
  console.log(`${school}的${classs}的${xingming}`)
}
/* acdution ('教育', 67, '王沙')
acdution('教育', 67, '杨康')
acdution('教育', 67, '昊天') */

const itacdution = curry(acdution)
const fn = itacdution('教育', 67)
fn('王沙')
fn('杨康')
fn('昊天')

14.for in和for of的区别

1、推荐在循环对象属性的时候使用for...in,在遍历数组的时候的时候使用 for...of

2、for...in循环出的是 key,for...of循环出的是value

3、注意,for...of是ES6新引入的特性。修复了ES5 引入的for...in的不足

4、for...of不能循环普通的对象,需要通过和Object.keys()搭配使用


?15.递归及应用场景

一个函数可以调用它本身

树形结构数据的转换**

深拷贝

一般树状结构的都可以使用递归查询,比如 查询地区,树状的菜单等等,递归比普通的算法耗内存,谨慎使用。还有一种叫作“尾递归”就是把上一个方法的返回值当作参数传给下一个方法,不用像递归再向上返回


16.eventloop事件循环

什么是Event Loop JavaScript的事件分两种,宏任务(macro-task)和微任务(micro-task)

宏任务:包括整体代码script,setTimeout,setInterval

微任务:Promise.then(非new Promise),process.nextTick(node 中) 事件的执行顺序——先执行宏任务,然后执行微任务,任务有同步的任务和异步的任务, 同步的进入主线程,异步的进入 EventTable并注册函数,异步事件完成后,会将回调函数放在 队列中,如果还有异步的宏任务,那么就会进行循环执行上述的操作。

事件循环先执行宏任务,其中同步任务立即执行,异步任务加载到对应的 EventQueue 中, 微任务也加载到对应的微任务的EventQueue 中,所有的同步微任务执行完之后,如果发现微 任务的EventQueue 中有未执行完的任务,先执行他们这样算是完成了一轮事件循环。接下来 查看宏任务的队列中是否有异步代码,有的话执行第二轮的事件循环,以此类推。


17.深拷贝与浅拷贝

浅拷贝

浅拷贝只复制指向某个对象的指针而不复制对象本身,新旧对象还是共享同一块内存。

Object.assign()

ES6的三个点 展开符? ...?

深拷贝

但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。

JSON.parse(JSON.stringify(obj))


网络

1.https和http的区别

1、https协议需要到CA申请证书,一般免费证书较少,因而需要一定费用。

2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl/tls加密传输协议

3、http和https使用的是完全不同的连接方式,用的端口不一样,前者是80,后者是443

4、http的连接很简单,是无状态的;HTTPS协议是由SSL/TLS+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全


2.常见http的状态码

- 状态代码由三位数字组成,第一个数字定义了响应的类别,且有五种可能取值。
? 1xx:指示信息 —— 表示请求已接收,继续处理。
? 2xx:成功 —— 表示请求已被成功接收、理解、接受。
? 3xx:重定向 —— 要完成请求必须进行更进一步的操作。
? 4xx:客户端错误 —— 请求有语法错误或请求无法实现。
? 5xx:服务器端错误 —— 服务器未能实现合法的请求。

? 200 OK:客户端请求成功。
? 400 Bad Request:客户端请求有语法错误,不能被服务器所理解。
? 401 Unauthorized:请求未经授权,这个状态代码必须和 WWW-Authenticate 报头域一起使用。
? 403 Forbidden:服务器收到请求,但是拒绝提供服务。
? 404 Not Found:请求资源不存在,举个例子:输入了错误的URL。
? 500 Internal Server Error:服务器发生不可预期的错误。
? 503 Server Unavailable:服务器当前不能处理客户端的请求,一段时间后可能恢复正常。?


3.如何减少重绘和回流

什么是重绘Repaint

重排 (回流 reflow)

重绘:当元素的一部分属性发生改变,如外观、背景、颜色等不会引起布局变化,只需要浏览器 根据元素的新属性重新绘制,使元素呈现新的外观叫做重绘。

重排(回流):当render 树中的一部分或者全部因为大小边距等问题发生改变而需要DOM 树 新计算的过程

重绘不一定需要重排(比如颜色的改变),重排必然导致重绘(比如改变网页位置

方法

需要要对元素进行复杂的操作时,可以先隐藏(display:"none"),操作完成后再显示

需要创建多个DOM节点时,使用DocumentFragment 创建完后一次性的加入document 缓存Layout属性值,如:var left = elem.offsetLeft; 这样,多次使用 left 只产生一次回流

尽量避免用table 布局(table元素一旦触发回流就会导致table 里所有的其它元素回流)

避免使用css 表达式(expression),因为每次调用都会重新计算值(包括加载页面)

尽量使用 css 属性简写,如:用 border 代替 border-width, border-style, border-color


4.描述输入url地址到网页展示的过程

  • 1、输入网址

  • 2、DNS解析

  • 3、建立tcp连接

  • 4、客户端发送HTPP请求

  • 5、服务器处理请求

  • 6、服务器响应请求

  • 7、浏览器展示HTML

  • 8、浏览器发送请求获取其他在HTML中的资源。


5.跨域问题及解决方案

1.通过 jsonp 跨域

2.跨域浏览器

3.开发环境中跨域的解决proxy:代理

原理就是:服务器与服务器之间没有跨域的问题,通过服务器进行中转, proxy进行代理

在vue.config.js文件中配置proxy -- p小写, 配置完要重启脚手架

 devServer:{
   proxy: {
   // 'abc' 哪些接口需要代理
      '/abc': {
        target: 'http://localhost:3000/api',
        // target: '真实接口基地址'
        // 真实调用的接口基地址它会target+/abc=>http://localhost:3000/api/abc
        pathRewrite: {   // 路径重写
        // 自己配的基地址
          '^/abc': ''
        }
      }
    }
}

4.CORS 核心思想 ,一般是后端用的

5.通过反向代理? 上线时候用的


6.get请求和post请求的区别

  1. GET提交的数据会放在URL之后,以?分割URL和传输数据,参数之间以&相连,如EditPosts.aspx?name=test1&id=123456. POST方法是把提交的数据放在HTTP包的Body中.

  2. GET提交的数据大小有限制(因为浏览器对URL的长度有限制),而POST方法提交的数据没有限制.

  3. GET方式需要使用Request.QueryString来取得变量的值,而POST方式通过Request.Form来获取变量的值。

  4. GET方式提交数据,会带来安全问题,比如一个登录页面,通过GET方式提交数据时,用户名和密码将出现在URL上,如果页面可以被缓存或者其他人可以访问这台机器,就可以从历史记录获得该用户的账号和密码


7.http的协议的三个内容

通用头域、请求消息、响应消息和主体信息

包含请求方法、URI、HTTP 版本信息


8.请求头中的contentType有什么用处

enctype 属性规定在发送到服务器之前应该如何对表单数据进行编码。 默认地,表单数据会编码为 "application/x-www-form-urlencoded"。就是说,在发送到服务器之前,所有字符都会进行编码(空格转换为 "+" 加号,特殊符号转换为 ASCII HEX 值)。

用来设置程序间传递信息进行编码 属性规定发送到服务器端之前,应该如何对表单数据进行编码,所有的字符都会进行编码,空格转为+ 特殊的符号转为ASCLL值


?dom

1.事件冒泡和事件捕获

事件冒泡:从内到外? ?text -- div-- body-- document -- window

事件捕获:从外到内? window-- document -- body -- div -- text


2.?事件委托

给父元素注册事件,利用事件冒泡,当子元素的事件触发,会冒泡到父元素,然后去控制相应的子元素

优点:

1、减少事件注册,节省内存。

2、在table 上代理所有td 的click事件。

3、在ul上代理所有 li的click 事件。

4、简化了dom节点更新时,相应事件的更新。

5、不用在新添加的li上绑定click事件。

6、当删除某个li时,不用移解绑上面的click事件。

缺点:

1、事件委托基于冒泡,对于不冒泡的事件不支持

2、层级过多,冒泡过程中,可能会被某层阻止掉。

3、理论上委托会导致浏览器频繁调用处理函数,虽然很可能不需要处理。所以建议就近委托, 比如在table上代理td,而不是在 document 上代理td。

4、把所有事件都用代理就可能会出现事件误判。比如,在 document 中代理了所有button 的 click事件,另外的人在引用改js 时,可能不知道,造成单击button 触发了两个click事件


?3.如何添加和删除事件

addEventListener()和removeEventListener()

addEventListener()与removeEventListener()用于处理指定和删除事件处理程序操作。

它们都接受3个参数:如 addEventListener("事件名" , "事件处理函数" , "布尔值"); (注:事件名不含"on",如“click”)

?

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-01-03 15:59:25  更:2022-01-03 16:02:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 12:58:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码