Why are immediate functions used in JavaScript to encapsulate modules?

Keywords: Javascript Programming

Recently, I am learning the basics of JavaScript, and I am learning object-oriented programming When you learn how to implement modularity in JavaScript, one of the important points is how to encapsulate private variables.

The main methods to encapsulate private variables are:

  1. Using constructors
    function StringBuilder() {
      var buffer = [];
    
      this.add = function (str) {
         buffer.push(str);
      };
    
      this.toString = function () {
        return buffer.join('');
      };
    }
    // The disadvantage of the above method is that every time a new instance is generated, the method in it will generate a new instance, resulting in memory waste. Therefore, the following improvements are made
    function StringBuilder() {
      this._buffer = [];
    }
    
    StringBuilder.prototype = {
      constructor: StringBuilder,
      add: function (str) {
        this._buffer.push(str);
      },
      toString: function () {
        return this._buffer.join('');
      }
    };
    // At this time, all instances will share the two methods and will not generate repeatedly
    // But the problem comes again. The private variables we encapsulate are not private, and can be modified directly outside_buffer,as
    var sb = new StringBuilder();
    sb._buffer = 'hello, sb';
  2. Use execute now function
    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('A rookie who loves programming');
    console.log(sb.toString()); // hello A rookie who loves programming

In the immediate execution function, the focus is on the function of createStringBuilder, which implements the internal and external docking interfaces, protects the private members of StringBuilder internally, provides the external interfaces to be accessed, and realizes the real private variable encapsulation. Let's use a simple example to compare the above three ways:

// Constructor, var1 It can't be modified by the outside world, but every instance generated, fn Will be copied
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,Variable not accessible
console.log(c10 === c11);   // false
c10.fn();   // 10
c11.fn();   // 10
c10.fn();   // 11
c11.fn();   // 11

// Improve it
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,Variable accessible
console.log(c20.fn === c21.fn); // true

// To solve the above problems
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

Posted by su1d on Wed, 04 Dec 2019 15:59:42 -0800