js advanced - object oriented and design patterns

(1) Process oriented programming and process oriented programming (understand) #

Process oriented is to analyze the steps needed to solve the problem, and then use functions to realize these steps step by step. When using, you can call them one by one.

Object oriented is to decompose the problem into various objects. The purpose of establishing objects is not to complete a step, but to describe the behavior of something in the whole problem-solving step.

For specific implementation, let's take a look at the most classic problem of "putting elephants in the refrigerator" #

Process oriented solution (with steps as the core): open the door (refrigerator); Put into (refrigerator, elephant); Close the door (refrigerator).

// The method of opening the door, todo, means waiting to be realized
function openDoor() {
    // todo
}
// Method of loading
function putInto() {
    // todo
}
// Method of closing door
function closeDoor() {
    // todo
}

// step1
openDoor();
// step2
putInfo();
// step3
closeDoor();

Object - oriented solution (object - centered): refrigerator Open the door (refrigerator) Put it in the fridge Door closing ()

var iceBox = {
  openDoor() {
    // todo
  },
  putInto() {
    // todo
  },
  closeDoor() {
    // todo
  },
};
iceBox.openDoor();
iceBox.putInto();
iceBox.closeDoor();

Another example is to get a driver's license:

To get a driver's license, you must run part by part. After all the processes are completed, you will get the driver's license

You can also pay a related company. They send someone to help you. That person is not familiar with a process, so another advantage of object-oriented is that you don't need the specific implementation of the function at all. Just call the method of the object directly, such as Axios js

(2) Object oriented programming knowledge atlas (understanding) #

We mainly master the following points:

  1. How to create objects
    • Factory mode
    • Constructor Pattern
    • Prototype mode
  2. Three characteristics of objects
    • Encapsulation: an object is a combination of data and functions, that is, encapsulating attributes and methods
    • Inheritance: the so-called inheritance is that you don't have it and others have it. Take it for your own use and become your own thing
    • Polymorphism: polymorphism is actually separating what you do from who does it.

(3) js create object #

(1) Create objects using factory mode #

function createPerson(name,age,job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    return o;
}
var p1 = createPerson('Zhang San',29,'Test Engineer');
var p2 = createPerson('Li Si',28,'Front end Engineer');

(2) Creating objects using constructor mode #

function Person(name, age, job) { 
  this.name = name;
  this.age = age;
  this.job = job; 
  this.sayName = function() {
    console.log(this.name);
  }
}
 
var p1 = new Person("Zhang San", 29, "Test Engineer");
var p2 = new Person("Li Si", 28, "Front end Engineer");
p1.sayName();
p2.sayName();

What exactly does new () in js do

When using new to create an object, the system "secretly" does the following actions:

(1) Create a new object; (2) Assign the scope of the constructor to the new object (so this points to the new object); (3) Execute the code in the constructor (add properties and methods to the new object); (4) Returns a new object.

(3) Creating objects using prototype mode #

function Person() {
}
Person.prototype.type = 'human beings';
Person.prototype.say = function() {
  console.log('Ha ha ha');
}

var person = new Person();
console.log(person.type);
person.say();

(4) Determine the ownership of the instance object #

function Person() {
}
Person.prototype.type = 'human beings';
Person.prototype.say = function() {
  console.log('Ha ha ha');
}

var person = new Person();   
console.log(person instanceof Person);
var arr = [1,2,3];
console.log(arr instanceof Array);
console.log(arr instanceof Person);

(4) Prototype and prototype chain #

(1) Prototype (prototype object) #

  1. Each constructor has a prototype attribute that points to the prototype object of the function
  2. The prototype object is also the invisible "father" of the constructor instance
  3. The instance inherits all the properties and methods of the prototype object
  4. The instance has an internal pointer to the prototype object of its constructor
  5. The prototype object has a constructor pointing to the constructor (understand)
function Person(name,age) {
  this.name = name;
  this.age = age;
}

Person.prototype.father = 'Lao Wang';
Person.prototype.age = 30;
Person.prototype.getFather = function() {
  console.log(this.father);
}

// P1 and P2 are "produced" by person. Person can be regarded as a mother, while P1 and P2 are sons
var p1 = new Person('son of a bitch',1);
var p2 = new Person('Two fat',2);
console.log(p1);
console.log(p2);

Illustration:

(2) Prototype chain #

  1. Each constructor has a prototype attribute pointing to the prototype object, and its instance has an internal pointer pointing to the prototype object,
  2. If the prototype object is also an instance of another type, there will also be an internal pointer to another prototype object inside the prototype object
  3. If another prototype object is an instance of another type, the above relationship is still established. In this way, the link between the instance and the prototype object is formed layer by layer, which is called the prototype chain
  4. At the end of the prototype chain is the prototype Object of Object, which confirms the saying that "everything is an Object"

Example explanation

function Father() {
    this.fatherName = 'Ah three';
    this.fatherAge = 60;
}

function Son() {
    this.sonName = 'the other woman';
    this.sonAge = 25;
}
Son.prototype = new Father();

var son = new Son();

console.log('Laozi:',son.sonName);
console.log('Son:',son.fatherName);

// Everything is an object
console.log(son instanceof Son);
console.log(son instanceof Father);

var arr = [1,2,3];
console.log(arr instanceof Array);

var date = new Date();
console.log(date instanceof Date);

console.log(son instanceof Object);
console.log(arr instanceof Object);
console.log(date instanceof Object);

(5) js polymorphism #

Polymorphism is the ability of the same behavior to have multiple different forms or forms.

The idea of polymorphism actually separates "what you want to do" from "who will do it". What are the benefits of polymorphism?

The most fundamental advantage of polymorphism is that you don't have to ask the object "what type are you" and then call a behavior of the object according to the answer. You just call the behavior, and all other polymorphism mechanisms will be arranged for you.

function Duck(){}
Duck.prototype.sing = function(){
    console.log('Quack quack');
}
function Chicken(){}
Chicken.protorype.sing = function(){
    console.log('Cluck');
}
function singStart(animal){
    animal.sing();
}
singStart(new Duck());  // Quack quack
singStart(new Chicken());  // Cluck

(6) js inheritance #

Prototype inheritance #

function Father() {
  this.names = ['tom', 'kevin'];
}
Father.prototype.getName = function () {
  console.log(this.names);
}

function Child() {

}
Child.prototype = new Father();

var child1 = new Child();
child1.names.push('boaz');	// ['tom', 'kevin','boaz']
child1.getName();

var child2 = new Child();
child2.getName(); // ['tom', 'kevin','boaz']

Disadvantages of prototype inheritance:

  • The reference type attribute of the parent class will be shared by all child class instances. If any child class instance modifies the reference type attribute of the parent class, other child class instances will be affected
  • When creating a subclass instance, you cannot pass parameters to the parent class

1. Borrowing constructor inheritance

function Father(name) {
		this.name = name;
		this.say = function () {
			console.log('hello');
		}
	}

function Child(name) {
    this.name = name;
    Father.call(this,name);
}

var p1 = new Child('Tom');
console.log('p1', p1);
p1.say();
var p2 = new Child('Kevin');
console.log('p2', p2);
p2.say();

advantage:

  1. Avoid reference type properties being shared by all instances
  2. Parameters can be passed to the parent class

Disadvantages:

  1. Method must be defined in constructor
  2. Every time you create an instance, you create a method

2. Combination inheritance (combination of prototype inheritance and borrowing constructor inheritance)

function Father(name, age) {
	this.name = name;
	this.age = age;
	console.log(this);
}
Father.prototype.say = function() {
	console.log('hello');
}

function Child(name,age) {
	Father.call(this,name,age);
}
Child.prototype = new Father();

var child = new Child('Tom', 22);
console.log(child);  

The only disadvantage of common inheritance methods is that the constructor of the parent class will be called twice

3. Parasitic inheritance

function createObj(o) {
	var clone = object.create(o);
	clone.sayName = function () {
		console.log('hello');
	}
	return clone;
}

var father = {
  name: 'people',
  nation: 'China'
}

var son = createObj(father);
// son inherits father, owns the attribute of father and the method of sayName
console.log(son);

Is to create an encapsulated function to enhance the properties of the original object. Like borrowing a constructor, each instance will create a method

4. Parasitic combinatorial inheritance

es5 is the perfect way to inherit

// Prototype + borrowing constructor + parasitism
function Person() {
	console.log(22);
	this.class = 'human beings';
}

// Prototype inheritance pattern
Person.prototype.say = function() {
	console.log(this.name);
}

/**
 * Parasitic man prototype.__ proto__ ===  Person. prototype;
 * Man Father of father = = = father of Person
 */
 Man.prototype = Object.create(Person.prototype);
 Man.prototype.constructor = Man;


function Man(name, age) {
	this.name = name;
	this.age = age;
	// Borrow constructor mode
	Person.call(this);
}

var man = new Man('Zhang Sanfeng', 100);
console.log(man);

This is es5 the best way of inheritance, which combines the advantages of all inheritance methods.

  • Prototype inheritance can access the methods defined on the parent class prototype
  • Parasitic inheritance, the parent constructor does not need to be called twice
  • Using the constructor, you can put the attributes in the parent class constructor into the instance of the child class

Inheritance mode of Es6 #

class Father{
	constructor(name) {
		this.name = name;
	}
	sayName() {
		console.log(this.name);
	}
}

class Child extends Father{
	constructor(name, age) {
        // Call the parent constructor
		super(name);
		this.age = age;
	}
}

var child = new Child('Tom',22);
child.sayName();

Summary: three simple inheritance methods

  1. Prototype inheritance
  2. Borrowing constructor inheritance
  3. Parasitic inheritance

Two complex inheritance methods

  1. Combinatorial inheritance: 1 + 2 combination
  2. Parasitic combinatorial inheritance: combination of 1 + 2 + 4

TIP

Design mode

(7) What is a design pattern #

Suppose there is an empty room, we should put something in it day after day. Of course, the simplest way is to throw these things directly, but over time, you will find it difficult to find what you want from this house, and it is not easy to adjust the position of some things. So it may be a better choice to make some cabinets in the room. Although the cabinet will increase our cost, it can bring benefits to us in the maintenance stage. The rule of using these cabinets to store things may be a model.

(8) Factory mode #

  1. Factory pattern is a design pattern used to create objects.
  2. We do not expose the logic of object creation, but encapsulate the logic in a function, so this function can become a factory.
  3. Role (application scenario): used to perform some repetitive operations when creating similar objects.
function bookFatory(name, year, vs) {
  var book = new Object();
  book.name = name;
  book.year = year;
  book.vs = vs;
  book.price = "No price";
  if (name === "JS Advanced programming") {
    book.price = "79";
  }
  if (name === "css world") {
    book.price = "69";
  }
  if (name === "VUE Authoritative guide") {
    book.price = "89";
  }
  return book;
}
var book1 = bookFatory("JS Advanced programming", "2013", "Third Edition");
var book2 = bookFatory("ES6 Introductory tutorial", "2017", "Sixth Edition");
var book3 = bookFatory("css world", "2015", "first edition");
console.log(book1);
console.log(book2);
console.log(book3);

(9) Singleton mode #

Singleton is to ensure that there is only one instance of a class. Generally, the implementation method is to judge whether the instance exists first. If it exists, it will be returned directly. If it does not exist, it will be created and then returned. This ensures that there is only one instance object of a class. The advantage is that it can reduce unnecessary memory overhead

Application scenario:

  • Database connection object
  • No matter how many times you click in other places, only one login pop-up window will pop up
  • Global data store object (vuex)
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Document</title>
</head>

<body>
    <button onclick="add()">add</button>
    <button onclick="find()">find</button>

    <script>
        // Create an object that accesses the database 
        function Dbase() {
            if (Dbase.instance) {
                return Dbase.instance;
            } 
            
            this.name = "Database connection object";
            this.desc = "This is a connection mongodb Database objects";
            this.url = '//127.0.0.1:27017';
            this.dbase = 'film';
            this.find = function () {
                console.log("Find data");
            };
            this.delete = function () {
                console.log("Delete data");
            };
            this.update = function () {
                console.log("Update data");
            };
            this.add = function () {
                console.log("Add data");
            };
            // Assign this to dBASE instance
            Dbase.instance = this; 
        }

        // The object of new multiple times is the same
        var db1 = new Dbase();
        var db2 = new Dbase();
        console.log(db1 === db2); 

        function add() {
            var dbase = new Dbase();  
            dbase.add();
        }

        function find() {
            var dbase = new Dbase();
            dbase.find();
        }
    </script>
</body>

</html>

(10) Publish subscribe mode #

Publish subscribe mode, also known as observer mode, defines a one to many relationship between objects, allowing multiple observer objects to listen to a topic object at the same time. When an object changes, all objects that depend on it will be notified.

Publish subscribe mode in real life;

For example, Xiaohong recently saw a pair of shoes on Taobao. However, after contacting the seller, she found that the shoes were sold out, but Xiaohong liked the shoes very much. Therefore, she contacted the seller and asked when they were available. The seller told her that they would not be available until a week later. The seller told Xiaohong that if you like, you can collect our store and inform you when they are available, So Xiao Hong collected this shop, but at the same time, Xiao Ming and Xiao Hua also like this pair of shoes and collected this shop; They will be notified in turn when the goods arrive;

In the above story, we can see that it is a typical publish and subscribe mode. The seller belongs to the publisher, and Xiaohong and Xiaoming belong to the subscriber. The seller subscribes to the store. As the publisher, when the shoes arrive, the seller will notify Xiaoming and Xiaohong in turn, and use Wangwang and other tools to publish messages to them in turn;

Advantages of publish subscribe mode: #

1. Support simple broadcast communication. When the object state changes, it will automatically notify the subscribed object. 2. For example, Liezi, Xiaoming and Xiaohong above don't need to visit Taobao every day to see if the shoes have arrived. At the right time, the publisher (seller) will notify the subscriber (Xiaohong, Xiaoming, etc.).

For the first point, we often use it in our daily work, such as our ajax Request, request succeeded(success)And failure(error)Callback function, we can subscribe ajax of success and error event. We don't care about the state of objects running asynchronously, we only care about success When or error We need to do something of our own when we're ready~

Example 1: the event of JS is the publish subscribe mode #

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Document</title>
</head>

<body>
     
    <button>Shenzhen Daily </button>

    <script>
       var button = document.querySelector('button');
       // take in a newspaper
       button.addEventListener('click',reader1,false);
        // take in a newspaper
       button.addEventListener('click',reader2,false);

       function reader1 () { 
           console.log('I'm Reader 1');
       }

       function reader2 () { 
           console.log('I am Reader 2');
       }

       setTimeout(function() {
           // Publish a newspaper
           button.click();
       },3000)
    </script>
</body>

</html>

Implementing publish subscribe with js #

class Event {
  constructor () {}
  // First, define an event container to hold the event array (because subscribers can be multiple)
  handlers = {}

  // Event adding method. The parameters include event name and event method
  addEventListener (type, handler) {
    // First, judge whether there is a type event container in handlers. If not, create a new array container
    if (!(type in this.handlers)) {
      this.handlers[type] = []
    }
    // Save event to
    this.handlers[type].push(handler)
  }

  // Two parameters of trigger event (event name, parameter)
  dispatchEvent (type, ...params) {
    // If the event is not registered, an error is thrown
    if (!(type in this.handlers)) {
      return new Error('The event is not registered')
    }
    // Convenience trigger
    this.handlers[type].forEach(handler => {
      handler(...params)
    })
  }

  // Event removal parameters (event name, deleted event, if there is no second parameter, delete the subscription and publication of the event)
  removeEventListener (type, handler) {
      // Invalid event thrown
      if (!(type in this.handlers)) {
        return new Error('Invalid event')
      }
      if (!handler) {
        // Remove events directly
        delete this.handlers[type]
      } else {
        const idx = this.handlers[type].findIndex(ele => ele === handler)
        // Throw exception event
        if (idx === undefined) {
          return new Error('No such binding event')
        }
        // Remove event
        this.handlers[type].splice(idx, 1)
        if (this.handlers[type].length === 0) {
          delete this.handlers[type]
        }
      }
    }
}


var event = new Event() // Create event instance
// Define a custom event: "load"
function load (params) {
  console.log('load', params)
}
event.addEventListener('load', load)
// Define another load event
function load2 (params) {
  console.log('load2', params)
}
event.addEventListener('load', load2)
// Trigger this event
event.dispatchEvent('load', 'load Event trigger')
// Remove load2 event
event.removeEventListener('load', load2)
// Remove all load events
event.removeEventListener('load')

task #

  1. Say the results of the following code and explain why

    var param = 1;
    function main() { 
      console.log('1',param);
      var param = 2;
      console.log('2',this.param);
      this.param = 3;
    }
    
    main(); 
    var m = new main(); 
    
  2. Say the results of the following code and explain why

    function Foo() {
      getName = function() {
        console.log('1');
      };
      return this;
    } 
    Foo.getName = function() {
      console.log('2');
    } 
    Foo.prototype.getName = function() {
      console.log('3');
    }
    // Function expression
    var getName = function() {
      console.log('4');
    }
    // Covers the above method
    function getName() {
      console.log('5');
    }
    
    Foo.getName(); // Call static method 2
    getName(); // 4 function declaration is earlier than variable declaration
     // this=>window, window.getName() 1
     // Note that getName=xxx has no var in front, so it becomes a global function
    Foo().getName();
    getName();  // 1
    new Foo.getName();  // 2
    new Foo().getName(); // new Foo() gets an empty object, where method 3 on its prototype is executed

Tags: Front-end

Posted by freynolds on Sat, 16 Apr 2022 21:38:17 +0930