前端面试整理

2019末前端面试整理

2020-01-06  本文已影响0人  aimee9004

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

1. session-cookie

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

2. token

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

3. OAuth(开放授权)

支付宝、微信、QQ登录

手写函数防抖和函数节流

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

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

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"

事件对象

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

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

// 被观察者
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方法

观察者模式是不是发布订阅模式?
辨别模式的关键是设计意图还是设计结构(理念),虽然《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]
上一篇下一篇

猜你喜欢

热点阅读