interview-question-note(1)

防抖和节流

防抖和节流是闭包的实际应用

防抖函数

当持续触发事件 一定时间内没有再触发事件 事件处理函数才会执行一次 如果设定的时间到来之前 又一次触发了事件 就重新开始延时
如: 键盘一直输入内容 键盘抬起了并且满足1秒内没有再次输入

内存泄露是指你用不到(访问不到)的变量,依然占居着内存空间,不能被再次利用起来。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>防抖函数</title>
</head>
<body>
    <input type="text" id="input">

    <script>
        // document.querySelector('#input').addEventListener('keyup',function(e){ debounce(1000,e.target.value)})
        // let timer = null
        // function debounce(delay,value){
      
      
        //     clearTimeout(timer)
        //     timer =setTimeout(function(){
      
      
        //         console.log(value);
        //     },delay)
        // }
        // 一直在内存当中 内存泄漏 闭包
        // 内存泄露是指你用不到(访问不到)的变量,依然占居着内存空间,不能被再次利用起来。  
        // 函数柯里化
        //以上完成了基本需求但是我们定义了一个全局变量,基于尽可能少的使用全局变量
        // 我们将变量放入debounce函数的内部
        document.querySelector('#input').addEventListener('keyup',function(e){
      
       debounceFuc(e.target.value)})
        var debounceFuc = debounce(1000,fn)
        // 前面为什么要用callback是因为可以封装 不然写死了 用一个防抖就得重复写 callback灵活
        function debounce(delay,callback){
      
      
            let timer = null
            return function(value){
      
      
              clearTimeout(timer)
              timer = setTimeout(function(){
      
      
            //    console.log(value);
            callback(value)
              },delay)
            }
        } 
        function fn(value){
      
      
            console.log(value);
        }

        // 这里是基于闭包实现的,按钮 element 监听了 click 事件,并执行 debounce 方法,debounce 方法又返回一个新函数
        // ,这里的 timer 就会一直存在,不被销毁,因为函数被外部引用。
        // 所以下次点击的时候 timer 还是存在,我们点击的时候首先会 clearTimeout,也就是取消上次的请求
    </script>
</body>
</html>

实际应用场景

使用echarts时,改变浏览器宽度的时候,希望重新渲染
echarts的图像,可以使用此函数,提升性能(虽然echarts里有自带的resize函数)
典型案例 :输入搜索 输入结束后n秒才进行搜索请求,n秒内又输入的内容,就重新计时
解决搜索的bug

节流函数

当持续触发事件的时候 保证一段时间内 只调用一次事件处理函数
一段时间内 只做一件事

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>节流函数</title>
</head>
<body>
    <button id="button">点击</button>
    <script>
        document.querySelector('#button').onclick = throttle(handle,2000)
        let timeOut = null
        function throttle(func,wait){
      
      
         
         return function(){
      
      
            if(!timeOut){
      
      
                timeOut = setTimeout(function(){
      
      
                 func()

                 timeOut = null
                },wait)

            }
         }
        }
        function handle(){
      
      
            console.log(Math.random());
        }
    </script>
</body>
</html>

实际应用场景

典型案例:鼠标不断点击触发,规定在n秒内多次点击只有一次生效

防抖节流优化图片懒加载

防抖-优化不断触发的窗口变化
重新计算可见区域的高度
节流-实现性能较好的懒加载
滑动时图片的显示

登录验证

传统的登录验证方案

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
分布式下,同域单点登录的session同步解决方案
1.IPhash

最原始的方式是iphash方法。通过IP值计算hash值,第一次该客户的的请求由代理服务器nginx发送到了系统A,则以后每次只要是该IP的哈希值,均发给系统A。这样做虽然能解决问题,但是是伪负载均衡,如果系统A挂了,则会造成系统瘫痪,该用户无法正常使用,会产生单点故障。此方法早已被淘汰。

2.session复制

集群服务器的代码逻辑都是相同的。当用户在系统A登录后,其登录信息保存在session域中。集群服务器之间可以进行通讯,进行session同步。说明白点就是将自己的session复制给其他服务器,保证所有正常工作的集群的session域的数据一模一样,让大家都知道这个用户登陆了。
3.中间存储媒介

第三种方法是在第二种方法的基础上改进的。不用每个集群都保存一份数据,而是在每个服务器处理完之后,将数据保存到一个第三方的存储结构。所有的服务器都会从第三方存储结构中去拿数据。一般使用非关系型数据库Redis作为第三方存储。
如图所示,不管是分布式服务器还是集群服务器,在用户登录之后会生成一个可以唯一确定客户端的id,依次id为键,以该用户为值将客户端的登录信息存到Redis中,然后会以Token的形式返回key值给客户端。当该客户的在此发起请求时携带Token一起发送,无论哪个服务器处理此次请求,都会从Token中拿到uuid,然后去Redis中查找该用户的信息。如此便可实现单点登录。

4.总结
Session同步技术使得不管是集群服务器,还是分布式服务器,都可以共享用户登录信息。给单点登录的实现贡献了浓墨重彩的一笔。

基于token身份认证方案就是第三种 中间存储媒介解决方案
在这里插入图片描述

jwt验证方案

现在用的最多的还是jwt方案
在这里插入图片描述
在这里插入图片描述

预编译

作用域创建的阶段就是预编译的阶段
预编译的时候做了那些事
js的变量对象 AO对象 供js引擎自己去访问的
预编译的四个步骤
1 创建ao对象
2 找形参和变量的声明 作为ao对象的属性名 值是undefined
3 实参和形参相统一
4 找函数声明 (函数声明会覆盖变量声明)

在这里插入图片描述

this

在函数中直接使用
函数作为对象的方法被调用(谁调用我 我就指向谁)

在这里插入图片描述
上面的写法是call写法的语法糖

在这里插入图片描述

箭头函数

在这里插入图片描述

手写实现call apply

call apply作用 区别 理解 实际开发场景
改变this指向 参数区别call单向数据 apply数组
js继承 原型链继承 构造函数继承 call实现
js数据类型
es5 伪数组转化成数组

实战中使用call的场景

  • 实现js继承
  • 判断复杂数据类型
  • es5伪数组转化为数组
console.log(Object.prototype.toString.call({
    
    })==='[object Object]');
console.log(Object.prototype.toString.call([])==='[object Array]');
 function get() {
    
    
            console.log(arguments);
            console.log([...arguments]);    //es6
            console.log(Array.prototype.slice.call(arguments));  //es5
        }
        get(1, 2, 3)

call的作用 改变this指向

        var person = {
    
    
            getName:function(){
    
    
                return this.name
            }
        }
        var person1 = {
    
    
            name:'zhangyue'
        }
        console.log(person.getName.call(person1));

实现手写call

tips: JS—arguments对象
arguments 是一个类数组对象(伪数组)。代表传给一个function的参数列表。

         var person = {
    
    
            getName:function(){
    
    
                return this.name
            }
        }
          var person1 = {
    
    
            name:'zhangyue'
        }
        // 参数接收的 改变this指向的参数
        Function.prototype.myCall = function(context){
    
    
            // 这里面的this是谁   是getname 因为谁调用this就指向谁
            // 这里的this必须是一个function
            if(typeof this !== 'function'){
    
    
                throw new Error('error')
            }
            // context = context || window  传了就是context 不传就是window
            // 考虑参数    拿到除了第一个参数之外的参数
            var args = [...arguments].slice(1)
            console.log(args);
            context.fn = this
            var result = context.fn(args)
            return result
        }
       
        console.log(person.getName.myCall(person1,1,2,3));

事件的循环机制 even-loop

js语言特点

  • 单线程
  • 解释性语言

event-loop事件循环机制 由三部分组成

  • 调用栈
  • 微任务队列
  • 消息队列

even-loop开始时会从全局一行一行的执行 遇到函数调用 会压入到调用栈当中 被压入的函数被称之为帧 当函数返回后会从调用栈中弹出

js中的异步操作 比如 fetch setTimeout setInterval 压入到调用栈中的时候里面的消息会进入到消息队列中去 消息队列中的会等到调用栈清空后再执行

promise async await的异步操作的时候会加入到微任务中去 会在调用栈清空时立即执行
调用栈中加入的微任务会立马执行
在这里插入图片描述

BFC

BFC的理解

块级格式化上下文,它是指一个独立的块级渲染区域,只有Block-level BOX(块级盒子)参与,该区域拥有一套渲染规则来约束块级盒子的布局,且与外部区域无关

从一个现象开始说起

  • 一个盒子不设置height,当内容元素都浮动时,无法撑起自身
    那么这个盒子没有bfc

如何创建BFC

  • float的 不为 none
  • position 不为 static或relative
  • display 为 iinline-block,flex,inline-flex
  • overflow 为 hidden

BFC的其他作用

  • 取消盒子margin塌陷
  • 阻止元素被浮动元素覆盖

margin塌陷
在这里插入图片描述
想要的是子盒子距离父盒子有个上边距,可是父盒子一起被带下来了
父元素身上加上overflow: hidden; 开启BFC 就解决了margin塌陷的问题

阻止元素被浮动元素覆盖
在这里插入图片描述
蓝色的浮动元素遮挡了红色盒子,给红色设置overflow:hidden;解决被覆盖的问题

深拷贝浅拷贝

前置知识

数据存储

  • 一般数据类型
    number string boolean null undefined Symbol
  • 引用数据类型
    object array Set Map

一般数据类型都是存储在栈里面的 包括它的名字和值
而复杂类型 比如对象 它的名字是放在栈里面的但是它真正的内容是放在堆里面的
栈里面只是存放了它的引用
在这里插入图片描述

赋值和浅拷贝的区别

赋值 赋值的对象和原来的对象引用的是同一个,改变当前的原对象也会变

浅拷贝

  • 创建的是一个新对象
  • 拷贝值(如果属性是一般数据类型 拷贝的就是基本类型的值 ; 如果属性是引用数据类型 那么拷贝的就是内存的地址)
        var num = 123
        var person = {
    
    name:'张三'}

        var person1 = person
        person1.name = '李四'
        console.log(person.name);  //李四
        console.log(person1.name); //李四
        // 上面的代码是浅拷贝吗?
        // 不是浅拷贝 上面的操作是赋值

        // 浅拷贝
        // 创建一个新的对象
        // 层次的理解
        // 拷贝值 (如果属性是一般数据类型 拷贝的是基本数据类型 
        // 如果属性是引用数据类型 那么拷贝的就是内存的地址)
        // 说的直白一点 浅拷贝如果碰到的是引用数据类型 那么拷贝前和拷贝后是相互影响的

        // 深拷贝
        // 如果属性是引用类型,那么就会开辟一个新的空间
        var person3 = {
    
    name1:'张三',name2:'张三222',name3:'张三333',hobby:['篮球','足球']}

        function shallowClone(source){
    
    
            var newObj = {
    
    }
            for (var i in source){
    
    
                // console.log('i',i);
                if(source.hasOwnProperty(i)){
    
    
                    newObj[i] = source[i]
                }
            }
            return newObj
        }
        person4 = shallowClone(person3)
        // person5 = deepClone(person3)
        person4.name1 = '李四'
        person4.hobby[1] = '冰球'
        // person4.hobby = '冰球'
        // console.log(person5); 
        console.log(person4); 
       console.log(person3); 

        // 这里使用的hasOwnProperty的原因是:
        // for in 会遍历到原型链上的属性,所以要用这个判断,遍历到的属性是不是确实在source对象上面的
        // hasOwnProperty(属性名)确认该属性是否是其对象的自有属性,若是则返回true

在这里插入图片描述

深浅拷贝的应用场景

vue增删改查中的修改用到了深浅拷贝

前后端交互跨域处理

代理必须弄清楚弄明白
代理后地址前面会多出/api 有两种解决方案
在这里插入图片描述
1 后端接口前加/api
在这里插入图片描述
2 前端加上rewrite

在这里插入图片描述

utils - storage.js 里面是对localstorge的封装
vuex是持久化存储吗 页面刷新后会丢失吗

优化条件语句大厂面试题

在这里插入图片描述

 function printAnimalsDetails({
     
     type,name,gender}={
     
     }){
    
    
           if(!type) return 'no animal type'
           if (!name) return 'no animal name'
           if(!gender) return 'no animal gender'
           return `${
      
      name} is ${
      
      gender} - ${
      
      type}`
        }
        console.log(printAnimalsDetails({
    
    name:'zhangsan'}));
        console.log(printAnimalsDetails({
    
    name:'zhangsan',type:'gg',gender:'nan'}));
        console.log(printAnimalsDetails());

tips: vscode如何设置ctrl+滚轮缩放
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_51867622/article/details/129179965
今日推荐