一、惰性载入函数(lazy function)

使用场景:当一个函数中的判断分支只用执行一次(第一次调用时执行),后续不会再变化,则可以使用惰性函数来提高性能。

  1. var addEvent = function(elem, type, handler) {
  2. if (window.addEventListener) {
  3. elem.addEventListener(type, handler, false);
  4. }
  5. else if (window.attachEvent) {
  6. elem.attachEvent('on' + type, handler);
  7. }
  8. };

上面的函数是一个事件监听函数,每次调用时都会判断使用标准的事件监听函数还是IE事件监听函数,其实只用判断一次就可以知道该使用哪种监听函数,改为惰性函数的代码如下:

  1. var addEvent=function(elem, type, handler){
  2. if (window.addEventListener) {
  3. addEvent=function(elem, type, handler){
  4. elem.addEventListener(type, handler, false);
  5. }
  6. }
  7. else if (window.attachEvent) {
  8. addEvent=function(elem, type, handler){
  9. elem.attachEvent(type, handler, false);
  10. }
  11. }
  12. //当addEvent函数第一次被外部调用时,会被覆盖为另外的函数,但覆盖后的函数体的代码不会执行,因此需要执行一次
  13. addEvent(elem,type,handler);
  14. }

另一种方法是声明后立即给出合适的函数

  1. var addEvent2=(function(elem, type, handler){
  2. if (window.addEventListener) {
  3. return function(elem, type, handler){
  4. elem.addEventListener(type, handler, false);
  5. }
  6. }
  7. else if (window.attachEvent) {
  8. return function(elem, type, handler){
  9. elem.attachEvent(type, handler, false);
  10. }
  11. }
  12. })(document.body,'click',function(){
  13. console.log('单击了');
  14. })
  15. console.log(addEvent2)

二、一次性函数(once function)

即只会执行一次的函数,核心思想是执行某个函数一次后将函数覆盖为null。

  1. //一次执行函数的工厂
  2. function once(fn,context){
  3. var result;
  4. return ()=>{
  5. if(typeof(fn)==='function'){
  6. result=fn.apply(context||this,arguments);
  7. fn=null;
  8. }
  9. return result;
  10. }
  11. }
  12. var canOnlyFireOnce=once(()=>{
  13. console.log('测量屏幕宽度');
  14. return {deviceWidth:'375px',deviceHeight:'480px'}
  15. })
  16. var deviceInfo=canOnlyFireOnce(); //输出“测量屏幕宽度”
  17. var deviceInfo2=canOnlyFireOnce(); //不会输出任何东西
  18. console.log(deviceInfo2);

三、记忆函数

核心思想:让一个函数记住处理过的参数,并可以根据相应的参数把结果缓存起来,避免重复计算。

实现方式:

1.使用闭包

  1. function memoryFunction(fn){
  2. var cacheArgs,cacheReturn;
  3. return function(a){
  4. if(a===cacheArgs){
  5. return cacheReturn;
  6. }
  7. cacheArgs=a;
  8. cacheReturn=fn.call(null,a);
  9. return cacheReturn;
  10. }
  11. }
  12. var demo=memoryFunction((a)=>a*1000);
  13. var b=demo(1), c=demo(1);
  14. console.log(b,c)

上面代码中,第二次调用demo函数时,直接返回值,不会再次计算

2.函数也是一个对象,因此可以动态的给函数增加静态的属来记录缓存键和结果

  1. function isPrime(value) { 
  2. if (!isPrime.answers) { 
  3. isPrime.answers = {}; 
  4. }
  5. //创建缓存 
  6. if (isPrime.answers[value] !== undefined) {  
  7. return isPrime.answers[value]; 
  8. }
  9. //检查缓存键
  10. var prime = value !== 0 && value !== 1; // 1 is not a prime  
  11. for (var i = 2; i < value; i++) {  
  12. if (value % i === 0) {    
  13. prime = false;    
  14. break;  
  15. }
  16. } 
  17. //缓存计算的结果
  18. return isPrime.answers[value] = prime;
  19. }

  

四、纯函数(pure function)

所谓纯函数就是一个函数返回的结果只依赖于其参数,并且在执行过程中没有副作用,这样的函数就叫纯函数。

条件1:返回结果直依赖参数

  1. const a = 1
  2. const foo = (b) => a + b
  3. foo(2) // => 3

上面的代码中,foo函数的返回值依赖了外部的a变理,因此不是纯函数

  1. const a = 1
  2. const foo = (x, b) => x + b
  3. foo(1, 2) // => 3

 上面的代码中,foo函数的返回值只跟其参数有关且没有副作用,因此是纯函数

条件2:执行过程没有副作用

什么是副作用?所谓副作用就是指函数执行过程中对外产生了可观察的变化。看例子

  1. const a = 1
  2. const counter = { x: 1 }
  3. const foo = (obj, b) => {
  4. obj.x = 2
  5. return obj.x + b
  6. }
  7. foo(counter, 2) // => 4
  8. counter.x // => 2

上面代码中foo 的结果只跟传入参数有关,但在内部加了一句 obj.x = 2,计算前 counter.x 是 1,但是计算以后 counter.x 是 2。foo 函数的执行对外部的 counter 产生了影响,修改了外部传进来的对象,也就是产生了副作用,因此不是纯函数。

  1. const a = 1
  2. const counter = { x: 1 }
  3. const foo = (obj, b) => {
  4. return obj.x + b
  5. }
  6. foo(counter, 2) // => 3
  7. counter.x // => 1

上面代码中foo的结果只跟传入的参数有关,且计算的过程里面并不会对传入的对象进行修改,计算前后的 counter 不会发生任何变化,计算前是 1,计算后也是 1,它现在是纯的。

下面的代码也是纯函数,因为对象是在函数内定义的,对外部不可见。

  1. const foo = (b) => {
  2. const obj = { x: 1 }
  3. obj.x = 2
  4. return obj.x + b
  5. }

五、高阶函数(high order functions)

所谓高阶函数是这样一种函数:即可以把函数作为参数传递,或者返回的值是一个函数。

比如Array.Map,Array.Sort,还有我们上面写的一次性执行函数演示代码都是高阶函数。

六、组合函数(compose function)

 作用:将需要嵌套执行的函数平铺。嵌套执行指的是,一个函数的返回值将作为另一个函数的参数。

  1. function C(){
  2. console.log('C')
  3. return function(){
  4. console.log('C函数回调执行')
  5. }
  6. }
  7. function B(CM){
  8. console.log('B')
  9. return function(){
  10. console.log('B函数回调执行')
  11. CM()
  12. }
  13. }
  14. function A(BM){
  15. console.log('A')
  16. return function(){
  17. console.log('A函数回调执行')
  18. BM()
  19. }
  20. }
  21. A(B(C()))()

改为compose方式后调用如下;

compose(A,B,C)()

compose函数的实现:

  1. function compose(...funcs) {
  2. //没有传入函数参数,就返回一个默认函数(直接返回参数)
  3. if (funcs.length === 0) {
  4. return arg => arg
  5. }
  6.  
  7. if (funcs.length === 1) {
  8. // 单元素数组时调用reduce,会直接返回该元素,不会执行callback;所以这里手动执行
  9. return funcs[0]
  10. }
  11. // 依次拼凑执行函数
  12. return funcs.reduce((prev, current) => (...args) => prev(current(...args)))
  13. }

举例分析: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)

把一个接收多个参数的函数分解成逐层调用的函数,每一层接收一部分参数,余下的参数由下一层再进行分解。

假如有如下函数:

  1. function add(a,b,c,d,e){
  2. return a+b+c+d+e;
  3. }
  4. console.log(add(1,2,3,4,5)); //15

现在要求每一步调用最多只能传2个参数,改写为柯里化版本如下:

  1. function curryAdd(a,b){
  2. return (c,d)=>{
  3. return (e)=>{
  4. return a+b+c+d+e;
  5. }
  6. }
  7. }
  8. console.log(curryAdd(1,2)(3,4)(5)); //15

看似把简单问题进行了复杂化,那么柯里化函数有什么作用呢?最大的用处就是可以固定不可变参数和可变参数,消除重复参数

  1. function ajax(url,type,data){
  2. // ...
  3. }
  4. ajax('www.my.com','GET')
  5. ajax('www.my.com','POST')
    //采化柯里化固定重复参数
  6. let newAjax=curryAjax('www.my.com')
    //只需要传入可变参数即可
  7. newAjax('GET')
  8. newAjax('POST')

  

八、防抖函数(debouncing)

核心思想:对同一个函数进行连续调用时,只有最后次调用生效,

实现方式:使用setTimeout方法,每次调用时,清除上一次的timer,并将本次的timer记录下来就可以保证只有最后一次调用会生效

  1. function debounce(method,time){
  2. var timer = null ;
  3. return function(){
  4. var context = this;
  5. //在函数执行的时候先清除timer定时器;
  6. if(timer)clearTimeout(timer);
  7. timer = setTimeout(function(){
  8. method.call(context);
  9. },time);
  10. }
  11. }

  

九、节流函数(throttling)

核心思想:对同一个函数进行连续调用时,只有当上一次函数执行后过了你规定的时间间隔,才能进行下一次该函数的调用

实现方式:使用setTimeout方法,给定两个时间,后面的时间减去前面的时间,到达我们给定的时间就去触发一次这个事件

  1. function throttle(method,time){
  2. var timer = null;
  3. var startTime = new Date();
  4. return function(){
  5. var context = this;
  6. var endTime = new Date();
  7. var resTime = endTime - startTime;
  8. //判断大于等于我们给的时间采取执行函数;
  9. if(resTime >= time){
  10. method.call(context);
  11. //执行完函数之后重置初始时间,等于最后一次触发的时间
  12. startTime = endTime;
  13. }
  14. }
  15. }

  

js函数相关高级用法的更多相关文章

  1. JS Replace() 高级用法(转)

    在很多项目中,我们经常需要使用JS,在页面前面对前台的某些元素做做修改,js 的replace()方法就必不可少. 经常使用"ABCABCabc".replace("A& ...

  2. 再谈Newtonsoft.Json高级用法

    上一篇Newtonsoft.Json高级用法发布以后收到挺多回复的,本篇将分享几点挺有用的知识点和最近项目中用到的一个新点进行说明,做为对上篇文章的补充. 阅读目录 动态改变属性序列化名称 枚举值序列 ...

  3. 细说 ASP.NET Cache 及其高级用法

    许多做过程序性能优化的人,或者关注过程程序性能的人,应该都使用过各类缓存技术. 而我今天所说的Cache是专指ASP.NET的Cache,我们可以使用HttpRuntime.Cache访问到的那个Ca ...

  4. 细说 ASP.NET Cache 及其高级用法【转】

    阅读目录 开始 Cache的基本用途 Cache的定义 Cache常见用法 Cache类的特点 缓存项的过期时间 缓存项的依赖关系 - 依赖其它缓存项 缓存项的依赖关系 - 文件依赖 缓存项的移除优先 ...

  5. Python爬虫入门之Urllib库的高级用法

    1.设置Headers 有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我们需要设置一些Headers 的属性. 首先,打开我们的浏览 ...

  6. 详解Vue中watch的高级用法

    我们通过实例代码给大家分享了Vue中watch的高级用法,对此知识点有需要的朋友可以跟着学习下. 假设有如下代码: <div> <p>FullName: {{fullName} ...

  7. Python爬虫Urllib库的高级用法

    Python爬虫Urllib库的高级用法 设置Headers 有些网站不会同意程序直接用上面的方式进行访问,如果识别有问题,那么站点根本不会响应,所以为了完全模拟浏览器的工作,我们需要设置一些Head ...

  8. [转]细说 ASP.NET Cache 及其高级用法

    本文转自:http://www.cnblogs.com/fish-li/archive/2011/12/27/2304063.html 阅读目录 开始 Cache的基本用途 Cache的定义 Cach ...

  9. jquery ajax实例教程和一些高级用法

    jquery ajax的调用方式:jquery.ajax(url,[settings]),jquery ajax常用参数:红色标记参数几乎每个ajax请求都会用到这几个参数,本文将介绍更多jquery ...

随机推荐

  1. [19/03/27-星期三] 容器_Iterator(迭代器)之遍历容器元素(List/Set/Map)&Collections工具类

    一.概念 迭代器为我们提供了统一的遍历容器的方式 /* *迭代器遍历 * */ package cn.sxt.collection; import java.security.KeyStore.Ent ...

  2. 你真的了解现在的PHP吗?

    前段时间,公司的项目从PHP5.3升级到PHP7,现在项目里开始使用PHP7的一些新语法和特性.反观PHP的5.4.5.5.5.6版本,有点认知缺失的感觉.所以,决定看<Modern PHP&g ...

  3. Linear Search

    Search I You are given a sequence of n integers S and a sequence of different q integers T. Write a ...

  4. 使用GraphViz画caffe网络结构图

    参考http://blog.csdn.net/happynear/article/details/45440709 1. 安装pydot: sudo pip install pydot 2. 安装Gr ...

  5. String.format字符串拼接

    一.String.Format1.简介      String类的format()方法用于创建格式化的字符串以及连接多个字符串对象. 2.参数      format()方法有两种重载形式. form ...

  6. Etherlab debian安装记录

    debian wheezy 7.11(虚拟机安装选择桥接网卡) #set ustc source #apt-get install sudo #nano /etc/sudoers;add userNa ...

  7. Css animation 与 float 、flex 布局问题

    1. 有这样一段css html 代码 <div class="container"> <div class="float-left"> ...

  8. react系列教程

    这个系列将从基础语法讲起,把react全家桶都讲到,然后到具体的使用,最后完成后,会写一个完整的demo. 前置要求: 基本的CSS,JS要熟练. 部分ES6语法需要了解.可以参考下面提到的阮一峰老师 ...

  9. Oracle 常用脚本

    ORACLE 默认用户名密码 sys/change_on_install SYSDBA 或 SYSOPER 不能以 NORMAL 登录,可作为默认的系统管理员 system/manager SYSDB ...

  10. 由Oracle 11g SYSAUX 和 SYSTEM 表空间回收引发的联想

    0x00--目的 整理一下以前一个SYSTEM表空间和SYSAUX表空间使用率达到99%上限的处理思路和相关知识点,好记性不如烂笔头 0x01--表空间使用率现状 通过查询可得知目前表空间使用情况如下 ...