In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article introduces the knowledge of "how to encapsulate code". In the operation of actual cases, many people will encounter such a dilemma. Next, let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!
Why encapsulate the code?
We often hear: "write code with good encapsulation, high cohesion, and low coupling." So what is a good package, and why should we package it? In fact, the seal contains the following benefits:
Encapsulated code, internal variables will not pollute the outside.
It can be called externally as a module. External callers do not need to know the details of the implementation, just use it according to the agreed specification.
Open to expansion and close to modification, that is, the principle of opening and closing. The external module can not be modified, which not only ensures the correctness of the module, but also sets aside an extended interface, which is flexible to use.
How to encapsulate the code?
JS Ecology already has many modules, some of which are well packaged and easy to use, such as jQuery,Vue and so on. If we take a closer look at the source code of these modules, we will find that their encapsulation has rules to follow. These rules can be summed up as design patterns. There are mainly four design patterns for code encapsulation: factory pattern, creator pattern, singleton pattern and prototype pattern. Let's take a look at these four design patterns with some framework source code:
Factory model
The name of the factory pattern is straightforward, and the encapsulated module produces the required objects in batches like a factory. One of the characteristics of common factory patterns is that you don't need to use new when calling, and the parameters passed in are relatively simple. However, the number of calls may be frequent, and it is often necessary to produce different objects, and it is much more convenient not to use new when calling frequently. The code structure of a factory pattern is as follows:
Function factory (type) {switch (type) {case 'type1': return new Type1 (); case' type2': return new Type2 (); case 'type3': return new Type3 ();}}
In the above code, we pass in type, and then the factory creates different objects based on different type.
Example: pop-up window assembly
Let's take a look at the example of using the factory pattern, if we have the following requirements:
Our project needs a pop-up window, there are several kinds of pop-up window: message pop-up window, confirmation pop-up window, cancel pop-up window, their color and content may be different.
For these kinds of pop-up windows, let's first create a class:
Function infoPopup (content, color) {} function confirmPopup (content, color) {} function cancelPopup (content, color) {}
If we use these classes directly, it looks like this:
Let infoPopup1 = new infoPopup (content, color); let infoPopup2 = new infoPopup (content, color); let confirmPopup1 = new confirmPopup (content, color);
Every time you use it, you have to go to the corresponding pop-up window class of new. We use factory mode to transform it, and that's it:
/ / add a new method popup to wrap all these classes function popup (type, content, color) {switch (type) {case 'infoPopup': return new infoPopup (content, color); case' confirmPopup': return new confirmPopup (content, color); case 'cancelPopup': return new cancelPopup (content, color);}}
Then we use popup instead of new, just call the function:
Let infoPopup1 = popup ('infoPopup', content, color)
Transform into object-oriented
Although the above code implements the factory pattern, switch never feels very elegant. We use the object-oriented transformation of popup, change it to a class, and mount different types of pop-up windows on this class as factory methods:
Function popup (type, content, color) {/ / if it is called through new, return the corresponding pop-up window if (this instanceof popup) {return new this [type] (content, color);} else {/ / if it is not called by new, use new call, you will go to the above line of code return new popup (type, content, color) }} / / all types of pop-up windows are mounted on the prototype to become instances method popup.prototype.infoPopup = function (content, color) {} popup.prototype.confirmPopup = function (content, color) {} popup.prototype.cancelPopup = function (content, color) {}
Encapsulated into a module
This popup not only makes us call without a new, but also encapsulates all kinds of pop-up windows related to it. The popup can be directly used as a module export for others to call, or it can be mounted on the window as a module for others to call. Because popup encapsulates all the details of the pop-up window, even if the interior of the popup is changed, or the type of the pop-up window is added, or the name of the pop-up window class has changed, as long as the external interface parameters remain unchanged, it will not affect the outside. Mounted on window as a module, you can use self-executing functions:
(function () {function popup (type, content, color) {if (this instanceof popup) {return new this [type] (content, color);} else {return new popup (type, content, color);}} popup.prototype.infoPopup = function (content, color) {} popup.prototype.confirmPopup = function (content, color) {} popup.prototype.cancelPopup = function (content, color) {} window.popup = popup }) () / / the popup module can be used directly outside let infoPopup1 = popup ('infoPopup', content, color)
Factory model of jQuery
JQuery is also a typical factory pattern. If you give him a parameter, he will return you the DOM object that matches the parameter. So how does jQuery achieve this factory model without new? In fact, it is the internal jQuery that calls new for you, and the calling process of jQuery is simplified, and that's it:
(function () {var jQuery = function (selector) {return new jQuery.fn.init (selector); / / new to init, init is the real constructor} jQueryjQuery.fn = jQuery.prototype / / jQuery.fn is the abbreviation of jQuery.prototype jQuery.fn.init = function (selector) {/ / which implements the real constructor} / / to make the prototypes of init and jQuery point to the same object, so that the instance method jQueryjQuery.fn.init.prototype = jQuery.fn; / / finally mounts the jQuery to window window.$ = window.jQuery = jQuery;}) ()
The above code structure comes from the jQuery source code, from which you can see that the new you omitted when calling is called for you in jQuery, in order to make a large number of calls more convenient. But this structure requires the help of an init method, and finally the prototypes of jQuery and init are tied together, and there is an easier way to achieve this requirement:
Var jQuery = function (selector) {if (! (this instanceof jQuery)) {return new jQuery (selector);} / / execute the real constructor}
The above code is much more concise, and it can also be called directly without new. The feature here is that when the function is called by new, this points to the object out of new, and the object out of new is naturally the instance of the class, and the this instanceof jQuery here is true. If it's a normal call, it's false, so let's new it for him.
Builder model
The builder pattern is used for the construction of complex large objects. For example, Vue,Vue contains a powerful and logically complex object, and a lot of parameters need to be passed in during the construction. There are not many situations like this that need to be created, and the builder pattern applies when the created object itself is very complex. The general structure of the builder model is as follows:
Function Model1 () {} / / Module 1 function Model2 () {} / / Module 2 / / final use class function Final () {this.model1 = new Model1 (); this.model2 = new Model2 ();} / / var obj = new Final ()
In the above code, we finally use Final, but the structure of Final is more complex, there are many sub-modules, Final is to combine these sub-modules to complete the function, which requires fine construction is applicable to the builder pattern.
Example: editor plug-in
Suppose we have a need like this:
Write an editor plug-in, initialization requires the configuration of a large number of parameters, and many internal functions are very complex, you can change the font color and size, you can also move forward and backward.
Generally speaking, there is only one editor for a page, and the functions in it may be very complex, and you may need to adjust colors, fonts, etc. In other words, other classes may be called within the plug-in and then combined to implement the function, which is suitable for the builder pattern. Let's analyze which modules are needed to make such an editor:
The editor itself must need a class, which is an interface for external calls.
A class that controls parameter initialization and page rendering is required
You need a class that controls fonts
A state management class is required
/ / the editor itself exposes function Editor () {/ / the editor is to combine various modules to realize the function this.initer = new HtmlInit (); this.fontController = new FontController (); this.stateController = new StateController (this.fontController) } / / initialization parameters Render page function HtmlInit () {} HtmlInit.prototype.initStyle = function () {} / initialize style HtmlInit.prototype.renderDom = function () {} / render DOM / / font controller function FontController () {} FontController.prototype.changeFontColor = function () {} / / change font color FontController.prototype.changeFontSize = function () {} / / Change font size / / status controller function StateController (fontController) {this.states = [] / / an array that stores all states this.currentState = 0; / / a pointer to the current state this.fontController = fontController / / inject font manager to make it easier to change font when changing state} StateController.prototype.saveState = function () {} / / Save state StateController.prototype.backState = function () {} / / backward state StateController.prototype.forwardState = function () {} / / forward state
The above code actually sets up the shelf of an editor plug-in, and the specific function is to fill in the specific content of these methods, which is actually the mutual call of each module. For example, if we want to implement the function of backing state, we can write like this:
StateController.prototype.backState = function () {var state = this.states [this.currentState-1]; / / take out the previous state this.fontController.changeFontColor (state.color); / / change back to the last color this.fontController.changeFontSize (state.size); / / change back to the last size}
Singleton mode
Singleton mode is suitable for scenes where there is only one instance object globally. The general structure of singleton mode is as follows:
Function Singleton () {} Singleton.getInstance = function () {if (this.instance) {return this.instance;} this.instance = new Singleton (); return this.instance;}
In the above code, the Singleton class mounts a static method getInstance. If you want to get an instance object, you can only get it by this method. This method will check whether there is an existing instance object, return it if there is one, and create a new one if not.
Example: global data store object
If we have such a need now:
We need to manage a global data object, which can only have one, and if there are more than one, the data will be out of sync.
This requirement requires that there is only one data storage object globally, which is a typical scenario suitable for singleton mode. We can directly apply the above code template, but the above code template must be called getInstance to obtain instance. If a user directly adjusts Singleton () or new Singleton (), there will be a problem. This time, we will write it another way, so that he can be compatible with Singleton () and new Singleton (), making it more foolish to use:
Function store () {if (store.instance) {return store.instance;} store.instance = this;}
The above code supports calls using new store (). We use a static variable instance to record whether it has been instantiated. If it is instantiated, return this instance. If there is no instantiation, assign this to this static variable, because the new call is used, and the this points to the instantiated object and implicitly returns this.
If we still want to support the direct call to store (), we can use the method used in the previous factory pattern to check whether this is an instance of the current class, and if not, just call it with new for him:
Function store () {/ / add an instanceof detection if (! (this instanceof store)) {return new store ();} / / the following if (store.instance) {return store.instance;} store.instance = this;}
Then we call it in two ways to detect:
Example: vue-router
In fact, vue-router also uses singleton mode, because if there are multiple routing objects on a page, it may cause state conflicts. The singleton implementation of vue-router is a little different. The following code comes from vue-router source code:
Let _ Vue; function install (Vue) {if (install.installed & & _ Vue = Vue) return; install.installed = true _ Vue = Vue}
Every time we call vue.use (vueRouter), we actually execute the install method of the vue-router module. If the user accidentally calls vue.use (vueRouter) many times, it will result in multiple execution of install, resulting in incorrect results. The install of vue-router writes the installed attribute as true on the first execution, and records the current Vue, so that executing install again in the same Vue will directly return, which is also a singleton mode.
We can see that the three kinds of code here are all singleton modes. Although their forms are different, the core idea is the same. They all use a variable to mark whether the code has been executed, and if it has been executed, it will return the last execution result. This ensures that multiple calls will get the same result.
Prototype model
The most typical application of prototype pattern is JS itself. The prototype chain of JS is prototype pattern. In JS, you can use Object.create to specify an object as a prototype to create an object:
Const obj = {x: 1, func: () = > {}} / / create a new object based on obj const newObj = Object.create (obj); console.log (newObj.__proto__ = obj); / / true console.log (newObj.x); / / 1
In the above code, we use obj as a prototype, and then new objects created with Object.create will have properties and methods on this object, which is actually a prototype pattern. And the object-oriented of JS is actually a more embodiment of this pattern. For example, the inheritance of JS can be written as follows:
Function Parent () {this.parentAge = 50;} function Child () {} Child.prototype = new Parent (); ChildChild.prototype.constructor = Child; / / Note reset constructor const obj = new Child (); console.log (obj.parentAge); / / 50
The inheritance here is to make the subclass Child.prototype.__proto__ point to the prototype of the parent class, thus getting the methods and properties of the parent class.
That's all for "how to encapsulate Code". Thank you for reading. If you want to know more about the industry, you can follow the website, the editor will output more high-quality practical articles for you!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.