js函数相关高级用法
一、惰性载入函数(lazy function)
使用场景:当一个函数中的判断分支只用执行一次(第一次调用时执行),后续不会再变化,则可以使用惰性函数来提高性能。
var addEvent = function(elem, type, handler) {
if (window.addEventListener) {
elem.addEventListener(type, handler, false);
}
else if (window.attachEvent) {
elem.attachEvent('on' + type, handler);
}
};
上面的函数是一个事件监听函数,每次调用时都会判断使用标准的事件监听函数还是IE事件监听函数,其实只用判断一次就可以知道该使用哪种监听函数,改为惰性函数的代码如下:
var addEvent=function(elem, type, handler){
if (window.addEventListener) {
addEvent=function(elem, type, handler){
elem.addEventListener(type, handler, false);
}
}
else if (window.attachEvent) {
addEvent=function(elem, type, handler){
elem.attachEvent(type, handler, false);
}
}
//当addEvent函数第一次被外部调用时,会被覆盖为另外的函数,但覆盖后的函数体的代码不会执行,因此需要执行一次
addEvent(elem,type,handler);
}
另一种方法是声明后立即给出合适的函数
var addEvent2=(function(elem, type, handler){
if (window.addEventListener) {
return function(elem, type, handler){
elem.addEventListener(type, handler, false);
}
}
else if (window.attachEvent) {
return function(elem, type, handler){
elem.attachEvent(type, handler, false);
}
}
})(document.body,'click',function(){
console.log('单击了');
})
console.log(addEvent2)
二、一次性函数(once function)
即只会执行一次的函数,核心思想是执行某个函数一次后将函数覆盖为null。
//一次执行函数的工厂
function once(fn,context){
var result;
return ()=>{
if(typeof(fn)==='function'){
result=fn.apply(context||this,arguments);
fn=null;
}
return result;
}
}
var canOnlyFireOnce=once(()=>{
console.log('测量屏幕宽度');
return {deviceWidth:'375px',deviceHeight:'480px'}
})
var deviceInfo=canOnlyFireOnce(); //输出“测量屏幕宽度”
var deviceInfo2=canOnlyFireOnce(); //不会输出任何东西
console.log(deviceInfo2);
三、记忆函数
核心思想:让一个函数记住处理过的参数,并可以根据相应的参数把结果缓存起来,避免重复计算。
实现方式:
1.使用闭包
function memoryFunction(fn){
var cacheArgs,cacheReturn;
return function(a){
if(a===cacheArgs){
return cacheReturn;
}
cacheArgs=a;
cacheReturn=fn.call(null,a);
return cacheReturn;
}
}
var demo=memoryFunction((a)=>a*1000);
var b=demo(1), c=demo(1);
console.log(b,c)
上面代码中,第二次调用demo函数时,直接返回值,不会再次计算
2.函数也是一个对象,因此可以动态的给函数增加静态的属来记录缓存键和结果
function isPrime(value) {
if (!isPrime.answers) {
isPrime.answers = {};
}
//创建缓存
if (isPrime.answers[value] !== undefined) {
return isPrime.answers[value];
}
//检查缓存键
var prime = value !== 0 && value !== 1; // 1 is not a prime
for (var i = 2; i < value; i++) {
if (value % i === 0) {
prime = false;
break;
}
}
//缓存计算的结果
return isPrime.answers[value] = prime;
}
四、纯函数(pure function)
所谓纯函数就是一个函数返回的结果只依赖于其参数,并且在执行过程中没有副作用,这样的函数就叫纯函数。
条件1:返回结果直依赖参数
const a = 1
const foo = (b) => a + b
foo(2) // => 3
上面的代码中,foo函数的返回值依赖了外部的a变理,因此不是纯函数
const a = 1
const foo = (x, b) => x + b
foo(1, 2) // => 3
上面的代码中,foo函数的返回值只跟其参数有关且没有副作用,因此是纯函数
条件2:执行过程没有副作用
什么是副作用?所谓副作用就是指函数执行过程中对外产生了可观察的变化。看例子
const a = 1
const counter = { x: 1 }
const foo = (obj, b) => {
obj.x = 2
return obj.x + b
}
foo(counter, 2) // => 4
counter.x // => 2
上面代码中foo
的结果只跟传入参数有关,但在内部加了一句 obj.x = 2
,计算前 counter.x
是 1,但是计算以后 counter.x
是 2。foo
函数的执行对外部的 counter
产生了影响,修改了外部传进来的对象,也就是产生了副作用,因此不是纯函数。
const a = 1
const counter = { x: 1 }
const foo = (obj, b) => {
return obj.x + b
}
foo(counter, 2) // => 3
counter.x // => 1
上面代码中foo的结果只跟传入的参数有关,且计算的过程里面并不会对传入的对象进行修改,计算前后的 counter
不会发生任何变化,计算前是 1,计算后也是 1,它现在是纯的。
下面的代码也是纯函数,因为对象是在函数内定义的,对外部不可见。
const foo = (b) => {
const obj = { x: 1 }
obj.x = 2
return obj.x + b
}
五、高阶函数(high order functions)
所谓高阶函数是这样一种函数:即可以把函数作为参数传递,或者返回的值是一个函数。
比如Array.Map,Array.Sort,还有我们上面写的一次性执行函数演示代码都是高阶函数。
六、组合函数(compose function)
作用:将需要嵌套执行的函数平铺。嵌套执行指的是,一个函数的返回值将作为另一个函数的参数。
function C(){
console.log('C')
return function(){
console.log('C函数回调执行')
}
}
function B(CM){
console.log('B')
return function(){
console.log('B函数回调执行')
CM()
}
}
function A(BM){
console.log('A')
return function(){
console.log('A函数回调执行')
BM()
}
}
A(B(C()))()
改为compose方式后调用如下;
compose(A,B,C)()
compose函数的实现:
function compose(...funcs) {
//没有传入函数参数,就返回一个默认函数(直接返回参数)
if (funcs.length === 0) {
return arg => arg
} if (funcs.length === 1) {
// 单元素数组时调用reduce,会直接返回该元素,不会执行callback;所以这里手动执行
return funcs[0]
}
// 依次拼凑执行函数
return funcs.reduce((prev, current) => (...args) => prev(current(...args)))
}
举例分析:compose(f4,f3,f2,f1)()
- reduce回调函数第一次执行时,返回值为 函数
(...args) => f4(f3(...args))
,作为下一次执行的prev参数 - 回调函数第二次执行时,返回值为 函数
(...args) => f4(f3(f2(...args)))
,作为下一次执行的prev参数 - 回调函数第三次执行时,返回值为 函数
(...args) => f4(f3(f2(f1(...args))))
七、函数柯里化(function currying)
把一个接收多个参数的函数分解成逐层调用的函数,每一层接收一部分参数,余下的参数由下一层再进行分解。
假如有如下函数:
function add(a,b,c,d,e){
return a+b+c+d+e;
}
console.log(add(1,2,3,4,5)); //15
现在要求每一步调用最多只能传2个参数,改写为柯里化版本如下:
function curryAdd(a,b){
return (c,d)=>{
return (e)=>{
return a+b+c+d+e;
}
}
}
console.log(curryAdd(1,2)(3,4)(5)); //15
看似把简单问题进行了复杂化,那么柯里化函数有什么作用呢?最大的用处就是可以固定不可变参数和可变参数,消除重复参数
function ajax(url,type,data){
// ...
}
ajax('www.my.com','GET')
ajax('www.my.com','POST')
//采化柯里化固定重复参数
let newAjax=curryAjax('www.my.com')
//只需要传入可变参数即可
newAjax('GET')
newAjax('POST')
八、防抖函数(debouncing)
核心思想:对同一个函数进行连续调用时,只有最后次调用生效,
实现方式:使用setTimeout方法,每次调用时,清除上一次的timer,并将本次的timer记录下来就可以保证只有最后一次调用会生效
function debounce(method,time){
var timer = null ;
return function(){
var context = this;
//在函数执行的时候先清除timer定时器;
if(timer)clearTimeout(timer);
timer = setTimeout(function(){
method.call(context);
},time);
}
}
九、节流函数(throttling)
核心思想:对同一个函数进行连续调用时,只有当上一次函数执行后过了你规定的时间间隔,才能进行下一次该函数的调用
实现方式:使用setTimeout方法,给定两个时间,后面的时间减去前面的时间,到达我们给定的时间就去触发一次这个事件
function throttle(method,time){
var timer = null;
var startTime = new Date();
return function(){
var context = this;
var endTime = new Date();
var resTime = endTime - startTime;
//判断大于等于我们给的时间采取执行函数;
if(resTime >= time){
method.call(context);
//执行完函数之后重置初始时间,等于最后一次触发的时间
startTime = endTime;
}
}
}
js函数相关高级用法的更多相关文章
- JS Replace() 高级用法(转)
在很多项目中,我们经常需要使用JS,在页面前面对前台的某些元素做做修改,js 的replace()方法就必不可少. 经常使用"ABCABCabc".replace("A& ...
- 再谈Newtonsoft.Json高级用法
上一篇Newtonsoft.Json高级用法发布以后收到挺多回复的,本篇将分享几点挺有用的知识点和最近项目中用到的一个新点进行说明,做为对上篇文章的补充. 阅读目录 动态改变属性序列化名称 枚举值序列 ...
- 细说 ASP.NET Cache 及其高级用法
许多做过程序性能优化的人,或者关注过程程序性能的人,应该都使用过各类缓存技术. 而我今天所说的Cache是专指ASP.NET的Cache,我们可以使用HttpRuntime.Cache访问到的那个Ca ...
- 细说 ASP.NET Cache 及其高级用法【转】
阅读目录 开始 Cache的基本用途 Cache的定义 Cache常见用法 Cache类的特点 缓存项的过期时间 缓存项的依赖关系 - 依赖其它缓存项 缓存项的依赖关系 - 文件依赖 缓存项的移除优先 ...
- Python爬虫入门之Urllib库的高级用法
1.设置Headers 有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我们需要设置一些Headers 的属性. 首先,打开我们的浏览 ...
- 详解Vue中watch的高级用法
我们通过实例代码给大家分享了Vue中watch的高级用法,对此知识点有需要的朋友可以跟着学习下. 假设有如下代码: <div> <p>FullName: {{fullName} ...
- Python爬虫Urllib库的高级用法
Python爬虫Urllib库的高级用法 设置Headers 有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我们需要设置一些Head ...
- [转]细说 ASP.NET Cache 及其高级用法
本文转自:http://www.cnblogs.com/fish-li/archive/2011/12/27/2304063.html 阅读目录 开始 Cache的基本用途 Cache的定义 Cach ...
- jquery ajax实例教程和一些高级用法
jquery ajax的调用方式:jquery.ajax(url,[settings]),jquery ajax常用参数:红色标记参数几乎每个ajax请求都会用到这几个参数,本文将介绍更多jquery ...
随机推荐
- 「uoj#188. 【UR #13】Sanrd」
题目 不是很能看懂题意,其实就是求\([l,r]\)区间内所有数的次大质因子的和 这可真是看起来有点鬼畜啊 这显然不是一个积性函数啊,不要考虑什么特殊的函数了 我们考虑Min_25筛的过程 设\(S( ...
- XXE攻防——XML外部实体注入
XXE攻防——XML外部实体注入 转自腾讯安全应急响应中心 一.XML基础知识 XML用于标记电子文件使其具有结构性的标记语言,可以用来标记数据.定义数据类型,是一种允许用户对自己的标记语言进行定义的 ...
- ASP.NET SingalR + MongoDB 实现简单聊天室(一):搭建基本框架
ASP.NET SingalR不多介绍.让我介绍不如看官网,我这里就是直接上源代码,当然代码还是写的比较简单的,考虑的也少,希望各位技友多多提意见. 先简单介绍聊天室功能: 用户加入聊天室,自动给用户 ...
- 美化浏览器JSON格式
工具下载地址: https://github.com/weibanggang/JSON-handle 原始 优化后 直接将文件拖到浏览器即可
- java 编写小工具 尝试 学习(一)
1.单片机 调试经常 需要 用 串口 工具 发送 一些 特定的 协议或者 命令,每次要 翻译 写成 2进制 很麻烦 ,因此 打算自己用 java 写一个 工具 方便自己 调试,2017年3月2 ...
- 使用RMAN增量备份处理Dataguard因归档丢失造成的gap
场景: 备库执行日志应用出现如下报错: Thu Mar 29 11:21:45 2018FAL[client]: Failed to request gap sequence GAP - thread ...
- mysql使用数据库
哈哈 只能怪自己太菜哈 刚接触这个MySQL没多久 今天用终端登陆MySQL的时候mysql -u root -p 然后就想看看自己的数据库 我用的MySQL的客户端是navicat for mysq ...
- 离不开的微服务架构,脱不开的RPC细节(值得收藏)!!!
服务化有什么好处? 服务化的一个好处就是,不限定服务的提供方使用什么技术选型,能够实现大公司跨团队的技术解耦,如下图所示: 服务A:欧洲团队维护,技术背景是Java 服务B:美洲团队维护,用C++实现 ...
- php ecshop 二级域名切换跳转时session不同步,解决session无法共享同步导致无法登陆或者无法退出的问题
echshop基础上做了单点登录的 一级域名与二级域名 退出时 清空session 都是一级域名的session 因为二级域名的session是设置在二级域名上的 echshop基础上没有做单点登录的 ...
- Apache Spark on K8s的安全性和性能优化
前言 Apache Spark是目前最为流行的大数据计算框架,与Hadoop相比,它是替换MapReduce组件的不二选择,越来越多的企业正在从传统的MapReduce作业调度迁移到Spark上来,S ...