(笔记)面试题汇总附加答案(持续更新)

JS部分

1. 编写一个方法,该方法接收两个参数,分别为 k 和 一个无序的纯数字数组。该方法在执行后,会返回数组中第 k 大的数字。特别注意,如果数组中,有两位数值一样的数字,同数值数字排名并列。如 [3,1,3,2,5,4,5] 中,第 1 大的数字为 5,第2大的数字为 4,第5大的数字为 1?

  • 这道题目考察数组的常用基本操作方法。思路是先做数组内部值的排序,排序完成之后因为需要由大到小所以在反转下数组 。最后在做数组的去重处理,最终返还答案。实现代码如下:
function getNum(k, arr) {            
    let res = arr.sort((a,b)=>b-a);   // 将数组转化成set去重     
    let set = new Set(res);  // 将类数组转回数组        
    let newArr = Array.from(set);        
    if (typeof newArr[k-1] !== "undefined") { // 返回查找到的数据    
        return newArr[k-1];  
    } else {            // 未找到数据排除错误          
        throw Error("未找到对应数据");        
    }   
 }    
let arr = [3132545];    
let res = getNum(1, arr);    
console.log(res);
复制代码

2.proto 和 prototype 之前有什么关系?

  • 所有对象都有 proto 属性,函数这个特殊对象除了具有 proto 属性,还有特有的原型属性prototype。prototype对象默认有两个属性,constructor属性和__proto__ 属性。prototype属性可以给函数和对象添加可共享(继承)的方法、属性,而__proto__ 是查找某函数或对象的原型链方式。constructor,这个属性包含了一个指针,指回原构造函数。

3.call(), .apply() .bind() 的区别和作用?bind 方法如何来实现?

  • call 、apply 、bind 作用是 改变函数执行时的上下文,简而言之就是改变函数运行时的this指向。区别在于调用方式及参数传递上。具体如下:
function fn(...args) {        
console.log(this,args); 
}    
fn(1,2);  // fn函数默认this指向是 window对象    
let obj = {        
    myname:"张三"  
}    
fn.call(obj,1,2);  // this 会变成 传入的obj ,args 会变成[1,2];    
fn.apply(obj,[1,2]); // this会变成传入的obj ,传入的参数必须是一个数组;    
fn.bind(obj)(1,2); // this 也会变成传入的obj ,bind不是立即执行需要执行一次
复制代码

上所述call、apply、bind都可以改变this指向,区别在于 参数传递方式不同,call、apply是立即执行bind不是立即执行。

  • bind实现如下
Function.prototype.myBind = function (context) {   
    // 判断调用对象是否为函数   
    if (typeof this !== "function") {     
        throw new TypeError("Error");   
     }   // 获取参数   
    var args = [...arguments].slice(1);    
    fn = this;   
    return function Fn() {     
    // 根据调用方式,传入不同绑定值     
        return fn.apply(this instanceof Fn ? new fn(...arguments) : context, args.concat(...arguments));   
    } 
}
复制代码

4. js中基础数据类型有哪几种?了解包装对象么?

  • 基础数据类型有6种:  boolean null undefined number string symbol  基础数据类型都是值 ,所以没有方法提供调用的 例如:undefined.split(“”);那为什么比如 ”abc“.split(“”)类似这种调用可以被允许?原因是js中会存在包装对象,会把字符串先包装成对象然后在调用对象下的一些方法,方法调用完成之后在销毁对象,这样就完成了基础数据类型的函数调用功能。

5.什么是宏任务?什么是微任务?

  • 微任务:一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前。  
  • 宏任务:宏任务的时间粒度比较大,执行的时间间隔是不能精确控制的,对一些高实时性的需求就不太符合。  

常见微任务:

  1. Promise.then
  2. MutaionObserver
  3. Object.observe(已废弃;Proxy 对象替代)
  4. rocess.nextTick(Node.js)

常见宏任务 :   

  1. script (可以理解为外层同步代码)  
  2. setTimeout/setInterval  
  3. UI rendering/UI事件  
  4. postMessage,MessageChannel  
  5. setImmediate,I/O(Node.js)

image.png

6.Promise.allSettled 了解吗?动手实现一下 Promise.allSettled?

function MyallSettled(list){
    let resArr = new Array(list.length);
    let num = 0;
    return new Promise(resolve => {            
        list.forEach((item,key) => {               
            let obj = {};                
            item.then(res =>{                    
                obj['status'] = "fulfilled";                    
                obj.value = res;                    
                resArr[key]= obj;         
                num++                   
                if(num===list.length){                        
                resolve(resArr);              
            }},err=>{                  
                obj['status'] = "rejected";                    
                obj.reson = err;                    
                resArr[key] = obj;                    
                num++                    
                if(num===list.length){                        
                    resolve(resArr);                  
                }                
            })         
         })       
      });    
}
复制代码

vue部分

1、vue 中组件间有哪些通信方式?

  • 1.prop与 $emit适用于父子组件通信这种方法是 Vue 组件的基础,相信大部分同学耳闻能详,所以此处就不举例展开介绍。
  • 2.ref 与 parent 与parent 与 children适用于父子组件通信ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例parent/parent / children:访问父 / 子实例–
  • 3.EventBus (emit/emit / on)适用于父子、隔代、兄弟组件通信这种方法通过一个空的 Vue 实例/作为中央事件总线(事件中心),用它来触发事件和监听事件,从而实现任何组件间的通信,包括父子、隔代、兄弟组件。
  • 4.attrs/attrs/listeners适用于隔代组件通信attrs:包含了父作用域中不被prop所识别(且获取)的特性绑定(classstyle除外)。当一个组件没有声明任何prop时,这里会包含所有父作用域的绑定(classstyle除外),并且可以通过vbind=attrs:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 ( class 和 style 除外 )。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 ( class 和 style 除外 ),并且可以通过 v-bind=“attrs” 传入内部组件。通常配合 inheritAttrs 选项一起使用。$listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on=“$listeners” 传入内部组件
  • 5.provide / inject适用于隔代组件通信祖先组件中通过 provider 来提供变量,然后在子孙组件中通过 inject 来注入变量。provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
  • 6.Vuex适用于父子、隔代、兄弟组件通信Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。每一个 Vuex 应用的核心就是 store(仓库)。“store” 基本上就是一个容器,它包含着你的应用中大部分的状态 ( state )。Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化。

2.vue 中 v-show 和 v-if 的区别是什么?

  • v-show 只是在 display: none 和 display: block 之间切换。无论初始条件是什么都会被渲染出来,后面只需要切换 CSS,DOM 还是一直保留着的。  
  • v-if 的话就得说到 Vue 底层的编译了。当属性初始为 false 时,组件就不会被渲染,直到条件为 true,并且切换条件时会触发销毁/挂载组件,  并且基于 v-if 的这种惰性渲染机制,可以在必要的时候才去渲染组件,减少整个页面的初始渲染开销。

3.keep-alive有什么作用

  •  如果你需要在组件切换的时候,保存一些组件的状态防止多次渲染,就可以使用 keep-alive 组件包裹需要保存的组件。
  •  对于 keep-alive 组件来说,它拥有两个独有的生命周期钩子函数,分别为 activated 和 deactivated 。用 keep-alive 包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行 deactivated 钩子函数,命中缓存渲染后会执行 actived 钩子函数。

4.说下vue生命周期钩子函数?

  • beforeCreate :这个时期,this变量还不能使用,在data下的数据,和methods下的方法,watcher中的事件都不能获得到。
  • created这个时候可以操作vue实例中的数据和各种方法,但是还不能对”dom”节点进行操作。
  • beforeMounte:在挂载开始之前被调用:相关的 render 函数首次被调用
  • mounted:挂载完毕,这时dom节点被渲染到文档内,一些需要dom的操作在此时才能正常进行
  • beforeUpdate:data中数据已经更新完毕,页面视图还未响应更改– updated:数据和视图都更新完毕
  • beforeDestroy:销毁之前,实例上事件、指令等都可以使用,这里组件没有真正的销毁。
  • destroyed:数据、指令、等完全销毁

5.Vue中computed和watch区别?

  • computed 是计算属性,依赖其他属性计算值,并且 computed 的值有缓存,只有当计算值变化才会返回内容。
  • watch 监听到值的变化就会执行回调,在回调中可以进行一些逻辑操作。

react部分

1.React 的组件间通信都有哪些形式?

  1. 父传子:在 React 中,父组件调用子组件时可以将要传递给子组件的数据添加在子组件的属性中,在子组件中通过 props 属性进行接收。这个就是父组件向子组件通信。
  2. 子传父:React 是单向数据流,数据永远只能自上向下进行传递。当子组件中有些数据需要向父级进行通信时,需要在父级中定义好回调,将回调传递给子组件,子组件调用父级传递过来的回调方法进行通信。
  3. 跨组件通信 – context。使用 context API,可以在组件中向其子孙级组件进行信息传递。

2.React 中如何实现路由懒加载?

  • 在 React 16 中,新增了 lazy 方法,通过 lazy 方法可以轻松实现组件懒加载,当然要实现路由懒加载的话,其实也只需要把路由组件结合 lazy 使用即可
 import {Route} from "react-router-dom";  
 import React,{Suspense} from 'react';       
 const HomeView = React.lazy(()=>import("./home"));     
 function App(){          
     return <div>              
     <h1>路由懒加载</h1>              
     <Route path="/" exact render={()=>{                    
         return <Suspense fallback={<div>组件Loading进来之前的占位内容</div>}>                    
         <HomeView />              
     </Suspense>             
     }} />           
     </div>       
}        
 export default App;
复制代码
  •  在上述代码中,我们使用 lazy 引入了一个动态组件,然后将该组件放入了根路由中。这样的话只有用户访问网站首页时,才会动态加载这个组件。  这里要注意,在 React 规范中,lazy 和 Suspense 必须配合使用,lazy 引入的动态组件必须要放入 Suspense 中,Suspense 的 fallback 属性是 lazy 的组件没有加载进来之前的占位内容。

3. React 的生命周期函数都有哪些,分别有什么作用?

  1. constructor: 初始化组件,初始化组件的 state 等。
  2. static getDerivedStateFromProps():该函数用于将 props 中的信息映射到 state 中。
  3. render: 生成虚拟DOM
  4. componentDidMount:组件挂载完成,通过在该函数中去处理副作用 更新阶段:
  5. static getDerivedStateFromProps()
  6. shouldComponentUpdate():该生命周期函数用于判断是否要进行组件更新。
  7. getSnapshotBeforeUpdate():组件已经完成 diff,即将更新真实 DOM,用户获取上一次的DOM快照。该函数必须搭配 componentDidUpdate 一块使用,返回值会变成 componentDidUpdate 第三个参数。
  8. componentDidUpdate(): 组件更新完成,通常在该函数中进行副作用处理。 即将卸载: componentWillUnmount:组件即将卸载,用于删除组件添加到全局的数据或事件。
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享