项目里面的前端鉴权是怎么实现的?
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设计模式与开发实践》一书中说了分辨模式的关键是意图而不是结构。
如果以结构来分辨模式,发布订阅模式相比观察者模式多了一个中间件订阅器,所以发布订阅模式是不同于观察者模式的;如果以意图来分辨模式,他们都是实现了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新,那么他们就是同一种模式,发布订阅模式是在观察者模式的基础上做的优化升级。
不过,不管他们是不是同一个设计模式,他们的实现方式确实有差别,我们在使用的时候应该根据场景来判断选择哪个
类数组和数组
- 类数组
- 拥有length属性,其他属性(索引)为非负整数(对象中的索引会被当做字符串来处理)
- 不具有数组所具有的方法
判断是否是数组
function isLikeArray(o) {
if(typeof o === 'object' && isFinite(o.length) && o.length >= 0 && o.length < 4294967296) {
// 4294967296: 2^32
return true
}else {
return false
}
}
- 类数组转换为数组
- Array.from方法转为数组,不支持就用Array.prototype.slice方法替代
const toArray = (() => Array.from ? Array.from : obj => [].slice.call(obj))
- 数组
类数组和数组的区别
- instanceof
- constructor
- toString
- isArray()
Document
- 1
- 2
- 3
- 4
- 5
- 6
apply小妙用
- 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
- 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]