preface
Design patterns are a necessary skill for a programmer to advance to a higher level. They are also the touchstone for judging an engineer’s work experience and ability. Design pattern is the condensed and summary of programmers’ years of work experience, which can optimize the code to a greater extent and reconstruct the existing code reasonably. As a qualified front-end engineer, learning design patterns is another way to summarize and reflect on my work experience, as well as an important means to develop high-quality, maintainable and extensible code.
We are familiar with several major frameworks of Gold Canon, such as jquery, React and VUE, which also apply a lot of design patterns, such as observer pattern, agent pattern, singleton pattern and so on. So as an architect, design patterns are a must.
In the process of interview for middle and senior front end engineers, the interviewer will also properly investigate the applicant’s understanding of design patterns. Therefore, the author summarizes and draws a mind map and practical cases for javascript design patterns based on years of work experience and learning and exploration. Let’s explore and learn together next.
You will reap
- The singleton pattern
- Constructor pattern
- Builder mode
- The proxy pattern
- The appearance model
- Observer mode
- The strategy pattern
- Iterator pattern
The body of the
Let’s start with the overview. What can design patterns do for us?
Code can be decoupled
scalability
reliability
organized
reusability
1. Singletons
1.1 Concept Interpretation
Singleton pattern: ensure that a class has only one instance, generally judge whether the instance exists, if there is a direct return, do not exist then create and return, so that a class can be guaranteed to have only one instance object.
1.2 role
- Intermodule communication
- Guarantee the uniqueness of the objects of a class
- Prevention of variable contamination
1.3 Precautions
- Using this correctly
- Closures are prone to memory leaks, so clean up unnecessary variables in a timely manner
- Creating a new object is expensive
1.4 Actual Cases
Singleton pattern is widely used in different programming languages, in the actual software application application more such as computer task manager, recycle bin, website counter, multi-threaded thread pool design.
1.5 Code implementation
(function(){
// Fish farming game
let fish = null
function catchFish() {
// If the fish exists, return directly
if(fish) {
return {
fish,
water: function() {
let water = this.fish.getAttribute('weight')
this.fish.setAttribute('weight', ++water)
}
}else {
// If the fish doesn't exist, get the fish and return it
fish = document.querySelector('#cat')
return {
fish,
water: function() {
let water = this.fish.getAttribute('weight')
this.fish.setAttribute('weight', ++water)
}
}
}
}
// Give water every three hours
setInterval((a)= > {
catchFish().water()
}, 3*60*60*1000)
})()
Copy the code
2. Constructor pattern
Concept of interpretation
Constructor pattern: Used to create objects of specific types for reuse of business logic and functionality.
role
- Creates an object of a specific type
- Encapsulation of logic and business
Matters needing attention
- Pay attention to the boundaries of your business logic
- With singleton to achieve initialization and other work
- Constructor naming convention, first letter capitalized
- New object, putting public methods on the prototype chain
The actual case
The constructor pattern, I think, is a pattern of code and a test of how well the programmer understands the business code. It is often used by libraries of tools that implement javascript, such as Lodash, and javascript frameworks.
The code shown
function Tools(){
if(! (this instanceof Tools)){
return new Tools()
}
this.name = 'JS library'
// Get the DOM method
this.getEl = function(elem) {
return document.querySelector(elem)
}
// Check whether it is an array
this.isArray = function(arr) {
return Array.isArray(arr)
}
// Other general methods...
}
Copy the code
3. Builder mode
Concept of interpretation
Builder pattern: Take a complex logic or function and work it out in a structured way.
role
- Distribution creates a complex object or implements a complex function
- Decouple the encapsulation process without paying attention to the details of specific creation
Matters needing attention
- It needs to be supported by reliable algorithms and logic
- Expose certain interfaces as needed
The actual case
In fact, the builder pattern is also used in many fields. I have written many JS plug-ins before, most of which use the builder pattern. You can learn the reference on github. Other cases are as follows:
- Jquery’s Ajax wrapper
- Jquery Plug-in Encapsulation
- React/VUE specific component design
The code shown
The author will take the previous use of builder pattern to achieve a case :Canvas entry practical use of javascript object-oriented implementation of a graphic captcha, let us use the builder pattern to achieve a very common captcha plug-in!
// Canvas draws the graph verification code
(function(){
function Gcode(el, option) {
this.el = typeof el === 'string' ? document.querySelector(el) : el;
this.option = option;
this.init();
}
Gcode.prototype = {
constructor: Gcode,
init: function() {
if(this.el.getContext) {
isSupportCanvas = true;
var ctx = this.el.getContext('2d'),
// Set the canvas width and height
cw = this.el.width = this.option.width || 200,
ch = this.el.height = this.option.height || 40,
textLen = this.option.textLen || 4,
lineNum = this.option.lineNum || 4;
var text = this.randomText(textLen);
this.onClick(ctx, textLen, lineNum, cw, ch);
this.drawLine(ctx, lineNum, cw, ch);
this.drawText(ctx, text, ch); }},onClick: function(ctx, textLen, lineNum, cw, ch) {
var _ = this;
this.el.addEventListener('click'.function(){
text = _.randomText(textLen);
_.drawLine(ctx, lineNum, cw, ch);
_.drawText(ctx, text, ch);
}, false)},// Draw the interference line
drawLine: function(ctx, lineNum, maxW, maxH) {
ctx.clearRect(0.0, maxW, maxH);
for(var i=0; i < lineNum; i++) {
var dx1 = Math.random()* maxW,
dy1 = Math.random()* maxH,
dx2 = Math.random()* maxW,
dy2 = Math.random()* maxH;
ctx.strokeStyle = 'rgb(' + 255*Math.random() + ', ' + 255*Math.random() + ', ' + 255*Math.random() + ') '; ctx.beginPath(); ctx.moveTo(dx1, dy1); ctx.lineTo(dx2, dy2); ctx.stroke(); }},/ / draw text
drawText: function(ctx, text, maxH) {
var len = text.length;
for(var i=0; i < len; i++) {
var dx = 30 * Math.random() + 30* i,
dy = Math.random()* 5 + maxH/2;
ctx.fillStyle = 'rgb(' + 255*Math.random() + ', ' + 255*Math.random() + ', ' + 255*Math.random() + ') ';
ctx.font = '30px Helvetica';
ctx.textBaseline = 'middle'; ctx.fillText(text[i], dx, dy); }},// Generate a specified number of random characters
randomText: function(len) {
var source = ['a'.'b'.'c'.'d'.'e'.'f'.'g'.'h'.'i'.'j'.'k'.'l'.'m'.'o'.'p'.'q'.'r'.'s'.'t'.'u'.'v'.'w'.'x'.'y'.'z'];
var result = [];
var sourceLen = source.length;
for(var i=0; i< len; i++) {
var text = this.generateUniqueText(source, result, sourceLen);
result.push(text)
}
return result.join(' ')},// Generate unique characters
generateUniqueText: function(source, hasList, limit) {
var text = source[Math.floor(Math.random()*limit)];
if(hasList.indexOf(text) > - 1) {
return this.generateUniqueText(source, hasList, limit)
}else {
return text
}
}
}
new Gcode('#canvas_code', {
lineNum: 6
})
})();
/ / call
new Gcode('#canvas_code', {
lineNum: 6
})
Copy the code
4. Proxy mode
Concept of interpretation
Proxy pattern: One object controls access to another through some kind of proxy.
role
- Remote proxy (local proxy of one object to another)
- Virtual proxies (you can use thumbnails instead of real images if you need to create expensive objects such as rendering a large web page)
- Secure proxy (protects access to real objects)
- Caching proxy (some expensive operations provide temporary storage, and the next operation, if passed the same parameters as before, can directly return the stored operation results)
Matters needing attention
Using proxies can add complexity to your code, so use them selectively.
The actual case
We can use the proxy pattern to implement the following functions:
- Optimize computational performance by caching proxies
- Image placeholder/skeleton screen/preload etc
- Merge requests/resources
The code shown
Next, let’s talk about the proxy pattern by implementing a computational cache.
// Cache proxy
function sum(a, b){
return a + b
}
let proxySum = (function(){
let cache = {}
return function(){
let args = Array.prototype.join.call(arguments.', ');
if(args in cache){
return cache[args];
}
cache[args] = sum.apply(this.arguments)
return cache[args]
}
})()
Copy the code
5. Appearance mode
Concept of interpretation
Facade: Provides a consistent representation of a set of interfaces in a subsystem, making the subsystem easier to use without having to focus on the complex and cumbersome details inside. For example, the following is a good illustration of the design idea of the appearance mode:
role
- There is some decoupling between the interface and the caller
- Create a classic three-tier MVC structure
- In the development phase, the dependency and coupling between different subsystems are reduced, which facilitates the iteration and extension of each subsystem
- Provide a clear interface to large complex systems
Matters needing attention
There is a performance penalty when the look and feel pattern is called consecutively by the developer because of the availability checks that are performed on each call
The actual case
We can use the facade pattern to design methods for event binding that are compatible with different browsers and other methods or abstract classes that require a uniform implementation of the interface.
The code shown
Next, let’s understand how the appearance pattern works by implementing a browser-compatible event listener function.
function on(type, fn){
// For supporting dom2 level event handlers
if(document.addEventListener){
dom.addEventListener(type,fn,false);
}else if(dom.attachEvent){
// For Internet Explorer 9 below Internet Explorer
dom.attachEvent('on'+type,fn);
}else {
dom['on'+ type] = fn; }}Copy the code
6. Observer mode
Concept of interpretation
Observer pattern: Defines a one-to-many relationship in which all observation objects listen to a topic object at the same time and notify all observer objects when the topic object’s state changes, allowing them to automatically update themselves.
role
- There is a dynamic relationship between the target object and the observer, which increases flexibility
- Support for simple broadcast communication, automatically notify all subscribed objects
- The abstract coupling between the target object and the observer can be independently extended and reused
Matters needing attention
Observer mode generally should pay attention to listen first, then trigger (special cases can also be published first, then subscribe, such as QQ offline mode)
The actual case
The observer mode is a classic design pattern with the following main applications:
- System Message Notification
- Web log Recording
- Content subscription
- Javascript event mechanism
- Observer of React/Vue etc
The code shown
Next we implement an observer mode using native javascript:
class Subject {
constructor() {
this.subs = {}
}
addSub(key, fn) {
const subArr = this.subs[key]
if(! subArr) {this.subs[key] = []
}
this.subs[key].push(fn)
}
trigger(key, message) {
const subArr = this.subs[key]
if(! subArr || subArr.length ===0) {
return false
}
for(let i = 0, len = subArr.length; i < len; i++) {
const fn = subArr[i]
fn(message)
}
}
unSub(key, fn) {
const subArr = this.subs[key]
if(! subArr) {return false
}
if(! fn) {this.subs[key] = []
} else {
for (let i = 0, len = subArr.length; i < len; i++) {
const _fn = subArr[i]
if (_fn === fn) {
subArr.splice(i, 1)}}}}}/ / test
/ / subscribe
let subA = new Subject()
let A = (message) = > {
console.log('Subscriber receives message:' + message)
}
subA.addSub('A', A)
/ / release
subA.trigger('A'.'I'm Xu Xiaoxi') // A Received message: --> My name is Xu Xiaoxi
Copy the code
7. Policy mode
Concept of interpretation
Policy mode: The policy mode can classify different algorithms reasonably and encapsulate them individually, so that different algorithms can be replaced with each other without affecting the users of the algorithms.
role
- Different implementation, consistent effect
- The invocation mode is the same, reducing the cost of use and the coupling between different algorithms
- Separate algorithm models are defined to facilitate unit testing
- Avoid redundant code judgments such as if else and so on
The actual case
- Implement more elegant form validation
- The character scorer in the game
- The winning and losing algorithm of board and card games
The code shown
Next, let’s implement a pattern for implementing summation algorithms based on different types to help you understand the strategy pattern.
const obj = {
A: (num) = > num * 4.B: (num) = > num * 6.C: (num) = > num * 8
}
const getSum =function(type, num) {
return obj[type](num)
}
Copy the code
8. Iterator pattern
Concept of interpretation
Iterator pattern: Provides a way to access the elements of an aggregate object sequentially, without the consumer having to care about the method’s internal representation.
role
- Provides a uniform interface for traversing different collections
- A way to protect the original collection but provide external access to internal elements
The actual case
The most common examples of iterator patterns are array traversal methods such as forEach, Map, and Reduce.
The code shown
The next step is to give you a better understanding of the iterator pattern by wrapping an iterator function that not only iterates through arrays and strings, but also through objects. The [iteratee=_.identity] method is also a typical application of the policy pattern.
function _each(el, fn = (v, k, el) = >{{})// Determine the data type
function checkType(target){
return Object.prototype.toString.call(target).slice(8.- 1)}// Array or string
if(['Array'.'String'].indexOf(checkType(el)) > - 1) {
for(let i=0, len = el.length; i< len; i++) {
fn(el[i], i, el)
}
}else if(checkType(el) === 'Object') {
for(let key in el) {
fn(el[key], key, el)
}
}
}
Copy the code
The last
If you want to know the complete mind map of this article, more H5 games, Webpack, node, gulp, CSS3, javascript, nodeJS, Canvas data visualization knowledge and practical front-end, welcome to join us in the public number “Interesting Talk front-end” to learn and discuss, and explore the boundary of the front end.
More recommended
- 2 years of vUE project practical experience summary
- Quickly implement a customizable progress bar component in Master React/Vue Component Design
- Master React/Vue Component Design creates materialui-like button click animations with pure CSS and encapsulates react components
- In 2019, take a look at some of my top questions and advice for job seekers
- Re-encapsulates a real-time preview jsoneditor component based on jsonEditor (React version)
- “Front-end combat summary” the use of pure CSS website skin and focus diagram switch animation
- “Front-end combat summary” using CSS3 to achieve cool 3D rotation perspective
- Add a loading progress bar to your site using pace. Js
- The Application of design Pattern of “Summary of Front End Actual Combat” — Memorandum Pattern
- “Front End Combat Summary” using postMessage to achieve pluggable cross-domain chatbot
- “Front-end combat summary” of the variable promotion, function declaration promotion and variable scope detailed explanation
- “Front-end combat summary” how to change the URL without refreshing the page
- A picture shows you how to play vue-Cli3 quickly
- Vue Advanced Advanced series – Play with Vue and vuex in typescript
- Implementing a CMS full stack project from 0 to 1 based on nodeJS (Part 1)
- Implementing a CMS full stack project from 0 to 1 based on nodeJS (middle)
- Implement a CMS full stack project from 0 to 1 based on nodeJS (Part 2)
- Write a mock data server using nodeJS in 5 minutes
- With CSS3 to achieve stunning interviewers background that background animation (advanced source)
- Teach you to use 200 lines of code to write a love bean spell H5 small game (with source code)
- Cartesian product is implemented and applied in javascript