Front knowledge
In the next chapter, I mainly talk about Collerization and combination. In fact, Collerization is still inseparable from the closure mentioned in the last chapter. Closure is the basis for the realization of Collerization. But here needs to write a pre-knowledge, let me briefly introduce.
scope
A scope is the area of a program that defines variables and determines the accessibility of variables that are currently executing code. A scope is a code in which specific variables or functions can be accessed in a specific, independent area. Here is a small example to deepen your understanding of scopes
function test(a,b){
let innerVariable=1;
return 0;
}
// The innerVariable scope is only available within a function
let outVariable=innerVariable;
Copy the code
Classification of scopes
Before and after ES5, scopes were divided into global and function scopes. After ES6, a block-level scope was added.
Var and let const.
The figure shows that a, B are stored in the script area (block-level scope) and C are stored in the global area.
Var can float up. That is, variables defined by var can be used before they are defined. Const, let variables can float up, but they are not accessible until they are defined. If you are careful, you can see that there is a difference between using const, let variables first and then declaring an error.
Function context
Reference article (Understanding JavaScript execution Context – Zhihu.com)
closure
With the above knowledge, you can analyze closures more deeply. In short, functions that have access to other internal function variables are called closures.
function fun1() {
var a = 1;
return function fun2 () {
console.log(a);
};
}
var fn = fun1();
fn();// Form a closure to get information about the inner scope from the outside.
Copy the code
(1) Compile phase, variables and functions are declared, the scope is determined.
(2) Run function fun1(), create the execution context of fun1() function, internal storage of all variable functions in fun1() information.
(3) After fun1() is executed, the reference to fun2 is assigned to the external variable fn. The pointer to fn points to fun2. Fn is in the global scope and fun2 is in the function scope. But the internal variables of fun1() are accessed.
(4) Fn is executed globally, and console.log(a) requests a variable from the scope. If it does not find a variable in the scope, it goes up to the parent level to find the parent. The a variable was found at fun1() and returned to console.log so 1 was printed out.
Some closure based fantasy
In c++ object-oriented class members are public,private, and protected, and in terms of inheritance,private and protected are basically the same, so I’m going to treat them all as private, and private members are things that you don’t want to access, But JS does not have the private keyword. But I think a mature programming language should not only be able to complete the functional logic, but also forcibly avoid some things that shouldn’t happen from the language level. For example, members of a class that do not want to be seen by the outside world should not be avoided at the functional logic stage, but should be exposed at the time of writing the code.
Js uses the concept of closures to simulate the effect of private.
function getImformation() {
var name = "gaby";
var age = 20;
return function () {
return {
getName: function () {
return name;
},
getAge: function () {
returnage; }}; }; }var obj = getImformation()();
obj.getName();
obj.getAge();
obj.age;
Copy the code
Closures can also cause problems, they can cause problems with garbage collection. (about garbage collection, will be discussed later in the js performance optimization section) is mainly caused by variable reference, if you know c++ shared_ptr is not difficult to understand, the problem is very similar, do not have to understand.
JavaScript has an internal garbage collection mechanism, with counting methods. When a variable in memory is referenced once and counts +1, the garbage collection mechanism asks for these variables at a fixed time interval and marks variables with a count of 0 as invalid variables to clear free memory.
The fun1() function is insulated from external influences. All variables are completed inside the function. After fun1() is executed, the internal variables are theoretically destroyed and memory is reclaimed. But we wrote a closure, which caused the global scope to always have an A variable, which kept sucking up memory and causing a memory leak.
Currie,
Finally into the topic of Currization, in fact, after deep analysis of closures, currization understanding is a matter of easy solution. Currie is to compress multiple parameters of a function into one, is the dimensionality reduction of function parameters, (suddenly think of high school math teachers always say encountered higher order function first drop times ha ha ha) this thing is not the normal multi-parameter function one by one, layer by layer when the closure is written (may describe not appropriate, see the case).
// Normal multi-argument function
function add(x,y,z){
return x+y+z;
}
// After currified
function add() {
return function(x) {
return function(y) {
return function(z) {
returnx + y + z; }}}}let f = add();
// Test case
console.log(f(1) (2) (3));
Copy the code
A little bit of onion peeling off your heart layer by layer. This may seem a bit stiff, but you can actually write a separate method that returns a normal function called Curry. The Lodash library also provides this method, called Curry. Here are a few examples of curry using the Lodash library.
// Currization implements string matching numbers
const { method } = require('lodash');
const lodash = require('lodash');
let match = lodash.curry((arg, str) = > str.match(arg));
//let findSpace = match(/\s+/g);
let findNumber = match(/\d+/g);
let filter = lodash.curry((method, str) = > (lodash.filter(str, method)))
let filterNumber = filter(findNumber);
let str = "guaqiu52"
// See! Is a parameter
console.log(filterNumber(str));
Copy the code
The General implementation of the Cremation method is as follows
const curry=function(fn){
return function curryFn(. args){
if(args.length<fn.length){
return function(){
returncurryFn(... args,... arguments) } }else{
returnfn(... args); }}}Copy the code
Vue. Js source using a curry: SRC/platform/web/patch. The js in the future I will be in vue source part explain to everybody said.
combination
Between pure functions is can be merged into a more powerful function, directly on the case!
function f1() {
console.log(1);
}
function f2() {
console.log(2);
}
// composition is really a wrapper around the execution of multiple pure functions.
function compose(f1, f2) {
f1();
f2();
}
compose(f1, f2);
Copy the code
The ladash library also provides methods for composition:
Flow executes from left to right
FlowRight executes from right to left (more commonly)
Can each subpure function take more than one argument if you use flowRight to participate in the composition? The answer is that only the rightmost function can have multiple arguments. Why is that? FlowRight executes the function from right to left and takes the result of the previous function as an argument to the current function. This process can be abstracted as a pipe (my output is your input), so we cannot pass parameters to it. The rightmost function has no function to pass to it, so we can pass as many arguments as we want. (Just like if you are responsible for the water supply pipe, if one day you secretly add coke to the water, our water will taste like Coke.)
Ok! Throw a case I slip away, functional programming I also just contact, need big bull errata guidance, I say I think is also shallow that layer, functor what also did not introduce, perhaps wait for me to thoroughly understand, the heart has its own pitfalls that day can really speak through functional programming.
const { method } = require('lodash');
const lodash = require('lodash');
const reverse = arr= > arr.reverse();
const first = arr= > arr[0]
const toUpper = s= > s.toUpperCase();
const LastToUpper = lodash.flowRight(toUpper, first, reverse);
console.log(LastToUpper(['z'.'j'.'l']));
Copy the code