前端面试题

前端面试题

1.PureComponent 是什么以及如何利用它?

PureComponent 是 React.Component 的子类,它实现了带有浅层 prop 和状态比较的 shouldComponentUpdate 方法

2.react的Props 和 State 有什么区别?

 props 和 state 都是 React 组件中使用的普通 JavaScript 对象。props 从父组件传递到子组件,用于组件内不会更改的数据。
 另一方面,状态在组件本身内进行管理,并且可以使用 setState 方法进行更新。props 是不可变的,而 state 可以更新。

3.React 组件中有哪些生命周期方法?

React 组件中的一些常见生命周期方法包括 componentDidMount、componentWillMount、componentWillUpdate、componentDidUpdate、shouldComponentUpdate 和 componentWillReceiveProps。

4.Array.forEach() 循环和 Array.map() 方法之间的主要区别以及为什么您会选择其中一种方法?

主要区别在于 Array.forEach() 迭代数组的每个元素并对每个元素执行操作,但它不返回新数组。另一方面,Array.map() 通过将函数应用于原始数组的每个元素来创建新数组。当您想要对每个元素执行操作而不返回新数组时,您可以选择 Array.forEach() ;当您需要将数组转换为新数组时,您可以选择 Array.map() 。

5.vue2 和 vue3 的区别和变化?

  1.vue2中响应式原理是object.defineProperty;vue3中响应式原理是proxy
  2.vue2中不支持多根节点;vue3中支持多个根节点

    指令与插槽:1.vue2中使用slot可以直接使用slot,而vue3中必须使用v-slot的形式  
                          2.v-for与v-if在vue2中v-for指令的优先级较高,不建议一起使用;在vue3中,只是                               把当前的v-if当成一个判断语句,不会相互冲突
                          3.vue3中移除了v-on.native修饰符
                          4.vue3中移除了过滤器

    生命周期: 1.vue3中setUp函数替代了vue2中的beforeCreate和created,vue3中生命周期函数都     带有on前缀
                     2.vue2中卸载阶段是beforeDestory,destoryed;vue3中卸载阶段是                  onBeforeUnmount,     onUnmounted
                     3.碎片化:vue2不支持碎片化,vue3是支持碎片化的
                     4.vue2中的数据都是在data(){return{}}中存储的,vue3的数据课方法都定义在setup语法糖中,并统一进行return

 父子组件传值的方法总结:使用技巧:1.子组件内, props定义变量, 在子组件使用变量  2.父组件内, 使用子组件, 属性方式给props变量传值
  注意事项:1.父组件的数据发生了改变,子组件会自动跟着变 2.子组件不能直接修改父组件传递                         过来的props,会报错,props是只读的
          3.子组件修改,不通知父级,会造成数据不一致   4.父组件传给子组件的是一个对象,子组                  件修改对象的属性,是不会报错的,对象是引用类型, 互相更新

 prop:无论是子组件向父组件传值还是父组件向子组件传值,他们都有一个共同点就是有中间介质,子向父的介质是自定义事件,父向子的介质是props中的属性。抓准这两点    对于父子通信就好理解了。

   Vue-2 的主要生命周期钩子:
   beforeCreate:实例初始化之后,但在数据观测和事件配置之前被调用。在这个阶段,data 和 methods 等选项尚未初始化,因此无法访问它们。
   created:实例创建完成后调用,数据已经初始化完成,可以访问 data 和 methods 中的数据和方法,但无法访问到 $el 属性。
   beforeMount:在挂载开始之前被调用,此时模板编译已经完成但还未挂载到页面中。
   mounted:实例被挂载到页面后调用,此时可以访问到 $el 属性,也可以操作 DOM 和通过 AJAX 获取数据。
   beforeUpdate:数据更新时调用,但在 DOM 重新渲染之前。
   updated:数据更新完成时调用,此时 DOM 已经重新渲染。
   beforeDestroy:实例销毁之前调用,在这个阶段实例仍然完全可用,可以进行一些清理工作。
   destroyed:实例销毁之后调用,此时无法再访问实例中的数据和方法。
      
   Vue-3 的主要生命周期钩子:
   onBeforeMount:在挂载之前被调用,渲染函数首次被调用。
   onMounted:组件挂载时调用。
   onBeforeUpdate:数据更新时调用,发生在虚拟DOM打补丁之前。
   onUpdated:因数据更改导致的虚拟DOM重新渲染和打补丁时调用。
   onBeforeUnmount:在卸载组件实例之前调用,此阶段的实例依旧是正常的。

6.promise和async/await的区别和使用区别?

1.函数前面多了一个 async 关键字。await 关键字只能用在 async定义的函数内。async函数会隐式地返回一个promise,该 promise的reosolve 值就是函数return 的值
2.第1点暗示我们不能在外层代码中使用 await,因为不在 async 函数内。

使用方面:1.async和await是配对使用的,await存在于async的内部。否则会报错
        2.await表示在这里等待一个 promise 返回,再接下来执行。
        3.await后面跟着的应该是一个 promise 对象,(也可以不是,如果不是接下来也没什么意义了)

7.vue中v-if与v-show的区别以及使用场景?

区别:手段:v-if 是通过控制Dom节点的存在与否来控制元素的显隐;v-show 是通过设置 DOM 元素的display样式,block为显示,none为隐藏
     编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show 只是简单的基于css 切换
     编译条件:v-if也是惰性的,如果初始条件为假,则什么也不做;只有在条件第一次变为真时才开始局部编译;v-show 是惰性的,在任何条件下都被编译,然后被缓存,而      且 DOM 元素保留
     性能消耗:v-if有更高的切换消耗;v-show有更高的初始染消耗
     
    总结:v-if 判断是否加载,可以减轻服务器的压力,在需要时加载,但有更高的切换开销;v-show 调整DOM 元素的 CSS 的 dispaly 属性,可以使客户端操作更加流       畅,但有更高的初始渲染开销。如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。

8.vue常用的有哪些命令?

1.v-model:用于表单输入
2.v-on:事件绑定
3.v-bind:动态绑定一个值和传入变量
4.v-once:事件只能使用一次,无论点击多少次,执行一次之后都不会执行了
5.v-html:会将span的内容替换成rawfhtml的属性值,直接作为HTML代码解析
6.v-for:HTML标签结合使用,用于数据的遍历摆放
7.v-if:用来进行条件判断的,直接操作DOM
8.v-else:用来进行条件判断的,是与v-if指令连用,意义为条件不成立时执行
9.v-show:根据真假切换元素的显示状态

9.react父组件props变化的时间子组件怎么监听?

当props发生变化时执行,初始化render时不执行,在这个回调函数里面,你可以根据属性的变化,通过调用
this.setState()来更新你的组件状态,旧的属性还是可以通过this.props来获取,这里调用更新状态是安全
的,并不会触发额外的render调用

代码:props发生变化时触发:
componentWillReceiveProps(props){
console.log(props)
this.setState({show:props.checked})
}

10.防抖函数

  • 触发高频时间后n秒内函数只会执行一次,如果n秒内高频率时间在次触发,则重新计算时间

  • 实现方式:每次触发事件时设置一个延时调用方法,并且取消之前的延时调用方法

  • 缺点:如果事件在规定的时间间隔内被不断的触发,则调用方法会不断的延迟

//防抖函数debounce代码:
function debounce(fn){
    let timeout = null    //创建一个标记用来存放定时器的返回值
    return function (){
        //每当用户输入的时候把前一个 setTimeout clear掉
        clearTimeout(timeout);
        //然后又创建一个新的setTimeout,这样就能保证interval
        //间隔时间内如果持续触发,就不会执行fn函数
        timeout = setTimeout(() => {
            fn.apply(this,arguments)
            //fn.apply(this,arguments)是给传来的fn赋上该函数的属性,使其可以指向,
            //可以直接调用return的函数
            //arguments是传来的fn的参数
        },500)
    }
}
//需要处理的函数
function handle(){
    console.log(Math.random())
}
//滚动事件
window.addEventListener('scroll',debounce(handle));

11.节流函数

  • 高频事件触发,但在n秒内只会执行一次,所以节流会稀释函数的执行频率

  • 实现方式:每次触发事件时,如果当前有等待执行的函数,则直接return

function throttle(fn){
    //通过闭包保存一个标记
    let canRun = true	
    return function(){
        //在函数开头判断标记是否为true,不为true则return
        if(!canRun)	return
        /*将标记设置为false,如果上次触发的函数还没完成时,
        再次调用时由于canRun为false,直接return*/
        canRun = false
        setTimeout(() => {
            //最后在setTimeout执行完毕后再把标记设置为true(关键)表示可以执行下一次循环了。
            //当定时器没有执行的时候标记永远是false,在开头被return掉
        	fn.apply(this,arguments);
            caRun = true
        },500)
    }
}

function sayHi(e){
    console.log(e.target.innerWidth, e.target.innerHeight);
}
window.addEventListenter('resize', throttle(sayHi))
  • 防抖函数和节流函数的总结:

    • 防抖函数:将多次操作合并为一次操作进行,原理时维护一个计时器,规定在delay时间后触发函数,但是在delay时间内再次触犯的话,就会取消之前的计时器而重新设置。这样一来,只有最后一次操作能被触发

    • 节流函数:使得一定时间内只触发一次函数。原理时通过判断是否有延迟调用函数未执行

    • 区别:节流函数不管事件触犯有多频繁,都会保证在规定的时间内一定会执行一次真正的事件处理函数,而函数防抖只是在最后一次事件后才触犯一次函数。比如在页面的无限加载场景下,我们需要用户在滚动页面时,每隔一段时间发一次Ajax,而不是在用户停下滚动页面操作时才去请求数据。这样的场景就适合节流技术来实现。

12.flex 布局常用属性?

flex 是 Flexible Box 的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性。可以随着页面大小的改变自适应页面布局。
(1)flex-direction:指定flex主轴的方向,默认为row水平方向。column为垂直方向。
(2)justify-content:主轴方向上的对齐方式,默认为flex-start,起始位置对齐
   flex-end:结束位置对齐。center:行中间对齐。space-between:两端对齐,中间间距相等
(3)align-items:侧轴上的对齐方式,就是垂直方向。默认为stretch,高度占满整个容器。center:垂直居中。
(4)flex-wrap:是否换行,默认nowrap,不换行,可能会溢出。wrap:换行,溢出的Flex子项会自动放到下一行。
(5)align-content:多行的对齐方式。默认stretch占满
(6)align-self:单独指定某flex子项的对齐方式
(7)flex:复合属性,flex:flex-grow(扩展比率),flex-shrink(比率),flex-basis(伸缩基准值);常用flex:1,就元素平均布局

13.Cookie与localStorage和sessionStorage有什么异同?

1.它们都是在浏览器端用于存储数据的方式,但它们之间存在一些区别。
2.存储时间有效期:Cookie的有效期是可以设置的,默认情况下是关闭浏览器后失效,但也可以设置一个过期时间,在过期时间之前有效。
3.sessionStorage的有效期仅保持在当前页面,关闭当前会话页或者浏览器后就会失效。
4.localStorage的有效期是在不进行手动删除的情况下一直有效,除非主动删除或者清空缓存。
5.存储大小:Cookie的存储大小通常不能超过4KB,因此只适合保存很小的数据,如会话标识。
6.localStorage和sessionStorage的存储容量相对较大,通常在5MB到10MB之间,具体限制可能因浏览器而异。
7.作用域:sessionStorage不能在不同的浏览器中共享,即使是同一个页面。
8.localStorage在所有同源窗口中都是共享的。Cookie也是在所有同源窗口中共享的,默认情况下属于当前页面。
9.存储方式:Cookie的数据存储在浏览器的HTTP头中,每次请求都会携带,因此可能会影响性能。sessionStorage和localStorage都是存储在浏览器的本地缓存中,不会随HTTP请求一起发送。

总结:Cookie、localStorage和sessionStorage在存储时间有效期、存储大小、作用域和存储方式等方面有所不同。选择哪种存储方式取决于具体的需求和场景

14.aixos是什么?怎么使用他,怎么用来解决跨域问题?

Axios是一个基于Promise的HTTP客户端,用于浏览器和Node.js。它可以在浏览器中发送异步请求并处理响应数据。
使用Axios可以通过以下步骤来发送HTTP请求:
1.首先,需要在项目中引入Axios库。可以通过npm安装Axios,然后在代码中使用import axios from 'axios'或者const axios = require('axios')来引入。
2.使用Axios发送请求时,可以使用axios.get(url)、axios.post(url, data)等方法来发送不同类型的请求。其中,url是请求的地址,data是要发送的数据(可选)。
3.发送请求后,Axios会返回一个Promise对象,可以使用.then()和.catch()方法来处理请求的响应结果或错误。

解决跨域问题是Axios的一个常见应用场景。跨域问题指的是在浏览器中,当前页面的域名与请求的目标域名不一致时,浏览器会阻止跨域请求。为了解决这个问题,可以在服务器端设置响应头部信息,允许跨域请求。
在Axios中解决跨域问题可以通过以下方式:
1.在服务器端设置响应头部信息,允许跨域请求。可以在服务器端的响应中添加Access-Control-Allow-Origin头部字段,并设置为允许跨域的域名或通配符*。
2.在Axios请求中设置withCredentials为true,表示允许携带跨域请求的凭证信息(如Cookie)。
3.如果服务器端要求使用特定的请求方法(如PUT、DELETE等),可以在Axios请求中设置headers字段,指定请求方法。

/* 解决跨域代码 */

import axios from 'axios';
/* 创建一个axios实例 */
const instance = axios.create({
  baseURL: 'http://api.example.com', // 设置请求的基础URL
  timeout: 5000, // 设置请求超时时间
  withCredentials: true, // 允许携带cookie
});

/* 请求拦截器 */
instance.interceptors.request.use(
  (config) => {
    /*在发送请求之前做一些处理,比如添加请求头等*/
    return config;
  },
  (error) => {
    /* 请求错误时做一些处理 */
    return Promise.reject(error);
  }
);

/* 响应拦截器 */
instance.interceptors.response.use(
  (response) => {
    /*对响应数据做一些处理,比如解析返回的数据等 */
    return response.data;
  },
  (error) => {
    /* 响应错误时做一些处理 */
    return Promise.reject(error);
  }
);

/* 发送跨域请求 */
instance.get('/api/data')
  .then((response) => {
    /*请求成功的处理逻辑*/
    console.log(response);
  })
  .catch((error) => {
    /*请求失败的处理逻辑*/
    console.error(error);
  });

15.vue使用路由的过程?

1.npm i vue-router
2.创建src/router/index.js文件
3.在index.js文件中编写代码
  import Vue from 'vue'
  import VueRouter from 'vue-router'
  let Home=()=>import('../components/Home.vue')
  Vue.use(VueRouter)
  let routes=[{path:'/home',name:'Home',component:Home}]
  let router=new VueRouter({routes})
  export default router
  4.在main.js中引入路由并挂载
    import router from './router'
      new Vue({
      router,
      store,
       render:h=>h(App)
    }).$mount('#app')

16.vue中route、routes、router、$route的区别?

1.route:是定义在路由文件中的一个对象,包含路径和组件之间的对应关系
2.routes:在路由文件中的一个数组,存放很多个route
3.$route:当前组件对应的url对象http://localhost:9999/#/home就是home.vue的$route
4.router:在路由文件中定义的VueRouter类型的对象,称路由器,其中包含很多route
5.$router:是全局Vue对象的一个属性,可以通过this.$router来获得到router

17.什么是Vuex?

 1.Vuex是一个专为Vue.js应用程序开发的状态管理模式
 2.Vuex可以存储各单文件组件共享的数据
 3.Vuex有常用的5个属性state、getters、mutations、actions、modules

18.vue双向数据绑定的原理?

具体步骤:1.需要observer的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter,这样的话,给这个对象的某个值赋值,就会触发setter,那么就能           监听到了数据变化
        2.compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,           收到通知,更新视图
        3.Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是:
        (1)在自身实例化时往属性订阅器(dep)里面添加自己
        (2)自身必须有一个update()方法
        (3)待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
        (4)MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最              终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视新;视图交互变化(input) -> 数据model变更的双向绑定效果。

19.Async/Await 如何通过同步的方式实现异步?

​
一.异步问题:传统的异步编程技术有回调函数和 Promise。
使用回调函数时,我们需要将后续的操作写在回调函数中,
这样才能确保在异步操作完成后执行。回调函数虽然简单易用,
但是嵌套多个回调函数会导致代码难以阅读和维护。
而 Promise 解决了这个问题,它可以链式调用,避免了回调函数嵌套的问题。

二.Async/Await 的实现原理
2-1:Async 和 Await 都是异步编程的关键字。
在 ES2017 中,Async 函数用来声明一个异步函数,
它的定义方式类似于普通的函数,但是在函数关键字前面添加 async 关键字,代码所示:
async function fetchData() {
  // 异步操作
}

2-2:Async 函数内部使用 await 关键字来等待异步操作完成。
await 表示等待异步操作返回结果后再继续执行后续的代码。
代码所示:
async function fetchData() {
  const result = await fetch("/api/data");
  console.log(result);
}
我们使用了 fetch 函数来获取服务器数据,fetch 返回的
是 Promise 实例。我们在该 Promise 实例前面加上 await
 关键字,表示等待该 Promise 对象返回数据后再继续执行后续的代码。

2-3:当 Async 函数被调用时,它返回的是一个 Promise 对象。
Promise 对象有三种状态:已完成、已拒绝和未完成。
如果 Async 函数内部没有抛出异常,则该 Promise 对象将进入已完成状态,
并返回 Async 函数返回值;如果 Async 函数内部抛出异常,
则该 Promise 对象将进入已拒绝状态,并返回抛出的异常。
例如,下面这个例子中,Async 函数返回的 Promise 
对象的状态为已完成,并返回字符串 “Hello World!” 
代码所示:
async function hello() {
  return "Hello World!";
}
hello().then((result) => console.log(result)); // 输出 "Hello World!"

2-4:Async/Await 实现一个简单的异步操作;代码所示:
async function fetchData() {
  try {
    const response = await fetch("https://jsonplaceholder.typicode.com/posts");
    const data = await response.json();
    console.log(data);
  } catch (error) {
    console.error(error);
  }
}
fetchData();
我们使用了 fetch 函数来获取服务器数据,并且使用 await 
等待数据返回。如果出现异常,则使用 try…catch 处理异常。
这段代码使用起来非常直观和易于理解

三.Async/Await 的同步实现原理
3-1:虽然使用 Async/Await 可以使异步代码看起来像同步代码,
但是底层仍然是异步执行的。那么,Async/Await 是如何通过同步
的方式实现异步的呢?答案就是 Generator 函数和 Promise。
3-2:Generator 函数是一种特殊的函数,它可以被暂停和恢复执行。
在 Generator 函数中,我们可以使用 yield 关键字将控制权交给调用方,并在下次调用时从上次暂停的位置继续执行。这种特性可以用来实现异步操作。
3-3:Promise 是 ES6 引入的另一种异步编程技术。
Promise 对象表示一个尚未完成或失败的操作,
它可以被异步执行,并返回一个代表操作结果的值。

3-4:Async 函数实际上是一种特殊的 Generator 函数,
它使用 yield 关键字暂停执行,并在异步操作完成后,
通过调用 next 方法恢复执行。这个过程中,Async 函数内部
创建了一个 Promise 对象,并将该 Promise 对象返回给调用方。
下面是 Async 函数的简化版实现:
function asyncToGenerator(generatorFunc) {
  return function () {
    const generator = generatorFunc.apply(this, arguments);
    return new Promise((resolve, reject) => {
      function step(key, arg) {
        let generatorResult;
        try {
          generatorResult = generator[key](arg);
        } catch (error) {
          reject(error);
        }
        const { value, done } = generatorResult;
        if (done) {
          resolve(value);
        } else {
          Promise.resolve(value).then(
            (result) => step("next", result),
            (error) => step("throw", error)
          );
        }
      }
      step("next");
    });
  };
}
解析:我们定义了一个名为 asyncToGenerator 的函数,
它接收一个 Generator 函数作为参数,并返回一个 Promise 对象。
asyncToGenerator 函数内部,我们首先调用传入的 Generator 函数,
获取到一个迭代器对象。然后,我们在 Promise 对象的构造函数中
使用递归调用的方式来处理每一次迭代。如果当前迭代已经完成,
则调用 resolve 函数,将结果返回给调用方;否则,
将该迭代的 Promise 对象通过 then 方法注册成功和失败回调函数,
并在回调函数中继续处理下一次迭代。

四:Async/Await 的使用场景
4-1:Async/Await 通常用于处理多个异步操作的情况,
它可以避免回调地狱和 Promise 层层嵌套的问题。
假设我们需要获取某些商品的信息并计算它们的总价格,
其中每个商品需要从服务器获取,并且需要等待前一个
商品请求完成后才能发送下一次请求。
在写传统异步代码时,我们可能会陷入回调地狱:
function getTotalPrice(items) {
  let totalPrice = 0;
  fetchItem(0, items);

  function fetchItem(index, items) {
    if (index >= items.length) {
      console.log("totalPrice:", totalPrice);
      return;
    }
    const item = items[index];
    fetch(`/api/items/${item.id}`).then((response) => {
      response.json().then((data) => {
        item.price = data.price;
        totalPrice += item.price * item.count;
        fetchItem(index + 1, items);
      });
    });
  }
}
解析:我们首先定义了一个 getTotalPrice 函数,
它接收一个商品列表作为参数,并计算所有商品的总价格。
我们在该函数中定义了一个名为 fetchItem 的递归函数,
用于依次获取每个商品的价格,并累加到 totalPrice 变量中。
在 fetchItem 函数中,我们使用 fetch 函数获取商品信息,
然后使用嵌套的 Promise.then 调用来等待异步操作返回。
这段代码虽然可行,但是非常难以理解和维护。

4-2:使用 Async/Await 可以让代码更加直观和易于理解:
async function getTotalPrice(items) {
  let totalPrice = 0;
  for (let item of items) {
    const response = await fetch(`/api/items/${item.id}`);
    const data = await response.json();
    item.price = data.price;
    totalPrice += item.price * item.count;
  }
  console.log("totalPrice:", totalPrice);
}
我们使用了 Async/Await 和 for…of 循环,避免了回调
地狱和 Promise 层层嵌套的问题。这样的代码看起来非常简单和直观。

总结:1.Async/Await 是一种比较新的异步编程技术,
它使异步代码看起来像同步代码,更加直观和易于理解。
     2.Async/Await 的实现原理是 Generator 函数和 Promise,
它通过同步的方式实现异步。使用 Async/Await 
可以避免回调地狱和 Promise 层层嵌套的问题。
     3.Async/Await 通常用于处理多个异步操作的情况,这样的代码看起来非常简单和直观。

​

20.浏览器渲染原理,回流,重绘的概念和原理?

浏览器的渲染机制:1.处理 HTML 并构建 DOM 树
               2.处理 CSS 构建 CSSOM 树
               3.将 DOM 与 CSSOM 合并成一个渲染树。
               4.根据渲染树来布局,计算每个节点的位置
               5.调用 GPU 绘制,合成图层,显示在屏幕上。
               
重绘与回流:1.重绘:当元素样式的改变不影响布局时,浏览器将使用重绘对元素进行更新,,此时由于只需要U层面的重新像素绘制,因此损耗较少   
          2.回流:当元素的尺寸、结构或触发某些属性时,浏览器会重新渲染页面,称为回流。此时,浏览器需要重新经过计算,计算后还需要重新页面布局,因此是较重的操            作。会触发回流的操作:页面初次渲染 - 浏览器窗口大小改变 - 元毒尺寸、位罟、内容发生改变 - 元素字体大小变化- 添加或者删除可见的 dom 元素 - 激活            CSS 伪类(例如::hover)-查询某些属性或调用某些方法: clientWidthclientHeight 、clientTop ,clientLeft - offsetWidth 、                      offsetHeight , offsetTop 、 offsetLeftscrollWidth,scrollHeight,scrollTop,scrollLeft-getComputedStyle()-                          getBoundingClientRect();scrollTo() 

          总结:回流必定触发重绘,重绘不一定触发回流。重绘的开销较小,回流的代价较高。所以尽量减少触发回流的操作,以达到更好的性能

21.Vue 中 key 值的作用?

当我们使用v-for指令对数组进行遍历渲染时,需要为每一项提供一个唯一的key值。这个key值的作用是帮助Vue识别节点身份,以便在数据发生变化时,能够准确地找到对应的节点进行更新。如果没有提供key值,Vue会使用一种基于索引的就地复用策略,这可能会导致一些难以预料的问题,如组件状态混乱、动画效果错误等。

22.MVVM 和 MVC 区别?它和其它框架(如 jQuery)的区别是什么?适合哪些场景?

1-1:MVVM 和 MVC 区别:1.mvc: Model-View- Controller (单向通信-模型-视图-控制器) View跟Model,必须通过Controller来承上启下
                     2.mvvm: Model-View-ViewModel (数据的双向绑定-模型-视图-视图模型)数据绑定将模型(Model)转化成视图(View),即将后端传递的                       数据转化成所看到的页面;DOM 事件监听将视图(View)转化成模型(Model),即将所看到的页面转化成后端的数据。
                  总结:mvvm主要解决了mvc中大量的DOM操作使页面渲染性能降低,加载速度变慢,影响用户体验。
1-2:它和其它框架(jquery)的区别是什么?
vue: 通过对数据的操作就可以完成对页面视图的渲染;jquery: 操作DOM,对其进行赋值、取值、事件绑定等 操作

1-3:适合哪些场景?
vue: 复杂数据操作的后台页面,表单填写页面;jquery: 一些html5的动画页面,一些需要js来操作页面样式的页面;或者 两者结合。

23.封装函数?

1、输入一个值,返回其数据类型
function type(para) {
    return Object.prototype.toString.call(para)
}
2、数组去重
function type(para) {
    return Object.prototype.toString.call(para)
}

function unique2(arr) {
    var obj = {};
    return arr.filter(ele => {
        if (!obj[ele]) {
            obj[ele] = true;
            return true;
        }
    })
}

function unique3(arr) {
    var result = [];
    arr.forEach(ele => {
        if (result.indexOf(ele) == -1) {
            result.push(ele)
        }
    })
    return result;
}
3、字符串去重
String.prototype.unique = function () {
    var obj = {},
        str = '',
        let = this.length;
    for (var i = 0; i < len; i++) {
        if (!obj[this[i]]) {
            str += this[i];
            obj[this[i]] = true;
        }
    }
    return str;
}
4、去除连续的字符串
function uniq(str) {
    return str.replace(/(\w)\1+/g, '$1')
}
5、深拷贝和浅拷贝
/* 深克隆(深克隆不考虑函数)*/
function deepClone(obj, result) {
    var result = result || {};
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop)) {
            if (typeof obj[prop] == 'object' && obj[prop] !== null) {
                /* 引用值(obj/array)且不为null */
                if (Object.prototype.toString.call(obj[prop]) == '[object Object]') {
                    // 对象
                    result[prop] = {};
                } else {
                    // 数组 
                    result[prop] = [];
                }
                deepClone(obj[prop], result[prop])
    } else {
        // 原始值或func
        result[prop] = obj[prop]
    }
  }
}
return result;
}

/* 深浅克隆是针对引用值 */
function deepClone(target) {
    if (typeof (target) !== 'object') {
        return target;
    }
    var result;
    if (Object.prototype.toString.call(target) == '[object Array]') {
        // 数组
        result = []
    } else {
        // 对象
        result = {};
    }
    for (var prop in target) {
        if (target.hasOwnProperty(prop)) {
            result[prop] = deepClone(target[prop])
        }
    }
    return result;
}

/* 无法复制函数 */
var o1 = jsON.parse(jsON.stringify(obj1));
6、reverse底层原理和扩展
/* 改变原数组 */
Array.prototype.myReverse = function () {
    var len = this.length;
    for (var i = 0; i < len; i++) {
        var temp = this[i];
        this[i] = this[len - 1 - i];
        this[len - 1 - i] = temp;
    }
    return this;
}
7、圣杯模式的继承
function inherit(Target, Origin) {
    function F() {};
    F.prototype = Origin.prototype;
    Target.prototype = new F();
    Target.prototype.constructor = Target;
    // 最终的原型指向
    Target.prop.uber = Origin.prototype;
}
8、找出字符串中第一次只出现一次的字母
String.prototype.firstAppear = function () {
    var obj = {},
        len = this.length;
    for (var i = 0; i < len; i++) {
        if (obj[this[i]]) {
            obj[this[i]]++;
        } else {
            obj[this[i]] = 1;
        }
    }
    for (var prop in obj) {
       if (obj[prop] == 1) {
         return prop;
       }
    }
}
9、找元素的第n级父元素
function parents(ele, n) {
    while (ele && n) {
        ele = ele.parentElement ? ele.parentElement : ele.parentNode;
        n--;
    }
    return ele;
}
10、返回元素的第n个兄弟节点
function retSibling(e, n) {
    while (e && n) {
        if (n > 0) {
            if (e.nextElementSibling) {
                e = e.nextElementSibling;
            } else {
                for (e = e.nextSibling; e && e.nodeType !== 1; e = e.nextSibling);
            }
            n--;
        } else {
            if (e.previousElementSibling) {
                e = e.previousElementSibling;
            } else {
                for (e = e.previousElementSibling; e && e.nodeType !== 1; e = e.previousElementSibling);
            }
            n++;
        }
    }
    return e;
}
11、封装mychildren,解决浏览器的兼容问题
function myChildren(e) {
    var children = e.childNodes,
        arr = [],
        len = children.length;
    for (var i = 0; i < len; i++) {
        if (children[i].nodeType === 1) {
            arr.push(children[i])
        }
    }
    return arr;
}
12、判断元素有没有子元素
function hasChildren(e) {
    var children = e.childNodes,
        len = children.length;
    for (var i = 0; i < len; i++) {
        if (children[i].nodeType === 1) {
            return true;
        }
    }
    return false;
}
13、我一个元素插入到另一个元素的后面
Element.prototype.insertAfter = function (target, elen) {
    var nextElen = elen.nextElenmentSibling;
    if (nextElen == null) {
        this.appendChild(target);
    } else {
        this.insertBefore(target, nextElen);
    }
}
14、返回当前的时间(年月日时分秒)
function getDateTime() {
        var date = new Date(),
        year = date.getFullYear(),
        month = date.getMonth() + 1,
        day = date.getDate(),
        hour = date.getHours() + 1,
        minute = date.getMinutes(),
        second = date.getSeconds();
        month = checkTime(month);
        day = checkTime(day);
        hour = checkTime(hour);
        minute = checkTime(minute);
        second = checkTime(second);
    
function checkTime(i) {
        if (i < 10) {
                i = "0" + i;
       }
      return i;
    }
    return "" + year + "年" + month + "月" + day + "日" + hour + "时" + minute + "分" + second + "秒"
}
15、获得滚动条的滚动距离
function getScrollOffset() {
    if (window.pageXOffset) {
        return {
            x: window.pageXOffset,
            y: window.pageYOffset
        }
    } else {
        return {
            x: document.body.scrollLeft + document.documentElement.scrollLeft,
            y: document.body.scrollTop + document.documentElement.scrollTop
        }
    }
}
16、获得视口的尺寸
function getViewportOffset() {
    if (window.innerWidth) {
        return {
            w: window.innerWidth,
            h: window.innerHeight
        }
    } else {
        // ie8及其以下
        if (document.compatMode === "BackCompat") {
            // 怪异模式
            return {
                w: document.body.clientWidth,
                h: document.body.clientHeight
            }
        } else {
            // 标准模式
            return {
                w: document.documentElement.clientWidth,
                h: document.documentElement.clientHeight
            }
        }
    }
}
17、获取任一元素的任意属性
function getStyle(elem, prop) {
    return window.getComputedStyle ? window.getComputedStyle(elem, null)[prop] : elem.currentStyle[prop]
}
18、绑定事件的兼容代码
function addEvent(elem, type, handle) {
    if (elem.addEventListener) { //非ie和非ie9
        elem.addEventListener(type, handle, false);
    } else if (elem.attachEvent) { //ie6到ie8
        elem.attachEvent('on' + type, function () {
            handle.call(elem);
        })
    } else {
        elem['on' + type] = handle;
    }
}
19、解绑事件
function removeEvent(elem, type, handle) {
    if (elem.removeEventListener) { //非ie和非ie9
        elem.removeEventListener(type, handle, false);
    } else if (elem.detachEvent) { //ie6到ie8
        elem.detachEvent('on' + type, handle);
    } else {
        elem['on' + type] = null;
    }
}
20、取消冒泡的兼容代码
function stopBubble(e) {
    if (e && e.stopPropagation) {
        e.stopPropagation();
    } else {
        window.event.cancelBubble = true;
    }
}
21、检验字符串是否是回文
function isPalina(str) {
    if (Object.prototype.toString.call(str) !== '[object String]') {
        return false;
    }
    var len = str.length;
    for (var i = 0; i < len / 2; i++) {
        if (str[i] != str[len - 1 - i]) {
            return false;
        }
    }
    return true;
}

function isPalindrome(str) {
    str = str.replace(/\W/g, '').toLowerCase();
    console.log(str)
    return (str == str.split('').reverse().join(''))
}
22、兼容getElementsByClassName方法
Element.prototype.getElementsByClassName = Document.prototype.getElementsByClassName = function (_className) {
    var allDomArray = document.getElementsByTagName('*');
    var lastDomArray = [];
    function trimSpace(strClass) {
        var reg = /\s+/g;
        return strClass.replace(reg, ' ').trim()
    }
    for (var i = 0; i < allDomArray.length; i++) {
        var classArray = trimSpace(allDomArray[i].className).split(' ');
        for (var j = 0; j < classArray.length; j++) {
            if (classArray[j] == _className) {
                lastDomArray.push(allDomArray[i]);
                break;
            }
        }
    }
    return lastDomArray;
}
23、运动函数
function animate(obj, json, callback) {
    clearInterval(obj.timer);
    var speed,
        current;
    obj.timer = setInterval(function () {
        var lock = true;
        for (var prop in json) {
            if (prop == 'opacity') {
                current = parseFloat(window.getComputedStyle(obj, null)[prop]) * 100;
            } else {
                current = parseInt(window.getComputedStyle(obj, null)[prop]);
            }
            speed = (json[prop] - current) / 7;
            speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
 
            if (prop == 'opacity') {
                obj.style[prop] = (current + speed) / 100;
            } else {
                obj.style[prop] = current + speed + 'px';
            }
            if (current != json[prop]) {
                lock = false;
            }
        }
        if (lock) {
            clearInterval(obj.timer);
            typeof callback == 'function' ? callback() : '';
        }
    }, 30)
}
24、弹性运动
function ElasticMovement(obj, target) {
    clearInterval(obj.timer);
    var iSpeed = 40,
        a, u = 0.8;
    obj.timer = setInterval(function () {
        a = (target - obj.offsetLeft) / 8;
        iSpeed = iSpeed + a;
        iSpeed = iSpeed * u;
        if (Math.abs(iSpeed) <= 1 && Math.abs(a) <= 1) {
            console.log('over')
            clearInterval(obj.timer);
            obj.style.left = target + 'px';
        } else {
            obj.style.left = obj.offsetLeft + iSpeed + 'px';
        }
    }, 30);
}
25、封装自己的forEach方法
Array.prototype.myForEach = function (func, obj) {
    var len = this.length;
    var _this = arguments[1] ? arguments[1] : window;
    // var _this=arguments[1]||window;
    for (var i = 0; i < len; i++) {
        func.call(_this, this[i], i, this)
    }
}
26、封装自己的filter方法
Array.prototype.myFilter = function (func, obj) {
    var len = this.length;
    var arr = [];
    var _this = arguments[1] || window;
    for (var i = 0; i < len; i++) {
        func.call(_this, this[i], i, this) && arr.push(this[i]);
    }
    return arr;
}
27、数组map方法
Array.prototype.myMap = function (func) {
    var arr = [];
    var len = this.length;
    var _this = arguments[1] || window;
    for (var i = 0; i < len; i++) {
        arr.push(func.call(_this, this[i], i, this));
    }
    return arr;
}
28、数组every方法
Array.prototype.myEvery = function (func) {
    var flag = true;
    var len = this.length;
    var _this = arguments[1] || window;
    for (var i = 0; i < len; i++) {
        if (func.apply(_this, [this[i], i, this]) == false) {
            flag = false;
            break;
        }
    }
    return flag;
}
29、数组reduce方法
Array.prototype.myReduce = function (func, initialValue) {
    var len = this.length,
        nextValue,
        i;
    if (!initialValue) {
        // 没有传第二个参数
        nextValue = this[0];
        i = 1;
    } else {
        // 传了第二个参数
        nextValue = initialValue;
        i = 0;
    }
    for (; i < len; i++) {
        nextValue = func(nextValue, this[i], i, this);
    }
    return nextValue;
}
30、获取url中的参数
function getWindonHref() {
    var sHref = window.location.href;
    var args = sHref.split('?');
    if (args[0] === sHref) {
        return '';
    }
    var hrefarr = args[1].split('#')[0].split('&');
    var obj = {};
    for (var i = 0; i < hrefarr.length; i++) {
        hrefarr[i] = hrefarr[i].split('=');
        obj[hrefarr[i][0]] = hrefarr[i][1];
    }
    return obj;
}
31、数组排序
/* 快排 [left] + min + [right] */
function quickArr(arr) {
    if (arr.length <= 1) {
        return arr;
    }
    var left = [],
        right = [];
    var pIndex = Math.floor(arr.length / 2);
    var p = arr.splice(pIndex, 1)[0];
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] <= p) {
            left.push(arr[i]);
        } else {
            right.push(arr[i]);
        }
    }
    // 递归
    return quickArr(left).concat([p], quickArr(right));
}

/* 冒泡 */
function bubbleSort(arr) {
    for (var i = 0; i < arr.length - 1; i++) {
        for (var j = i + 1; j < arr.length; j++) {
            if (arr[i] > arr[j]) {
                var temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
    }
    return arr;
}

function bubbleSort(arr) {
    var len = arr.length;
    for (var i = 0; i < len - 1; i++) {
        for (var j = 0; j < len - 1 - i; j++) {
            if (arr[j] > arr[j + 1]) {
                var temp = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
    return arr;
}
32、遍历Dom树
/* 给定页面上的DOM元素,将访问元素本身及其所有后代(不仅仅是它的直接子元素)对于每个访问的元素,函数讲元素传递给提供的回调函数 */
function traverse(element, callback) {
    callback(element);
    var list = element.children;
    for (var i = 0; i < list.length; i++) {
        traverse(list[i], callback);
    }
}
33、原生JS封装ajax
function ajax(method, url, callback, data, flag) {
    var xhr;
    flag = flag || true;
    method = method.toUpperCase();
    if (window.XMLHttpRequest) {
        xhr = new XMLHttpRequest();
    } else {
        xhr = new ActiveXObject('Microsoft.XMLHttp');
    }
    xhr.onreadystatechange = function () {
        if (xhr.readyState == 4 && xhr.status == 200) {
            console.log(2)
            callback(xhr.responseText);
        }
    }
 
    if (method == 'GET') {
        var date = new Date(),
        timer = date.getTime();
        xhr.open('GET', url + '?' + data + '&timer' + timer, flag);
        xhr.send()
        } else if (method == 'POST') {
        xhr.open('POST', url, flag);
        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        xhr.send(data);
    }
}
34、异步加载script
function loadScript(url, callback) {
    var oscript = document.createElement('script');
    if (oscript.readyState) { // ie8及以下版本
        oscript.onreadystatechange = function () {
            if (oscript.readyState === 'complete' || oscript.readyState === 'loaded') {
                callback();
            }
        }
    } else {
        oscript.onload = function () {
            callback()
        };
    }
    oscript.src = url;
    document.body.appendChild(oscript);
}
35、cookie管理
var cookie = {
    set: function (name, value, time) {
        document.cookie = name + '=' + value + '; max-age=' + time;
        return this;
    },
    remove: function (name) {
        return this.setCookie(name, '', -1);
    },
    get: function (name, callback) {
        var allCookieArr = document.cookie.split('; ');
        for (var i = 0; i < allCookieArr.length; i++) {
            var itemCookieArr = allCookieArr[i].split('=');
            if (itemCookieArr[0] === name) {
                return itemCookieArr[1]
            }
        }
        return undefined;
    }
}
36、实现bind()方法
Function.prototype.myBind = function (target) {
    var target = target || window;
    var _args1 = [].slice.call(arguments, 1);
    var self = this;
    var temp = function () {};
    var F = function () {
        var _args2 = [].slice.call(arguments, 0);
        var parasArr = _args1.concat(_args2);
        return self.apply(this instanceof temp ? this : target, parasArr)
    }
    temp.prototype = self.prototype;
    F.prototype = new temp();
    return F;
}
37、实现call()方法
Function.prototype.myCall = function () {
    var ctx = arguments[0] || window;
    ctx.fn = this;
    var args = [];
    for (var i = 1; i < arguments.length; i++) {
        args.push(arguments[i])
    }
    var result = ctx.fn(...args);
    delete ctx.fn;
    return result;
}
38、实现apply()方法
Function.prototype.myApply = function () {
    var ctx = arguments[0] || window;
    ctx.fn = this;
    if (!arguments[1]) {
        var result = ctx.fn();
        delete ctx.fn;
        return result;
    }
    var result = ctx.fn(...arguments[1]);
    delete ctx.fn;
    return result;
}
39、防抖
function debounce(handle, delay) {
    var timer = null;
    return function () {
        var _self = this,
            _args = arguments;
        clearTimeout(timer);
        timer = setTimeout(function () {
            handle.apply(_self, _args)
        }, delay)
    }
}
40、节流
function throttle(handler, wait) {
    var lastTime = 0;
    return function (e) {
        var nowTime = new Date().getTime();
        if (nowTime - lastTime > wait) {
            handler.apply(this, arguments);
            lastTime = nowTime;
        }
    }
}
41、requestAnimFrame兼容性方法
window.requestAnimFrame = (function () {
    return window.requestAnimationFrame ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame ||
        function (callback) {
            window.setTimeout(callback, 1000 / 60);
        };
})();
42、cancelAnimFrame兼容性方法
window.cancelAnimFrame = (function () {
    return window.cancelAnimationFrame ||
        window.webkitCancelAnimationFrame ||
        window.mozCancelAnimationFrame ||
        function (id) {
            window.clearTimeout(id);
        };
})();
43、jsonp底层方法
function jsonp(url, callback) {
    var oscript = document.createElement('script');
    if (oscript.readyState) { // ie8及以下版本
        oscript.onreadystatechange = function () {
            if (oscript.readyState === 'complete' || oscript.readyState === 'loaded') {
                callback();
            }
        }
    } else {
        oscript.onload = function () {
            callback()
        };
    }
    oscript.src = url;
    document.body.appendChild(oscript);
}
44、获取url上的参数
function getUrlParam(sUrl, sKey) {
    var result = {};
    sUrl.replace(/(\w+)=(\w+)(?=[&|#])/g, function (ele, key, val) {
        if (!result[key]) {
            result[key] = val;
        } else {
            var temp = result[key];
            result[key] = [].concat(temp, val);
        }
    })
    if (!sKey) {
        return result;
    } else {
        return result[sKey] || '';
    }
}
45、格式化时间
function formatDate(t, str) {
    var obj = {
        yyyy: t.getFullYear(),
        yy: ("" + t.getFullYear()).slice(-2),
        M: t.getMonth() + 1,
        MM: ("0" + (t.getMonth() + 1)).slice(-2),
        d: t.getDate(),
        dd: ("0" + t.getDate()).slice(-2),
        H: t.getHours(),
        HH: ("0" + t.getHours()).slice(-2),
        h: t.getHours() % 12,
        hh: ("0" + t.getHours() % 12).slice(-2),
        m: t.getMinutes(),
        mm: ("0" + t.getMinutes()).slice(-2),
        s: t.getSeconds(),
        ss: ("0" + t.getSeconds()).slice(-2),
        w: ['日', '一', '二', '三', '四', '五', '六'][t.getDay()]
    };
    return str.replace(/([a-z]+)/ig, function ($1) {
        return obj[$1]
    });
}
46、验证邮箱的正则表达式
function isAvailableEmail(sEmail) {
    var reg = /^([\w+\.])+@\w+([.]\w+)+$/
    return reg.test(sEmail)
}
47、函数柯里化
/* 是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果的新函数的技术 */
function curryIt(fn) {
    var length = fn.length,
        args = [];
    var result = function (arg) {
        args.push(arg);
        length--;
        if (length <= 0) {
            return fn.apply(this, args);
        } else {
            return result;
        }
    }
    return result;
}
48、大数相加
function sumBigNumber(a, b) {
    /* 结果 */
    var res = '', 
    /* 按位加的结果及进位 */
    temp = 0;
    a = a.split('');
    b = b.split('');
    while (a.length || b.length || temp) {
        /* ~~按位非 1.类型转换,转换成数字 2.~~undefined==0 */
        temp += ~~a.pop() + ~~b.pop();
        res = (temp % 10) + res;
        temp = temp > 9;
    }
    return res.replace(/^0+/, '');
}
49、单例模式
function getSingle(func) {
    var result;
    return function () {
        if (!result) {
            result = new func(arguments);
        }
        return result;
    }
50、获取地址栏地址的参数信息
function getUrlParams() {
  var params = {};
  var url = window.location.href;
  var paramStr = url.substring(url.indexOf("?") + 1);
  var paramArr = paramStr.split("&");
  
  for (var i = 0; i < paramArr.length; i++) {
    var param = paramArr].split("=");
    var key = decodeURIComponent(param);
    var value = decodeURIComponent(param);
    params[key] = value;
  }
  
  return params;
}

/* 调用查看 */
var params = getUrlParams();
console.log(params);

24.pinia的持久化操作 ?

1.安装 Pinia:npm install pinia

2.创建一个简单的 Store: import { defineStore } from 'pinia';  
export const useCounterStore = defineStore('counter', {  
  state: () => ({  
    count: 0,  
  }),  
  actions: {  
    increment() {  
      this.count++;  
    },  
    decrement() {  
      this.count--;  
    },  
  },  
});

3.添加持久化逻辑:import { defineStore } from 'pinia';  
export const useCounterStore = defineStore('counter', {  
  state: () => {  
    // 尝试从 localStorage 恢复状态  
    const savedState = localStorage.getItem('counterState');  
    return savedState ? JSON.parse(savedState) : { count: 0 };  
  },  
  actions: {  
    increment() {  
      this.count++;  
      this.saveState(); // 在状态变化后保存状态  
    },  
    decrement() {  
      this.count--;  
      this.saveState(); // 在状态变化后保存状态  
    },  
    saveState() {  
      // 将当前状态保存到 localStorage  
      localStorage.setItem('counterState', JSON.stringify(this.state));  
    },  
  },  
});

25.vue3 如何实现父传子,子传父?

1.父组件通过 props 向子组件传递数据。 子组件 (Child.vue)
2.子传父(Emits)子组件通过触发自定义事件来向父组件传递数据或消息。父组件 (Parent.vue)

26.Vue3中组件通信的方法有些,流程是什么?

1.在vue2中父给子传值用到了:方法=要传递过去的数据,子组件通过props接收父组件传递过来的数据,子传父:子组件通过this.$emite(方法,要传递过去的数据),父组件通过@方法=方法名称接收;

2.在vue3中父给子传值用到了:方法=要传递过去的数据,子组件通过props接收父组件传递过来的数据,但是在子组件中这个方法要写在setup中,不然不会展示出来,

3.子传父:子组件通过contex(方法,要传递过去的数据),父组件通过@方法=方法名称接收

4.Provide和inject传值:用于祖孙传值,这两个是成对出现的,有inject就必须有provide,这个方法不需要知道他的组件是谁,只需要在需要传值的地方写入inject即可将下载provide的地方的数据直接传递过去,当然他也可以用于父子传值,不需要想props那也复杂,也不需要知道父组件是谁,即可立即使用,并把数据接收,传递成功  

5.Vuex传值
6.Refs传值

27.Vue中的生命周期

  • beforeCreate:在初始化实例之后和事件配置之前被调用

  • create:data已初始化,dom树未挂载

  • beforeMount:在挂载前被调用

  • mounted:已挂载完成渲染到页面,可以进行dom操作

  • beforeUpdate:数据有更新被调用

  • updated:虚拟dom重新渲染补丁以最小的dom开支来重新渲染dom

  • activated:keep-alive组件激活时使用

  • deactivated:keep-alive组件停用时使用

  • bforeDestroy:销毁之前调用,可以访问实例对象

  • destroy:销毁之后调用

28.Get和POST的区别

  • get是不安全的,请求过程中,请求数据被放在Url中,Post的所有操作客户是看不见的

  • Get因为受到Url的长度限制,所以传输的数据量比较小,Post传输量大,一般默认不受限制

  • Get执行效率比Post方法好,Get是from表单提交的默认方法

29.JS基础问题

  1. 变量类型判断

    • 判断 typeof或instanceof(不完全准确)

    • 完全准确 Object.prototype.toString.call 或 jQuery中的$.type

  2. 数据类型

    • js的数据类型有几种: 8种

      Number、String、Boolean、Null、undefined、object、symbol、bigint

    • Object中包含了哪几种类型?

      包含了Data、function、Array

  3. 作用域

    • 全局作用域:

      所有的浏览器都支持window对象,他表示浏览器窗口,JavaScript全局对象、函数以及变量均自从成 为window对象的成员。所以、全局变量是window对象的属性,全局函数是window对象的方法,甚 至html dom的document也是window对象的属性之一

    • 词法作用域:

      函数在定义他们的作用域里运行,而不是在执行他们的作用域里运行。也就是说词法作用域取决于源 码,通过静态分析就能确定,因此词法作用域也叫静态作用域

    • 动态作用域:

      动态作用域于词法作用域相对而言的,不同于词法作用域在定义时确定,动态作用域在执行时确定, 其生存周期到代码片段执行为止。动态变量存在于动态作用域中,任何给定的值,在确定调用其函数 之前,都是不可知的

    • 作用域链:

      JavaScript里的一切皆为对象,包括函数。函数对象和其他对象一样,拥有可以通过代码访问的属性和 一系列进攻JavaScript引擎访问的内部属性。其中一个内部属性是作用域,包含了函数被创建的作用域

      中对象的集合,称为函数的作用域链,他用来保证对执行环境有权访问的变量和函数的有序访问

  4. 闭包

    • 官方定义:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分

    • 一句话概括就是:闭包就是一个函数,捕获作用域内的外部绑定。这些绑定是为了之后使用而被绑定,即使用作用一已经销毁

  5. 异步请求

    • 不需要等待响应,随时可以发送下一次请求

    • 请求方式

promise({
    
}).then(res => {
    ...请求完成进行操作
})catch(e){
    console.log(e)//请求错误时不会经过.then直接来到catch
}


async function(){
    try{
        const res = await ......(调用api接口)
    }catch(e){
        
    }
}

//还有一个只是在这两个中的一个过度
Generator

6.ES6/7新特性

  includes方法,查找一个值在不在数组里,若是存在则返回true,不存在返回false。

30.什么是原型链?

  • 原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。那么假如我们让原型对象等于另一个类型的实例,结果会怎样?显然,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立。如此层层递进,就构成了实例与原型的链条。这就是所谓的原型链的基本概念。

function Person(age){
    this.age = age
}
Person.prototype.name = 'kavin'
var person1 = new Person()
var person2 = new Person()
console.log(person1.name)	//kavin
console.log(person2.name)	//kavin

console.log(person._proto_ === Person.prototype)	//true

console.log(Person === Person.prototype.constructor)	//true

console.log(person.constructor === Person)    //true

  • 15
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值