1.函数懒加载

如:判断当前环境是否微信

function isWechat() {const result =typeof wx === "object" &&navigator.userAgent.match(/MicroMessenger/i) == "micromessenger";// 改写函数,直接返回结果,下次运行则无须经过重重判断了;isWechat = function () {return result;};return result;
}

以上写法会产生闭包,result 变量不会被释放,以下针对此问题进行改造:

function isWechat() {const result =typeof wx === "object" &&navigator.userAgent.match(/MicroMessenger/i) == "micromessenger";if (result) {isWechat = function () {// 返回的是字面量而不是变量return true;}} else {isWechat = function () {return false;}}return result;
}

2.赋值立即执行函数

const obj = {// 赋值可以写成立即执行函数,这样不仅仅局限于三元运算符了prop: (function() {....return value;}())
}

3.闭包的应用

如:单请求限制

真实业务场景,如微信小程序的登录,当打开某个页面,用户 token 若过期,该页面所有接口都会 401,此时应发起登录,但需要避免多个接口的 401 触发多次登录请求,解决办法,可参考以下代码

const handleLogin = (function () {let promise;return function () {// 返回请求的promiseif(promise) return promise;promise = loginApi({...}).finally(() => {// 请求响应后,需要清空promise// 避免下次再发起登录出问题,同时也释放了变量promise = null;})return promise;}
}())

以上闭包的应用,单例模式的设计实现也类似

3.1 闭包应用-请求结果缓存

以下请求缓存的封装可直接 copy 使用哦; 包含请求结果缓存、相同请求单一限制、最大缓存接口数控制。

// 最多缓存接口数
const CACHE_MAX = 20;
const cache = (function () {const cache = {};const cacheArr = [];return {get: function (params) {const uniKey = JSON.stringify(params);return new Promise((resolve, reject) => {if (cache[uniKey]) {// promise特性,如果resolve出去的是一个promise,则会替代外层promiseresolve(cache[uniKey]);} else {const promise = getRequest(params).then((res) => {if (cacheArr.length > CACHE_MAX) {const _api = cacheArr.shift();this.remove(_api);}this.set(uniKey, res);resolve(res);return res;}).catch((err) => {reject(err);});// 此处还做了单请求限制return (cache[uniKey] = promise);}});},set: function (uniKey, data) {cache[uniKey] = data;cacheArr.push(uniKey);},remove: function (uniKey) {// 释放内存cache[uniKey] = null;delete cache[uniKey];},};
}());

4.函数结果缓存

对于一些计算需要耗费较大的性能的纯函数,我们可以针对参数进行结果缓存

function _sin(value) {return Math.sin(value);
}const _sin = (function () {// 利用闭包创建缓存空间const cache = {};return function (value) {// 缓存中有,则从缓存中拿if (cache[value]) return cache[value];// 存入缓存并返回结果return (cache[value] = Math.sin(value));};
})();

4.1 函数结果缓存的简单封装:

function fnCache(fn) {const cache = {};return function (...args) {// 将参数变为字符串,作为缓存keyconst key = JSON.stringify(args);if(key in cache) {return cache[key];}return cache[key] = fn.apply(this, args);}
}
// 用法示例:
function sum() { ...}
const cacheSum = fnCache(sum);// 我们还可以将key的生成方式暴露出去
function fnCache(fn, keyCreator) {const cache = {};return function (...args) {// 优先自定义的key生成函数const key = keyCreator ? keyCreator(args) : JSON.stringify(args);if(key in cache) {return cache[key];}return cache[key] = fn.apply(this, args);}
}

5.compose

compose函数应用广泛,一般用于控制程序流程; 假如有这样一个场景,需要对传入的参数依次进行:取绝对值,取整,再平方;你可能会这么写:

function abs(value) {return Math.abs(value);
}
function floor(value) {return Math.floor(value);
}
function square(value) {return value ** 2;
}
const result = square(floor(abs(-2.4)));

这么写存在一定的弊端,假如需要改变一下函数执行顺序或增加一个流程,都会很困难;

compose改写:

function compose(...fns) {return fns.reduce((a, b) => (...args) => a(b(...args)))
}
function abs(value) {return Math.abs(value);
}
function floor(value) {return Math.floor(value);
}
function square(value) {return value ** 2;
}
const result = compose(square, floor, abs)(2.4);

可以看到经过compose改造,现在可以很简单对流程进行修改或增加了;悄悄告诉你,其实这就是redux中间件的核销源码哦

异步compose

讲完同步的,咱们再来讲异步的

function fn1(next) {console.log(1);next();
}
function fn2(next) {console.log(2);next();
}
function fn3(next) {console.log(3);next();
}
function compose(...chain) {function exec(index) {if (index == chain.length) return;let current;current = chain[index];return current(() => exec(++index))}// 初始从第1个函数开始执行exec(0);
};
compose(fn1, fn2, fn3);

核心原理是通过传递next给每个函数,函数内部自行控制什么时候往下执行;再悄悄告诉你哦,其实koa的核心与此类似哦;

对于compose的封装,webpack提供了tapable库,里面封装了各种针对同步、异步的compose的封装,感兴趣的可以自行查阅。

6.Promise 实现 chain,将请求变成串行

let promise = Promise.resolve();const tasks = [request1, request2, request3];tasks.forEach((request) => {promise = promise.then(() => request());
});promise.then((res) => {// 执行到这里表示请求已经串行执行完成
});

7.usePromise

假如有这个一个场景,父组件需要在两个子组件获取完请求结果后做些什么

function usePromise() {let resolve,reject;// Promise的回调函数参数会被同步执行const promise = new Promsie((_resolve, _reject) => {resolve = _resolve;reject = _reject;})return {promise,resolve,reject}
}<Child1 @on-got-data="child1Promise.resolve"/>
<Child2 @on-got-data="child2Promise.resolve"/>const child1Promise = usePromise();
const child2Promise = usePromise();Promise.allSettled([child1Promise.promise,child2Promise.promise
]).then(() => {// 执行到这里表示Child1、Child2都已经派发过on-got-data事件
})

以上写法算是一个怪招,只是提供一下 promise 的思路,不太建议使用,因为不止会产生闭包,而且当 promise 一直没有结果时,会一直占用内存。

8.函数缺省值,及必填限制

// 使用或运算设置缺省值
function fn(a) {a = a || 1;
}// 使用es6函数参数默认值
function fn(a = 1) {}// 当a未传入,则为触发赋值默认值,导致抛出错误
function triggerError(key) {throw new Error(`缺少必填参数${key}`);
}
function fn(a = triggerError("a")) {}

9.使用箭头函数简化代码

// 将[1,2,3]每个值+1// 原始写法
[1, 2, 3].map(function (item) {return item + 1;
})// es6箭头函数,可以省掉return
[1, 2, 3].map((item) => item + 1)// return 对象的简化写法
[1, 2, 3].map((item) => { value: item }) // 这样写大括号内会被当成函数体!
[(1, 2, 3)].map((item) => ({ value: item })); // 用括号括起来就解决啦

10.访问对象深层属性,避免报错

const obj = {info: undefined,
};// 假如我们要访问obj.info.name属性,此时直接访问则为报错// 1.if判断:
let name;
if (obj.info) {name = obj.info.name;
}// 2.或运算,注意需要将或运算内容括起来
let name = (obj.info || {}).name;// 3.可选链,新特性,需要考虑兼容性
let name = obj?.info?.name;

11.短路语句

function fn(callback) {callback && callback();
}

12.创建[1,2,3]数组

const arr = [...new Array(3).keys()];

13.截断、清空数组

// 截断
// 1
arr = arr.slice(0, 3);// 2
arr.length = 3;// 清空数组
// 1
arr = [];// 2
arr.splice(0, arr.length);// 3
arr.length = 0;

14.数组乱序

arr.sort(() => Math.random() - 0.5);

15.数组去重

// 1.双循环
// 其他比如for+for、for+includes等,都可以归类于双循环
function unique(arr) {return arr.filter((item, index) => arr.indexOf(item) === index);
}// 2.hash(对象属性唯一的特点)
function unique(arr) {const obj = Object.create(null);const res = [];for (let i = 0; i < arr.length; i++) {if (!obj[arr[i]]) {res.push(arr[i]);obj[arr[i]] = true;}}return res;
}// 3.Set
function unique(arr) {return [...new Set(arr)];
}

16.限制最大最小值

// 1.三元运算
const num = 10;
const result = num > 5 ? 5 : num;// 2.Math.min
const num = 10;
const result = Math.min(num, 5);

17.字符串补 0

// 1
let day = "9";
("00" + day).slice(-2); // 09// 2
let day = "9";
day.padStart(2, "0");

18.获取当前时间戳

// 1
new Date().getTime();// 2
+new Date();// 3
Date.now();

19.交换两个值

let num1 = 1;
let num2 = 2;
[num1, num2] = [num2, num1];

20.对象、数组克隆

// 浅克隆对象
const obj = { a: 1, b: 2, o: { c: 3 } };
const cloneObj1 = { ...obj1 };
const cloneObj2 = Object.assign({}, obj1);// 浅克隆数组
const arr = [1, 2, 3];
const cloneArr1 = [...arr1];
const cloneArr2 = arr1.slice(0);// 深克隆,这种方式最简单,只不过缺点也很多
const cloneObj3 = JSON.parse(JSON.stringify(obj));

21.去除数组假值

const arr = [false, "", null, undefined, 0];
arr.filter(Boolean); // 一行搞定,需要注意的是,0也会被过滤掉

22.干掉 if

// 假如有这样一段代码
if (type === "success") {return "green";
}
if (type === "warning") {return "yellow";
}
if (type === "error") {return "red";
}// switch改造
switch (type) {case "success":return "green";case "warning":return "yellow";case "error":return "red";
}// 对象映射改造
const typeMap = {success: "green",warning: "yellow",error: "red",
};
return typeMap[type];

以上是对于特别简单的情况下去除if,真正的能干掉if,还得是设计模式,设计模式yyds!

关于JS的20多个小技巧相关推荐

  1. Android 4.0操作系统的20个使用小技巧

    为什么80%的码农都做不了架构师?>>>    安卓4.0操作系统,它的一大卖点就是整合所有硬件的使用体验,无论是低端智能手机还是高端智能手机,只要运行Android ICS操作系统 ...

  2. goland 20.1.1小技巧

    golang 20.1.1小技巧磨刀不误砍柴工 版本号: Year.Major.Minor             2020   1        1 在命令行使用goland: 使用过vscode的 ...

  3. 分享一个为js生成PDF添加水印的小技巧

    分享一个为js生成PDF添加水印的小技巧 程序员工作中有时我们会遇到这样的情况--客户为了生成档案的版权问题,要为生成的文本 或者页面添加版权水印,以HTML代码页面生成PDF文件为例,介绍一下添加水 ...

  4. Windows XP的20个特殊小技巧

    Windows XP的20个特殊小技巧 Windows系统中总有无尽的技巧可以供我们发掘,每次都有惊喜.看看这次给大家带来了什么? 1.在记事本中自动记录文件的打开时间 在记事本中,我们可以记录每次打 ...

  5. css 自动换行_前端必备!20个CSS小技巧

    在日常学习和工作中,你是否经常觉得时间不够用?为了帮助你提高效率,今天,就为大家分享一些CSS小技巧,如果你感觉有用,也可以收藏与分享给你的小伙伴们~ 1. 文字水平居中 将一段文字置于容器的水平中点 ...

  6. 不用AJAX实现前台JS调用后台C#方法(小技巧)

    纯属小技巧,高手见笑了. 一提到如何在前台JS调用后台C#方法,AJAX成为了必然的想法. 只是实现的细节采用AJAX 1.0或者AjaxPro的区别. 其实如果不用AJAX,我们也能够很方便地利用J ...

  7. html使用js的变量_JS变异小技巧:使用JavaScript全局变量绕过XSS过滤器

    什么是JavaScript全局变量? JavaScript全局变量在函数外部声明或使用window对象声明,它可以通过任何函数访问. 假设你的目标Web应用程序容易受到映射到JavaScript字符串 ...

  8. JavaScript笔记-使用JS管理URL链接(前端小技巧)

    如下这个JavaScript代码: var common_ops = {buildUrl:function( path ,params ){//params = { "test": ...

  9. 写给Node.js新手的7个小技巧

    一些我更愿意在开始就知道东西 利用 Node.js 开发是一个非常有趣,和令人满足的过程, 他有3万多个模块可以选择使用,并且所有的模块可以非常容易的集成入现有的应用之中. 无论如何,对于一些刚开始使 ...

最新文章

  1. Python fabric实现远程操作和部署
  2. StringUtils工具类的常用方法
  3. [CCF] 201612-2 工资计算
  4. .NET Core 使用RSA算法 加密/解密/签名/验证签名
  5. 前端性能优化之性能测试
  6. SSM 整合 3:一个 Spring 入门程序带你来了解什么是控制反转(IoC)/依赖注入(DI)!
  7. topcoder srm 661 div1
  8. oracle解压后不能运行,求救:oracle10安装后net Manager等工具无法启动
  9. 用easyx画电子钟_实时钟表 · Joker/EasyX - Gitee.com
  10. Android MVP开发模式及Retrofit + RxJava封装
  11. Generalised Dice Overlap as a Deep Learning Loss Function for Highly Unbalanced Segmentations
  12. Java线程状态转换
  13. webservice测试工具
  14. JM8.6之参考图像管理
  15. 卡耐基梅隆大学计算机科学课本,美国卡耐基梅隆大学计算机科学硕士.pdf
  16. 杨海朝 mysql_老男孩Mysql高级DBA 实战新浪首席DBA 老男孩教育杨海朝老师全程主讲 老男孩Mysql视频...
  17. 浅析嵌入式开发中的RAM和ROM
  18. Android英文名词
  19. 电子标签与电子标签库存管理
  20. Java 异步响应servlet_java – 使用jersey流式传输大型响应,异步

热门文章

  1. Fiddler抓包Android手机https、http教程
  2. 高效学习-笔记-左耳听风
  3. 工控前辈经验之谈 | 编写PLC程序我从做Excel表开始
  4. 训练大规模对比学习的一些小笔记
  5. android-检测耳机的插入和拔出动作
  6. 【学术篇】不知道该起啥标题了怎么办OvO
  7. 大型电子商务平台架构
  8. 微信开放平台 错误码61007: api is unauthorized to component
  9. 校园导游系统数据结构课程设计(附完整代码)
  10. Html页脚声明,HTML创建与页脚和页眉和内容