First, let’s review memory

var str1 = "abc";
var str2 = "abc";
console.log(str1 == str2)
console.log(str1 === str2)
// The above code actually does this
// var str = String("abc")
Copy the code
// So if
var str1 = String("abc");
var str2 = new String("abc");
console.log(str1 == str2)
console.log(str1 === str2)
// We can print str1 and str2 on the console to see why they are different.
Copy the code

We can draw the conclusion that:

  • = =The values of variables (objects) are compared
  • = = =Compare the addresses of variables (objects)
  • In the future, I don’t care what programming language I’m talking aboutnewKeyword, must be to open a new block of memory in the heap

Browser parsing HTML

Templates and instances

<div id="myDiv"></div>
Copy the code
var myDiv = document.getElementById("myDiv");
Copy the code
  • The browser parses pairs of HTML tags, stores them in memory, and points them toward each other, forming what is known as a DOM tree
  • You can usetypeof mydivTo view
  • If it isObjectThat must be in the heap space, and the rest in the constant pool.
  • thismyDivIs, in fact,divInstance of tag
  • You can usemyDiv.constructorTo see which instance class the instance is

Can I use new HTMLDivElement() to create a new HTMLDiv class?

Right or wrong, guess first.

The browser does not allow you to create a new HTMLDiv class. How to create a new HTMLDiv class?

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — I’m line — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

The browser provides a method called document.createElement(“div”) that creates a DOM object in memory that is an HTMLDivElement object.

var myDiv1 = document.createElement("div");
Copy the code

This is a typical factory model. Constructor and mydiv1. constructor are identical, indicating that the two are different instances generated from the same template

But the problem is, I want my template to have only one instance, save memory, such as the body tag, globally unique, how to design this?

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — I’m a guide you — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

JavaScript has a feature that allows dynamic objects to copy their behavior and properties at will.

Come up with your own understanding.

Don’t worry. I’ll go on.

var obj = {};
// This is a simple singleton, and an instance of Object, in which we can extend any properties we want
Var Obj = {name: "ABC ",age: 1}
Copy the code

This code is very common in our project code, but the downside of this singleton, which is also a singleton pattern, is that this singleton is not extensible at all, and it’s unsafe to use, because we can change the contents of this at any time.

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — I am not serious to you — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

So how do you design the singleton pattern in JavaScript?

(function(){}) ()// Those who are familiar with my style will know
// Create an anonymous function and call it immediately
// What is the use of writing this?
Copy the code

This is useful because it helps me implement a closure. The {} in this code helps me implement a temporary closure scope.

var SingleTest = (function(){
    // This return function is a template class
    return function(){
        console.log("Enter the constructor function");
    }
})()

// This time we can
var i1 = new SingleTest();
var i2 = new SingleTest();
console.log(i1===i2) // false
Copy the code

If you’re familiar with JavaScript, there are two ways to use functions: a function call (lowercase) and a constructor (uppercase).

But I want no matter how NEW I do, I want to use the same address in memory, which is i1===i2, so what do I do?

var SingleTest = (function(){
    var _instance = null;
    return function(){
        console.log("Enter the constructor function");
        if(! _instance) {console.log("First time new, local variable (instance) _instance is null");
            _instance = this;
            return _instance;
        } else {
            console.log("Not the first time new, local variable (instance) _instance is not null, return directly");
            return_instance; }}}) ()Copy the code

So let’s just understand this code.

This represents a reference to the memory space being created, so properties or methods defined can be manipulated with this.

At this point console.log(i1===i2) to see what happens.

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — I’m shady parameters you — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

What if I want to pass a parameter to this singleton and we want to access the name property inside the instance?

var SingleTest = (function(){
    var _instance = null;
    return function(ops){
        // We often do that
        // In this way we can filter out the empty reference problem caused by not passing arguments
        ops = ops || {};
        if(! _instance) { _instance =this;
            // Iterate over our arguments through the for loop
            for (var prop in ops) {
                _instance[prop] = ops[prop];
            }
            return _instance;
        } else {
            for (var prop in ops) {
                _instance[prop] = ops[prop];
            }
            return_instance; }}}) ()var i1 = new SingleTest({name:"zhangsan"});
var i2 = new SingleTest({name:"lisi"});
console.log(i1.name);
// What is the output value?
// There are two for loops in this code.
Copy the code
var SingleTest = (function(){
    var _instance = null;
    var _default = {}
    // Encapsulate the for loop
    function _init(ops) {
        for (var prop in ops) {
            this[prop] = ops[prop]; }}return function(ops=_default){/ / es6 support
        // ops = ops || {}; This approach is out
        if(! _instance) { _instance =this;
            _init.call(_instance, ops);
        } else {
            _init.call(_instance, ops);
        }
        return _instance;
    }
})()

var i1 = new SingleTest({name:"zhangsan"});
var i2 = new SingleTest({name:"lisi"});
console.log(i1.name);
Copy the code

This code is pretty optimized, but it can be optimized, for example, if I have not just an _init method, but other methods, like function _method1(){} function _method2(){}, and when I call it inside of a function, you’ll see, That’s not a good idea. So how do you optimize when there are multiple methods?

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — I was proper optimization, jun — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

In a nutshell, these methods are added to the prototype chain.

var SingleTest = (function(){
    var _instance = null;
    var _default = {}
    function SingleInstance(ops=_default){
        if(! _instance) { _instance =this;
            this._init(ops);
        } else {
            _instance._init(ops);
        }
        return _instance;
    }
    // Add the method to the prototype
    // _ means private properties or methods, industry rules.
    SingleInstance.prototype._init = function(ops) {
        for (var prop in ops) {
            this[prop] = ops[prop]; }}returnSingleInstance; }) ()var i1 = new SingleTest({name:"zhangsan"});
var i2 = new SingleTest({name:"lisi"});
console.log(i1.name);
Copy the code

You’ll notice that this doesn’t reduce the amount of code, but the advantage is that you can use this to call existing methods directly to each other while writing other methods. Another advantage is that if I want to create a different instance later, I can handle _instance directly, because I’ve wrapped the singleton into a closure that doesn’t affect outside callers.

But there’s a bug! If someone tries to call SingleTest({name:”mazi”}), you’ll notice that the console has an error. So how do you optimize to make this call compatible?

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — I was the evil bug you — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

The reason is that this calls the function stack directly, which means that the scope of the current function is not this in the heap. Don’t ask me what a function stack is, that’s not the topic, it’s simply putting functions on the stack to execute.

The running of the theme.

var SingleTest = (function(){
    var _instance = null;
    var _default = {}
    function SingleInstance(ops=_default){
        // instanceof is an instance that indicates whether this is SingleInstance
        if (this instanceof SingleInstance) {
            if(! _instance) { _instance =this;
                this._init(ops);
            } else{ _instance._init(ops); }}else {
            if(! _instance) { _instance =new SingleInstance();
                _instance._init(ops);
            } else{ _instance._init(ops); }}return _instance;
    }
    SingleInstance.prototype._init = function(ops) {
        for (var prop in ops) {
            this[prop] = ops[prop]; }}returnSingleInstance; }) ()var i0 = SingleTest({name:"wangwu"})
var i1 = new SingleTest({name:"zhangsan"});
var i2 = new SingleTest({name:"lisi"});
console.log(i0 === i1);
console.log(i0 === i2);
Copy the code

At this point, the singleton has been optimized. Maybe you can optimize it, but that’s not important, that’s enough. All I’m saying is, don’t memorize the code, try to understand the idea, the idea is universal.