Javascript进阶专题总结(函数、异步编程、设计模式)
函数式编程什么时候用
编程方法:函数式(js),面向对象(java,c++),命令式
函数式(工具式操作)
优点:JavaScript种函数是一等公民,便于拆分组合可扩展性好,方便tree-shaking
缺点:管理难度大,复杂逻辑难以组织,模块难以划分
function c1() {console.log(1);
}
推荐应用函数式编程:
- 工具型库 工具库 loadsh underscore 项目重要的基础设置之一
- 第三方库 造一个库(轮子) 推广出去给很多项目使用 必然会有大量不需要的方法(方便tree-shaking)
工具库组成部分
- 一些常见的window操作 cookies 内核
- 一些常见的数据操作
- 一些业务面常见操作
// 纯函数方法
// window层面操作
export function setCookies() {}
export function getCookies() {}
// 常用数据操作
export function filtersame() {}
// 业务面常见操作
// 例:经常更新token
export function updateToken() {}
面向对象式(具体功能,业务逻辑)
优点:模块分明,逻辑清晰,方便组织庞大业务
缺点:不好配合tree-shaking,JavaScript对于面向对象实现不完美
function class1() {}
class1.prototype.f1 = function () {console.log(1);
}
为什么要管理异步(异步目的)
确保执行顺序
异步作为JavaScript的特产,他一定程度上弥补了JavaScript单线程的问题。但是也带来了执行顺序的问题。
所以我们需要确保我们方法得执行按顺序来。此外有的时候我们可能不知道一个操作是同步还是异步。用一个promise绝对不会错。
做异步的一个技巧
- 先梳理执行顺序,然后再通过异步知识安排执行
- 回调函数promise化
// 验证
// 1.验证是否是纯数字(同步)
function testNumber() {}
// 2.请求后端,这个数字是否存在(异步)
function back() {}
// 3.请求第三方,验证是否合格(异步)
function other() {}
// 需顺序执行
testNumber();
back();
other();
// 我要做这个事情有哪些步骤,这些步骤有没有异步,
// 要完成这个操作逻辑顺序是什么,然后组织代码按顺序执行
var arr = [testNumber,back,other];
var promise = Promise.resolve();
// 依次执行数组
while(arr.length){promise = promise.then(arr.shift()).then(res=>{if(res.error) {break; }return res; })
}
async function run() {for(var i=0;i<arr.length;i++){var _result = await arr[i]();if(_result.error) {break; }}return _resulte
}
run().then((res)=>{})
// 回调函数promise化
// nodejs 回调
// 读取一个文件
// 梳理顺序:
// 1.拷贝文件夹read(创建一个readcopy文件夹)
// 2.读取readw文件夹
// 3.循环-》读取一个文件
// 4.写入readcopy
// 原生的回调函数
fs.mkdir("./readcopy", ()=>{fs.readdir("./read", (err, context) => {context.forEach((file) => {fs.readFile("./read/" + file, (err, context) => [fs.writeFile("./readcopy/" + file, context, () => {}) ]) }) })
})
// 改写chengpromise
// 先改一个
function readFilePromise(path) {return new Promise((resole, reject) => {fs.readFile(path,(err, context) => {if(err){reject(err) } resolve(context); }) })
}
// 调用
readFilePromise(path).then((res) => {})
// 当我们面对,需要大量的产出相似对象的时候-》工厂模式
function makePromise(fn) {var fn = fn;var handle = function (path, data) {return new Promise((resolve,reject) => {fn.call(this, path, function (err, content) {if(err){reject(err) } else {if(data) {resolve(data) }else{resolve(content) }}}) }) return handle;}return handle;
}
// 使用创建工厂
var dirPromise = makePromise(fs.readdir);
var readFilePromise = makePromise(fs.readFile);
var mkdirPromise = makePromise(fs.mkdir);
var copyDir = function(res){res.forEach((file) => {readFilePromise("./read/" + file).then((res)=>{fs.writeFile("./readcopy/" +file,res,()=>{}) }) })
}
Promise.resolve().then(mkdirPromise.bind(this, "./readcopy"))// bind 绑定参数.then(dirPromise(this, "./read")).then(copyDir)async function run() {var _result = await mkdirPromise.bind(this, "./readcopy")var context = await dirPromise.bind(this, "./read")copyDir(context);
}
设计模式分析
如何梳理模块
// 炒菜-》点单 收银-》传菜 服务-》厨师 前台 服务员
// 需求-》 实现这个需求,需要做那些事-》要实现这些事情,应该设计那些模块-》去写这些模块// 轮播图-》多种播放方式(渐显渐隐,左右切换,上下,百叶窗切换)
// 创建轮播图结构-》开始自动轮播-》播放方式算法-》控制它手动切换
// 轮播图初始化(创建轮播的结构,事件绑定) 轮播控制模块-》 轮播动画效果模块
轮播图整体类 :可以不用建造者模式(用个单纯的类)
播放效果mover(type): 策略模式
轮播效果模块(异步)-》(告诉第几张)轮播控制模块(观察者模式)
// 请为项目设计一个商品信息缓存器,需求描述如下:
// (1)可根据商品id判断商品是否加载过,如果加载过,直接从缓存里拿;如没有,则请求;
// (2)如果是热门商品,缓存于全局的对象里;
// 如果是非热门商品,则缓存于localStorage中;
// 全局对象和localStorage中的商品数量上限可以配置;
// (3)可主动调用api来更新某个商品的信息。// maxNum 最多缓存商品数,可以缓存maxNum个热门商品,maxNum个非热门商品
function Goods(maxNum) {if(Goods.install){return Goods.install;}this.hotGoods = {}localStorage.setItem("noHotGoods", "{}");this.maxNum = maxNum || 50;Goods.install = this;
}
Goods.install = null;
Goods.prototype.get = async function(id) {const goodData = nullconst noHotGoods = JSON.parse(localStorage.getItem("noHotGoods"))if (this.hotGoods[id]) {return this.hotGoods[id]} else if (noHotGoods[id]) {return noHotGoods[id]} else {goodData = await getGoodAjax(id)this.set(id, goodData) return goodData}
}
Goods.prototype.set = function(id, goodData) {/*if (goodData.isHot) {// 判断是否是热门商品const arr = Object.keys(this.hotGoods);if(this.maxNum === arr.length) {// console.log('热门商品缓存已达上限,删除第一个商品')delete this.hotGoods[arr[0]]}this.hotGoods[id] = goodData} else {const noHotGoods = JSON.parse(localStorage.getItem("noHotGoods"));const arr2 = Object.keys(noHotGoods);if(this.maxNum === arr2.length) {// console.log('非热门商品缓存已达上限,删除第一个商品')delete noHotGoods[arr2[0]]}noHotGoods[id] = goodDatalocalStorage.setItem("noHotGoods", JSON.stringify(noHotGoods));}*/let theGood = this.hotGoods;if (!goodData.isHot) {theGood = JSON.parse(localStorage.getItem("noHotGoods"));}const arr = Object.keys(theGood);if(this.maxNum === arr.length) delete theGood[arr[0]]theGood[id] = goodDataif (goodData.isHot) {this.hotGoods = theGood} else {localStorage.setItem("noHotGoods", JSON.stringify(theGood));}
}
var shopGoods = new Goods();
// 获取id=1的商品
var good1 = shopGoods.get(1);
// 更新id=1的商品信息
good1 = shopGoods.set(getGoodAjax(1));