美文网首页前端面试整理
2019末前端面试整理

2019末前端面试整理

作者: aimee9004 | 来源:发表于2020-01-06 22:35 被阅读0次

    项目里面的前端鉴权是怎么实现的?

    1. session-cookie

    将登录的用户名和密码发送给后端,后端生成session,然后保存session生成唯一标识字符串,在响应头种下这个唯一标识字符串,返回给前端,前端将唯一标识字符串保存到cookie中,下次再发送http请求时带上该域名下的cookie信息,服务端解析请求头cookie中的唯一标识,然后根据唯一标识查找保存该客户端的session,并判断是否合法。

    2. token

    客户端使用用户名和密码登录,服务端接受请求,验证用户名和密码,验证成功后,签发一个token,发送给客户端,客户端收到token后保存起来,以后每次请求都带上签发的token

    3. OAuth(开放授权)

    支付宝、微信、QQ登录

    手写函数防抖和函数节流

    1. 函数防抖的应用场景(debounce)

    连续的事件,只需触发一次回调的场景有:

    • 搜索框搜索输入。只需用户最后一次输入完,再发送请求
    • 输入框内容校验等操作时
    • 窗口的resize、scroll。只需窗口调整完成后计算。防止重复渲染
    2. 函数节流的应用场景(throttle)

    间隔一段时间执行一次回调的场景有:

    • 滚动加载,加载更多或滚到底部监听
    • 谷歌搜索框,搜索联想功能
    • 高频点击提交,表单重复提交
    // 函数防抖
    /*
    *eg:当持续触发scroll事件时,事件处理函数handle只在停止滚动1000毫秒之后才会调用一次,也就是说在持续触发scroll事件的过程中,事件处理函数handle一直没有执行。
    */
    const _.debouce = (func, wait) => {
      let timer;
      return () => {
        clearTimeOut(timer)
        timer = setTimeout(func, wait)
      }
    }
    // 函数节流
    const _.throttle = (func, wait) => {
      let timer;
      return () => {
        if(timer) {
          return;
        }
        timer = setTimeout(() => {
          func();
          timer = null;
        }, wait)
      }
    }
    
    3. 总结

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

    函数节流:使得一定时间内只触发一次函数。原理是通过判断是否到达一定时间来触发函数。

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

    创建对象都有哪几种方式

    1. 字面量的方式
    // 字面量形式
    var student = {
      name: '易烊千玺',
      type: 'TFBoys',
      like: '跳舞,书法',
      dancing: function() {
        console.log('跳舞很棒')
      }
    }
    console.log(student)
    student.dancing()
    

    优点:写起来简单方便
    缺点:如果要生成大量的类似对象,将会写一堆重复的代码

    2. 工厂模式
    // 工厂模式
    function Student(name, type, like) {
      return {
        name: name,
        type: type,
        like: like,
        dancing: function() {
          console.log('跳舞很棒')
        }
      }
    }
    var s1 = Student('易烊千玺', '艺术家', '跳舞')
    console.log(s1)
    

    优点:可以快速生成批量的对象
    缺点:每创建一个对象,都会生成一个一模一样的方法(函数),会占内存

    3. 构造函数创建对象
    // 构造函数
    function Teacher() {
      this.name = '苏老师';
      this.type = '老师';
      /*this.movies = function() {
        console.log('拍电影')
      }*/
    }
    // 设置创建对象的原型函数
    Teacher.prototype.movies = function() {
      console.log('拍电影1')
    }
    // 如果不用new来构建函数,那么就是一个普通函数调用,并且this的指向是window
    // 用new创建一个新的对象,this指向t1
    var t1 = new Teacher()
    console.log(t1)
    

    原型链:原型上不断继承原型,从而形成原型链

    4. ES6的class写法
    class Cat {
      constructor() {
        this.name = '波斯猫'
      }
      run() {
        console.log('会跑')
      }
      say() {
        console.log('喵喵喵')
      }
    }
    var c1 = new Cat()
    console.log(c1)
    typeof Cat // "function"
    

    事件对象

    每个事件调用的执行函数,都会默认传入一个事件对象,这个对象会包含当次事件的相关信息

    • 冒泡事件
      事件由里面一层一层向上触发,直到HTML元素,这种事件模式就是冒泡事件。
    • 捕获事件
      由HTML开始一层一层向下触发,直到最小的子元素,这种事件模式就是捕获

    发布订阅模式(Pub-Sub Pattern)与观察者模式(Observer Pattern)

    • 观察者模式: 观察者(Observer)直接订阅(Subscribe)主题(Subject),而当主题被激活的时候,会触发(Fire Event)观察者里的事件。
    // 被观察者
    class Subject {
      constructor() {
        this.observers = []    // 观察者队列
      }
      addObserver(observer) {
        this.observers.push(observer)    // 往观察者队列 添加观察者
      }
      notify() {    // 通知所有观察者,实际上是把观察者的update()都执行了一遍
        this.observers.forEach(observer => {
          observer.update()    // 依次取出观察者,并执行观察者的update方法
        })
      }
    }
    var subject = new Subject()    // 被观察者
    const update = () => {
      console.log('被观察者发出通知')    // 收到广播时要执行的方法
    }
    var ob1 = new Observer(update)    // 观察者1
    var ob2 = new Observer(update)    // 观察者2
    subject.addObserver(ob1)    // 观察者1订阅subject的通知
    subject.addObserver(ob2)    // 观察者2订阅subject的通知
    subject.notify()    // 发出广播,执行所有观察者的update方法
    
    • 发布订阅模式: 订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Topic),当发布者(Publisher)发布该事件(Publish topic)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。
      有事件调度中心

    观察者模式是不是发布订阅模式?
    辨别模式的关键是设计意图还是设计结构(理念),虽然《JavaScript设计模式与开发实践》一书中说了分辨模式的关键是意图而不是结构。
    如果以结构来分辨模式,发布订阅模式相比观察者模式多了一个中间件订阅器,所以发布订阅模式是不同于观察者模式的;如果以意图来分辨模式,他们都是实现了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新,那么他们就是同一种模式,发布订阅模式是在观察者模式的基础上做的优化升级。
    不过,不管他们是不是同一个设计模式,他们的实现方式确实有差别,我们在使用的时候应该根据场景来判断选择哪个

    类数组和数组

    • 类数组
    1. 拥有length属性,其他属性(索引)为非负整数(对象中的索引会被当做字符串来处理)
    2. 不具有数组所具有的方法
      判断是否是数组
    function isLikeArray(o) {
      if(typeof o === 'object' && isFinite(o.length) && o.length >= 0 && o.length < 4294967296) {
        // 4294967296: 2^32
        return true
      }else {
        return false
      }
    }
    
    • 类数组转换为数组
    1. Array.from方法转为数组,不支持就用Array.prototype.slice方法替代
      const toArray = (() => Array.from ? Array.from : obj => [].slice.call(obj))
    • 数组

    类数组和数组的区别

    1. instanceof
    2. constructor
    3. toString
    4. isArray()
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Document</title>
    </head>
    <body>
        <ul id="list">
            <li>1</li>
            <li>2</li>
            <li>3</li>
            <li>4</li>
            <li>5</li>
            <li>6</li>
        </ul>
        <script type="text/javascript">
        // 获取所有li
        var lis = document.getElementsByTagName("li");
        // 定义数组
        var arr = [];
        // 请问有几种方式来区别类数组和数组?
         
        // typeof 用来判断类型 (是值类型还是引用类型) 返回的是一个字符串
      
        // 第一种方式 instanceof
        console.log(arr instanceof Array);
        console.log(lis instanceof Array);
      
        // 第二种方式
        console.log(arr.constructor === Array)
        console.log(lis.constructor === Array)
      
        // 第三种方式
        console.log(Object.prototype.toString.call(arr) === "[object Array]")
        console.log(Object.prototype.toString.call(lis) === "[object Array]")
      
        // 使用ES5提供的方法
        console.log(Array.isArray(arr))
        console.log(Array.isArray(lis))
        </script>
    </body>
    </html>
    

    apply小妙用

    1. Math.max实现得到数组中最大的一项
      因为Math.max 参数里面不支持Math.max([param1,param2]) 也就是数组 ,但是它支持Math.max(param1,param2,param3…)
      可以根据刚才apply的那个特点来解决
      var max=Math.max.apply(null,array),这样轻易的可以得到一个数组中最大的一项 (apply会将一个数组装换为一个参数接一个参数的传递给方法)
    Math.max(4,21,8,11,99)    // 99
    Math.max.apply(null, [4,21,8,11,99])    // 99
    
    1. Array.prototype.push可以实现两个数组合并
      同样push方法没有提供push一个数组,但是它提供了push(param1,param,…paramN);
      (当然也可以用arr1.concat(arr2),但是concat方法并不改变arr1本身,需要重新定义一个变量)
    var arr1 = [1, 2, 3]
    var arr2 = [11, 22, 33]
    Array.prototype.push.apply(arr1, arr2)
    // arr1: [1, 2, 3, 11, 22, 33]
    

    相关文章

      网友评论

        本文标题:2019末前端面试整理

        本文链接:https://www.haomeiwen.com/subject/hqefoctx.html