Editor's recommended language:
This article is designed to help you master several important higher-order programming skills in JavaScript, such as:
,
,
,
, compose
.
High-level programming
In this article, we will mainly explain what are the high-level programming ideas in JavaScript, and what practical uses do they have in projects?
Singleton design pattern
A separate instance for managing the current correlation characteristics of things, refers
and
, similar to the implementation of packet features, all the features described one example of a packet in the binding.
Take a look at a simple singleton design pattern:
let module1 = (function () {
function tools() {}
function share() {}
return {
name: 'house',
tools
};
})();
module1.tools();
Here we can expose the methods defined by the module1 module for use by external modules.
There is also a singleton pattern based on closures called: advanced singleton design pattern. Before vue/react came out, it was the most commonly used modular idea for teamwork, and it was often used for this
.
The singleton pattern in the form of closure is as follows:
let A = (function () {
function fn() {
B.getXxx();
}
function query() {}
return {
query
}
})();
let B = (function () {
function fn() {}
function getXxx() {}
A.query();
return {
getXxx
}
})();
In the above example, we can define A B
two modules separately, first declare the function in our own module, and then expose it to the other's module. This is the earliest modular idea, too
.
Lazy function
Let's first look at such an example, encapsulating a function to get the element style.
Gets the style, we usually think of window.getComputedStyle
and element.currentStyle
these two API, but their execution is conditional.
For example: the former is only Google
compatible with IE
browsers , while the latter is compatible with browsers.
function getCss(element, attr) {
if ('getComputedStyle' in window) {
return window.getComputedStyle(element)[attr];
}
return element.currentStyle[attr];
}
getCss(document.body, 'margin');
getCss(document.body, 'padding');
getCss(document.body, 'width');
From this example, we can see that if you need to get the style of the element three times, obviously you need to judge whether the method is compatible or not every time you enter the function, which causes unnecessary waste. The best solution-
thinking.
In layman's terms, the
initialization is executed during the first rendering. If the second execution is still the same effect, we need to use the idea of closure to solve this problem.
function getCss(element, attr) {
if ('getComputedStyle' in window) {
getCss = function (element, attr) {
return window.getComputedStyle(element)[attr];
};
} else {
getCss = function (element, attr) {
return element.currentStyle[attr];
};
}
//
return getCss(element, attr);
}
getCss(document.body, 'margin');
getCss(document.body, 'padding');
getCss(document.body, 'width');
In this function, when we execute the getCss function for the first time, we can already determine getComputedStyle
whether it is compatible or not, so there is no need
for the second time . According to the returned result of the first judgment, the second time is directly determined , Which one is used for the third function execution? In API
this way, every time the function is executed, there will be less
, which improves the running speed of js to a certain extent.
So let s look at this
where is reflected?
Process: In fact, it was the first time the getCss
function was executed to create the
next one
, and the getCss
function was regenerated in it, and its reference address was re-assigned to the global function getCss
, causing the
next one to getCss
be unable to be released, forming one
. Each time it is executed in the future, the small function inside is executedgetCss
.
Curriculum function
Curriculum function meaning of is to pass parameters to the function step by step, pass some parameters each time, and return a more specific function to receive the remaining parameters. In the middle, multiple layers of functions that receive some parameters can be nested until the final result is returned. .
The most basic currying split
//
function add(a, b, c) {
return a + b + c;
}
//
function addCurrying(a) {
return function (b) {
return function (c) {
return a + b + c;
}
}
}
//
add(1, 2, 3); //6
//
addCurrying(1)(2)(3) //6
It is currying function addCurrying
each time
and use
, until after the three parameters are passed, the function returns inside the last execution
, in fact, is full use of
to achieve.
Package Ke Lihua general type
The currying function above is not involved
, nor is it universal, and cannot be converted to a function with an arbitrary or unknown number of formal parameters. .
Let's encapsulate a universal currying conversion function , which can convert any function into currying.
//add
function add (a,b,c,d) {
return a+b+c+d
}
function currying (fn, ...args) {
//fn.length
//args.length currying
// add (a,b,c,d) currying(add,1,2,3,4)
if (fn.length === args.length) {
return fn(...args)
} else {
// newArgs
return function anonymous(...newArgs) {
//
let allArgs = [...args, ...newArgs]
return currying(fn, ...allArgs)
}
}
}
let fn1 = currying(add, 1, 2) //3
let fn2 = fn1(3) //6
let fn3 = fn2(4) //10
Curriculum function thought
use
and store some information in advance (the idea of preprocessing)
We use one
to describe:
function currying(...outerArgs) {
return function anonymous (...innerArgs) {
let args = outerArgs.concat(innerArgs)
return args.reduce((previousValue, currentValue) => previousValue + currentValue)
}
}
let fn1 = currying(1, 2)
let fn2 = fn1(3)
let fn3 = fn2(4)
Supplement what is the thought of preprocessing:
In the first
fn1
time the function is executed, it creates a function execution context, the local variables 1, 2 stored in the context of the day, after the executionfn2 fn3
time, you need to getfn1
a return result, using the stored 1, 2 parameters , This mechanism forms
reduce
The little friend who didn't understand came over:
Case 1: When reduce has no second parameter
let Array = [10, 20, 30, 40, 50];
Array.reduce(previousValue, currentValue, currentIndex, arr){
return previousValue + currentValue;
}
- When the function is triggered for the first time, previousValue is the first item (
10
), and currentValue is the second item (20
) - When the function is triggered for the second time, previousValue is
30
), currentValue is the third item (30
) - When the function is triggered for the X time, the previousValue is
X+1
item - currentIndex: corresponds to
currentValue
the index value - arr: is a constant array itself
Case 2: When reduce has a second parameter
let Array = [10, 20, 30, 40, 50];
Array.reduce((previousValue, currentValue, currentIndex, arr){
return previousValue + currentValue;
}, 0)
- When the function is triggered for the first time, previousValue is the second parameter (
0
), and currentValue is the first item (10
) - When the function is triggered for the second time, previousValue is
10
), currentValue is the second item (20
) - When the function is triggered for the X time, the previousValue is
X
item - currentIndex: corresponds to
currentValue
the index value - arr: is a constant array itself
compose function
compose combination function : flattening multi-level function nested calls
compose function often based on reduce
ideas to solve the
problem:
In the project, we often encounter such a problem:
const fn1 = x => x + 10;
const fn2 = x => x - 10;
const fn3 = x => x * 10;
const fn4 = x => x/10;
console.log(fn3(fn1(fn2(fn1(4)))))
In the above example, it is obvious that the level of nesting is deeper, and
the idea of calling is needed at this time
Function call flattening : If it is a multi-level nested call function, after calling a function, pass it to the next function as the actual parameter of another function
Solution: execute sequentially from left to right
/**
* @param funcs ( ) => [fn1, fn3, fn2, fn4]
* @param args ( ) => [5]
*/
function compose(...funcs) {
return function anonymous(...args) {
if(funcs.length === 0) return args;
if(funcs.length === 1) return funcs[0](...args);
//funcs
return funcs.reduce((n, func) => {
//
//n func
//
//n func func
return Array.isArray(n) ? func(...n) : func(n);
}, args)
}
}
let res = compose(fn1, fn3, fn2, fn4)(5)
//
console.log(compose()(5)); //=>5
console.log(compose(fn1)(5)); //=>5+10 = 15
console.log(compose(fn1, fn3)(5)); //=>fn1(5)=15 fn3(15)=150
console.log(compose(fn1, fn3, fn2)(5)); //=>fn1(5)=15 fn3(15)=150 fn2(150)=140
console.log(compose(fn1, fn3, fn2, fn4)(5)); //=>fn1(5)=15 fn3(15)=150 fn2(150)=140 fn4(140)=14
The flat execution process of the compose function:
-
compose()(5), if no function parameter is passed in the compose() function, it will directly return the following parameter 5
-
compose(fn1, fn3, fn2, fn4)(5), execute fn1(5) first, and then transfer the result of fn1(5) to fn3, such as fn3(fn1(5)) => fn3(15), By analogy fn2(fn3(fn1(5))) => fn4(150), later
Array.prototype.reduce
method -
reduce
The second parameter set is to unifyn
the return result of each function (the first timen
is 5, whichfunc
is fn1), and thefn1(5)
function needs to be executed again. It can be seen that the necessity of the second parameter is to unify each time The result of the callback function isnumber
Functional programming and imperative programming
Callback function : pass a function as a value to another function, and execute this function in another function (this is an important knowledge to realize functional programming)
Functional programming :,
don t care about the process, leave the process to others to handle, reflect
(advocate)
Imperative programming :,
you need to implement the process yourself
Functional programming :
Encapsulate as an API method, we only need to call the API method in the future to get the desired result.
let arr = [10, 20, 30, 40, 50];
let res = arr.reduce((n, item) => {
return n + item;
});
Imperative programming : implement the main logic with code and focus on the process
let res = 0;
for (let i = 0; i < arr.length; i++) {
res += arr[i];
}
After reading three things
If you think this content is quite helpful to you, I would like to invite you to do three small favors for me:
- Like, repost so that more people can see the introduction content (collecting or not like, it is a hooligan!!)
- Pay attention to the public account "Front-end Time House" and share original knowledge from time to time.
- At the same time, you can look forward to follow-up articles ing
You can also come to my personal blog:
Front-end time house: www.javascriptlab.top/