zoukankan      html  css  js  c++  java
  • JavaScript中为什么使用立即执行函数来封装模块?

    最近在学习JavaScript基础,在学习到面向对象编程时,学习到在JavaScript中实现模块化的方法,其中一个重要的点是如何封装私有变量。

    实现封装私有变量的方法主要是:

    1. 使用构造函数
      function StringBuilder() {
        var buffer = [];
      
        this.add = function (str) {
           buffer.push(str);
        };
      
        this.toString = function () {
          return buffer.join('');
        };
      }
      // 上面这种做法有个缺点,就是每生成一个新的实例,其中的方法就会生成一个新的实例,造成内存浪费,因此做如下改进
      function StringBuilder() {
        this._buffer = [];
      }
      
      StringBuilder.prototype = {
        constructor: StringBuilder,
        add: function (str) {
          this._buffer.push(str);
        },
        toString: function () {
          return this._buffer.join('');
        }
      };
      // 此时所有实例会共享这两个方法,不会重复生成
      // 但是问题又来了,我们封装的私有变量变得不私有了,在外部可以直接修改_buffer,如
      var sb = new StringBuilder();
      sb._buffer = 'hello, sb';
    2. 使用立即执行函数
      var module = (function() {
          function StringBuilder() {
              this._buffer = [];
          }
      
          StringBuilder.prototype = {
              constructor: StringBuilder,
              add: function (str) {
                  this._buffer.push(str);
              },
              toString: function () {
                  return this._buffer.join('');
              }
          };
      
          function createStringBuilder() {
              var _sb = new StringBuilder();
              return {
                  add: StringBuilder.prototype.add.bind(_sb),
                  toString: StringBuilder.prototype.toString.bind(_sb)
              };
          }
      
          return {
              createStringBuilder: createStringBuilder
          };
      
      })();
      
      console.log(module);    // { createStringBuilder: [Function: createStringBuilder] }
      var sb = module.createStringBuilder();
      sb.add('hello');
      sb.add('爱编程的小菜鸟');
      console.log(sb.toString()); // hello爱编程的小菜鸟

    在立即执行函数中,重点在于createStringBuilder这个函数,这个函数实现了内外对接的接口,对内保护了StringBuilder的私有成员,对外又能提供需要访问的接口,实现了真正的私有变量封装。下面我们用一个简单的例子对上面的三种方式进行对比:

    // 构造函数,var1无法被外界修改,但是每生成一个实例,fn都会被拷贝
    function Class1() {
        var var1 = 10;
        this.fn = function() {
            console.log(var1);
            var1 += 1;
        };
    }
    var c10 = new Class1();
    var c11 = new Class1();
    console.log(c10.var1); // undefined,变量不可被访问
    console.log(c10 === c11);   // false
    c10.fn();   // 10
    c11.fn();   // 10
    c10.fn();   // 11
    c11.fn();   // 11
    
    // 改进一下
    function Class2() {
        this._var1 = 10;
    }
    
    Class2.prototype = {
        constructor: Class2,
        fn: function() {
            console.log(this._var1);
            this._var1 += 1;
        }
    };
    var c20 = new Class2();
    var c21 = new Class2();
    c20.fn();   // 10
    c20.fn();   // 11
    c21.fn();   // 10
    c21.fn();   // 11
    console.log(c20._var1); // 11,变量可被访问
    console.log(c20.fn === c21.fn); // true
    
    // 为了解决上述问题
    var m = (function() {
        function Class3() {
            this.var1 = 10
        }
        Class3.prototype = {
            constructor: Class3,
            fn: function() {
                console.log(this.var1);
                this.var1 += 1;
            }
        };
    
        function createClass3() {
            var c3 = new Class3();
            return {
                fn: Class3.prototype.fn.bind(c3)
            };
        }
    
        return {
            createClass3: createClass3
        }
    })();
    var c30 = new m.createClass3();
    var c31 = new m.createClass3();
    c30.fn();   // 10
    c30.fn();   // 11
    c31.fn();   // 10
    c31.fn();   // 11
  • 相关阅读:
    解决Tomcat无法shutdown进程
    ConcurrentHashMap Put()操作示例代码
    Spring Data JPA
    JAVA CAS原理
    多线程
    多线程
    java 虚拟机--新生代与老年代GC
    TCP协议中的三次握手和四次挥手
    java中volatile关键字
    Java多线程
  • 原文地址:https://www.cnblogs.com/zhuangshq/p/10139226.html
Copyright © 2011-2022 走看看