Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

JavaScript closure and detailed introduction of several design patterns

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly introduces "JavaScript closure and the detailed introduction of several design patterns". In daily operation, I believe many people have doubts about JavaScript closure and the detailed introduction of several design patterns. The editor consulted all kinds of materials and sorted out simple and easy-to-use operation methods. I hope it will be helpful to answer the doubts of "JavaScript closure and the detailed introduction of several design patterns". Next, please follow the editor to study!

JavaScript closure

1. The most common way for closures is to return an inline function (what is an inline function? Is the function declared inside the function)

two。 There are scope and execution environment problems in JavaScript. Variables inside the function are inaccessible outside the function, but global variables can be obtained inside the function. For a variety of reasons, we sometimes need to get a variable inside a function, but we can't get it in a conventional way, so we can create a closure to access the variable externally.

3. The main purpose of closures is to read the internal variables of the function mentioned above, and another function is to keep these variables in memory all the time.

4. When using closures, it is important to note that because variables are kept in memory, it consumes memory, so closures cannot be abused. The solution is to delete all unused local variables before exiting the function.

* * it's the last set of closure code, which is more intuitive.

Function f () {var n = 999; function F1 () {alert (naughty 1);} return F1;} var result = f (); result (); / / 1000 result (); / / 1001 result (); / / 1002

Encapsulation: by declaring a method or property private, you can keep the implementation details of the object secret from other objects to reduce the coupling between objects, maintain the integrity of the data and restrict how it is modified. This makes the code more reliable and easier to debug. Encapsulation is the cornerstone of object-oriented design.

Although JavaScript is an object-oriented language, it doesn't have any internal mechanism for declaring members for public or private use, so we have to figure out how to implement this feature ourselves. Here is a complete set of code to analyze what are private properties and methods, what are privileged properties and methods, what are public properties and methods, and what are public static properties and methods.

Private properties and methods: functions have scope, variables declared with the var keyword within the function are inaccessible externally, and private properties and methods are essentially variables that you want to be inaccessible outside the object.

Privileged properties and methods: the this keyword used when creating properties and methods, which have access to private properties and methods because they are defined in the scope of the constructor; only those methods that require direct access to private members should be designed as privileged methods.

Common properties and methods: properties and methods that are directly chained to the prototype cannot access private members within the constructor, but can access privileged members, and subclasses inherit all common methods.

Share static properties and methods: * is understood by thinking of it as a namespace, which is actually equivalent to using the constructor as a namespace.

/ *-- Encapsulation-- * / var _ packaging = function () {/ / Private property and method var name = 'Darren'; var method1 = function () {/ /...} / / privileged property and method this.title =' JavaScript Design Patterns'; this.getName = function () {return name }} / / Common static properties and methods _ packaging._name = 'Darren code'; _ packaging.alertName = function () {alert (_ packaging._name);} / / Common properties and methods _ packaging.prototype = {init:function () {/ /...}}

Inheritance: inheritance itself is an abstract topic, and inheritance is a complex topic in JavaScript, because there are two ways to achieve inheritance in JavaScript, namely, type inheritance and prototype inheritance, each of which requires a lot of measures. I will explain this very important topic in JavaScript by analyzing examples below.

/ *-- classlike inheritance-- * / / first declare a superclass function Person (name) {this.name = name;} / / add the method getName Person.prototype.getName = function () {return this.name;} / / instantiate the superclass var a = new Person ('Darren1') alert (a.getName ()) to the prototype object of the superclass / / declare the class function Programmer (name,sex) {/ / the constructor of the superclass Person to be called in this class, and pass the parameter name to it Person.call (this,name); this.sex = sex;} / / the prototype object of this subclass is equal to the instance of the superclass Programmer.prototype = new Person () / / because the prototype object of the subclass is equal to the instance of the superclass, the prototype.constructor method is also equal to the superclass constructor. You can test it yourself. If you don't have this step, alert (Programmer.prototype.constructor), which is a reference to the Person superclass, so add the getSex method Programmer.prototype.getSex = function () {return this.sex to the subclass itself from the new assignment. } / / instantiate this subclass var _ m = new Programmer ('Darren2','male'); / / its own method alert (_ m.getSex ()); / / inherit the superclass method alert (_ m.getName ())

The code is not difficult, as long as you have a basic understanding of the prototype chain. The typological inheritance pattern is the main pattern of JavaScript inheritance, which is used in almost all JavaScript code written in an object-oriented manner, and because only JavaScript uses prototype inheritance in various popular languages, it still uses type inheritance. However, to be familiar with the JavaScript language, prototype inheritance is also something we must understand, and whether to use it in a project depends on the individual coding style.

/ *-- prototype inheritance-- * / clone () function is used to create a new Person object var clone = function (obj) {var _ f = function () {}; / / this is the core of prototype inheritance. The prototype object of the function is the literal quantity _ f.prototype = obj; return new _ f of the function. } / / declare an object literal var Person = {name:'Darren', getName:function () {return this.name;}} / / there is no need to define a subclass of Person, var Programmer = clone (Person) only needs to be cloned once / / you can directly obtain the default values provided by Person, or you can add or modify properties and methods alert (Programmer.getName ()) Programmer.name = 'Darren2' alert (Programmer.getName ()) / / declare subclasses, and perform a clone to var Someone = clone (Programmer).

The role of JavaScript design pattern-to improve the reusability and readability of the code, and to make the code easier to maintain and extend.

1. Monomer mode, factory mode, bridge mode personally think that this excellent front-end must master the pattern, which is very good for abstract programming and interface programming.

two。 The decorator pattern and the composition pattern have many similarities in that they both implement the same interface as the wrapped objects and pass calls to any methods to these objects. Decorator mode and combination mode are the two laborious models that I have described, and I personally have not used them, so I checked a lot of relevant information and documents, please.

3. Facade mode is a very interesting pattern, which is used in almost all JavaScript libraries. If you have experience in reverse thinking or reverse programming, it will be easier to understand this pattern (it sounds challenging, but you know it is a very simple pattern as soon as you touch it). There is also the configuration mode together with the facade mode, for example, this mode wraps the existing interface, and the rational use of it can improve the development efficiency to a great extent. There are similarities between the two models, so if you understand them together, you will start to understand them very quickly.

4. Sharing meta-mode is a mode for the purpose of optimization.

5. The proxy pattern is mainly used to control access to objects, including deferring the instantiation of classes that consume a lot of computing resources to create them.

6. Observer mode is a method used to observe the state of an object and to be notified when it changes. Used to allow objects to listen for events to respond to them. The observer mode is also known as the "subscriber mode".

7. Command mode is a way to encapsulate method calls, which can be parameterized and passed with naming patterns, and then executed when needed.

8. The responsibility chain pattern is used to eliminate coupling between the sender and receiver of the request.

What are the JavaScript design patterns?

Singleton mode: definitely the most basic and useful mode in JavaScript.

Monomers have a variety of uses in JavaScript, which are used to divide namespaces. You can reduce the number of global variables in a web page (it is risky to use global variables in a web page); you can avoid code conflicts (using reasonable namespaces) in multiplayer development, and so on.

In small and medium-sized projects or functions, monomers can be used as namespaces to organize their code under a global variable name; in larger or complex functions, monomers can be used to organize related code together for later maintenance.

The way to use singletons is to use a namespace to contain global objects of all your own code, for example:

Var functionGroup = {name:'Darren', method1:function () {/ / code}, init:function () {/ / code}}

Or

Var functionGroup = new function myGroup () {this.name = 'Darren'; this.getName = function () {return this.name} this.method1 = function () {}...}

Factory pattern: provides an interface for creating a series of related or interdependent objects without specifying their specific classes.

The factory transfers the creation of member objects to an external object, with the advantage of eliminating coupling between objects (what is coupling? Is to influence each other. By using factory methods instead of new keywords and concrete classes, you can centralize all instantiated code in one place, helping to create modular code, which is the purpose and advantage of the factory pattern.

For example: you have a big function to do, part of which is to consider extensibility, then this part of the code can be abstracted and treated as a completely new object. The advantage is that it is easy to maintain when it is extended in the future-you only need to manipulate the object's internal methods and properties to achieve the goal of dynamic implementation. A very famous example-the XHR factory:

Var XMLHttpFactory = function () {}; / / this is a simple factory pattern XMLHttpFactory.createXMLHttp = function () {var XMLHttp = null; if (window.XMLHttpRequest) {XMLHttp = new XMLHttpRequest ()} else if (window.ActiveXObject) {XMLHttp = new ActiveXObject ("Microsoft.XMLHTTP")} return XMLHttp;} / / XMLHttpFactory.createXMLHttp () this method returns a XHR object based on the specific circumstances of the current environment. Var AjaxHander = function () {var XMLHttp = XMLHttpFactory.createXMLHttp ();...}

The factory pattern also distinguishes between the simple factory pattern and the abstract factory pattern, which is introduced above, which is more widely used and easier to use. The way to use the abstract factory pattern is to design an abstract class first, which cannot be instantiated, but can only be used to derive subclasses. Example:

Var XMLHttpFactory = function () {}; / / this is an abstract factory pattern XMLHttpFactory.prototype = {/ / if this method is really called, an error is thrown, which cannot be instantiated, but can only be used to derive the subclass createFactory:function () {throw new Error ('This is an abstract class'). }} / / derived subclasses. At the beginning of the article, there is a basic introduction to the patterns that explain inheritance. If you don't understand, you can refer to the principle var XHRHandler = function () {XMLHttpFactory.call (this);}; XHRHandler.prototype = new XMLHttpFactory (); XHRHandler.prototype.constructor = XHRHandler; / / redefine the createFactory method XHRHandler.prototype.createFactory = function () {var XMLHttp = null If (window.XMLHttpRequest) {XMLHttp = new XMLHttpRequest ()} else if (window.ActiveXObject) {XMLHttp = new ActiveXObject ("Microsoft.XMLHTTP")} return XMLHttp;}

Bridge mode: bridge mode is often useful when implementing API. Of all the models, this model is the easiest to implement immediately.

Bridge pattern can be used to weaken the coupling between it and the classes and objects that use it, that is, to separate the abstraction from its implementation so that the two can change independently; this pattern is of great benefit to time-driven programming that is common in JavaScript. One of the most common and practical applications of Bridge pattern is the callback function of time listeners. Let's analyze a bad example:

Element.onclick = function () {new setLogFunc ();}

Why this example is not good is because you can't see from this code where the LogFunc method is going to be displayed, what options it has to configure, and how to modify it. To put it another way, the key to the bridge mode is to make the interface "bridgeable", which is actually configurable. Think of the functions in the page as modules, and the interface can reduce the coupling between modules.

It is not only you who master the benefits of the correct use of the bridge model, but also those who are responsible for maintaining your code. The abstraction is isolated from its implementation and each part of the software can be managed independently, making bug easier to find.

The purpose of the bridge pattern is to make API more robust, improve the modularity of components, lead to a more concise implementation, and increase the flexibility of abstraction. A good example:

Element.onclick = function () {/ / API controllability is improved, making the API more robust new someFunction (element,param,callback);}

Note: the bridge pattern can also be used to connect public API code with private implementation code, and to connect multiple classes together. The privileged method is mentioned in the introduction of the article, which is also a special case of the bridge mode. The examples found in "JS Design pattern" deepen your understanding of this pattern:

/ / in the wrong way / / according to the working mechanism of the callback function of the event listener, the event object is passed to the function as an argument. Instead of using this parameter in this example, you just get the ID from the this object. AddEvent (element,'click',getBeerById); function (e) {var id= this.id; asyncRequest ('GET','beer.url?id=' + id,function (resp) {/ / Callback response console.log (' Requested Beer:'+ resp.responseText);}) } / / good way / / logically analyzed, it makes sense to pass id to the getBeerById function, and the response result is always returned by a destroy function. With this understanding, what we are doing now is programming against the interface rather than the implementation, isolating the abstraction with the bridge pattern. Function getBeerById (id,callback) {asyncRequest ('GET','beer.url?id=' + id,function (resp) {callback (resp.responseText)});} addEvent (element,'click',getBeerByIdBridge); function getBeerByIdBridge (e) {getBeerById (this.id,function (beer) {console.log (' Requested Beer:'+ beer);});}

Decorator pattern: this pattern is to add functionality (or methods) to objects.

Dynamically add some additional responsibilities to an object. In terms of extended functionality, it is more flexible than generating subclasses.

The decorator pattern and the composition pattern have a lot in common. They both implement a unified interface with the wrapped objects and will pass any method bar to these objects. However, the composition pattern is used to organize multiple sub-objects into a whole, while the decorator pattern is used to add methods to existing objects without modifying them or deriving them from subclasses.

The decorator's operation is transparent, which means you can use it to wrap other objects and then continue to use them the way you used them before, as you can see in the following example. Let's understand it from the code:

/ / create a namespace of myText.Decorations var myText= {}; myText.Decorations= {}; myText.Core=function (myString) {this.show = function () {return myString;}} / / * times decorate myText.Decorations.addQuestuibMark = function (myString) {this.show = function () {return myString.show () +'?';} } / / second decoration myText.Decorations.makeItalic = function (myString) {this.show = function () {return''+ myString.show () +''};} / / get the instance of myText.Core var theString = new myText.Core ('this is a sample test String'); alert (theString.show ()); / / output' this is a sample test String' theString = new myText.Decorations.addQuestuibMark (theString); alert (theString.show ()) / / output 'this is a sample test String?' TheString = new myText.Decorations.makeItalic (theString); alert (theString.show ()); / / output 'this is a sample test String'

As can be seen from this example, all of this can be realized dynamically without knowing the interface of the component object in advance, and the decorator pattern has great flexibility in adding features to existing objects.

If you need to add features or methods to a class, and the solution of deriving subclasses from that class is impractical, you should use the decorator pattern. The most common reason why derived subclasses are not practical is that the number of features or methods to be added requires the use of large quantum classes.

Composite mode: combines objects into a tree structure to represent a "part-whole" hierarchy. It makes the customer's use of single object and composite object consistent.

Composite mode is a pattern tailored to create a dynamic user interface on Web. Using this mode, you can use a single command to stimulate complex or recursive behavior on multiple objects. The composition pattern is good at manipulating a large number of objects.

The benefits of combination mode are as follows: 1. Programmers can use the same method to deal with a collection of objects and their specific sub-objects; 2. It can be used to organize groups of sub-objects into a tree structure and make the whole tree convenient.

The scope of application of the combination mode: 1. There are a number of objects organized into a hierarchical system somewhere (the specific structure may not be known during development); 2. I want to be honest with this batch of objects or some of them.

In fact, the combination pattern is to combine a series of similar or similar objects into a large object, which provides some common interfaces to operate on these small objects, the code can be reused and the external operation is simple. For example: for the elements within the form, without considering the page design, there is generally only input left. For these input, there are name and value attributes, so you can combine these input elements as members of the form object, and the form object provides an external interface, you can achieve some simple operations, such as setting the value of an input, adding / deleting an input, and so on.

This pattern is difficult to describe. I'll find an example from "JS Design pattern". Let's take a look at the code: first create a composite object class.

/ / DynamicGallery Class var DynamicGallery = function (id) {/ / implement Composite,GalleryItem composite object class this.children = []; this.element = document.createElement ('div'); this.element.id = id; this.element.className =' dynamic-gallery';} DynamicGallery.prototype = {/ / implement Composite composite object interface add: function (child) {this.children.push (child) This.element.appendChild (child.getElement ());}, remove: function (child) {for (var node, I = 0; node = this.getChild (I); iTunes +) {if (node = = child) {this.children.splice (I, 1); break;}} this.element.removeChild (child.getElement ()) }, getChild: function (I) {return this.children [I];}, / / implement DynamicGallery composite object interface hide: function () {for (var node, I = 0; node = this.getChild (I); iTunes +) {node.hide ();} this.element.style.display = 'none' }, show: function () {this.element.style.display = 'block'; for (var node, I = 0; node = getChild (I); iTunes +) {node.show ();}}, / / help method getElement: function () {return this.element;}}

Recreate the leaf object class

Var GalleryImage = function (src) {/ / implement the method defined in the Composite and GalleryItem composite object this.element = document.createElement ('img'); this.element.className =' gallery-image'; this.element.src = src } GalleryImage.prototype = {/ / implement Composite interface / / these are leaf nodes, so we don't need to implement these methods, we just need to define add: function () {}, remove: function () {}, getChild: function () {}, / / implement GalleryItem interface hide: function () {this.element.style.display = 'none' }, show: function () {this.element.style.display =';}, / / help method getElement: function () {return this.element;}}

Now we can use these two classes to manage pictures:

Var topGallery = new DynamicGallery ('top-gallery'); topGallery.add (new GalleryImage (' / img/image-1.jpg')); topGallery.add (new GalleryImage ('/ img/image-2.jpg')); topGallery.add (new GalleryImage ('/ img/image-3.jpg')); var vacationPhotos = new DyamicGallery ('vacation-photos'); for (var I = 0, I < 30 VacationPhotos.add +) {vacationPhotos.add (new GalleryImage ('/ img/vac/image-' + I + '.jpg'));} topGallery.add (vacationPhotos); topGallery.show (); vacationPhotos.hide ()

Facade mode: facade mode is the core principle of almost all JavaScript libraries

A set of interfaces in the subsystem provides a consistent interface, and the facade pattern defines a high-level interface that makes the subsystem easier to use. simply put, it is an organizational pattern that can be used to modify the interfaces of classes and objects to make it easier to use.

There are two functions of facade mode: 1. Simplify the interface of the class; 2. Decouple the class from the client code that uses it.

The purpose of the facade mode is the graphic aspect.

Imagine the shortcut icons on the computer desktop that act as an interface to guide the user to a place, and each operation indirectly executes some behind-the-scenes commands.

When you are reading this blog, I assume that you already have experience with JavaScript, so you must have written or read this code:

Var addEvent = function (el,type,fn) {if (window.addEventListener) {el.addEventListener (type,fn);} else if (window.attachEvent) {el.attachEvent ('on'+type,fn);} else {el [' on'+type] = fn;}

This is a common JavaScript event listener function, this function is a basic facade, with it, there is an easy way to add event listeners to DOM nodes.

Now it's time to talk about the quintessence of the facade pattern, and why almost all JavaScript libraries use this pattern class. If you want to design a library now, put all the tool elements together to make it easier to use and easier to access. Look at the code:

/ / _ model.util is a namespace _ myModel.util.Event = {getEvent:function (e) {return e | | window.event;}, getTarget:function (e) {return e.target | | e.srcElement;}, preventDefault:function (e) {if (e.preventDefault) {e.preventDefault ();} else {e.returnValue = false }; / / the event tool is probably such a routine, and then use addEvent (document.getElementsByTagName ('body') [0],' click',function (e) {alert (_ myModel.util.Event.getTarget (e));}) in conjunction with the addEvent function

In my opinion, the solution to the problem of browser differences is to extract these differences in the facade method, which can provide a more consistent interface. The addEvent function is an example.

Adapter mode: converts the interface of one class to another interface that the customer wants. The adapter pattern allows classes that cannot work together because of interface incompatibility, and objects that use this pattern are also called wrappers because they are wrapping another object with a new interface.

On the face of it, it is a bit similar to the facade mode, except that how they change the interface, the facade mode shows a simplified interface that does not provide additional options, while the adapter pattern converts one interface to another, which does not filter out certain capabilities or simplify the interface. Let's start with a simple example:

/ / suppose you have a function with three string parameters, but now you have an object that contains three string elements Then you can use a configurator to connect the two var clientObject = {str1:'bat', str2:'foo', str3:'baz'} function interfaceMethod (str1,str2,str3) {alert (str1)} / / Configurator function function adapterMethod (o) {interfaceMethod (o.str1, o.str2, o.str3) The action of the} adapterMethod (clientObject) / / adapterMethod function is to wrap the interfaceMethod function and convert the parameters passed to it to the form required by the latter.

The adapter pattern works by wrapping the interface of an existing class with a new interface.

Example: adapt to two libraries. The following example implements the conversion from the $function of the Prototype library to the get method of YUI.

/ / first look at the differences between them in terms of interfaces / / Prototype $function function $() {var elements = new Array (); for (var iTunes I)

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.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report