• 设计模式(1):只执行一次的函数


    概述

    最近最近做项目的时候总会思考一些大的应用设计模式相关的问题,我把自己的思考记录下来,供以后开发时参考,相信对其他人也有用。

    只执行一次的函数

    我们经常会遇到这种情况,就是希望某个函数只执行一次,以后就不执行了。一般情况下,我们会这么写:

    <script>
    export default {
      data() {
        return {
          runOnce: true,
        };
      },
      methods: {
        func() {
          console.log('hello world', this);
        },
        funcRunOnce() {
          if (this.runOnce) {
            this.func();
            this.runOnce = false;
          }
        },
      },
    };
    </script>
    

    但是这样并不优雅,不仅污染了data,还用2个方法进行实现,实在难看。

    用闭包改进

    于是我们考虑用闭包,把data里面的runOnce这个变量放到闭包里面去,这样就不会污染data了。代码如下:

    <script>
    export default {
      methods: {
        func() {
          console.log('hello world', this);
        },
        funcRunOnce(params) {
          let runOnce = true;
          return () => {
            if (runOnce) {
              this.func();
              runOnce = false;
            }
          }();
        },
      },
    };
    </script>
    

    但是这么写显然是错了,因为每次调用funcRunOnce都会构造一次闭包,里面的runOnce这个变量根本不会共享。所以继续改写如下:

    // 方法1
    <script>
    export default {
      created() {
        this.funcRunOnce = this.runOnce(this.func);
      },
      methods: {
        func() {
          console.log('hello world', this);
        },
        runOnce(func) {
          let runOnce = true;
          return (params) => {
            if (runOnce) {
              func(params);
              runOnce = false;
            }
          };
        },
      },
    };
    </script>
    
    // 方法2
    <script>
    export default {
      methods: {
        func() {
          console.log('hello world', this);
        },
        runOnce(func) {
          let runOnce = true;
          return (params) => {
            if (runOnce) {
              func(params);
              runOnce = false;
            }
          };
        },
        funcRunOnce: this.runOnce(this.func),
      },
    };
    </script>
    

    使用utils

    可以看到,上面的方法仍然很不优雅,要么用一个created和2个方法实现,要么用三个方法实现。而都用了一个公共的方法runOnce。所以我们考虑把runOnce放到utils.js里面去。

    // utils.js
    export function runOnce(func) {
      let runOnce = true;
      return (params) => {
        if (runOnce) {
          func(params);
          runOnce = false;
        }
      };
    }
    
    //example.vue
    import { runOnce } from '@/utils';
    <script>
    export default {
      methods: {
        funcRunOnce: runOnce(() => {
          console.log('hello world', this);
        }),
      },
    };
    </script>
    

    上面的写法看起来非常简洁,但是实际上是不行的,因为this的指向错了。由于runOnce返回的函数并不是vue实例的方法,所以里面的this指向的是undefined

    注意:即使看起来我们好像在funcRunOnce方法中用箭头函数捕获了外面实例的this,但是实际上它捕获的并不是外面的实例的this,而是runOnce返回的函数里面的this。

    捕获this

    能用箭头函数的地方我们都用了,但是为什么我们还是捕获不了this呢?如此一来是不是完成不了这个任务了?

    并不是,方法还是有的,方法是不用箭头函数捕获this。代码如下:

    // utils.js
    export function runOnce(func) {
      let runOnce = true;
      return function(params) {
        if (runOnce) {
          func.apply(this, params);
          runOnce = false;
        }
      };
    }
    
    //example.vue
    import { runOnce } from '@/utils';
    <script>
    export default {
      methods: {
        funcRunOnce: runOnce(function h() {
          console.log('hello world', this);
        }),
      },
    };
    </script>
    

    通过查看代码可以看出,2个地方的箭头函数都被改写成了function,并且还用到了apply函数来强制施加this。

    理由很简单,由于runOnce函数里面没有用箭头函数,所以它返回的函数是属于vue实例的,所以它返回的函数的this,是指向vue实例的;又因为funcRunOnce里面没有用箭头函数,所以我们可以用apply把这个this强制附加到func里面去!

    同理我们还可以写出第一次不执行,后续才执行的函数:

    // utils.js
    // 第一次不执行,后续再执行
    export function notRunOnce(func) {
      let once = false;
      return function(params) {
        if (once) {
          func.apply(this, params);
        }
        once = true;
      };
    }
    

    学到了什么

    1. 在vue里面可以用赋值的形式初始化方法,或者在created里面初始化方法。
    2. 箭头函数虽然能捕获this,但不是万能的;有时候我们需要用function和apply结合来捕获this。
  • 相关阅读:
    atitit.按钮光标滑过高亮切换以及其他动态效果的实现css html js attilax总结
    atitit. 文件上传带进度条 atiUP 设计 java c# php
    atitit.新增编辑功能 跟orm的实现 attilax p31
    atitit. java jsoup html table的读取解析 总结
    atitit.设计文档操作日志的实现
    atitit.资源释放机制attilax总结
    (转)Android的消息机制,用Android线程间通信的Message机制,Android中Handler的使用方法——在子线程中更新界面,handler机制
    (转)Android笔记handler机制
    (转)数据存储
    (转)android连网详解
  • 原文地址:https://www.cnblogs.com/yangzhou33/p/11204180.html
Copyright © 2020-2023  润新知