1. 手写节流、防抖
节流【相当与技能冷却中,或者用户频繁点击按钮】
//假设你要实现技能冷却中,要怎么实现? //假设你要调用闪现,但是在闪现过程中的120秒内你再次调用闪现,不会做任何事情,因为正在冷却中 const d=(distance)=>{ //闪现的函数 console.log('闪现') }, //实现任意函数的节流 const abcFn=(f,time)=>{ let timer=null; let lengQue=false; return (...args)=>{ if(lengQue){ return }else{ f(...args);//调用闪现的函数 lengQue=true; timer=setTimeout(() => { // 方法区 lengQue= false; timer=null }, time); } } } //调用函数 const da=abcFn(d,120*1000)
防抖【相当于回城,或者拖动页面时】
//打断后重新计时 const f=()=>{ console.log('回城成功'); } const debounce=(f,time)=>{ let timer=null; return (...args)=>{ if(timer!=null){ clearTimerout(timer); //清空timer }else{ timer=setTimerout(()=>{ f(...args); timer=null },time) } } } //调用 const tp=debounce(f,3000) tp(); //3秒之后才会‘回城成功’
2. 手写发布订阅
发布订阅是非常著名的设计模式。
例如:你刷博客之类的,遇到感兴趣的会去关住他,去看他的内容,但他下次发布新内容时,网站会通过一些方法通知到我们,我们也会在第一时间了解到这些新内容,但至于会不会第一时间去看就起决于我们自己了。
const eventHub={ //queue:[] //一般使用q来代表数组 queueMap:{}, //在js里用空对象表示哈希表 on:(name,fn)=>{ eventHub.queueMap[name]=eventHub.map[name]||[];//取他的第name个,如果是空的就初始化(取后面 的 值) eventHub.queueMap[name].push(fn) //return undefined }, emit:(name,data)=>{ //把队列里的东西调用一下 const q=eventHub.queueMap[name] if(!q){return} //判断是否为空,若为空,就短路了什么也不用做 q.map(f=>f(data) //遍历。foreach、map但map有返回值 return undefined}, off:(name,fn)=>{ //这是只是读,可以给eventHub.queueMap[name]做别名 if(!eventHub.queueMap[name]){return} const index=eventHub.map[name].indexOf(fn) if(index<0){return } //短路法 eventHub.map[name].splice(index,1) //splice 是设置要删除的索引 } } //监听两次click,调用两次函数 eventHub.on('click',console.log) eventHub.on('click',console.error) //3秒钟后触发click setTimeout(()=>{ eventHub.emit('click','frank') },3000)
3. 深浅拷贝
- 浅拷贝:只拷贝一层 object.assign(target,sources);
- 深拷贝:不会只传地址,而会开辟一个新的空间,复制给另一个空间,拷贝完的空间给了要赋值的那个
// 手写深拷贝 var obj = { id: 1, name: 'andy', msg: { //这是对象 age: 18 }, color: ['pink', 'red'] //这是数组 }; var o = {}; //封装一个函数 function deepCp(newobj, oldobj) { //先遍历一遍obj for (var k in oldobj) { //我们要判断属性值是属于哪一种类型 //所以,第一步:获取属性值 var item = oldobj[k]; //第二步:判断这个值是不是数组 if (item instanceof Array) { newobj[k] = []; deepCp(newobj[k], item); } else if (item instanceof Object) { //第三步:判断是不是对象类型 newobj[k] = {}; deepCp(newobj[k], item); //运用递归,把原对象属性值给新对象 } else { //第四步:如果都不是,这就是简单数据类型,直接复制就可 newobj[k] = item; } } } deepCp(o, obj); //调用函数 //解答:为什么先判断是不是数组后判断是不是对象,因为对象包括数组
4. promise
(1) 地址:ES6 入门教程
(2) 概念:promise 是异步编程的一种解决方案。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。promsie 一旦创建会立即执行,无法中途取消。promsie对象必须返回then方法。可以说then方法是promise的核心。一个promise对象可以注册多个then方法,且回调函数返回的顺序和注册的顺序保持一致。
(3) 三种状态:pending (进行中) resoloved (已完成) rejected (已失败)
(4) 基本用法:
const promise = new Promise(function(resolve, reject) { // ... some code if (/* 异步操作成功 */){ resolve(value); } else { reject(error); } }); promise .then(function (a){}) .catch(function(error){}) .finally(()=>{}) ps: finally优点: 1)成功和失败的情况只需要写一次; 2)会返回原来的值
(5) 常用方法:
5.1 Promise.all([p1,p2])
1)都返回resolve(); 才能够拿到成功的返回值;
2)有一个返回reject(), 则进入catch(error), 拿到失败的返回值。
//手写promise.all let list=[1,3,5,6,4] promise.myall=function(list){ const results=[]; let count=0; return new promise((resolve,reject)=>{ list.map((item,index)=>{ item.then(result=>{ results[index]=result; count+=1; if(count>=list.length){resolve(results)} },reason=>reject(reason)) }) }) }
5.2 promise.race([p1,p2,p3])
只要
p1
、p2
、p3
之中有一个实例率先改变状态,p
的状态就跟着改变。那个率先改变的 Promise 实例的返回值,就传递给p
的回调函数。5.3 promise.allSettled()
只有等到参数数组的所有 Promise 对象都发生状态变更(不管是
fulfilled
还是rejected
),返回的 Promise 对象才会发生状态变更。5.4 promsie.any()
Promise.any()
跟Promise.race()
方法很像,只有一点不同,就是Promise.any()
不会因为某个 Promise 变成rejected
状态而结束,必须等到所有参数 Promise 变成rejected
状态才会结束.
5. 扩展运算符
对象扩展运算符 (...)
let ab={a:"erer",b:123}; let ac={... ab}; // 等价于 let ac=Object.assign({},ab) console.log(ac); //{a: 'erer', b: 123}
6.手写ajax
//首先申明一个对象 var xhr =new XMLHttpRequest() //发请求发到哪个地方呢(路径) xhr.open('GET','/XXX') //监听onreadystatechange事件 xhr.onreadystatechange=function() { if (xhr.readyState == 4) //4是下载操作已完成 { //看它的状态码,如果在这个区间内说明成功了 if (xhr.status >= 200 && xhr.status < 300||xhr.status===304) { success(xhr) } else { fail(xhr) } } }; //一般是全都设置好之后再发送,所以习惯吧send写在最下面 //设置请求体,get一般是空的,post是传一个json数据 xhr.send('{"name":"frank"}')