current position:Home>Decorator pattern of JavaScript Design Pattern
Decorator pattern of JavaScript Design Pattern
2021-08-29 07:13:18 【Niu Niu_ lz】
This is my participation 8 The fourth of the yuegengwen challenge 12 God , Check out the activity details :8 Yuegengwen challenge
A way of dynamically adding responsibility to an object is called decorator (decorator) Pattern . The decorator pattern can be based on not changing the object itself , Adding responsibilities to objects dynamically during program execution . Compared with inheritance , Decorator is a more light and flexible way .
JavaScript The decorator of
JavaScript It's quite easy for languages to change objects dynamically , We can directly override an object or a method of an object , No need to use “ class ” To implement decorator mode , The code is as follows :
var plane = {
fire: function () {
console.log(' Fire ordinary bullets ');
}
}
var missileDecorator = function () {
console.log(' Launch missiles ');
}
var atomDecorator = function () {
console.log(' Launch the atomic bomb ');
}
var fire1 = plane.fire;
plane.fire = function () {
fire1();
missileDecorator();
}
var fire2 = plane.fire;
plane.fire = function () {
fire2();
atomDecorator();
}
plane.fire();
// Output, respectively, : Fire ordinary bullets 、 Launch missiles 、 Launch the atomic bomb
Copy code
Decoration function
stay JavaScript You can easily extend properties and methods to an object , But it's hard to do without changing the source code of a function , Add some extra functionality to this function . While the code is running , It's hard to cut into the execution environment of a function .
To add some functionality to a function , The simplest and crudest way is to rewrite the function directly , But this is the worst way , It's a direct violation of openness - Closed principle :
var a = function () {
alert(1);
}
// Change to
var a = function () {
alert(1);
alert(2);
}
Copy code
The above example shows that a function can be rewritten by saving the original reference :
var a = function () {
alert(1);
}
var _a = a;
a = function () {
_a();
alert(a);
}
a();
Copy code
This is a very common practice in actual development , For example, we want to give window
binding onload
event , But I'm not sure if this event has been bound by others , To avoid overwriting the previous window.onload
Behavior in functions , We usually save the original window.onload
, Put it in a new window.onload
Internal execution :
window.onload = function () {
alert(1);
}
var _onload = window.onload || function () { };
window.onload = function () {
_onload();
alert(2);
}
Copy code
But there are two problems with this approach :
- Must maintain
_onload
This intermediate variable , Although it doesn't look impressive , But if the decoration chain of the function is long , Or there are more functions to decorate , There will be more and more of these intermediate variables . this
The question of being hijacked , staywindow.onload
There is no such trouble in the example of , Because calling ordinary functions_onload
when ,this
Point towindow
, Follow callwindow.onload
At the same .
use AOP Decoration function
First of all give Function.prototype.before
Methods and Function.prototype.after
Method :
Function.prototype.before = function (beforefn) {
var __self = this; // Save the reference of the original function
return function () { // Returns... That contains the original function and the new function " agent " function
beforefn.apply(this, arguments); // Execute the new function , And guarantee this Not hijacked , The parameters accepted by the new function will also be passed into the original function intact , The new function executes before the original function
return __self.apply(this, arguments); // Execute the original function and return the execution result of the original function , And guarantee this Not hijacked
}
}
Function.prototype.after = function (afterfn) {
var __self = this;
return function () {
var ret = __self.apply(this, arguments);
afterfn.apply(this, arguments);
return ret;
}
};
Copy code
Function.prototype.before
Take a function as an argument , This function is the newly added function , It loads the newly added function code .
Next, put the current this
Save up , This this
Point to the original function , And then return a “ agent ” function , This “ agent ” Functions are just structured like proxies , Does not assume the responsibility of agency ( For example, controlling the access of objects ). Its job is to forward the request to the newly added function and the original function respectively , And be responsible for ensuring their execution sequence , Let the newly added function execute before the original function ( Front decoration ), In this way, the effect of dynamic decoration is realized . adopt Function.prototype.apply
To dynamically pass in the correct this
, Ensures that the function is decorated ,this
It won't be hijacked .
Function.prototype.after
The principle of Function.prototype.before
As like as two peas , The only difference is that the newly added function is executed after the original function is executed .
So let's see , Use Function.prototype.before
To add new window.onload
How simple the event is :
window.onload = function () {
alert(1);
}
window.onload = (window.onload || function () { }).after(function () {
alert(2);
}).after(function () {
alert(3);
}).after(function () {
alert(4);
});
Copy code
above AOP
The realization is in Function.prototype
Add before
and after
Method , But many people don't like this way of polluting the prototype , Then we can do something , Pass both the original function and the new function as parameters before
perhaps after
Method :
var before = function (fn, beforefn) {
return function () {
beforefn.apply(this, arguments);
return fn.apply(this, arguments);
}
}
var a = before(
function () { alert(3) },
function () { alert(2) }
)
a = before(a, function () { alert(1) })
a();
Copy code
AOP Application example
use AOP The technique of decorating functions is very useful in practical development . Whether it's writing business code , Still at the framework level , We can all divide behavior into more granular functions according to responsibilities , They are then combined by decoration , This helps us to write a loosely coupled and highly reusable system .
Data statistics report
Separate business code and data statistics code , In any language , All are AOP One of the classic applications of . For example, there is a login in the page button
, Click on this. button
The login floating layer will pop up , At the same time, data shall be reported , To count how many users have clicked this login button
:
<html>
<button tag="login" id="button"> Click to open the login floating layer </button>
<script> var showLogin = function () { console.log(' Open login float '); log(this.getAttribute('tag')); } var log = function (tag) { console.log(' The report label is : ' + tag); // (new Image).src = 'http:// xxx.com/report?tag=' + tag; // The real reporting code is slightly } document.getElementById('button').onclick = showLogin; </script>
</html>
Copy code
We see in the showLogin
In the function , Be responsible for opening the login floating layer , Also responsible for data reporting , This is a function of two levels , Here it is coupled in a function . Use AOP After separation , The code is as follows :
<html>
<button tag="login" id="button"> Click to open the login floating layer </button>
<script> Function.prototype.after = function (afterfn) { var __self = this; return function () { var ret = __self.apply(this, arguments); afterfn.apply(this, arguments); return ret; } }; var showLogin = function () { console.log(' Open login float '); } var log = function () { console.log(' The report label is : ' + this.getAttribute('tag')); } showLogin = showLogin.after(log); // Open the login floating layer and report the data document.getElementById('button').onclick = showLogin; </script>
</html>
Copy code
use AOP Changing the parameters of a function dynamically
We need to give ajax
Request to add a token
. Now there is one for generating token
Function of :
var getToken = function () {
return 'Token'
}
Copy code
Now let's give everyone ajax
Add... To the request token
Parameters :
var ajax = function(type, url, param) {
param = param || {}
param.token = getToken
// send out ajax The code is omitted ……
}
Copy code
Although the problem has been solved , But our ajax
Functions become relatively rigid , Each from ajax All requests made in the function are automatically brought token
Parameters , Although there are no problems in the current project , But if you migrate this function to other projects in the future , Or put it in an open source library for others to use ,token
Parameters will be redundant .
To solve this problem , The first ajax
Function is reduced to a clean function :
var ajax= function( type, url, param ){
console.log(param);
// send out ajax The requested code is omitted ……
};
Copy code
And then put token
Parameters through Function.prototyte.before
Decorate to ajax
The parameters of the function param
In the object :
var getToken = function(){
return 'token';
}
ajax = ajax.before(function( type, url, param ){
param.Token = getToken();
});
ajax( 'get', 'http://xxx.com/userinfo', { name: 'sven' } );
Copy code
from ajax
Function to print log
You can see ,token
Parameters have been attached to ajax
Of the requested parameters : {name: "sven", Token: "token"}
You can clearly see that , use AOP The way to ajax Function dynamic decoration token
Parameters , To ensure the ajax
Function is a relatively pure function , Improved ajax
Reusability of functions , When it was moved to other projects , No modification required .
Plug in form validation
Many of us have written a lot of form validation code , In a Web In the project , There may be a lot of forms , If registered 、 Sign in 、 Modify user information, etc . Before the form data is submitted to the background , Often do some verification , For example, when logging in, you need to verify whether the user name and password are empty .
What we need to do now is to separate verification input and submission ajax
Requested code , To make validata
and formSubmit
Completely separate . First, rewrite Function.prototype.before
, If beforefn
The execution result of the false
, Indicates that the following original functions will not be executed :
Function.prototype.before = function (beforefn) {
var __self = this
return function () {
if (beforefn.apply(this, arguments) === false) {
// beforefn return false The situation is direct return, Don't execute the original function later
return;
}
return __self.apply(this, arguments)
}
}
var validata = function () {
if (username.value === '') {
alert(' The username cannot be empty ')
return false
}
if (password.value === '') {
alert(' The password cannot be empty ')
return false
}
}
var formSubmit = function () {
var param = {
username: username.value,
password: password.value
}
ajax('http://xxx.com/login', param)
}
formSubmit = formSubmit.before(validata)
submitBtn.onclick = function () {
formSubmit()
}
Copy code
It is worth noting that , Because the function passes Function.prototype.before
perhaps Function.prototype.after
After being decorated , What's returned is actually a new function , If you save some properties on the original function , Then these attributes will be lost . The code is as follows :
var func = function(){
alert( 1 );
}
func.a = 'a';
func = func.after( function(){ alert( 2 ) });
alert ( func.a ); // Output :undefined
Copy code
in addition , This decoration also overlaps the scope of the function , If the decorated chain is too long , Performance will also be affected .
Decorator mode and agent mode
The structure of decorator mode and agent mode look very similar , Both modes Describes how to provide some degree of indirect reference to objects , Their implementation part retains a reference to another object , And send a request to that object .
The difference between agent mode and decorator mode is :
- Their intention and design purpose .
- The purpose of the agency model is , When direct access to ontology is inconvenient or does not meet the needs , Provide an alternative to this ontology . Ontology defines key functions , The agent provides or denies access to it , Or do something extra before accessing the ontology .
- The role of decorator pattern is to dynamically add behavior to objects .
- The agency model emphasizes a relationship (Proxy The relationship with its entity ), This relationship can be expressed statically , in other words , This relationship can be determined from the beginning . Decorator mode is used when you can't determine all the functions of the object at first .
- Agent mode usually has only one layer of agents - Ontology reference , The decorator model often forms a long decorative chain .
And finally
If this article is helpful to you , Or if there's some inspiration , Give me some praise and pay attention to , Your support is my biggest motivation for writing , Thank you for your support .
copyright notice
author[Niu Niu_ lz],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2021/08/20210829071312749p.html
The sidebar is recommended
- Crazy blessing! Tencent boss's "million JVM learning notes", real topic of Huawei Java interview 2020-2021
- JS JavaScript how to get the subscript of a value in the array
- How to implement injection in vuex source code?
- JQuery operation select (value, setting, selected)
- One line of code teaches you how to advertise on Tanabata Valentine's Day - Animation 3D photo album (music + text) HTML + CSS + JavaScript
- An article disassembles the pyramid architecture behind the gamefi outbreak
- BEM - a front-end CSS naming methodology
- [vue3] encapsulate custom global plug-ins
- Another ruthless character fell by 40000, which was "more beautiful" than Passat and maiteng, and didn't lose BMW
- Huang Lei basks in Zhang Yixing's album, and the relationship between teachers and apprentices is no less than that in the past. Netizens envy Huang Lei
guess what you like
-
Zhou Shen sang the theme song of the film "summer friends and sunny days" in mainland China. Netizen: endless aftertaste
-
Pink is Wangyuan online! Back to the peak! The new hairstyle is creamy and sassy
-
Front end interview daily 3 + 1 - day 858
-
[golang] walk into go language lesson 24 TCP high-level operation
-
August 23, 2021 Daily: less than three years after its establishment, Google dissolved the health department
-
The female doctor of Southeast University is no less beautiful than the female star. She has been married four times, and her personal experience has been controversial
-
There are many potential safety hazards in Chinese restaurant. The top of the program recording shed collapses, and the artist will fall down if he is careless
-
Anti Mafia storm: He Yun's helpless son, Sun Xing, is destined to be caught by his dry son
-
Introduction to flex flexible layout in CSS -- learning notes
-
CSS learning notes - Flex layout (Ruan Yifeng tutorial summary)
Random recommended
- Today, let's talk about the arrow function of ES6
- Some thoughts on small program development
- Unwilling to cooperate with Wang Yibo again, Zhao Liying's fans went on a collective strike and made a public apology in less than a day
- JS function scope, closure, let, const
- Zheng Shuang's 30th birthday is deserted. Chen Jia has been sending blessings for ten years. Is it really just forgetting to make friends?
- Unveil the mystery of ascension
- Asynchronous solution async await
- Analysis and expansion of Vue infinite scroll source code
- Compression webpack plugin first screen loading optimization
- Specific usage of vue3 video play plug-in
- "The story of huiyeji" -- people are always greedy, and fairies should be spotless!
- Installing Vue devtool for chrome and Firefox
- Basic usage of JS object
- 1. JavaScript variable promotion mechanism
- Two easy-to-use animation JS that make the page move
- Front end Engineering - scaffold
- Java SQL Server intelligent fixed asset management, back end + front end + mobile end
- Mediator pattern of JavaScript Design Pattern
- Array de duplication problem solution - Nan recognition problem
- New choice for app development: building mobile applications using Vue native
- New gs8 Chengdu auto show announces interior Toyota technology blessing
- Vieira officially terminated his contract and left the team. The national security club sent blessings to him
- Less than 200000 to buy a Ford RV? 2.0T gasoline / diesel power, horizontal bed / longitudinal bed layout can be selected
- How does "heart 4" come to an end? Pinhole was boycotted by the brand, Ma Dong deleted the bad comments, and no one blessed him
- We are fearless in epidemic prevention and control -- pay tribute to the front-line workers of epidemic prevention!
- Front end, netty framework tutorial
- Xiaomi 11 | miui12.5 | android11 solves the problem that the httpcanary certificate cannot be installed
- The wireless charging of SAIC Roewe rx5 plus is so easy to use!
- Upload and preview pictures with JavaScript, and summarize the most complete mybatis core configuration file
- CSS transform Complete Guide (Second Edition) flight.archives 007
- Ajax foundation - HTTP foundation of interview essential knowledge
- Cloud lesson | explain in detail how Huawei cloud exclusive load balancing charges
- [JS] 10. Closure application (loop processing)
- Left hand IRR, right hand NPV, master the password of getting rich